1 前言

历史章节:

【BurpSuite 新版本插件开发】基础篇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 总结

  1. 流量过滤优先级
    • Proxy监听器优先用于过滤静态资源、敏感路径(如/actuator),减少无效流量。
  2. 全局修改策略
    • HTTP监听器适合按请求方法(GET/PUT/DELETE)统一添加参数或头信息,提升插件通用性。
  3. 重定向安全
    • 通过StatusCodeClassLocation头拦截恶意重定向,防止钓鱼跳转。

通过结合两种监听器的特性,可开发出兼顾细粒度控制和全局处理的Burp插件,满足渗透测试中的流量分析与安全增强需求。

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐