1 前言
历史章节:
【BurpSuite 2025最新版插件开发】基础篇1:环境搭建
【BurpSuite 2025最新版插件开发】基础篇2:插件生命周期与核心接口
【BurpSuite 2025最新版插件开发】基础篇3:请求拦截和修改简单示例
【BurpSuite 2025最新版插件开发】基础篇4:HTTP流量处理
【BurpSuite 2025最新版插件开发】基础篇5:UI组件开发
本文主要介绍 BurpSuite 插件创建 UI 后,UI 界面和数据传输的主要方式。
2 需求实现
2.1 极简数据传输
基于基础篇5完成的UI开发,我们先实现如下图所示功能:
- 将 Proxy - HTTP history 下的多个请求和响应信息发送到插件面板。
- 支持同时选中多个请求并发送到插件面板,这个功能 BurpSuite 的原生功能 Repeater 是不支持的,Repeater 一次只能添加一个。
2.1.1 代码示例
核心功能1
- 上下文菜单项注入
- 实现
ContextMenuItemsProvider
接口,在 BurpSuite 的上下文菜单中添加自定义菜单项 “发送到我的插件面板”。
- 实现
- 请求 / 响应处理
- 当用户右键点击请求 / 响应并选择该菜单项时:
- 获取选中的所有请求 - 响应对(
selectedRequestResponses()
)。 - 提取 HTTP 请求和响应的字符串表示。
- 将请求 / 响应内容传递给
MySuiteTab
组件进行显示。
- 获取选中的所有请求 - 响应对(
- 当用户右键点击请求 / 响应并选择该菜单项时:
- UI 更新
- 更新插件面板的 UI(通过
revalidate()
和repaint()
),确保内容实时显示。 - 在 BurpSuite 的输出日志中记录操作结果。
- 更新插件面板的 UI(通过
目标:创建一个自定义上下文菜单项,允许用户将选中的 HTTP 请求 / 响应发送到插件面板进行查看。
import burp.api.montoya.MontoyaApi;
import burp.api.montoya.http.message.requests.HttpRequest;
import burp.api.montoya.ui.contextmenu.AuditIssueContextMenuEvent;
import burp.api.montoya.ui.contextmenu.ContextMenuEvent;
import burp.api.montoya.ui.contextmenu.ContextMenuItemsProvider;
import burp.api.montoya.ui.contextmenu.WebSocketContextMenuEvent;
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
public class MyMenuItem implements ContextMenuItemsProvider {
private final MontoyaApi montoyaApi;
private final MySuiteTab mySuiteTab;
public MyMenuItem(MontoyaApi montoyaApi, MySuiteTab mySuiteTab) {
this.montoyaApi = montoyaApi;
this.mySuiteTab = mySuiteTab;
}
/**
* 提供上下文菜单项
*
* @param event 上下文菜单事件
* @return 菜单项列表
*/
@Override
public List<Component> provideMenuItems(ContextMenuEvent event) {
// 创建一个空的菜单项列表
List<Component> menuItems = new ArrayList<>();
// 检查事件是否包含选中的请求
if (!event.selectedRequestResponses().isEmpty()) {
// 创建菜单项
JMenuItem menuItem = new JMenuItem("发送到我的插件面板");
// 为菜单项添加动作监听器
menuItem.addActionListener(e -> {
// 获取所有选中的请求信息
for (var requestResponse : event.selectedRequestResponses()) {
// 获取请求信息
HttpRequest request = requestResponse.request();
String requestString = request.toString();
// 获取响应信息
String responseString = requestResponse.response().toString();
// 信息添加到插件面板
mySuiteTab.addReqInfo(requestString);
mySuiteTab.addReqInfo(responseString);
}
// 刷新插件面板布局和显示
mySuiteTab.getUiComponent().revalidate();
mySuiteTab.getUiComponent().repaint();
// 打印
montoyaApi.logging().logToOutput("请求信息已添加到插件面板");
});
// 将菜单项添加到菜单项列表中
menuItems.add(menuItem);
}
return menuItems;
}
@Override
public List<Component> provideMenuItems(WebSocketContextMenuEvent event) {
return ContextMenuItemsProvider.super.provideMenuItems(event);
}
@Override
public List<Component> provideMenuItems(AuditIssueContextMenuEvent event) {
return ContextMenuItemsProvider.super.provideMenuItems(event);
}
}
核心功能2
- 面板初始化
- 创建一个包含滚动文本区域的面板,用于显示请求 / 响应内容。
- 使用
BorderLayout
布局管理器,确保内容区域可滚动且自适应大小。
- 信息展示
- 通过
addReqInfo()
方法将请求 / 响应字符串追加到文本区域中。 - 文本区域设置为不可编辑(
setEditable(false)
),仅用于查看。
- 通过
- 组件集成
- 通过
getUiComponent()
方法返回面板组件,供 BurpSuite 主界面集成。 - 在初始化时记录日志,确认面板加载成功。
- 通过
目标:负责展示从上下文菜单传递过来的 HTTP 请求 / 响应信息。
import burp.api.montoya.MontoyaApi;
import javax.swing.*;
import java.awt.*;
public class MySuiteTab {
private final JPanel panel;
private final JTextArea reqInfoArea;
public MySuiteTab(MontoyaApi montoyaApi) {
// 初始化面板
panel = new JPanel();
panel.setLayout(new BorderLayout());
// 初始化文本显示请求信息
reqInfoArea = new JTextArea(20, 50);
reqInfoArea.setEditable(false);
JScrollPane scrollPane = new JScrollPane(reqInfoArea);
panel.add(scrollPane, BorderLayout.CENTER);
montoyaApi.logging().logToOutput("MySuiteTab 初始化成功");
}
/**
* 添加请求信息到文本区域
* @param reqInfo 请求信息
*/
public void addReqInfo(String reqInfo) {
reqInfoArea.append(reqInfo + "\n\n");
}
/**
* 获取选项卡的界面组件
* @return 选项卡显示的组件
*/
public Component getUiComponent() {
return panel;
}
}
核心功能3
- 插件初始化
- 设置插件名称为 “My Extension”,在 BurpSuite 中显示。
- 自定义面板注册
- 创建
MySuiteTab
实例(用于展示请求 / 响应信息)。 - 将自定义面板注册为 BurpSuite 的一个选项卡(Tab),标题为 “我的插件面板”。
- 创建
- 上下文菜单注册
- 创建
MyMenuItem
实例(处理右键菜单逻辑)。 - 将自定义上下文菜单项(如 “发送到我的插件面板”)注册到 BurpSuite 的 UI 中。
- 创建
这里额外解释 MyMenuItem
构造函数传入两个参数的原因:
montoyaApi
:MontoyaApi
是 Burp Montoya API 的核心接口,它提供了访问 Burp Suite 各种功能的入口,如 HTTP 请求处理、用户界面操作、日志记录等。·MyMenuItem· 类需要使用MontoyaApi
来完成一些操作,示例代码中是记录日志。mySuiteTab
:MySuiteTab
是自定义的套件选项卡类实例。MyMenuItem
类需要与该选项卡进行交互,在用户点击上下文菜单项时,将相关信息显示在MySuiteTab
对应的面板中。
import burp.api.montoya.BurpExtension;
import burp.api.montoya.MontoyaApi;
import burp.api.montoya.ui.menu.MenuBar;
import javax.swing.*;
@SuppressWarnings("unused")
public class Extension implements BurpExtension {
@Override
public void initialize(MontoyaApi montoyaApi) {
montoyaApi.extension().setName("My Extension");
// 右键菜单
MySuiteTab mySuiteTab = new MySuiteTab(montoyaApi);
montoyaApi.userInterface().registerSuiteTab("我的插件面板", mySuiteTab.getUiComponent());
// 选项菜单
montoyaApi.userInterface().registerContextMenuItemsProvider(new MyMenuItem(montoyaApi, mySuiteTab));
}
}
2.1.2 展示效果
选中2个请求后,通过右键发送数据:
插件面板内容:
第二个 HTTP 信息的请求 / 响应数据:
2.2 优化插件面板
2.2.1 优化内容
上述 HTTP 数据在插件面板的显示太过混乱,且不容易扩充该页面的功能,下面我们按照来优化如下几点:
- 插件面板左侧显示添加 HTTP 信息的序号、请求域名、请求方法、URL、响应码。
- 插件面板右侧上半部分,显示 HTTP 的请求具体内容。
- 插件面板右侧下半部分,显示 HTTP 的响应具体内容。
- 插件面板左侧点击不同请求,右侧同步切换 HTTP 的请求 / 响应内容。
- 右侧显示内容过多时,显示顶部内容,类似 Excel 的左上方对齐。
大概效果:
2.2.2 代码示例
核心实现1:
- 设置扩展名称:通过
montoyaApi.extension().setName
方法将扩展名称设置为My Extension
。 - 注册套件选项卡:创建
MySuiteTab
实例,使用montoyaApi.userInterface().registerSuiteTab
方法在 BurpSuite 中注册一个名为「我的插件面板」的选项卡。 - 注册上下文菜单项提供器:使用
montoyaApi.userInterface().registerContextMenuItemsProvider
方法注册上下文菜单项,用户在 Burp Suite 界面中右键点击时可显示自定义菜单项。
import burp.api.montoya.BurpExtension;
import burp.api.montoya.MontoyaApi;
import burp.api.montoya.ui.menu.MenuBar;
import javax.swing.*;
@SuppressWarnings("unused")
public class Extension implements BurpExtension {
@Override
public void initialize(MontoyaApi montoyaApi) {
montoyaApi.extension().setName("My Extension");
// 右键菜单
MySuiteTab mySuiteTab = new MySuiteTab(montoyaApi);
montoyaApi.userInterface().registerSuiteTab("我的插件面板", mySuiteTab.getUiComponent());
// 选项菜单
montoyaApi.userInterface().registerContextMenuItemsProvider(new MyMenuItem(montoyaApi, mySuiteTab));
}
}
核心实现2:
- 检查上下文菜单事件里是否有选中的请求响应。若有,则创建一个名为「发送到我的插件面板」的菜单项。
- 为菜单项添加动作监听器,当用户点击该菜单项时,获取选中请求的相关信息(如域名、请求方法、路径、状态码等),并调用
mySuiteTab.addRequestInfo
方法将这些信息添加到自定义插件面板。 - 刷新插件面板的布局和显示,同时记录日志。
import burp.api.montoya.MontoyaApi;
import burp.api.montoya.http.HttpService;
import burp.api.montoya.http.message.requests.HttpRequest;
import burp.api.montoya.ui.contextmenu.AuditIssueContextMenuEvent;
import burp.api.montoya.ui.contextmenu.ContextMenuEvent;
import burp.api.montoya.ui.contextmenu.ContextMenuItemsProvider;
import burp.api.montoya.ui.contextmenu.WebSocketContextMenuEvent;
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
public class MyMenuItem implements ContextMenuItemsProvider {
private final MontoyaApi montoyaApi;
private final MySuiteTab mySuiteTab;
public MyMenuItem(MontoyaApi montoyaApi, MySuiteTab mySuiteTab) {
this.montoyaApi = montoyaApi;
this.mySuiteTab = mySuiteTab;
}
/**
* 提供上下文菜单项
*
* @param event 上下文菜单事件
* @return 菜单项列表
*/
@Override
public List<Component> provideMenuItems(ContextMenuEvent event) {
// 创建一个空的菜单项列表
List<Component> menuItems = new ArrayList<>();
// 检查事件是否包含选中的请求
if (!event.selectedRequestResponses().isEmpty()) {
// 创建菜单项
JMenuItem menuItem = new JMenuItem("发送到我的插件面板");
// 为菜单项添加动作监听器
menuItem.addActionListener(e -> {
// 获取所有选中的请求信息
for (var requestResponse : event.selectedRequestResponses()) {
HttpRequest request = requestResponse.request();
HttpService service = requestResponse.httpService();
String domain = service.host();
String method = request.method();
String path = request.path();
int statusCode = requestResponse.response().statusCode();
String requestContent = request.toString();
String responseContent = requestResponse.response().toString();
mySuiteTab.addRequestInfo(domain, method, path, statusCode, requestContent, responseContent);
}
// 刷新插件面板布局和显示
mySuiteTab.getUiComponent().revalidate();
mySuiteTab.getUiComponent().repaint();
// 打印
montoyaApi.logging().logToOutput("请求信息已添加到插件面板");
});
// 将菜单项添加到菜单项列表中
menuItems.add(menuItem);
}
return menuItems;
}
@Override
public List<Component> provideMenuItems(WebSocketContextMenuEvent event) {
return ContextMenuItemsProvider.super.provideMenuItems(event);
}
@Override
public List<Component> provideMenuItems(AuditIssueContextMenuEvent event) {
return ContextMenuItemsProvider.super.provideMenuItems(event);
}
}
核心实现3:
- 定义
MySuiteTab
类,声明多个成员变量用于管理界面组件、请求响应数据以及界面布局。 - 界面初始化:创建主面板、分割面板、表格和文本区域等界面组件,并按布局组装。
- 事件监听:
- 为表格添加选择监听器,当用户选择表格中的某一行时,在右侧文本区域显示对应的请求和响应内容,并刷新滚动条。
- 监听面板显示事件,在面板显示时设置分割面板的比例。
- 将请求信息添加到表格中,同时把完整的请求和响应内容保存到列表里。
- 若为第一条记录,则在右侧文本区域显示该记录的请求和响应内容,并刷新滚动条。
import burp.api.montoya.MontoyaApi;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.ArrayList;
import java.util.List;
public class MySuiteTab {
private final JPanel panel;
private final JTable requestTable;
private final DefaultTableModel tableModel;
private final JTextArea requestArea;
private final JTextArea responseArea;
private int requestIndex = 1;
private final List<String> requestContents = new ArrayList<>();
private final List<String> responseContents = new ArrayList<>();
private final JSplitPane mainSplitPane;
private final JSplitPane rightSplitPane;
private final JScrollPane requestScrollPane;
private final JScrollPane responseScrollPane;
public MySuiteTab(MontoyaApi montoyaApi) {
// 初始化主面板
panel = new JPanel();
panel.setLayout(new BorderLayout());
// 初始化左右分割面板
mainSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
// 左半边面板显示表格
String[] columnNames = {"序号", "请求域名", "请求方法", "URL", "响应码"};
tableModel = new DefaultTableModel(columnNames, 0);
requestTable = new JTable(tableModel);
JScrollPane tableScrollPane = new JScrollPane(requestTable);
JPanel leftPanel = new JPanel(new BorderLayout());
leftPanel.add(tableScrollPane, BorderLayout.CENTER);
// 右半边面板
JPanel rightPanel = new JPanel(new BorderLayout());
// 初始化右侧上下分割面板
rightSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
// 右半边上部分显示请求
requestArea = new JTextArea(10, 30);
requestArea.setEditable(false);
requestScrollPane = new JScrollPane(requestArea);
rightSplitPane.setTopComponent(requestScrollPane);
// 右半边下部分显示响应
responseArea = new JTextArea(10, 30);
responseArea.setEditable(false);
responseScrollPane = new JScrollPane(responseArea);
rightSplitPane.setBottomComponent(responseScrollPane);
rightPanel.add(rightSplitPane, BorderLayout.CENTER);
// 将左右面板添加到分割面板
mainSplitPane.setLeftComponent(leftPanel);
mainSplitPane.setRightComponent(rightPanel);
// 将分割面板添加到主面板
panel.add(mainSplitPane, BorderLayout.CENTER);
// 表格点击事件
requestTable.getSelectionModel().addListSelectionListener(e -> {
if (!e.getValueIsAdjusting()) {
int selectedRow = requestTable.getSelectedRow();
if (selectedRow != -1 && selectedRow < requestContents.size() && selectedRow < responseContents.size()) {
requestArea.setText(requestContents.get(selectedRow));
responseArea.setText(responseContents.get(selectedRow));
// 触发重绘和重新验证布局,延迟设置响应内容的滚动条位置
refreshScrollBar();
}
}
});
// 监听组件显示事件,在组件显示时设置分割面板比例
panel.addComponentListener(new ComponentAdapter() {
@Override
public void componentShown(ComponentEvent e) {
super.componentShown(e);
mainSplitPane.setDividerLocation(0.5);
rightSplitPane.setDividerLocation(0.5);
}
});
montoyaApi.logging().logToOutput("插件面板初始化完成");
}
/**
* 向表格添加请求信息,并更新请求和响应内容
*
* @param domain 请求域名
* @param method 请求方法
* @param path 请求路径
* @param statusCode 响应码
* @param request 完整请求内容
* @param response 完整响应内容
*/
public void addRequestInfo(String domain, String method, String path, int statusCode, String request, String response) {
Object[] rowData = {requestIndex++, domain, method, path, statusCode};
tableModel.addRow(rowData);
requestContents.add(request);
responseContents.add(response);
// 默认显示第一个序号的数据
if (tableModel.getRowCount() == 1) {
requestArea.setText(request);
responseArea.setText(response);
// 触发重绘和重新验证布局,延迟设置响应内容的滚动条位置
refreshScrollBar();
}
}
/**
* 获取选项卡的界面组件
*
* @return 选项卡显示的组件
*/
public Component getUiComponent() {
return panel;
}
/**
* 刷新响应区域的滚动条位置到初始位置
*/
private void refreshScrollBar() {
SwingUtilities.invokeLater(() -> {
responseArea.revalidate();
responseArea.repaint();
// 重置垂直滚动条到顶部
requestScrollPane.getVerticalScrollBar().setValue(0);
responseScrollPane.getVerticalScrollBar().setValue(0);
// 重置水平滚动条到最左侧
requestScrollPane.getHorizontalScrollBar().setValue(0);
responseScrollPane.getHorizontalScrollBar().setValue(0);
});
}
}
2.2.3 优化效果
选中多个 HTTP 请求发送到插件面板:
点击插件面板的请求条目,相关数据正常显示:
3 总结
以下是各核心类的功能总结:
3.1 Extension.java
功能:作为扩展的入口类,负责初始化扩展并注册各项功能。
核心实现:
- 设置扩展名称为
My Extension
。 - 创建
MySuiteTab
实例并注册一个名为「我的插件面板」的套件选项卡。 - 注册上下文菜单项提供器
MyMenuItem
,实现右键菜单功能。
- 设置扩展名称为
3.2 MyMenuItem.java
功能:实现上下文菜单项的提供逻辑,用户可通过右键菜单将选中的请求信息发送到自定义插件面板。
核心实现 :
- 实现
ContextMenuItemsProvider
接口,处理不同类型的上下文菜单事件。 - 当用户右键点击且有选中的请求响应时,创建「发送到我的插件面板」菜单项。
- 点击菜单项后,获取请求相关信息(域名、请求方法、路径、状态码等),调用
MySuiteTab
的方法将信息添加到面板,刷新面板布局并记录日志。
- 实现
3.3 MySuiteTab.java
功能:创建并管理自定义的 Burp Suite 套件选项卡,展示 HTTP 请求和响应信息。
核心实现 :
- 初始化界面组件,包含主面板、分割面板、表格和文本区域等。
- 为表格添加选择监听器,用户选择表格行时,在右侧文本区域显示对应请求和响应内容。
- 提供
addRequestInfo
方法,将请求信息添加到表格,保存完整请求和响应内容,若为第一条记录则显示并刷新滚动条。 - 提供
getUiComponent
方法返回主界面组件供 Burp Suite 显示。 - 提供
refreshScrollBar
方法,将请求和响应区域的滚动条重置到初始位置。