【BurpSuite 2025最新版插件开发】基础篇6:UI组件与数据传输

发布于:2025-07-01 ⋅ 阅读:(24) ⋅ 点赞:(0)

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 的输出日志中记录操作结果。

目标:创建一个自定义上下文菜单项,允许用户将选中的 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 构造函数传入两个参数的原因

  • montoyaApiMontoyaApi 是 Burp Montoya API 的核心接口,它提供了访问 Burp Suite 各种功能的入口,如 HTTP 请求处理、用户界面操作、日志记录等。·MyMenuItem· 类需要使用 MontoyaApi 来完成一些操作,示例代码中是记录日志。
  • mySuiteTabMySuiteTab 是自定义的套件选项卡类实例。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 方法,将请求和响应区域的滚动条重置到初始位置。

网站公告

今日签到

点亮在社区的每一天
去签到