BurpSuite Montoya API 详解

前言

我们已经学习了什么是burp扩展怎么开发一个简单的burp扩展,现在是时候深入学习Montoya API 来帮助我们开发出一个实用的burp扩展。本文基于Montoya API 2025.4.x(对应burpsuite2025.4.x版本),介绍其内部结构及常用方法。


1. API 结构

1.1 概述

Montoya API 是 Burp Suite 的扩展接口,通过模块化设计提供丰富的功能。模块化扩展点:每个功能(如Proxy拦截、Scanner检查)以独立模块形式暴露,开发者按需调用。其核心结构分为以下模块:

  1. 基础模块
    • BurpExtension(扩展入口,包含初始化方法 initialize(MontoyaApi api),用于注入 API 实例,即实现initialize方法,其参数MontoyaApi由burp传入,通过MontoyaApi访问burp提供的服务)
    • MontoyaApi,提供访问 Burp 各模块的入口,例如:
      • burpSuite():访问 Burp 应用级功能(如导出配置、关闭 Burp)。
      • collaborator():操作 Collaborator 模块(生成反连 payload)。
      • comparer():数据比对功能。
      • http():HTTP 请求/响应处理。
      • extension():插件管理功能(如注册事件监听器)。
  2. 功能模块
    在这里插入图片描述

1.2 API接口文件解析

montoya-api-2025.4.jarjar包里主要是一大堆接口,这些接口定义了burp提供的服务,也就是通过调用接口里的方法,控制brup可以做什么。

去到官方文档的首页,是MontoyaApi接 口,罗列了一大堆接口规定的方法(函数)。
在这里插入图片描述
我们再打开SDK,会发现文件夹几乎就对应上面的方法。实际上,调用上面的方法,都是返回一个相应的对象,这些对象的结构声明就在对应的文件夹下的文件里。
在这里插入图片描述

我们从扩展的入口BurpExtension接口开始,进入MontoyaApi接口,接着到 MontoyaApi 对象方法里可实例化的各个接口,逐步剖析整套 MontoyaAPI SDK。

2. BurpExtension 接口

API doc
在这里插入图片描述
相应的翻译也在图片里注明了,这个接口很简单,写一个类implements这个接口,并实现其中的initialize(Montoya api)方法即可。
需要注意的是,我们常说要运行程序必须要有一个main方法,一个程序只能有一个main方法,扩展的main方法在哪?主方法在BurpSuite里,扩展由burp调用,MontoyaApi对象则由burp的主程序传进来。

public class HelloBurp implements BurpExtension {
	// 实现实现该方法
	@override
	void 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 on
	void disableIntercept();	// 设置 intercept off
	boolean 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 对象包含原始请求的完整信息。
  • 扩展操作:通过实现 ProxyHttpRequestHandlerhandleRequestReceived() 方法处理该对象:
    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 对象(包含可能已被修改的请求)。
  • 扩展操作:通过实现 ProxyHttpRequestHandlerhandleRequestToBeSent() 方法进行最终调整:
    public ProxyRequestToBeSentAction handleRequestToBeSent(InterceptedRequest interceptedRequest) {
        // 添加请求头
        HttpRequest modifiedRequest = interceptedRequest.withHeader("X-Author", "MingSec");
        // 继续发送修改后的请求
        return ProxyRequestToBeSentAction.continueWith(modifiedRequest);
    }
    

3. 核心交互流程

客户端 Burp Proxy 扩展插件 目标服务器 User 发送请求 生成 InterceptedRequest 返回 ProxyRequestReceivedAction 生成 HttpRequestToBeSent 返回 ProxyRequestToBeSentAction 发送最终请求 在 UI 中显示拦截请求 手动修改并放行 生成 HttpRequestToBeSent 返回 ProxyRequestToBeSentAction 发送最终请求 终止流程,不发送请求 alt [动作类型为 continueWith] [动作类型为 intercept] [动作类型为 drop] 客户端 Burp Proxy 扩展插件 目标服务器 User

4. 关键设计意图

  1. 职责分离

    • InterceptedRequest 专注原始请求数据,保持不可变性(需通过 withXxx() 生成新对象)。
    • ProxyRequestReceivedAction 控制请求的初步流向(拦截/放行/丢弃)。
    • ProxyRequestToBeSentAction 提供最终修改机会,确保所有插件修改生效。
  2. 扩展灵活性

    • 允许插件在 不同阶段 介入:
      • 接收阶段:快速决策是否拦截(如基于 URL 黑名单)。
      • 发送阶段:精细化修改(如添加签名头、加密敏感数据)。
  3. 状态一致性

    • 通过分阶段处理,确保修改操作有序(例如先由插件 A 修改头,再由插件 B 加密体)。

值得注意一点,InterceptedRequest的不可变性。InterceptedRequest接口中提供的对其自身的更改,都是产生一个新的HttpRequest类型的对象,将新的对象作为返回值,实际更改才会生效。

Http history tab 中展示的哪一个阶段的HttpRequest对象呢?

  • 传进来的原始请求对象InterceptedRequest
  • handleRequestReceived执行后返回的HttpRequest
  • handleRequestToBeSent执行后返回的HttpRequest

这个其实是可选的。在Settings -> Tools -> Proxy中,如下
在这里插入图片描述


5. 总结

  • InterceptedRequest 是代理拦截的原始请求入口。
  • ProxyRequestReceivedAction 决定请求的初步流向(放行/拦截/丢弃)。
  • ProxyRequestToBeSentAction 控制请求的最终形态,确保修改生效。
  • 协作关系:三者形成代理处理流水线,实现从拦截到发送的全流程控制。

详细流程(类时序图):

客户端 Burp Proxy ProxyRequestHandler 服务器 User 发送请求 生成 InterceptedRequest(原始请求) 调用 handleRequestReceived() 返回 ProxyRequestReceivedAction 生成 HttpRequestToBeSent(即将发送的请求) 调用 handleRequestToBeSent() 返回 ProxyRequestToBeSentAction 发送最终请求 显示拦截界面(用户手动操作) 用户修改后放行 生成 HttpRequestToBeSent 调用 handleRequestToBeSent() 返回 ProxyRequestToBeSentAction 发送最终请求 丢弃请求 alt [动作是 continueWith()] [动作是 intercept()] [动作是 drop()] 客户端 Burp Proxy ProxyRequestHandler 服务器 User

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;
    @Override
    public 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 为 on
            proxy.disableIntercept();   //设置 intercept 为 off
            try {
                Thread.sleep(7000); //睡眠 7 秒
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        //创建一个实现了ProxyRequestHandler接口的类(在下面)的对象
        MyProxyRequestHandler myProxyRequestHandler = new MyProxyRequestHandler();
        proxy.registerRequestHandler(myProxyRequestHandler);    //注册该handler
        api.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");
            }
        }
    }

    @Override
    public 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")) { //如果代理到的请求体中包含password
            this.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);   //将代理到的请求直接放行
    }

    @Override
    public 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);
    }
}


学习了关于处理Http消息的许多接口,接下来看看一些关于扩展其他功能的接口稍作休息。

5. burp.api.montoya.extension

此包下的接口定义了扩展本身的设置和卸载前的的处理机制,Extension对象即代表扩展本身。

5.1 Extension接口

在这里插入图片描述
返回一个Extension类型的对象,我们去Extension,如下
在这里插入图片描述
看来看去,好像就这个setName(String extensionName)方法所见即所得,设置扩展名称的代码就如下:

public class HelloBurp implements BurpExtension {
	// 实现实现该方法
	@override
	void initialize(MontoyaApi api) {
/* 加载插件时调用此方法,我们可以在这里写逻辑代码,我们可以写点什么?
  依靠主程序传入的 MontoyaApi 类型对象,做点什么那么就需要看 MontoyaApi 这个类型提供了什么
*/
	Extension extension = api.extension();
	extension.setName("bp扩展");

	//或者直接写为
	api.extension().setName("bp扩展");
	}

注意到Registration registerUnloadingHandler(ExtensionUnloadingHandler handler);就像上面Proxy中的例子,实现一个ExtensionUnloadingHandler接口的类,并其传给registerUnloadingHandler,则扩展在卸载时将调用该类中的方法。

5.2 ExtensionUnloadingHandler接口

public interface ExtensionUnloadingHandler
{
    /**
     * This method is invoked when the extension is unloaded.
     */
    void extensionUnloaded();
}


实现该类,重写其中方法,并通过Extension接口中registerUnloadingHandler注册,扩展在卸载时将调用该类中的方法。


6. Http http()

6.1 Proxy 和 Http

有了Proxy模块中对http包的处理能力,为什么还需要http包呢?
在 Burp 的 Montoya API 中,proxy 包和 http 包分别定义了与 HTTP 数据包相关的接口,这种设计看似重复,但实际上是基于 模块化职责分离功能分层 的考量。以下是具体原因分析:


  1. 职责分离:不同模块的职责划分

    • proxy
      聚焦于 代理交互流程,例如拦截请求/响应、修改流量、控制代理行为等。它定义的接口(如 InterceptedRequestInterceptedResponse)是代理流程中的核心对象,通常包含与拦截逻辑直接相关的功能(如 sendAndReceive())。
    • http
      提供 HTTP 消息的通用构建和解析能力,例如创建 HttpRequestHttpResponse 对象,处理 HTTP 头、体、状态码等底层细节。它不绑定代理流程,而是为整个框架(如扫描器、扩展开发)提供通用的 HTTP 消息处理能力。

    示例

    • 在代理拦截流程中,proxy 包的 InterceptedRequest 会封装一个 http.HttpRequest 对象(通过 getRequest() 方法),但前者额外提供了拦截控制方法(如 setRequest() 修改请求)。
    • http.HttpRequest 是一个独立的 HTTP 请求对象,可在任何需要构建/解析 HTTP 消息的场景中使用(如自定义工具模块)。

  1. 功能分层:接口的抽象层级不同
    • http基础层接口,定义了 HTTP 消息的通用结构(如 HttpRequestHttpResponse),不涉及具体的交互逻辑(如代理拦截、网络发送)。
    • proxy应用层接口,基于 http 包的抽象进行扩展,实现了与代理交互相关的功能(如拦截、转发、修改)。

  1. 接口复用与扩展性
    • http 包的接口是通用的,可被多个模块共享。例如:
      • 代理模块(proxy)需要处理拦截的 HTTP 请求/响应。
      • 扫描器模块需要分析 HTTP 消息以检测漏洞。
      • 自定义扩展可能需要构建或解析 HTTP 消息。
    • 如果所有功能都集中在 proxy 包中,会导致接口臃肿、职责混乱。通过 http 包的抽象,可以避免重复定义相同的数据结构。

  1. 代理流程与 HTTP 消息处理的解耦

    • 代理流程(proxy 包)
      关注的是 请求/响应的生命周期管理,例如:
      • 拦截请求时调用 interceptedRequest.getRequest() 获取原始请求。
      • 修改请求后调用 interceptedRequest.setRequest(...)
      • 通过 sendAndReceive() 发送请求并获取响应。
    • HTTP 消息处理(http 包)
      关注的是 消息的结构和内容操作,例如:
      • 使用 http.HttpRequest 解析请求头、参数、体。
      • 使用 http.HttpResponse 构造响应内容。

    解耦优势

    • 代理模块可以专注于流程控制(如拦截规则、转发逻辑),而 HTTP 消息的解析/构建由 http 包统一处理。
    • 修改 HTTP 消息的逻辑(如添加头、修改参数)可以在任意地方通过 http 包接口实现,无需依赖代理上下文。

总结

模块职责典型接口特点
proxy代理交互流程控制InterceptedRequest, InterceptedResponse聚焦拦截、修改、转发逻辑
httpHTTP 消息构建与解析HttpRequest, HttpResponse提供通用的 HTTP 消息处理能力

这种分层设计使得 Burp 的 API 更加模块化、可维护性更强,同时也为扩展开发提供了灵活的接口选择。

6.2 Http

在这里插入图片描述
注意这个方法
在这里插入图片描述

处理即将发送的请求,这是burp提供给我们对【全局Http消息】处理的能力,即无论Http的请求/响应来源于Proxy、Repeater、Intruder等任何可以产生Http消息的地方,都可以通过调用registerHttpHandler()是注册一个HttpHandler,在这个HttpHandler里面实现我们最想用的功能——改包。我们点进HttpHandler
在这里插入图片描述
这个接口里有两个方法,分别是对发包/请求和和回包/响应进行操作,具体的逻辑与之前的ProxyHttpHandler一致,都是事件驱动编程模型。
在这里插入图片描述

6.3 关键协作关系

  1. 代理模块与 HTTP 模块的协作

    • 数据模型共享:
      http 包中的 HttpRequest/HttpResponse 是代理模块的基础数据模型。
      例如:InterceptedRequest 是 HttpRequest 的子类,添加了代理特有的元数据。

    -流程优先级:
    代理模块的处理器(ProxyRequestHandler)优先于 HTTP 模块的处理器(HttpHandler)执行。

     代理拦截 → 代理处理 → 全局 HTTP 处理 → 流量发送 
    

7. 总结

主要的逻辑就是获取http消息,并在适当的时间点对http消息进行处理。http消息对象没什么好说的就是对该对象进行字符串的增删改查。http消息处理则是基于事件驱动编程模型,利用Montoya API 提供的几个关键类/方法,实现对数据包的处理。处理的类需要注册到burp引擎进行统一管理,所以我们可以关注注册这个核心方法,确定burp提供给我们的能力

  • registerRequestHandler
  • registerResponseHandler
  • registerHttpHandler

8. 参考

[1] MontoyaApi
[2] 新版Burpsuite加解密插件开发基础
[3] Burp Extensions: Singletons and Scope
[4] deepseek

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值