BurpSuite Montoya API 详解
文章目录
- 前言
- 1. API 结构
- 1.1 概述
- 1.2 API文件源码解析
- 2. BurpExtension 接口
- 3. MontoyaApi接口
- 4. package burp.api.montoya.proxy
- 4.1 Proxy 接口
- 4.2 ProxyRequestHandler接口
- 4.3 Demo
- 5. BurpSuite burpSuite()
- 6. Extension extension()
- 7. Http http()
- 参考
前言
我们已经学习了什么是burp扩展、怎么开发一个简单的burp扩展,现在是时候深入学习Montoya API 来帮助我们开发出一个实用的burp扩展。本文基于Montoya API 2025.4.x(对应burpsuite2025.4.x版本),介绍其内部结构及常用方法。
1. API 结构
1.1 概述
Montoya API 是 Burp Suite 的扩展接口,通过模块化设计提供丰富的功能。模块化扩展点:每个功能(如Proxy拦截、Scanner检查)以独立模块形式暴露,开发者按需调用。其核心结构分为以下模块:
- 基础模块
- BurpExtension(扩展入口,包含初始化方法
initialize(MontoyaApi api)
,用于注入 API 实例,即实现initialize方法,其参数MontoyaApi由burp传入,通过MontoyaApi访问burp提供的服务) - MontoyaApi,提供访问 Burp 各模块的入口,例如:
- burpSuite():访问 Burp 应用级功能(如导出配置、关闭 Burp)。
- collaborator():操作 Collaborator 模块(生成反连 payload)。
- comparer():数据比对功能。
- http():HTTP 请求/响应处理。
- extension():插件管理功能(如注册事件监听器)。
- BurpExtension(扩展入口,包含初始化方法
- 功能模块
1.2 API文件源码解析
montoya-api-2025.4.jar
jar包里主要是一大堆接口,这些接口定义了burp提供的服务,也就是通过调用接口里的方法,控制brup可以做什么。
去到官方文档的首页,是MontoyaApi
接 口,罗列了一大堆接口规定的方法(函数)。
我们再打开SDK,会发现文件夹几乎就对应上面的方法。实际上,调用上面的方法,都是返回一个相应的对象,这些对象的结构声明就在对应的文件夹下的文件里。
我们从扩展的入口BurpExtension接口
开始,进入MontoyaApi接口
,接着到 MontoyaApi 对象方法里可实例化的各个接口,逐步剖析整套 MontoyaAPI SDK。
2. BurpExtension 接口
API doc
相应的翻译也在图片里注明了,这个接口很简单,写一个类implements
这个接口,并实现其中的initialize(Montoya api)
方法即可。
需要注意的是,我们常说要运行程序必须要有一个main
方法,一个程序只能有一个main
方法,扩展的main
方法在哪?主方法在BurpSuite里,扩展由burp调用,MontoyaApi
对象则由bp的主程序传进来。
public class HelloBurp implements BurpExtension {// 实现实现该方法@overridevoid initialize(MontoyaApi api) {
/* 加载插件时调用此方法,我们可以在这里写逻辑代码,我们可以写点什么?依靠主程序传入的 MontoyaApi 类型对象,做点什么那么就需要看 MontoyaApi 这个类型提供了什么
*/
3. MontoyaApi接口
前面我们说了,burp中每个功能(如Proxy拦截、Scanner检查)以独立模块形式暴露,开发者按需调用。具体的实现方式就是通过MontoyaApi中的方法获取对应的模块对象。
那么,接下来的任务就是学习各个模块接口。那么多接口,该怎么学习呢?哪些是主要的接口,有没有一条线索将主要的接口串联起来?
我们回归本质:Burp的核心是能够在模块之间传递 HTTP 请求以执行特定任务的能力。那我们以Http数据包为线索,主要学习的方向就是:
- Http数据包的来源与发送
- Http数据包对象
- 模块之间数据包的传递
4. package burp.api.montoya.proxy
一般情况下,我们都是通过代理浏览器的HTTP流量获得HTTP数据包进行测试。可以确定,,代理模块Proxy中必然会产生HTTP请求的流量,我们通过跟踪一个HTTP请求,学习Montoya API 提供给我们的接服务能力。
包结构如下,这个包定义我们在 Proxy UI界面看到的、可控制的大部分功能。
4.1 Proxy 接口
burp中proxy模块的抽象。回顾proxy中的主要功能:
- 捕获流量(intercept on | off、forward、drop)
- Http history
对应的,Proxy接口的主要方法如下:
public interface Proxy {void enableIntercept(); // 设置 intercept onvoid disableIntercept(); // 设置 intercept offboolean isInterceptEnabled(); // 获取 intercept 状态List<ProxyHttpRequestResponse> history();Registration registerRequestHandler(ProxyRequestHandler handler);Registration registerResponseHandler(ProxyResponseHandler handler);
}
List<ProxyHttpRequestResponse> history();
,对应图形界面中的HTTP history
tab。该方法返回一个List<ProxyHttpRequestResponse>
,代表http的历史记录,List<ProxyHttpRequestResponse>
中的一个ProxyHttpRequestResponse
对象,即表示tab中的一行记录。
Registration registerRequestHandler(ProxyRequestHandler handler);
,学过GUI(图形用户接口)编程的师傅应该对这个方法感到熟悉,handler、注册handler,这是事件驱动编程中常用的术语,这里我们不关心什么是事件驱动编程(请问deepseek),只需要知道构造一个ProxyRequestHandler
类型的对象,并将其传给registerRequestHandler()
,当proxy中捕获到流量时,就会通知handler,调用handler里面的方法。
4.2 ProxyRequestHandler接口
我们来看一下ProxyRequestHandler.class
public interface ProxyRequestHandler {ProxyRequestReceivedAction handleRequestReceived(InterceptedRequest interceptedRequest);ProxyRequestToBeSentAction handleRequestToBeSent(InterceptedRequest interceptedRequest);
}
1. ProxyRequestHandler接口中又涉及的接口角色与职责:
接口 | 作用 | 触发阶段 |
---|---|---|
InterceptedRequest | 表示被代理拦截的 原始请求,包含未经修改的请求数据(如 URL、头、体)。 | 代理首次捕获到客户端请求时生成。 |
ProxyRequestReceivedAction | 定义代理对拦截请求的 处理动作(如放行、拦截、丢弃)。 | 在请求被代理接收后、发送到服务器前触发。 |
ProxyRequestToBeSentAction | 定义代理对即将发送的请求的 最终处理动作(如修改后发送、取消发送)。 | 在请求经过处理后、即将发送到服务器前触发。 |
终于看到Http流量的来源了,其被封装为一个InterceptedRequest
类型的对象,并传给了两个方法,方法会在不同阶段被自动调用(事件驱动编程)。跟踪Http请求的流转,不就是查看这些方法之间的调用顺序,也是在这些方法里实现我们对Http请求的处理逻辑(增删改)。
2. 处理流程与协作关系
阶段 1:请求拦截(InterceptedRequest
)
- 触发条件:客户端(如浏览器)通过 Burp 代理发送请求,代理捕获到该请求。
- 数据载体:
InterceptedRequest
对象包含原始请求的完整信息。 - 扩展操作:通过实现
ProxyHttpRequestHandler
的handleRequestReceived()
方法处理该对象:public ProxyRequestReceivedAction handleRequestReceived(InterceptedRequest interceptedRequest) {// 分析或修改请求if (interceptedRequest.url().contains("admin")) {// 拦截敏感请求并标记为待处理return ProxyRequestReceivedAction.intercept(interceptedRequest);}// 直接放行非敏感请求return ProxyRequestReceivedAction.continueWith(interceptedRequest); }
阶段 2:处理动作决策(ProxyRequestReceivedAction
)
- 动作类型:
continueWith(request)
:放行请求(可选传入修改后的请求)。intercept(request)
:拦截请求并等待用户操作(通过 Burp UI)。drop()
:直接丢弃请求。
- 示例:
// 修改请求头后放行 InterceptedRequest modifiedRequest = interceptedRequest.withHeader("X-Token", "123"); return ProxyRequestReceivedAction.continueWith(modifiedRequest);
阶段 3:发送前最终处理(ProxyRequestToBeSentAction
)
- 触发条件:请求经过
ProxyRequestReceivedAction
处理后决定放行。 - 数据载体:
InterceptedRequest
对象(包含可能已被修改的请求)。 - 扩展操作:通过实现
ProxyHttpRequestHandler
的handleRequestToBeSent()
方法进行最终调整:public ProxyRequestToBeSentAction handleRequestToBeSent(InterceptedRequest interceptedRequest) {// 添加请求头HttpRequest modifiedRequest = interceptedRequest.withHeader("X-Author", "MingSec");// 继续发送修改后的请求return ProxyRequestToBeSentAction.continueWith(modifiedRequest); }
3. 核心交互流程
4. 关键设计意图
-
职责分离
InterceptedRequest
专注原始请求数据,保持不可变性(需通过withXxx()
生成新对象)。ProxyRequestReceivedAction
控制请求的初步流向(拦截/放行/丢弃)。ProxyRequestToBeSentAction
提供最终修改机会,确保所有插件修改生效。
-
扩展灵活性
- 允许插件在 不同阶段 介入:
- 接收阶段:快速决策是否拦截(如基于 URL 黑名单)。
- 发送阶段:精细化修改(如添加签名头、加密敏感数据)。
- 允许插件在 不同阶段 介入:
-
状态一致性
- 通过分阶段处理,确保修改操作有序(例如先由插件 A 修改头,再由插件 B 加密体)。
值得注意一点,InterceptedRequest
的不可变性。InterceptedRequest接口中提供的对其自身的更改,都是产生一个新的HttpRequest类型的对象,将新的对象作为返回值,实际更改才会生效。
Http history tab 中展示的哪一个阶段的HttpRequest对象呢?
- 传进来的原始请求对象
InterceptedRequest
handleRequestReceived
执行后返回的HttpRequest
handleRequestToBeSent
执行后返回的HttpRequest
这个其实是可选的。在Settings -> Tools -> Proxy
中,如下
5. 总结
InterceptedRequest
是代理拦截的原始请求入口。ProxyRequestReceivedAction
决定请求的初步流向(放行/拦截/丢弃)。ProxyRequestToBeSentAction
控制请求的最终形态,确保修改生效。- 协作关系:三者形成代理处理流水线,实现从拦截到发送的全流程控制。
4.3 Demo
通过一个例子,验证前面的知识。不要忘记这张时序图
package com.mingsec;import burp.api.montoya.BurpExtension;
import burp.api.montoya.EnhancedCapability;
import burp.api.montoya.MontoyaApi;
import burp.api.montoya.core.HighlightColor;
import burp.api.montoya.http.message.requests.HttpRequest;
import burp.api.montoya.proxy.Proxy;
import burp.api.montoya.proxy.ProxyHttpRequestResponse;
import burp.api.montoya.proxy.http.InterceptedRequest;
import burp.api.montoya.proxy.http.ProxyRequestHandler;
import burp.api.montoya.proxy.http.ProxyRequestReceivedAction;
import burp.api.montoya.proxy.http.ProxyRequestToBeSentAction;import java.util.List;
import java.util.Set;public class Ext2025_4 implements BurpExtension {//将MontoyaApi作为静态属性,方便后续传给其他类static MontoyaApi montoya;@Overridepublic void initialize(MontoyaApi api) {//赋值给静态属性Ext2025_4.montoya = api;api.extension().setName("ext2025_4");api.logging().logToOutput("Ext2025_4 by MingSec");//获取Proxy模块的抽象 => Proxy对象Proxy proxy = api.proxy();//判断此时intercept状态boolean interceptEnabled = proxy.isInterceptEnabled();if (interceptEnabled) { //intercept 为 onproxy.disableIntercept(); //设置 intercept 为 offtry {Thread.sleep(7000); //睡眠 7 秒} catch (InterruptedException e) {throw new RuntimeException(e);}}//创建一个实现了ProxyRequestHandler接口的类(在下面)的对象MyProxyRequestHandler myProxyRequestHandler = new MyProxyRequestHandler();proxy.registerRequestHandler(myProxyRequestHandler); //注册该handlerapi.logging().logToOutput("7秒之期已到,启动!");proxy.enableIntercept();proxy.disableIntercept();//? 获取当前状态下的history,并将requestBody中含password字符串的proxyHttpRequestResponse标注List<ProxyHttpRequestResponse> history = proxy.history();for (ProxyHttpRequestResponse proxyHttpRequestResponse : history) {if (proxyHttpRequestResponse.request().bodyToString().contains("password")) {proxyHttpRequestResponse.annotations().setHighlightColor(HighlightColor.RED);proxyHttpRequestResponse.annotations().setNotes("mingsec");}}}@Overridepublic Set<EnhancedCapability> enhancedCapabilities() {return BurpExtension.super.enhancedCapabilities();}
}//实现 ProxyRequestHandler接口
class MyProxyRequestHandler implements ProxyRequestHandler {MontoyaApi api = Ext2025_4.montoya;String keyword = "password";boolean flag = false;private boolean contains(InterceptedRequest interceptedRequest) {return interceptedRequest.bodyToString().contains(keyword);}@Override/**Proxy代理到流量时调用,返回值ProxyRequestReceivedAction* ProxyRequestReceivedAction 接口中有3个静态方法用于返回一个该类型* - ProxyRequestReceivedAction.intercept(HttpRequest httpRequest) 拦截该请求,等待用户在UI中处理* - ProxyRequestReceivedAction.doNotIntercept(HttpRequest httpRequest) 直接放行* - ProxyRequestReceivedAction.continueWith(HttpRequest httpRequest) //根据当前规则处理* - ProxyRequestReceivedAction.drop(HttpRequest httpRequest) 丢弃该请求相当于在UI中手动drop*/public ProxyRequestReceivedAction handleRequestReceived(InterceptedRequest interceptedRequest) {this.flag = false;if (interceptedRequest.bodyToString().contains("password")) { //如果代理到的请求体中包含passwordthis.flag = true;//给请求设置高亮和注释interceptedRequest.annotations().setHighlightColor(HighlightColor.BLUE);interceptedRequest.annotations().setNotes("mingsec");//修改请求,返回一个修改后新的请求HttpRequest httpRequest = interceptedRequest.withAddedHeader("author", "mingsec");return ProxyRequestReceivedAction.intercept(httpRequest); //拦截请求,在UI中展示}return ProxyRequestReceivedAction.doNotIntercept(interceptedRequest); //将代理到的请求直接放行}@Overridepublic ProxyRequestToBeSentAction handleRequestToBeSent(InterceptedRequest interceptedRequest) {api.logging().logToOutput(hashCode());HttpRequest httpRequest = null;if (flag) {interceptedRequest.annotations().setNotes("mingsec-modified");interceptedRequest.annotations().setHighlightColor(HighlightColor.GREEN);httpRequest = interceptedRequest.withHeader("author", "mingsec by handler");}return ProxyRequestToBeSentAction.continueWith(httpRequest);}
}
5. BurpSuite burpSuite()
我们看方法细节
无需传参,只要调用该方法,返回一个BurpSuite
类型的对象,BurpSuite
接口中声明了许多方法,我们使用该接口的实例化对象调用其中方法,这些方法exposes application-level functionality
,
6. Extension extension()
返回一个Extension类型的对象,我们去Extension,如下
看来看去,好像就这个setName(String extensionName)
方法所见即所得,设置扩展名称的代码就如下:
public class HelloBurp implements BurpExtension {// 实现实现该方法@overridevoid initialize(MontoyaApi api) {
/* 加载插件时调用此方法,我们可以在这里写逻辑代码,我们可以写点什么?依靠主程序传入的 MontoyaApi 类型对象,做点什么那么就需要看 MontoyaApi 这个类型提供了什么
*/Extension extension = api.extension();extension.setName("bp扩展");//或者直接写为api.extension().setName("bp扩展");}
7. Http http()
注意这个方法
处理即将发送的请求,这是我们最常用的抓包改包功能。调用registerHttpHandler()
是注册一个HttpHandler
,在这个HttpHandler
里面实现我们最想用的功能——改包。我们点进HttpHandler
。
这个接口里有两个方法,分别是对发包/请求
和和回包/响应
进行操作,怎么进行操作呢?这个时候想一下我们改包的具体操作是什么?更改http请求包,更切确地说——更改http请求的文本/字符串。那我们去哪里获取将要发送的http请求包呢?我们先看这两个方法的详情
调用这个方法需要传入一个HttpRequestToBeSent
的实例,看参数说明,这个就是我们需要的http请求包,点进去。
写一个小demo验证我们上面所说的方法。
参考
[1] MontoyaApi
[2] 新版Burpsuite加解密插件开发基础
[3] Burp Extensions: Singletons and Scope
[4] deepseek