前言
burp插件入门。入门,我们大概有一个框架,心里不再有怎么做,为什么可以这么做的疑问。现在就要更具体的来回答“怎么做”这个问题。我们通过官方的文档,一步一步实现一个可以处理HTTP数据包的小扩展。
1. 插件的官方文档
从官方发的documentation跳转到Montoya API JavaDoc
跳转到MontoyaApi接口
,看接口的描述::
Burp Suite 使用此接口将一组方法传递给
extensions
,这些extensions
可在Burp中执行各种操作。当加载扩展时,Burp调用它的BurpExtension.initialize(MontoyaApi)方法并传递一个MontoyaApi接口的实例。然后,扩展可以根据需要调用该接口实例的方法,以扩展Burp的功能。
意思就是说,我们要写一个BurpExtension类
,实现initialize(MontoyaApi)
方法,在该方法里面可以写我们的插件代码了。这个MontoyaApi接口的实例对象是Burp Suite传递过来的,我们通过该对象(调用对象方法)就可以访问Burp的功能了。我们再点进BurpExtension类
看到,BurpExtension
是一个接口,所以我们要编写一个类实现该接口,再通过上面MontoyaApi
接口的一个实例对象,调用Burp的功能。
现在,就有了我们的基本代码框架了
- 实现
BurpExtension
接口 - 调用MontoyaApi实例的方法访问Burp功能
// 导入两个最基本的接口
import burp.api.montoya.BurpExtension;
import burp.api.montoya.MontoyaApi;
import burp.api.montoya.logging.Logging;
//新建一个类,实现BurpExtension接口
public class HelloWorld implements BurpExtension {
//实现initialize(MontoyaApi api)方法,其中 api对象 是调用这个对象的对象(Burp主程序)传过来的
@Override
public void initialize(MontoyaApi api) {
// 利用api对象访问Burp提供的功能
// set extension name 设置扩展的名称
api.extension().setName("Hello montoya extension");
Logging logging = api.logging();
// write a message to our output stream 输出信息
logging.logToOutput("Hello output.");
// write a message to our error stream
logging.logToError("Hello error.");
}
}
那之后的事情就明确了:
- 我们想要实现什么功能 ----> 编写我们的逻辑代码
- 实现功能需要Burp的支撑 ----> MontoyaApi 接口中的方法
2. Montoya API jar包结构
解压Montoya API 的jar包,我们之前导入的BurpExtension
接口,就是对应下图中BurpExtension.class
,其目录就为burp > api > montoya
。下面还有一个MontoyaApi接口
,就是我们主要使用的对象/方法集合。各个文件夹内也是各种类和接口的定义,每个文件夹对应burp里面的一个工具/模块接口。
3. HTTP 处理程序
到目前为止,我们还是很难去写出一个有用的扩展,或者说,我们还是无从下手。我们不了解MontoyaApi
对象,不了解其中的使用过程,所以总感觉摸不着头脑。所以多看例子、官方文档、多写一些小demo,熟悉其中的对象调用流程、方法,之后才会有“这就是Bp插件”的感觉,才能体会到面向对象、面向接口的编程思想。
burp的核心是能够在 Burp 工具之间传递 HTTP 请求以执行特定任务的能力,现在我们要编写自己的工具,那么首先就需要获取到burp拦截或记录的HTTP请求。怎么获取?我们说过: 通过MontoyaApi
的实例来访问Burp中的功能
通过下面的文档,我们知道需要通过MontoyaApi
实例调用http()
方法,通过返回的HTTP实例
访问HTTP请求和响应。
调用该方法,返会一个Http接口的实现
,也就是一个实现了Http接口的类的对象
。点进Http
接口
进去之后,发现要注册一个handler
来处理http数据包,点进HTTPHandler
根据描述,我们还需要实现HttpHandler
这个接口,并调用之前的http()
方法注册这个handler
,之后就可以通过handler
来对数据包进行操作了。我们又发现,HttpHandler
接口中只有两个方法,但是该方法中传入了HttpRequestToBeSent
和HttpResponseReceived
的两个对象,那大概我们就可通过这两个对象操作HTTP数据包,点进去。
点进来就可以发现一些熟悉的术语,像什么ContentType
之类的,可以看出HttpRequestToBeSent
就是HTTP请求的抽象,一个HttpRequestToBeSent
的实例/对象就代表一个HTTP请求,这个实例还提供了对Http Request 的各种操作方法。
4. 小结
- 实现
BurpExtension
接口,调用http()
创建HTTP实例
- 实现
HtpHandler
接口,重写其中的方法,Burp主程序会分别传入HttpRequestToBeSent
和HttpRespnseReceived
2个实例,利用这2个实例可以对流经Burp的数据包做一定的操作 - 调用
HTTP实例
注册HttpHandler
,注册过后的handler才会被调用
5. 代码示例
整个的流程我们前面已经分析完了,现在我们来实现一个只有一条规则的HaE(一个扩展),HaE的核心就是解析HTTP数据包,匹配敏感字符串并在HTTP history中高亮和标注该(请求-响应)数据包。HTTP history 中的条目是在请求完成后才会被记录的,所以可能在处理响应的阶段,当响应被接收后,获取对应的请求-响应对象,然后设置Notes。
现在的功能需求是:
- 监听所有代理流量。
- 检查请求中是否包含敏感参数(如 password)。
- 在 Proxy 的 Notes 列中标记存在敏感参数的请求并高亮
思路就是:
- 确定Burp的哪个API可以操作Proxy历史中的Notes --> HttpResponseReceived对象
- 获取请求对象 --> HttpResponseReceived对象的initiatingRequest()方法
- 匹配请求体中是否包含“password=” --> contains()方法
- 命中规则就高亮并注释
使用的API版本:
<!-- https://mvnrepository.com/artifact/net.portswigger.burp.extensions/montoya-api -->
<dependency>
<groupId>net.portswigger.burp.extensions</groupId>
<artifactId>montoya-api</artifactId>
<version>2025.2</version>
</dependency>
扩展代码实现:
package com.mingsec;
import burp.api.montoya.BurpExtension;
import burp.api.montoya.MontoyaApi;
import burp.api.montoya.core.HighlightColor;
import burp.api.montoya.http.handler.*;
public class Notes implements BurpExtension {
private MontoyaApi api;
@Override
public void initialize(MontoyaApi api) {
this.api = api;
api.extension().setName("Proxy Notes Marker");
// 注册 HTTP 处理器
api.http().registerHttpHandler(new HttpHandler() {
@Override
public RequestToBeSentAction handleHttpRequestToBeSent(HttpRequestToBeSent request) {
// 不需要修改请求,直接放行
return RequestToBeSentAction.continueWith(request);
}
@Override
public ResponseReceivedAction handleHttpResponseReceived(HttpResponseReceived response) {
// 检查请求是否包含敏感参数
if (isRequestContainsSensitiveParam(response)) {
// 在 Proxy 历史记录中设置 Notes 和粉红色高亮
response.annotations().setNotes("⚠️ Contains敏感参数");
response.annotations().setHighlightColor(HighlightColor.PINK);
}
return ResponseReceivedAction.continueWith(response);
}
});
}
// 检查请求是否包含敏感参数(如 password)
private boolean isRequestContainsSensitiveParam(HttpResponseReceived response) {
String requestBody = response.initiatingRequest().bodyToString();
return requestBody.contains("password=");
}
}
验证:
设置Burp代理,请求登录DVMA靶场,成功高亮和标记。