1 前言
歷史章節:
【BurpSuite 2025最新版插件開發】基礎篇1:環境搭建
【BurpSuite 2025最新版插件開發】基礎篇2:插件生命周期與核心接口
【BurpSuite 2025最新版插件開發】基礎篇3:請求攔截和修改簡單示例
【BurpSuite 2025最新版插件開發】基礎篇4:HTTP流量處理
【BurpSuite 2025最新版插件開發】基礎篇5:UI組件開發
【BurpSuite 2025最新版插件開發】基礎篇6:UI組件與數據傳輸
本章節注意講解 BurpSuite 插件中對于數據持久化存儲的基本使用。
2 接口簡介
BurpSuite 官方接口
2.1 PersistedList<T>
:項目級列表存儲
- 功能定位
存儲有序的、可重復的數據列表,支持泛型類型(如字符串、整數等),數據隨Burp項目文件保存。 - 核心特性
- 類型安全:通過泛型約束元素類型(如
PersistedList<String>
)。 - 項目隔離:每個項目獨立保存列表數據,切換項目時自動加載對應數據。
- 動態操作:支持
add
、remove
、size
等列表操作,適合存儲可變數據集合(如URL歷史記錄)。
- 類型安全:通過泛型約束元素類型(如
- 使用場景
存儲插件運行時動態生成的列表數據(如掃描結果、自定義Payload列表)。
2.2 PersistedObject
:項目級復雜對象存儲(僅供專業版)
- 功能定位
存儲單個結構化對象(如配置類、自定義數據模型),需實現java.io.Serializable
接口。 - 核心特性
- 復雜數據支持:可存儲嵌套對象、集合等復雜結構。
- 項目綁定:數據與項目關聯,適合保存項目特定的配置或狀態。
- 版本兼容性:需注意序列化版本UID,避免跨版本兼容性問題。
- 使用場景
存儲插件的完整配置(如多模塊掃描策略)或復雜狀態數據。
2.3 Persistence
:持久化功能入口
- 功能定位
工廠接口,用于創建和管理PersistedList
與PersistedObject
實例。 - 核心方法
createPersistedList(String name, Class<T> elementType)
:創建命名列表。persistedObject(String name)
:獲取或創建命名對象。
- 使用場景
插件初始化時通過montoya.persistence()
獲取實例,再創建具體持久化存儲。
2.4 Preferences
:用戶級全局配置
- 功能定位
存儲與項目無關的用戶偏好或全局設置(如API密鑰、界面主題)。 - 核心特性
- 跨項目共享:數據存儲在用戶配置文件中,所有項目均可訪問。
- 基本類型支持:僅支持字符串、布爾值、整數等簡單類型。
- 監聽機制:可注冊監聽器實時響應配置變化。
- 使用場景
存儲插件的全局設置(如默認掃描選項、認證憑證)。
2.5 持久化接口對比與選擇建議
接口名稱 | PersistedList | PersistedObject | Persistence | Preferences |
---|---|---|---|---|
功能定位 | 存儲有序、可重復的數據列表,支持泛型類型。 | 存儲單個結構化對象(如配置類、數據模型)。 | 工廠接口,用于創建和管理其他持久化接口。 | 存儲用戶級全局配置(與項目無關)。 |
數據作用域 | 項目級(隨項目文件保存)。 | 項目級(隨項目文件保存)。 | - | 用戶級(跨項目共享)。 |
支持數據類型 | 泛型列表(需指定元素類型)。 | 內置類型(如HTTP請求/響應)、自定義對象。 | - | 基本類型(String、Boolean、Integer等)。 |
序列化要求 | 元素需實現 Serializable (如自定義類)。 | 文檔未明確要求,但自定義對象可能需適配。 | - | 無需序列化。 |
核心方法 | add , remove , get , size , clear | set , get , setChildObject , remove | createPersistedList , persistedObject | put , get , remove , addListener |
典型場景 | 存儲動態生成的項目相關列表(如URL歷史)。 | 存儲復雜配置或項目狀態(如多模塊策略)。 | 插件初始化時獲取持久化功能入口。 | 存儲全局用戶偏好(如API密鑰、主題)。 |
版本限制 | 社區版/專業版均可使用。 | 專業版(標注 [Professional only] )。 | 社區版/專業版均可使用。 | 社區版/專業版均可使用。 |
關鍵說明
PersistedList
適合動態增刪的列表場景,但查詢效率依賴列表長度(O(n))。PersistedObject
支持復雜數據結構,但需注意專業版限制及可能的序列化適配。Persistence
是創建其他持久化對象的唯一入口,需通過montoya.persistence()
獲取。Preferences
適合存儲與項目無關的配置,數據跨項目共享且無需序列化。
3 實戰模擬
插件實現如下需求:
- 通過 HTTP 接口獲取不同類型用戶的信息:token、uid、role 后進行持久化存儲。
- 在業務接口中使用不同類型用戶的信息調用業務接口,來測試業務接口的權限隔離。
- 使用 BurpSuite 版本通用的
PersistedList
接口實現數據持久化。
4 代碼示例
4.1 服務端代碼
使用 python 代碼實現極簡服務端,實現如下需求:
- 預先定義了系統固定的用戶和管理員信息,包含 token、uid 和 role 三個字段。
- 實現 3 個接口:
-
獲取用戶信息接口(/user_info)
- 請求方法:GET
- 功能:返回預先定義的用戶信息,包含 token、uid 和 role。
- 響應示例:
-
獲取管理員信息接口(/admin_info)
- 請求方法:GET
- 功能:返回預先定義的管理員信息,包含 token、uid 和 role。
- 響應示例:
-
添加用戶接口(/add_user)
-
請求方法:POST
-
請求參數:以 JSON 格式傳遞 token、uid 和 role 三個參數。
-
功能:檢查傳入的參數是否與預先定義的管理員信息一致,若一致則返回添加成功的消息;若不一致則返回添加失敗的消息。
-
成功響應示例:
-
失敗響應示例:
-
服務端 python 代碼:
from flask import Flask, request, jsonifyapp = Flask(__name__)# 模擬用戶和管理員信息
USER_INFO = {"token": "user_token_123","uid": "user_uid_123","role": "user"
}ADMIN_INFO = {"token": "admin_token_123","uid": "admin_uid_123","role": "admin"
}# 獲取用戶信息接口
@app.route('/user_info', methods=['GET'])
def get_user_info():return jsonify(USER_INFO)# 獲取管理員信息接口
@app.route('/admin_info', methods=['GET'])
def get_admin_info():return jsonify(ADMIN_INFO)# 添加用戶接口
@app.route('/add_user', methods=['POST'])
def add_user():data = request.get_json()if not data or 'token' not in data or 'uid' not in data or 'role' not in data:return jsonify({"message": "Missing parameters"}), 400if data['token'] == ADMIN_INFO['token'] and data['uid'] == ADMIN_INFO['uid'] and data['role'] == ADMIN_INFO['role']:return jsonify({"message": "User added successfully"}), 200else:return jsonify({"message": "Adding user failed"}), 400if __name__ == '__main__':app.run(debug=True)
通過命令行啟動:
4.2 插件代碼
實現需求:
- 攔截 HTTP 響應、持久化存儲用戶數據。
- 通過右鍵菜單觸發的業務接口的測試請求。
- 測試請求分別使用 user 和 admin 的信息請求
/add_user
接口。
- Extension.java
- 插件的主類,實現了
BurpExtension
接口,設置插件名稱。 - 創建兩個
PersistedList<String>
實例,用于持久化存儲用戶信息和管理員信息。 - 注冊
CustomHttpHandler
來處理 HTTP 請求/響應。 - 注冊
TestMenu
右鍵菜單項。
- 插件的主類,實現了
import burp.api.montoya.BurpExtension;
import burp.api.montoya.MontoyaApi;
import burp.api.montoya.persistence.PersistedList;@SuppressWarnings("unused")
public class Extension implements BurpExtension {@Overridepublic void initialize(MontoyaApi montoyaApi) {montoyaApi.extension().setName("My Extension");// 創建持久化對象PersistedList<String> userInfoList = PersistedList.persistedStringList();PersistedList<String> adminInfoList = PersistedList.persistedStringList();// HTTP 監聽器montoyaApi.http().registerHttpHandler(new CustomHttpHandler(montoyaApi, userInfoList, adminInfoList));// 注冊右鍵-測試請求montoyaApi.userInterface().registerContextMenuItemsProvider(new TestMenu(montoyaApi, userInfoList, adminInfoList));}
}
- CustomHttpHandler.java
- 該類實現了
HttpHandler
接口,用于監聽和處理 HTTP 請求與響應。 - 在
handleHttpResponseReceived
方法中,檢查響應內容是否包含"role": "user"
或"role": "admin"
,并分別將這些信息添加到userInfoList
和adminInfoList
中。
- 該類實現了
import burp.api.montoya.MontoyaApi;
import burp.api.montoya.http.handler.*;
import burp.api.montoya.persistence.PersistedList;public class CustomHttpHandler implements HttpHandler {private final MontoyaApi montoyaApi;private final PersistedList<String> userInfoList;private final PersistedList<String> adminInfoList;public CustomHttpHandler(MontoyaApi montoyaApi, PersistedList<String> userInfoList, PersistedList<String> adminInfoList) {this.montoyaApi = montoyaApi;this.userInfoList = userInfoList;this.adminInfoList = adminInfoList;}@Overridepublic RequestToBeSentAction handleHttpRequestToBeSent(HttpRequestToBeSent httpRequestToBeSent) {return RequestToBeSentAction.continueWith(httpRequestToBeSent);}@Overridepublic ResponseReceivedAction handleHttpResponseReceived(HttpResponseReceived httpResponseReceived) {// 持久化存儲if (httpResponseReceived.bodyToString().contains("\"role\": \"user\"")) {userInfoList.add(httpResponseReceived.body().toString());String userValue = userInfoList.stream().findFirst().orElse("無用戶信息");montoyaApi.logging().logToOutput("獲取 UserInfoList: " + userValue);}if (httpResponseReceived.bodyToString().contains("\"role\": \"admin\"")) {adminInfoList.add(httpResponseReceived.body().toString());String adminValue = adminInfoList.stream().findFirst().orElse("無管理員信息");montoyaApi.logging().logToOutput("獲取 AdminInfoList: " + adminValue);}// 打印響應montoyaApi.logging().logToOutput("響應體: " + httpResponseReceived.bodyToString());return ResponseReceivedAction.continueWith(httpResponseReceived);}
}
- TestMenu.java
- 該類實現了
ContextMenuItemsProvider
接口,為 Burp 的上下文菜單提供自定義菜單項。 - 提供一個名為“測試請求”的菜單項;點擊菜單項后會調用
MyRequest.sendTestRequest(...)
方法,傳遞userInfoList
和adminInfoList
。 - 使用事件監聽機制來觸發請求。
- 該類實現了
import burp.api.montoya.MontoyaApi;
import burp.api.montoya.persistence.PersistedList;
import burp.api.montoya.ui.contextmenu.ContextMenuEvent;
import burp.api.montoya.ui.contextmenu.ContextMenuItemsProvider;import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;public class TestMenu implements ContextMenuItemsProvider {private final MontoyaApi montoyaApi;private final PersistedList<String> userInfoList;private final PersistedList<String> adminInfoList;public TestMenu(MontoyaApi montoyaApi, PersistedList<String> userInfoList, PersistedList<String> adminInfoList) {this.montoyaApi = montoyaApi;this.userInfoList = userInfoList;this.adminInfoList = adminInfoList;}@Overridepublic List<Component> provideMenuItems(ContextMenuEvent event) {List<Component> menuItems = new ArrayList<>();JMenuItem menuItem = new JMenuItem("測試請求");menuItem.addActionListener(e -> {MyRequest myRequest = new MyRequest(montoyaApi);myRequest.sendTestRequest(userInfoList, adminInfoList);});menuItems.add(menuItem);return menuItems;}
}
- MyRequest.java
- 該類封裝了發送 HTTP 請求的邏輯。
sendTestRequest(...)
方法從PersistedList<String>
中提取第一個用戶信息和管理員信息;如果信息為空,則記錄錯誤日志;- 使用
SwingWorker
異步執行網絡操作,避免阻塞主線程; sendRequest(...)
方法解析 JSON 數據,并構造新的 HTTP POST 請求發送到服務器。
import burp.api.montoya.MontoyaApi;
import burp.api.montoya.http.HttpService;
import burp.api.montoya.http.message.requests.HttpRequest;
import burp.api.montoya.persistence.PersistedList;
import burp.api.montoya.utilities.json.JsonUtils;import javax.swing.*;public class MyRequest {private final MontoyaApi montoyaApi;public MyRequest(MontoyaApi montoyaApi) {this.montoyaApi = montoyaApi;}public void sendTestRequest(PersistedList<String> userInfoList, PersistedList<String> adminInfoList) {String userValue = userInfoList.stream().findFirst().orElse("");String adminValue = adminInfoList.stream().findFirst().orElse("");if (userValue.isEmpty() || adminValue.isEmpty()) {montoyaApi.logging().logToError("no user info or admin info");return;}new SwingWorker<Void, Void>() {@Overrideprotected Void doInBackground() {sendRequest(userInfoList, "user");sendRequest(adminInfoList, "admin");return null;}}.execute();}private void sendRequest(PersistedList<String> dataList, String roleType) {try {String infoValue = dataList.stream().findFirst().orElse(null);if (infoValue == null) {montoyaApi.logging().logToError("數據為空: " + roleType);return;}JsonUtils jsonUtils = montoyaApi.utilities().jsonUtils();String role = jsonUtils.readString(infoValue, "role");String token = jsonUtils.readString(infoValue, "token");String uid = jsonUtils.readString(infoValue, "uid");String requestBody = String.format("{\"role\":\"%s\",\"token\":\"%s\",\"uid\":\"%s\"}", role, token, uid);HttpService httpService = HttpService.httpService("localhost", 5000, false);HttpRequest httpRequest = HttpRequest.httpRequest().withPath("/add_user").withService(httpService).withBody(requestBody).withHeader("Content-Type", "application/json").withMethod("POST");montoyaApi.http().sendRequest(httpRequest);} catch (Exception e) {montoyaApi.logging().logToError("error:" + e.getMessage());}}
}
5 效果展示
5.1 抓包接口獲取用戶數據
獲取 user 信息:
獲取 admin 信息:
日志打印:
5.2 右鍵觸發測試請求
觸發請求 /add_user
接口:
日志打印:可以看到輸出日志符合服務端的判斷。
插件:
sendRequest(userInfoList, "user");
sendRequest(adminInfoList, "admin");
服務端:
if data['token'] == ADMIN_INFO['token'] and data['uid'] == ADMIN_INFO['uid'] and data['role'] == ADMIN_INFO['role']:return jsonify({"message": "User added successfully"}), 200else:return jsonify({"message": "Adding user failed"}), 400
6 總結
-
整個插件的功能流程如下:
- 攔截響應:通過
CustomHttpHandler
類攔截 HTTP 響應,識別包含"role": "user"
或"role": "admin"
的響應體,并將其持久化存儲到PersistedList
中; - 持久化存儲:使用 Montoya API 的
PersistedList
來保存用戶和管理員信息; - 觸發測試請求:通過右鍵菜單項(由
TestMenu
類實現)觸發測試請求; - 異步發送請求:在后臺線程中使用
MyRequest
類發送包含用戶和管理員信息的 HTTP 請求,避免阻塞 UI。
- 攔截響應:通過
-
本插件適用于需要從響應中提取特定信息并基于這些信息發起新請求的安全測試場景。
注:由于社區版不支持保存項目到本地,因此要最大程度的發揮persistence
的作用建議使用專業版。