BurpSuite 插件开发-Montoya Api

BurpSuite 插件开发 - Montoya Api

今年十月份,PortSwigger 发布了新版本的 BurpSuite,其中包含了新版本的 Montoya 插件 API,并宣布会逐步放弃支持旧版插件

github 上的 Api 跟 Burp 导出的 Api 不一样,所以建议使用 Maven 或 Gradle 创建项目,但是不知道为什么有时候下载的包含注释有时候不含

新建项目

初始化

环境:IntelliJ IDEA、JDK 1.8

然后在 build.gradle 文件内添加 implementation 'net.portswigger.burp.extensions:montoya-api:+' 这句话

或者在 pom.xml 中添加( 创建时选择 Maven)

<dependencies>
    <dependency>
        <groupId>net.portswigger.burp.extensions</groupId>
        <artifactId>montoya-api</artifactId>
        <version>LATEST</version>
    </dependency>
</dependencies>

相较于之前一锅炖的情况,此次 Burp 贴心的帮我们分了类

不难看出,collaborator、comparer、decoder、intruder、proxy、repeater、scanner、scope、sitemap、是与 Burp 上的功能相对应的,那也就能猜出 Api 所提供的能力应该也与之对应

剩下的,core、http、internal、logging、burpsuite、persistence、ui、utilities、websocket 提供了 Burp 其他能力

设置打包

首先打开 File->Project Structure,项目结构设置

然后再看到 Project Settings->Artifacts,点击+号,新建一个导出格式,注意选择From modules with xxx

实现插件入口

新建一个 package,并创建一个类,实现 BurpExtension 接口

然后点击 Build->Build Artifacts 即可打包 jar 文件

打包时可能会出现错误说 xx 函数不能为 private,删除这个函数的 private 关键字即可

Montoya Api

首先来看一下在初始化插件时提供的 montoyaApi 吧,家人们

很多地方都会用到这个 Api,所以可以把它定义为一个 public static 变量,方便在其他地方使用它提供的功能

extension()

提供插件 相关信息

void setName(String extensionName)

很显然,就是用来设置插件名称的

String filename()

返回插件 jar 文件所在位置

如:C:\I\Love\You\Desktop\JAVA\MontoyaExt\MontoyaExt.jar

boolean isBapp()

判断插件是不是来自官方的 BappStore

void unload()

卸载(关闭)插件

Registration registerExtensionUnloadHandler(ExtensionUnloadHandler handler)

用于注册插件卸载监听器,需要自行实现 ExtensionUnloadHandler 接口才可以,那么如何注册呢?后面写。

burpSuite()

Version version()

获取 burp 的版本,返回一个 Version 对象,至于这个对象有怎样的属性以及方法,可以点击查看

例如,获取Burp是 Professional、Community Edition、Enterprise Edition 中那个版本即可这样使用

String edition = Api.burpSuite().version().edition().name;

List<String> commandLineArguments()

返回一个包含命令行启动 Burp 时参数的 List<String>

String exportProjectOptionsAsJson(String... paths)

导出 Burp project 的配置信息,其参数为 paths 可能不太好理解,其实就是 json 文件中的某些键,如果为空的话,则表示导出所有配置信息

例如我只想导出 Proxy 的 Options 的 Proxy Listenters 以及 Repeater 的配置,就可以这样写

String configString = Api.burpSuite().exportProjectOptionsAsJson("proxy.request_listeners","repeater");

void importProjectOptionsFromJson(String json)

与 exportProjectOptionsAsJson 相反,从 json 字符串中导入Burp 配置信息

void shutdown(ShutdownOptions... options)

关闭 Burp,其中关闭参数 ShutdownOptions 目前只有一个选项:PROMPT_USER,会在关闭时弹窗提示,如果不填的话则是直接关闭(千万在测试的时候写上 PROMPT_USER,否则的话之后就打不开 Burp 了,除非删除或移动 jar 文件位置,快快给我这种脚本小子上一课吧)

logging()

很显然,用来打印信息的

void logToOutput(String message)

打印日志信息,输出到 Burp

void logToError(String message)

打印错误信息,输出到 Burp

PrintStream error()

返回一个日志输出流,同样的会打印在 log 窗口

PrintStream logStream = api.logging().output();
logStream.print("aaaa");

PrintStream output()

返回一个错误输出流,同上,不过是打印在 error 窗口

void raiseInfoEvent(String message)

在 Dashboard 页的 Event log 处记录一个 Info 等级的日志

void raiseCriticalEvent(String message)

记录一个 Critical 等级的日志

void raiseDebugEvent(String message)

记录一个 Debug 等级的日志

void raiseErrorEvent(String message)

记录一个 Error 等级的日志

userInterface()

主要是一些 UI 相关的功能

void applyThemeToComponent(Component component)

用来将 Burp 风格的样式应用到用户实现的 UI 页面上,比如字体大小、颜色等

JPanel myUI = new JPanel();
api.userInterface().applyThemeToComponent(myUI);

SwingUtils swingUtils()

返回一个 SwingUtils 类,该类的方法可以操作一些 ui 相关的东西,具体我也没用过

Registration registerSuiteTab(String title, Component component)

用来注册一个同 Proxy、Repeater 同级别的 Tab 页面,如:

JPanel myUI = new JPanel();
api.userInterface().registerSuiteTab("Test",myUI);

HttpRequestEditor createHttpRequestEditor(EditorOptions options)

用来创建一个类似 Proxy 页面中的 Request 界面,其中传的 EditorOptions 参数只有 READ_ONLY 可选,表示只读,如果不传则表示可读可写

JPanel myUI = new JPanel();
HttpRequestEditor myRequestEditor = api.userInterface().createHttpRequestEditor(READ_ONLY );
myUI.add(myRequestEditor.uiComponent());
api.userInterface().registerSuiteTab("Test",myUI);

HttpResponse createHttpResponseEditor(EditorOptions options)

用来创建一个类似 Proxy 页面中的 Response 界面

RawEditor createRawEditor(EditorOptions options)

用来创建一个原生编辑框,与另外两个相比其实区别不大,只是少了几个方法而已

Theme currentTheme()

返回一个主题常量:DARK、LIGHT

Registration registerContextMenuItemsProvider(ContextMenuItemsProvider provider)

用来注册一个右键菜单,其中 ContextMenuItemsProvider 参数需要自己创意一个类并实现ContextMenuItemsProvider 接口

public class MontoyaExt implements BurpExtension {
    public static MontoyaApi Api;
    @Override
    public void initialize(MontoyaApi montoyaApi) {
        Api = montoyaApi;
        Api.extension().setName("Test");
        api.userInterface().registerContextMenuItemsProvider(new MyContextMenus());
    }

    private class MyContextMenus implements ContextMenuItemsProvider{

        @Override
        public List<JMenuItem> provideMenuItems(ContextMenuEvent event) {
            ArrayList<JMenuItem> menus = new ArrayList<>();
            JMenuItem TestJMenuItem = new JMenuItem("Test");
            TestJMenuItem.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    Api.logging().logToOutput("Test");
                }
            });
            menus.add(TestJMenuItem);
            return menus;
        }
    }
}

Registration registerHttpRequestEditorProvider(ExtensionHttpRequestEditorProvider provider)

用来注册一个自定义的 Http 请求编辑框

package extension;

import burp.api.montoya.BurpExtension;
import burp.api.montoya.MontoyaApi;
import burp.api.montoya.http.message.HttpRequestResponse;
import burp.api.montoya.http.message.requests.HttpRequest;
import burp.api.montoya.ui.Selection;
import burp.api.montoya.ui.editor.HttpRequestEditor;
import burp.api.montoya.ui.editor.extension.EditorMode;
import burp.api.montoya.ui.editor.extension.ExtensionHttpRequestEditor;
import burp.api.montoya.ui.editor.extension.ExtensionHttpRequestEditorProvider;

import javax.swing.*;
import java.awt.*;

public class MyExtension implements BurpExtension {
    public static MontoyaApi Api;
    ExtensionHttpRequestEditor myExtensionHttpRequestEditor;
    @Override
    public void initialize(MontoyaApi montoyaApi) {
        Api = montoyaApi;
        montoyaApi.extension().setName("Test");

        this.myExtensionHttpRequestEditor = new MyExtensionHttpRequestEditor();

        Api.userInterface().registerHttpRequestEditorProvider(new MyExtensionHttpRequestEditorProvider());
    }
    private class MyExtensionHttpRequestEditorProvider implements ExtensionHttpRequestEditorProvider {

        @Override
        public ExtensionHttpRequestEditor provideHttpRequestEditor(HttpRequestResponse httpRequestResponse, EditorMode editorMode) {
            return myExtensionHttpRequestEditor;
        }
    }

    private class MyExtensionHttpRequestEditor implements ExtensionHttpRequestEditor{

        HttpRequestResponse MyHttpRequestResponse;
        JPanel MainPanel;
        HttpRequestEditor MyHttpRequestEditor;
        MyExtensionHttpRequestEditor(){
            this.MainPanel = new JPanel();
            MyHttpRequestEditor = Api.userInterface().createHttpRequestEditor();
            this.MainPanel.add(MyHttpRequestEditor.uiComponent());
        }
        @Override
        public HttpRequest getHttpRequest() {
            return this.MyHttpRequestResponse.httpRequest().addHeader("111","222");
        }

        @Override
        public void setHttpRequestResponse(HttpRequestResponse httpRequestResponse) {
            this.MyHttpRequestResponse = httpRequestResponse;
        }

        @Override
        public boolean isEnabledFor(HttpRequestResponse httpRequestResponse) {
            return true;
        }

        @Override
        public String caption() {
            return "Test";
        }

        @Override
        public Component uiComponent() {
            return this.MainPanel;
        }

        @Override
        public Selection selectedData() {
            return null;
        }

        @Override
        public boolean isModified() {
            return false;
        }
    }
}

Registration registerHttpResponseEditorProvider(ExtensionHttpResponseEditorProvider provider)

用来注册一个自定义的 Http 响应编辑框,同上

http()

http 请求相关功能

HttpRequestResponse issueRequest()

用来发起 http 请求,这个方法有三个不同的重载

  • HttpRequestResponse issueRequest(HttpRequest request)

  • HttpRequestResponse issueRequest(HttpRequest request, HttpMode httpMode)

  • HttpRequestResponse issueRequest(HttpRequest request, HttpMode httpMode, String connectionId)

其中,request 是一个 HttpRequest 对象;httpMode 是请求协议,有AUTO、HTTP_1、HTTP_2、HTTP_2_IGNORE_AlPN;connectionId 表示“要使用的连接的标识符”,不懂

ResponseKeywordsAnalyzer createResponseKeywordsAnalyzer(List<String> list)

用于创建新的响应关键字分析器,

ResponseVariationsAnalyzer createResponseVariationsAnalyzer()

创建新的响应变化分析器

Registration registerHttpHandler(HttpHandler httpHandler)

注册一个处理 Http 请求的监听器,所有经过 Proxy、Repeater... 的请求都会被它捕获,需要自行实现一个继承 HttpHandler 接口的类

Registration registerSessionHandlingAction(SessionHandlingAction sessionHandlingAction)

注册自定义会话处理操作。每个注册的操作都将在会话处理规则UI中提供,供用户选择作为规则操作。用户可以选择直接调用操作,也可以选择在宏执行之后调用操作

CookieJar cookieJar()

返回一个 CookieJar 对象,这个一般是用来构建 HttpRequest 对象用的

utilities()

提供一些编码工具

Base64Utils base64Utils()

返回一个 Base64Utils 对象,该对象内有针对 Base64 加解密的方法

例如实现base64解密:

Base64Utils MyBase64Utils = Api.utilities().base64Utils();
byte[] ByteResult = MyBase64Utils.getDecoder().decode("MW5kZXg=");

ByteUtils MyByteUtils = Api.utilities().byteUtils();
String StringResult = MyByteUtils.convertToString(ByteResult);

Api.logging().logToOutput(StringResult);

ByteUtils byteUtils()

返回一个 ByteUtils 对象,常用于byte与String之间的互相转换

CompressionUtils compressionUtils()

返回一个 CompressionUtils 对象,用于压缩数据

CryptoUtils cryptoUtils()

返回一个 CryptoUtils 对象,用于加密,例如实现 MD5 加密

ByteUtils MyByteUtils = Api.utilities().byteUtils();
CryptoUtils MyCryptoUtils = Api.utilities().cryptoUtils();
ByteArray MyByteArray = ByteArray.byteArray("1ndex");
ByteArray ResultByteArray = MyCryptoUtils.generateDigest(MyByteArray, DigestAlgorithm.MD5);
String EncryptString = MyByteUtils.convertToString(ResultByteArray.getBytes());
Api.logging().logToOutput(EncryptString);

HtmlUtils htmlUtils()

返回一个 HtmlUtils 对象,用于处理 HTML 编码解码

NumberUtils numberUtils()

返回一个 NumberUtils 对象,用于将如16进制字符串转换成文本字符串

RandomUtils randomUtils()

返回一个 RandomUtils 对象,用于创建一个随机长度的字符串

StringUtils stringUtils()

返回一个 StringUtils 对象,用于HEX与ASCII之间的相互转换

URLUtils urlUtils()

返回一个 URLUtils 对象,用于 URL 编解码

siteMap()

返回一个 SiteMap 对象,用来查询、修改 Burp 中的 SiteMap

void add(AuditIssue aduitIssue)

添加 SiteMap 记录,需要传一个 AuditIssue 对象参数

void add(HttpRequestResponse httpRequestResponse)

通过一个 HttpRequestResponse 对象添加一个添加 SiteMap 记录

List<AuditIssue> Issues()

获取所有 SiteMap 内容

List<AuditIssue> Issues(SiteMapFilter siteMapFilter)

获取符合条件的 SiteMap 内容,需要传一个 SiteMapFilter 对象参数

List<HttpRequestResponse> requestResponses()

获取SiteMap中所有的 HttpRequestResponse 对象

List<HttpRequestResponse> requestResponses(SiteMapFilter siteMapFilter)

获取符合条件的 SiteMap 内容

scope()

返回一个 Scope 对象,用来查询、添加 Burp 中的 Scope 内容

void includeInScope(String url)

用来往Include in scope中添加记录

Api.scope().includeInScope("https://xxx.com/a/b/c");

void excludeFromScope(String url)

用来往Exclude from scope中添加记录

boolean isInScope(String url)

判断某个记录是否在 Include in scope 记录里,注意没有 Enabled 的即使存在该记录仍返回 false

Registration registerHandler(ScopeChangeHandler handler)

用于注册一个scope变更监听器,需要传一个 ScopeChangeHandler 对象

persistence()

提供缓存相关功能

TemporaayFile temporaayFile()

返回一个 TemporaayFile 对象,使用该对象中的方法可以设置缓存、获取缓存

比方其中的 setxxx(String key, X xxx) 方法便是用来设置缓存的,getxxx(String key) 便是用来获取对应缓存的

Preferences preferences()

返回一个 Preferences 的 JAVA 缓存对象,该类允许从java首选项存储中存储和访问数据(对此我是一窍不通)

proxy()

提供 Proxy 面板中相关的一些功能

void disableIntercept()

很显然,关闭拦截

void enableIntercept()

很显然,开启拦截

List<ProxyRequestResponse> history()

获取所有 Proxy 中的请求历史

List<ProxyRequestResponse> history(ProxyHistoryFilter proxyHistoryFilter)

获取符合条件的 Proxy 中的请求历史,需要传一个 ProxyHistoryFilter 对象

Registration registerRequestHandler(ProxyHttpRequestHandler proxyHttpRequestHandler)

注册一个 Proxy 请求处理监听器,每一个流经 Proxy 的请求都会被 ProxyHttpRequestHandler 处理

Registration registerResponseHandler(ProxyHttpResponseHandler proxyHttpResponseHandler)

注册一个 Proxy 响应处理监听器,每一个流经 Proxy 的响应都会被 ProxyHttpResponseHandler 处理

Registration registerWebSocketCreationHandler(ProxyWebSocketCreationHandler proxyWebSocketCreationHandler)

注册一个 WebSocket 处理监听器,每一个流经 Proxy 的 WebSocket 时都会被 ProxyWebSocketCreationHandler 处理

websockets()

websocket 相关功能

Registration registerWebSocketCreationHandler(ProxyWebSocketCreationHandler proxyWebSocketCreationHandler)

注册一个 WebSocket 处理监听器,任何 Burp 工具创建 WebSocket 时都会被 ProxyWebSocketCreationHandler 处理

collaborator()

提供 Collaborator 面板相关功能,相当于一个 dnslog

CollaboratorClient createClient()

创建一个 CollaboratorClient 客户端,因为这个服务器在国外,所以访问可能会存在一些问题

CollaboratorClient restoreClient(SecretKey secretKey)

恢复一个创建过的 CollaboratorClient 客户端

comparer()

提供 Comparer 面板相关功能

void sendToComparer(ByteArray... byteArrays)

将信息发送到 Comparer 面板

Api.comparer().sendToComparer(ByteArray.byteArray("1ndex"),ByteArray.byteArray("2ndex"));

decoder()

提供 Decoder 面板相关功能

void sendToDecoder(ByteArray... byteArrays)

将信息发送到 Decoder 面板

intruder()

提供 Intruder 面板相关功能

void sendToIntruder(HttpRequest httpRequest)

将请求发送到 Intruder 面板

void sendToIntruder(Httpservice httpService,HttpRequestTemplate httpRequestTemplate)

将请求发送到 Intruder 面板

Registration registerPayloadGeneratorProvider(PayloadGeneratorProvider payloadGeneratorProvider)

注册一个 Intruder 有效负载生成器

Registration registerPayloadProcessor(PayloadProcessor payloadProcessor)

注册一个 PayloadProcessor

package extension;

import burp.api.montoya.BurpExtension;
import burp.api.montoya.MontoyaApi;
import burp.api.montoya.intruder.*;
import burp.api.montoya.ui.editor.extension.ExtensionHttpRequestEditor;


import static burp.api.montoya.intruder.Payload.from;
import static burp.api.montoya.intruder.PayloadProcessingResult.skipPayload;


public class MyExtension implements BurpExtension {
    public static MontoyaApi Api;
    ExtensionHttpRequestEditor myExtensionHttpRequestEditor;
    @Override
    public void initialize(MontoyaApi montoyaApi) {
        Api = montoyaApi;

        Api.intruder().registerPayloadProcessor(new MyPayloadProcessor());
        Api.intruder().registerPayloadGeneratorProvider(new MyPayloadGeneratorProvider());
        }

    class MyPayloadGeneratorProvider implements PayloadGeneratorProvider {

        @Override
        public String displayName() {
            return "TestPayloadGeneratorProvider";
        }

        @Override
        public PayloadGenerator providePayloadGenerator(AttackConfiguration attackConfiguration) {
            return new MyPayloadGenerator();
        }
    }
    class MyPayloadGenerator implements PayloadGenerator{

        @Override
        public Payload generatePayloadFor(IntruderInsertionPoint intruderInsertionPoint) {
            return from("Test");
        }
    }

    class MyPayloadProcessor implements PayloadProcessor {

        @Override
        public String displayName() {
            return "TestPayloadProcessor";
        }

        @Override
        public PayloadProcessingResult processPayload(Payload currentPayload, Payload originalPayload, IntruderInsertionPoint intruderInsertionPoint) {
            //跳过,不处理
            PayloadProcessingResult MyPayloadProcessingResult = skipPayload();
            return MyPayloadProcessingResult;
        }
    }
}

repeater()

提供 Repeater 面板相关功能

void sendToRepeater(HttpRequest httpRequest)

将请求发送到 Repeater 面板

void sendToRepeater(String name,HttpRequest httpRequest)

将请求发送到 Repeater 面板,并设置一个 Tab 名字

scanner()

提供 Scanner 面板相关功能

Scan createScan()

创建一个扫描

void generateReport(List<AuditIssue> issues, ReportFormat format,Path path)

生成扫描报告

Registration registerAuditIssueHandler(AuditIssueHandler auditIssueHandler)

注册一个审计监听器,该处理程序将收到Scanner报告的新审计问题的通知,交由 AuditIssueHandler 处理

Registration registerInsertionPointProvider(AuditInsertPointProvider auditInsertPointProvider)

注册一个扫描器插入点监听器,对于每个主动扫描的基本请求,Burp 将要求提供者提供适合该请求的任何自定义扫描仪插入点。

Registration registerScanCheck(ScanCheck scanCheck)

注册一个扫描监听器,每一个经过被动、主动扫描的请求均会被 ScanCheck 处理

看完你会发现,怎么好像少了 ui()、core()、internal()、persistence() 这几个包的方法呢?其实已经包含在 userInterface() 、sitemap() 等方法中了

其他方法

通过查看导出的 API 相关文件,你会发现其中还有一些接口的方法并不能通过初始化得到的 Montoya Api 调用,那么,除了Montoya Api提供的方法之外,我们还有哪些方法可以直接用呢?

所有接口中的被 static 关键字标记的方法。有的时候实现某个接口的方法时,需要返回实现特定接口的类,但是又不想实现该类,便可利用此类方法快速创建一个符合条件的类

实现接口

前面已经提到了很多 registerxxx() 的方法,参数中均是各种需要自己实现xx接口的类

要想在Burp处理请求时添加自定义逻辑,需要实现某些接口,并注册才可以。因此,首先看到能实现哪些接口

看到 官方文档

举个例子

Registration registerUnloadingHandler(ExtensionUnloadingHandler extensionUnloadingHandler)

看最简单的卸载插件监听,首先定义一个 MyExtensionUnloadingHandler 类实现自 ExtensionUnloadingHandler 接口,然后在 initialize 初始化函数中通过 registerUnloadingHandler 注册

package extension.core;

import burp.api.montoya.extension.ExtensionUnloadingHandler;

import static extension.MyExtension.Api;

public class MyExtensionUnloadingHandler implements ExtensionUnloadingHandler {
    @Override
    public void extensionUnloaded() {
        Api.logging().logToOutput("插件被卸载了");
    }
}
posted @ 2022-11-24 15:31  1ndex-  阅读(2648)  评论(0编辑  收藏  举报