【BurpSuite 新版本插件开发】基础篇4:HTTP流量处理
·
文章目录
1 前言
历史章节:
【BurpSuite 新版本插件开发】基础篇2:插件生命周期与核心接口
【BurpSuite 新版本插件开发】基础篇3:请求拦截和修改简单示例
本文基于 Montoya API,通过Proxy和HTTP两种监听器实现 HTTP 流量的拦截、过滤与修改,涵盖:
- Proxy 监听器:处理通过 Burp 代理的请求 / 响应,支持请求过滤、响应头添加等。
- HTTP 监听器:全局处理所有 Burp 模块(Proxy/Scanner 等)的流量,支持按请求方法修改、重定向拦截等。
2 Proxy 监听器
2.1 注册监听器
import burp.api.montoya.BurpExtension;
import burp.api.montoya.MontoyaApi;
public class Extension implements BurpExtension {
@Override
public void initialize(MontoyaApi montoyaApi) {
montoyaApi.extension().setName("My Extension");
// Proxy 请求监听器
montoyaApi.proxy().registerRequestHandler(new ProxyListenerRequest(montoyaApi));
// Proxy 响应监听器
montoyaApi.proxy().registerResponseHandler(new ProxyListenerResponse(montoyaApi));
}
}
2.2 处理 Proxy 请求
handleRequestReceived方法在 Proxy 收到 HTTP 请求之前调用:
- 可以修改请求。
- 可以修改注释。
- 可以控制是否应拦截请求并将其显示给用户以供手动审核或修改。
- 可以删除请求。
import burp.api.montoya.MontoyaApi;
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;
public class ProxyListenerRequest implements ProxyRequestHandler {
private final MontoyaApi montoyaApi;
public ProxyListenerRequest(MontoyaApi montoyaApi) {
this.montoyaApi = montoyaApi;
}
@Override
public ProxyRequestReceivedAction handleRequestReceived(InterceptedRequest interceptedRequest) {
// 打印请求内容
montoyaApi.logging().logToOutput("Request URL: " + interceptedRequest.url());
montoyaApi.logging().logToOutput("Request Method: " + interceptedRequest.method());
montoyaApi.logging().logToOutput("Request Headers: " + interceptedRequest.headers());
// 过滤 actuator 的请求
if (interceptedRequest.url().contains("actuator")) {
return ProxyRequestReceivedAction.drop();
}
// 过滤静态请求
if (interceptedRequest.url().endsWith(".css") ||
interceptedRequest.url().endsWith(".js") ||
interceptedRequest.url().endsWith(".png") ||
interceptedRequest.url().endsWith(".jpg") ||
interceptedRequest.url().endsWith(".gif")) {
return ProxyRequestReceivedAction.drop();
}
return null;
}
@Override
public ProxyRequestToBeSentAction handleRequestToBeSent(InterceptedRequest interceptedRequest) {
return null;
}
}
2.3 处理 Proxy 响应
当 Proxy 中收到 HTTP 响应时,将调用handleResponseReceived方法。
当 HTTP 响应在返回给客户端之前由 Proxy 处理完时,将调用handleResponseToBeSent方法。
import burp.api.montoya.MontoyaApi;
import burp.api.montoya.proxy.http.InterceptedResponse;
import burp.api.montoya.proxy.http.ProxyResponseHandler;
import burp.api.montoya.proxy.http.ProxyResponseReceivedAction;
import burp.api.montoya.proxy.http.ProxyResponseToBeSentAction;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class ProxyListenerResponse implements ProxyResponseHandler {
private final MontoyaApi montoyaApi;
public ProxyListenerResponse(MontoyaApi montoyaApi) {
this.montoyaApi = montoyaApi;
}
@Override
public ProxyResponseReceivedAction handleResponseReceived(InterceptedResponse interceptedResponse) {
// 添加安全响应头
interceptedResponse.withAddedHeader("X-Content-Type-Options", "nosniff");
interceptedResponse.withAddedHeader("X-Frame-Options", "DENY");
interceptedResponse.withAddedHeader("X-XSS-Protection", "1; mode=block");
// 打印响应头
montoyaApi.logging().logToOutput("Response Headers: " + interceptedResponse.headers());
return null;
}
@Override
public ProxyResponseToBeSentAction handleResponseToBeSent(InterceptedResponse interceptedResponse) {
String contentType = interceptedResponse.headerValue("Content-Type");
String responseBody = interceptedResponse.bodyToString();
if (contentType.contains("application/x-www-form-urlencoded")) {
responseBody = modifyFormData(responseBody);
}
// 构建新的响应
return ProxyResponseToBeSentAction.continueWith(interceptedResponse.withBody(Arrays.toString(responseBody.getBytes(StandardCharsets.UTF_8))));
}
/**
* 替换响应中的密码字段
*
* @param formData 表单数据
* @return 替换后的表单数据
*/
private String modifyFormData(String formData) {
String[] keyValuePairs = formData.split("&");
List<String> modifiedPairs = new ArrayList<>();
for (String pair : keyValuePairs) {
String[] parts = pair.split("=", 2);
if (parts.length == 2 && "password".equalsIgnoreCase(parts[0])) {
modifiedPairs.add(parts[0] + "=*");
} else {
modifiedPairs.add(pair);
}
}
return String.join("&", modifiedPairs);
}
}
3 HTTP 监听器
3.1 注册监听器
该监听器用于处理通过任何BurpSuite 工具将要发送的请求和收到的响应。
import burp.api.montoya.BurpExtension;
import burp.api.montoya.MontoyaApi;
public class Extension implements BurpExtension {
@Override
public void initialize(MontoyaApi montoyaApi) {
montoyaApi.extension().setName("My Custom Extension");
// 注册 http 监听器
montoyaApi.http().registerHttpHandler(new CustomHttpHandler(montoyaApi));
}
}
3.2 处理 HTTP 请求
通过实现handleHttpRequestToBeSent接口,将任何 Burp 工具发出请求,进行自定义分析或修改。
import burp.api.montoya.MontoyaApi;
import burp.api.montoya.http.handler.*;
import burp.api.montoya.http.message.params.HttpParameter;
import burp.api.montoya.http.message.params.HttpParameterType;
import burp.api.montoya.http.message.StatusCodeClass;
public class CustomHttpHandler implements HttpHandler {
private final MontoyaApi montoyaApi;
private static final String CUSTOM_PARAM_NAME = "X-Custom-Param";
private static final String CUSTOM_HEADER_NAME = "X-Custom-Header";
private static final String CUSTOM_BODY = "X-Custom-Body";
private static final String CUSTOM_VALUE = "Custom-Value";
private static final String CUSTOM_DOMAIN = "example.com";
public CustomHttpHandler(MontoyaApi montoyaApi) {
this.montoyaApi = montoyaApi;
}
@Override
public RequestToBeSentAction handleHttpRequestToBeSent(HttpRequestToBeSent httpRequestToBeSent) {
montoyaApi.logging().logToOutput("Handling HTTP request: " + httpRequestToBeSent.url());
// 处理不同类型的 HTTP 请求
String method = httpRequestToBeSent.method().toUpperCase();
switch (method) {
case "DELETE":
return RequestToBeSentAction.continueWith(httpRequestToBeSent.withBody(""));
case "PUT":
return RequestToBeSentAction.continueWith(httpRequestToBeSent.withHeader(CUSTOM_HEADER_NAME, CUSTOM_VALUE));
case "GET":
if (!HttpParameter.urlParameter(CUSTOM_PARAM_NAME, CUSTOM_VALUE).equals(
httpRequestToBeSent.parameter(CUSTOM_PARAM_NAME, HttpParameterType.URL))) {
return RequestToBeSentAction.continueWith(
httpRequestToBeSent.withParameter(HttpParameter.urlParameter(CUSTOM_PARAM_NAME, CUSTOM_VALUE)));
}
break;
case "POST":
if (!HttpParameter.bodyParameter(CUSTOM_BODY, CUSTOM_VALUE).equals(
httpRequestToBeSent.parameter(CUSTOM_BODY, HttpParameterType.BODY))) {
return RequestToBeSentAction.continueWith(
httpRequestToBeSent.withParameter(HttpParameter.bodyParameter(CUSTOM_BODY, CUSTOM_VALUE)));
}
break;
default:
break;
}
return RequestToBeSentAction.continueWith(httpRequestToBeSent);
}
}
关键点 :
- 使用
HttpRequestToBeSent.url()/headers()/bodyToString()分别获取请求的路径/请求头/请求体。 - 使用
HttpRequestToBeSent.method()动态识别方法类型。 - 使用
withBody()、withParameter()、withHeader()实现对请求体、请求参数、请求头的精准修改。
3.3 处理 HTTP 响应
通过实现handleHttpResponseReceived接口,将任何 Burp 工具接收的响应,进行自定义分析或修改。
@Override
public ResponseReceivedAction handleHttpResponseReceived(HttpResponseReceived httpResponseReceived) {
// 处理重定向响应
if (StatusCodeClass.CLASS_3XX_REDIRECTION.contains(httpResponseReceived.statusCode()) &&
httpResponseReceived.hasHeader("Location")) {
if (httpResponseReceived.header("Location").value().contains(CUSTOM_DOMAIN)) {
montoyaApi.logging().logToOutput("Redirecting to custom domain: " + httpResponseReceived.header("Location").value());
return ResponseReceivedAction.continueWith(
httpResponseReceived.withStatusCode((short) 200)
.withBody("Redirect blocked.")
);
}
}
return ResponseReceivedAction.continueWith(httpResponseReceived);
}
关键点:
- 使用
StatusCodeClass枚举类内置响应码类型校验实际响应的响应码。 - 使用
withStatusCode修改实际响应的响应码。
验证:
抓包后查看日志,重定向的响应内容被修改:
3.4 核心方法与 API 总结
| 方法 | 作用 |
|---|---|
request.url()/method()/headers() |
获取请求 URL、方法、头信息 |
request.withHeader()/withBody() |
修改请求头、请求体 |
response.statusCode() |
获取响应状态码 |
StatusCodeClass.CLASS_3XX_REDIRECTION |
枚举类,判断重定向响应 |
response.withStatusCode() |
修改响应状态码 |
4 Proxy 与 HTTP 两者关系
| 维度 | Proxy监听器 | HTTP监听器 |
|---|---|---|
| 作用范围 | 仅处理通过Burp代理的流量 | 处理所有Burp模块(Proxy/Scanner等)的流量 |
| 核心场景 | 流量审计、手动干预、代理过滤 | 全局请求修改、统一响应处理 |
| 典型应用 | 阻止静态资源请求、添加代理层安全头 | 按请求方法统一加参数、拦截恶意重定向 |
| 性能影响 | 仅处理代理流量,资源消耗较低 | 全局监听,需注意性能优化 |
5 总结
- 流量过滤优先级:
- Proxy监听器优先用于过滤静态资源、敏感路径(如
/actuator),减少无效流量。
- Proxy监听器优先用于过滤静态资源、敏感路径(如
- 全局修改策略:
- HTTP监听器适合按请求方法(GET/PUT/DELETE)统一添加参数或头信息,提升插件通用性。
- 重定向安全:
- 通过
StatusCodeClass和Location头拦截恶意重定向,防止钓鱼跳转。
- 通过
通过结合两种监听器的特性,可开发出兼顾细粒度控制和全局处理的Burp插件,满足渗透测试中的流量分析与安全增强需求。
更多推荐
所有评论(0)