【工具开发】Burpsuite 插件开发 2

Custom Scan Checks Example Extension

The sample extension demonstrates the following techniques:

  • Registering a custom scan check
  • Performing passive and active scanning when initiated by the user
  • Using the Burp-provided AuditInsertionPoint to construct requests for active scanning using specified payloads
  • Using a helper method to search responses for relevant match strings
  • Providing an MarkedHttpRequestResponse to highlight relevant portions of requests and responses,
  • Synchronously reporting custom scan issues in response to the relevant checks.
  • Guiding Burp on when to consolidate duplicated issues at the same URL (e.g., when the user has scanned the same item multiple times).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
import burp.api.montoya.MontoyaApi;
import burp.api.montoya.core.Marker;
import burp.api.montoya.http.message.HttpRequestResponse;
import burp.api.montoya.http.message.requests.HttpRequest;
import burp.api.montoya.scanner.AuditResult;
import burp.api.montoya.scanner.ConsolidationAction;
import burp.api.montoya.scanner.ScanCheck;
import burp.api.montoya.scanner.audit.insertionpoint.AuditInsertionPoint;
import burp.api.montoya.scanner.audit.issues.AuditIssue;
import burp.api.montoya.scanner.audit.issues.AuditIssueConfidence;
import burp.api.montoya.scanner.audit.issues.AuditIssueSeverity;

import java.util.LinkedList;
import java.util.List;

import static burp.api.montoya.core.ByteArray.byteArray;
import static burp.api.montoya.scanner.AuditResult.auditResult;
import static burp.api.montoya.scanner.ConsolidationAction.KEEP_BOTH;
import static burp.api.montoya.scanner.ConsolidationAction.KEEP_EXISTING;
import static burp.api.montoya.scanner.audit.issues.AuditIssue.auditIssue;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;

// 实现 ScanCheck 接口的 MyScanCheck 类
class MyScanCheck implements ScanCheck
{
private static final String GREP_STRING = "Page generated by:"; // 用于被动扫描的字符串
private static final String INJ_TEST = "|"; // 用于主动扫描的测试注入字符串
private static final String INJ_ERROR = "Unexpected pipe"; // 期望在响应中发现的错误信息

private final MontoyaApi api; // MontoyaApi 实例,用于访问 API 功能

MyScanCheck(MontoyaApi api)
{
this.api = api;
}

// 主动扫描方法
@Override
public AuditResult activeAudit(HttpRequestResponse baseRequestResponse, AuditInsertionPoint auditInsertionPoint)
{
// 构建包含测试负载的 HTTP 请求
HttpRequest checkRequest = auditInsertionPoint.buildHttpRequestWithPayload(byteArray(INJ_TEST)).withService(baseRequestResponse.httpService());

// 发送请求并获取响应
HttpRequestResponse checkRequestResponse = api.http().sendRequest(checkRequest);

// 获取响应中的特定错误信息的高亮显示
List<Marker> responseHighlights = getResponseHighlights(checkRequestResponse, INJ_ERROR);

// 根据响应中是否包含期望的错误信息来创建审计问题
List<AuditIssue> auditIssueList = responseHighlights.isEmpty() ? emptyList() : singletonList(
auditIssue(
"Pipe injection",
"Submitting a pipe character returned the string: " + INJ_ERROR,
null,
baseRequestResponse.request().url(),
AuditIssueSeverity.HIGH,
AuditIssueConfidence.CERTAIN,
null,
null,
AuditIssueSeverity.HIGH,
checkRequestResponse.withResponseMarkers(responseHighlights)
)
);

return auditResult(auditIssueList);
}

// 被动扫描方法
@Override
public AuditResult passiveAudit(HttpRequestResponse baseRequestResponse)
{
// 在响应中搜索预定义的字符串
List<Marker> responseHighlights = getResponseHighlights(baseRequestResponse, GREP_STRING);

// 如果找到字符串,则创建审计问题
List<AuditIssue> auditIssueList = responseHighlights.isEmpty() ? emptyList() : singletonList(
auditIssue(
"CMS Info Leakage",
"The response contains the string: " + GREP_STRING,
null,
baseRequestResponse.request().url(),
AuditIssueSeverity.HIGH,
AuditIssueConfidence.CERTAIN,
null,
null,
AuditIssueSeverity.HIGH,
baseRequestResponse.withResponseMarkers(responseHighlights)
)
);

return auditResult(auditIssueList);
}

// 问题合并策略
@Override
public ConsolidationAction consolidateIssues(AuditIssue newIssue, AuditIssue existingIssue)
{
// 如果问题名称相同,则保留现有问题,否则保留两个问题
return existingIssue.name().equals(newIssue.name()) ? KEEP_EXISTING : KEEP_BOTH;
}

// 辅助方法,用于获取响应中匹配字符串的高亮显示
private static List<Marker> getResponseHighlights(HttpRequestResponse requestResponse, String match)
{
List<Marker> highlights = new LinkedList<>();
String response = requestResponse.response().toString();

int start = 0;

while (start < response.length())
{
start = response.indexOf(match, start);

if (start == -1)
{
break;
}

Marker marker = Marker.marker(start, start+match.length());
highlights.add(marker);

start += match.length();
}

return highlights;
}
}

import burp.api.montoya.BurpExtension;
import burp.api.montoya.MontoyaApi;

public class CustomScanChecks implements BurpExtension
{
@Override
public void initialize(MontoyaApi api)
{
api.extension().setName("Custom Scanner checks");

api.scanner().registerScanCheck(new MyScanCheck(api));
}
}

发现原来是Pro版本才有scan功能,重新装了Pro版本

Custom Session Tokens Example Extension

This example demonstrates how you can couple a recorded macro with an extension to automatically gain a session token for a website and use it in later requests that Burp makes.

The macro mechanism that Burp provides allows you to record the request triggering creation of a session made via the proxy.

The extension uses the following techniques:

  • Registers a SessionHandlingAction handler
  • Fetches the list of macro requests and responses
  • Extracts the response headers from the last HttprequestResponse item in the list
  • Finds the relevant session header (in this example, this header is X-Custom-Session-Id)
  • Returns an HttpRequest with an updated session header
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
import burp.api.montoya.http.message.HttpHeader;
import burp.api.montoya.http.message.HttpRequestResponse;
import burp.api.montoya.http.message.requests.HttpRequest;
import burp.api.montoya.http.sessions.ActionResult;
import burp.api.montoya.http.sessions.SessionHandlingAction;
import burp.api.montoya.http.sessions.SessionHandlingActionData;

import java.util.List;

import static burp.api.montoya.http.sessions.ActionResult.actionResult;

// 实现 SessionHandlingAction 接口的类
public class MySessionHandlingAction implements SessionHandlingAction
{
@Override
public String name()
{
return "Use session token from macro"; // 此操作的名称,用于在 Burp Suite 中标识
}

@Override
public ActionResult performAction(SessionHandlingActionData actionData)
{
ActionResult result = actionResult(actionData.request(), actionData.annotations());

List<HttpRequestResponse> macroRequestResponseList = actionData.macroRequestResponses();

if (macroRequestResponseList.isEmpty())
{
return result; // 如果没有从宏中获取到请求响应,直接返回原始结果
}

// 从最后一个宏响应中提取响应头
List<HttpHeader> headers = macroRequestResponseList.get(macroRequestResponseList.size()-1).response().headers();

// 查找会话头部
HttpHeader sessionHeader = findSessionHeader(headers);

// 如果没有找到会话令牌,返回未修改的请求
if (sessionHeader == null)
{
return result;
}

// 创建一个更新了会话头部的 HTTP 请求
HttpRequest updatedRequest = actionData.request().withUpdatedHeader(sessionHeader);

return actionResult(updatedRequest, actionData.annotations());
}

// 在响应头中查找特定的会话标识符头部
private HttpHeader findSessionHeader(List<HttpHeader> headers)
{
HttpHeader sessionHeader = null;

for(HttpHeader header : headers)
{
// 只处理名为 "X-Custom-Session-Id" 的头部
if (!header.name().equals("X-Custom-Session-Id"))
{
continue;
}

// 获取会话令牌
sessionHeader = header;
}

return sessionHeader;
}
}

import burp.api.montoya.BurpExtension;
import burp.api.montoya.MontoyaApi;

//Burp will auto-detect and load any class that extends BurpExtension.
public class CustomSessionTokens implements BurpExtension
{
@Override
public void initialize(MontoyaApi api)
{
api.extension().setName("Session token example");

api.http().registerSessionHandlingAction(new MySessionHandlingAction());
}
}

这个插件主要用于以下几种场景中:

  1. 自动化会话管理
    • 在进行自动化渗透测试或功能测试时,特别是当会话令牌需要频繁更新以保持会话活跃的场合,此插件可以自动地从先前的交互(如登录后的响应)中提取新的会话令牌,并用其更新随后的请求。这确保了测试过程中的会话有效性和连续性。
  2. 多步骤过程中的令牌管理
    • 在需要执行多个依赖于特定会话状态的步骤的测试中,如购物车添加商品、结账等步骤,此插件能够确保每一步使用正确的会话令牌,从而避免测试因会话过期或令牌失效而失败。
  3. 应对防御机制
    • 在目标应用实施了严格的会话管理策略(例如会话固定、会话超时、每次请求后更新令牌等)的情况下,此插件通过动态更新会话令牌来帮助绕过这些机制,允许测试者模拟或维持一个持久的会话状态。
  4. 宏和自定义脚本中使用
    • 当使用 Burp Suite 的宏功能进行复杂的预配置任务时,如自动登录并执行一系列操作,此插件可以被配置为宏的一部分,用于在执行宏时自动处理会话令牌的更新。
  5. 维持活跃会话
    • 在测试需要长时间运行的脚本或过程时,例如长时间的漏洞扫描或大量数据的传输测试,此插件能够帮助维护会话的活跃状态,避免因会话超时而导致的中断。

Custom Intruder Payloads Example Extension

This example shows how you can use an extension to:

  • Generate custom Intruder payloads
  • Apply custom processing to Intruder payloads (including built-in ones)

When an extension registers itself as an Intruder payload provider, this will be available within the Intruder UI for the user to select as the payload source for an attack. When an extension registers itself as a payload processor, the user can create a payload processing rule and select the extension’s processor as the rule’s action.

The extension uses the following techniques:

  • Registers a new PayloadGeneratorProvider, which returns a new PayloadGenerator
  • Registers a new PayloadProcessor
  • The PayloadGenerator does the following:
    • Contains a list of payloads to be used
    • Iterates through the payload list, until there are no longer any payloads available
  • The PayloadProcessor does the following:
    • Decodes the base value of the payload
    • Parses the location of the input string in the decoded data
    • Rebuilds the serialized data with the new payload
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package aiassist;

import burp.api.montoya.MontoyaApi;
import burp.api.montoya.core.ByteArray;
import burp.api.montoya.intruder.PayloadData;
import burp.api.montoya.intruder.PayloadProcessingResult;
import burp.api.montoya.intruder.PayloadProcessor;
import burp.api.montoya.utilities.Base64Utils;
import burp.api.montoya.utilities.URLUtils;

import static burp.api.montoya.intruder.PayloadProcessingResult.usePayload;

// 实现 PayloadProcessor 接口的类
public class MyPayloadProcessor implements PayloadProcessor
{
public static final String INPUT_PREFIX = "input="; // 定义输入前缀,用于解析和重建数据
private final MontoyaApi api;

public MyPayloadProcessor(MontoyaApi api)
{
this.api = api; // 获取 Montoya API 实例
}

@Override
public String displayName()
{
return "Serialized input wrapper"; // 显示名,用于识别处理器
}

@Override
public PayloadProcessingResult processPayload(PayloadData payloadData)
{
Base64Utils base64Utils = api.utilities().base64Utils();
URLUtils urlUtils = api.utilities().urlUtils();

// 对基础值进行解码
String dataParameter = base64Utils.decode(urlUtils.decode(payloadData.insertionPoint().baseValue())).toString();

// 解析输入字符串在解码数据中的位置
String prefix = findPrefix(dataParameter);
if (prefix == null)
{
return usePayload(payloadData.currentPayload()); // 如果没有找到前缀,使用当前负载
}

String suffix = findSuffix(dataParameter);

// 使用新负载重建序列化数据
String rebuiltDataParameter = prefix + payloadData.currentPayload() + suffix;
ByteArray reserializedDataParameter = urlUtils.encode(base64Utils.encode(rebuiltDataParameter));

return usePayload(reserializedDataParameter); // 返回处理后的负载
}

private String findPrefix(String dataParameter)
{
int start = dataParameter.indexOf(INPUT_PREFIX);

if (start == -1)
{
return null; // 如果没有找到前缀,返回 null
}

start += INPUT_PREFIX.length();

return dataParameter.substring(0, start);
}

private String findSuffix(String dataParameter)
{
int start = dataParameter.indexOf(INPUT_PREFIX);

int end = dataParameter.indexOf("&", start);

if (end == -1)
{
end = dataParameter.length();
}

return dataParameter.substring(end);
}
}

import burp.api.montoya.intruder.AttackConfiguration;
import burp.api.montoya.intruder.PayloadGenerator;
import burp.api.montoya.intruder.PayloadGeneratorProvider;

public class MyPayloadGeneratorProvider implements PayloadGeneratorProvider
{
@Override
public String displayName()
{
return "My custom payloads";
}

@Override
public PayloadGenerator providePayloadGenerator(AttackConfiguration attackConfiguration)
{
return new MyPayloadGenerator();
}
}

import burp.api.montoya.intruder.GeneratedPayload;
import burp.api.montoya.intruder.IntruderInsertionPoint;
import burp.api.montoya.intruder.PayloadGenerator;

import java.util.List;

public class MyPayloadGenerator implements PayloadGenerator
{
private static final List<String> PAYLOADS = List.of("|", "<script>alert(1)</script>");
private int payloadIndex;

@Override
public GeneratedPayload generatePayloadFor(IntruderInsertionPoint insertionPoint)
{
payloadIndex++;

if (payloadIndex > PAYLOADS.size())
{
return GeneratedPayload.end();
}

String payload = PAYLOADS.get(payloadIndex);

return GeneratedPayload.payload(payload);
}
}

import burp.api.montoya.BurpExtension;
import burp.api.montoya.MontoyaApi;

public class IntruderPayloads implements BurpExtension
{
@Override
public void initialize(MontoyaApi api)
{
api.extension().setName("Intruder payloads");

api.intruder().registerPayloadGeneratorProvider(new MyPayloadGeneratorProvider());
api.intruder().registerPayloadProcessor(new MyPayloadProcessor(api));
}
}

在这里可以选择生成payload的方式

Persistence Example Extension

The extension works as follows:

  • It saves and loads a simple incrementing integer value with the project file.
    • Sends to the event log how many times Burp or the extension were restarted.
  • It saves and loads extension built http requests
    • Sends the requests to repeater with an incrementing tab counter when Burp is restarted or the extension is reloaded.
  • It saves the last 5 requests/responses issued by Burp
    • Prints the last 5 request/responses to the output log when burp is restarted or the extension is reloaded.
    • Uses Persisted Lists to automatically save/load data stored in the list.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
import burp.api.montoya.MontoyaApi;
import burp.api.montoya.http.message.requests.HttpRequest;
import burp.api.montoya.persistence.PersistedObject;

import static burp.api.montoya.http.message.requests.HttpRequest.httpRequest;
import static burp.api.montoya.http.message.requests.HttpRequest.httpRequestFromUrl;
import static example.persistence.PersistenceExample.STARTUP_COUNT_KEY;

public class SavingLoadingRequests {
public static final String SIMPLE_REQUEST_KEY = "simpleRequest";
public static final String REQUEST_WITH_HEADERS_KEY = "requestWithHeaders";
public static final String REQUEST_FROM_URL_KEY = "requestFromUrl";
private final MontoyaApi api;
private final PersistedObject myExtensionData;

// 构造函数
public SavingLoadingRequests(MontoyaApi api) {
this.api = api;
this.myExtensionData = api.persistence().extensionData();
}

// 运行示例
public void runExample() {
// 检查是否已经保存了示例请求
if (!checkForRequests()) {
api.logging().raiseInfoEvent("No Requests saved, creating requests");
createAndSaveExampleRequests();
}

sendExampleRequestsToRepeaterWithStartupCount();
}

// 检查是否存在保存的请求
private boolean checkForRequests() {
// 获取保存的 HTTP 请求的键集合,并检查所需的键是否都存在
return myExtensionData.httpRequestKeys().contains(SIMPLE_REQUEST_KEY) &&
myExtensionData.httpRequestKeys().contains(REQUEST_WITH_HEADERS_KEY) &&
myExtensionData.httpRequestKeys().contains(REQUEST_FROM_URL_KEY);
}

// 创建并保存示例请求
private void createAndSaveExampleRequests() {
HttpRequest simpleRequest = httpRequest("GET / HTTP1.0\r\n\r\n");
HttpRequest requestWithHeaders = httpRequest("GET / HTTP1.1\r\nHost: localhost\r\nMyHeader: Example\r\n\r\n");
HttpRequest requestFromUrl = httpRequestFromUrl("http://localhost");

// 将每个请求保存到其对应的键下
myExtensionData.setHttpRequest(SIMPLE_REQUEST_KEY, simpleRequest);
myExtensionData.setHttpRequest(REQUEST_WITH_HEADERS_KEY, requestWithHeaders);
myExtensionData.setHttpRequest(REQUEST_FROM_URL_KEY, requestFromUrl);
}

// 将请求发送到 Repeater,并在标签名称中加入启动计数
private void sendExampleRequestsToRepeaterWithStartupCount() {
HttpRequest simpleRequest = myExtensionData.getHttpRequest(SIMPLE_REQUEST_KEY);
HttpRequest requestWithHeaders = myExtensionData.getHttpRequest(REQUEST_WITH_HEADERS_KEY);
HttpRequest requestFromUrl = myExtensionData.getHttpRequest(REQUEST_FROM_URL_KEY);

Integer startupCount = myExtensionData.getInteger(STARTUP_COUNT_KEY);

api.repeater().sendToRepeater(simpleRequest, "Simple Request " + startupCount);
api.repeater().sendToRepeater(requestWithHeaders, "Request With Headers " + startupCount);
api.repeater().sendToRepeater(requestFromUrl, "Request From Url " + startupCount);
}
}

import burp.api.montoya.MontoyaApi;
import burp.api.montoya.http.handler.*;
import burp.api.montoya.http.message.HttpRequestResponse;
import burp.api.montoya.persistence.PersistedList;
import burp.api.montoya.persistence.PersistedObject;

import static burp.api.montoya.http.handler.RequestToBeSentAction.continueWith;
import static burp.api.montoya.http.handler.ResponseReceivedAction.continueWith;
import static burp.api.montoya.http.message.HttpRequestResponse.httpRequestResponse;

public class RequestResponseLogging {
private static final String REQUEST_RESPONSE_LIST_KEY = "last5"; // 用于保存数据的键

private final MontoyaApi api;
private final PersistedObject myExtensionData;

public RequestResponseLogging(MontoyaApi api) {
this.api = api;
this.myExtensionData = api.persistence().extensionData();
}

public void runExample() {
ensurePersistedListIsPresent();

// 从项目文件中加载请求/响应列表
PersistedList<HttpRequestResponse> myPersistedList = myExtensionData.getHttpRequestResponseList(REQUEST_RESPONSE_LIST_KEY);
printToOutput(myPersistedList);

// 注册 HTTP 处理器来处理请求和响应
api.http().registerHttpHandler(new HttpHandler() {
@Override
public RequestToBeSentAction handleHttpRequestToBeSent(HttpRequestToBeSent requestToBeSent) {
return continueWith(requestToBeSent);
}

@Override
public synchronized ResponseReceivedAction handleHttpResponseReceived(HttpResponseReceived responseReceived) {
// 保持列表中最多 5 条记录
if (myPersistedList.size() >= 5) {
myPersistedList.remove(0);
}

// 为了日志记录,我们不需要保留正文内容
myPersistedList.add(httpRequestResponse(responseReceived.initiatingRequest().withBody(""), responseReceived.withBody("")));

return continueWith(responseReceived);
}
});
}

private void printToOutput(PersistedList<HttpRequestResponse> myPersistedList) {
// 将加载的列表打印到输出日志
for (HttpRequestResponse httpRequestResponse : myPersistedList) {
api.logging().logToOutput(httpRequestResponse.request().toString());
api.logging().logToOutput("\n========================\n");
api.logging().logToOutput(httpRequestResponse.response().toString());
api.logging().logToOutput("\n**************************".repeat(2));
}
}

private void ensurePersistedListIsPresent() {
// 创建持久化的请求/响应列表
if (myExtensionData.getHttpRequestResponseList(REQUEST_RESPONSE_LIST_KEY) == null) {
// 创建一个新的空列表并将其保存到我们的键下
PersistedList<HttpRequestResponse> emptyPersistedList = PersistedList.persistedHttpRequestResponseList();
myExtensionData.setHttpRequestResponseList(REQUEST_RESPONSE_LIST_KEY, emptyPersistedList);
}
}
}

public class PersistenceExample implements BurpExtension {

static final String STARTUP_COUNT_KEY = "Startup Count"; // 用于保存启动次数的键

@Override
public void initialize(MontoyaApi api) {
// 为扩展设置名称,持久化数据将基于此名称进行保存和加载
api.extension().setName("Persistence example extension");

// 获取持久化对象,用于保存或加载数据
PersistedObject myExtensionData = api.persistence().extensionData();

// 从项目文件中获取整数值
Integer startupCount = myExtensionData.getInteger(STARTUP_COUNT_KEY);

// 如果值不存在,即此键未在项目文件中找到,则初始化为0
if (startupCount == null) {
startupCount = 0;
}

// 将启动次数增加1并保存回项目文件
myExtensionData.setInteger(STARTUP_COUNT_KEY, startupCount + 1);

// 从持久化数据中检索更新后的值并创建一个信息事件
api.logging().raiseInfoEvent("Startup count is: " + myExtensionData.getInteger(STARTUP_COUNT_KEY));

// 运行更复杂的示例,例如保存和加载请求
advancedExamples(api);
}

// 运行高级示例
private static void advancedExamples(MontoyaApi api) {
// 保存和加载请求的示例
SavingLoadingRequests savingLoadingRequests = new SavingLoadingRequests(api);
savingLoadingRequests.runExample();

// 使用请求响应列表的示例
RequestResponseLogging requestLogging = new RequestResponseLogging(api);
requestLogging.runExample();
}
}

WebSocket Handler Example Extension

The extension works as follows:

  • It registers a web socket created handler
  • When a web socket is created
    • It sends an initial text message
    • It registers a message listener for the websocket
    • Any message from the client that contains the text “password” is base64 encoded.

这个先不看了

This extension demonstrates registering a top level menu bar item with various actions.

It demonstrates the following techniques:

Creating a BasicMenuItem with a caption
Providing an action for a BasicMenuItem
Adding the Menu to Burp
Registering an ExtensionUnloadingHandler

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import burp.api.montoya.MontoyaApi;
import burp.api.montoya.extension.ExtensionUnloadingHandler;

public class MyExtensionUnloadingHandler implements ExtensionUnloadingHandler
{
private final MontoyaApi api;

public MyExtensionUnloadingHandler(MontoyaApi api)
{
this.api = api;
}

@Override
public void extensionUnloaded()
{
api.logging().logToOutput("Extension has been unloaded.");
}
}

import burp.api.montoya.BurpExtension;
import burp.api.montoya.MontoyaApi;
import burp.api.montoya.ui.menu.BasicMenuItem;
import burp.api.montoya.ui.menu.Menu;
import burp.api.montoya.ui.menu.MenuItem;

public class MenuBar implements BurpExtension
{
@Override
public void initialize(MontoyaApi api)
{
api.extension().setName("Add menu bar");
api.logging().logToOutput("Extension has been loaded.");

BasicMenuItem alertEventItem = BasicMenuItem.basicMenuItem("Raise critical alert").withAction(() -> api.logging().raiseCriticalEvent("Alert from extension"));

BasicMenuItem basicMenuItem = MenuItem.basicMenuItem("Unload extension");
MenuItem unloadExtensionItem = basicMenuItem.withAction(() -> api.extension().unload());

Menu menu = Menu.menu("Menu bar").withMenuItems(alertEventItem, unloadExtensionItem);

api.userInterface().menuBar().registerMenu(menu);

api.extension().registerUnloadingHandler(new MyExtensionUnloadingHandler(api));
}
}

Context Menu Example Extension

This extension adds a new context menu item to print out the request or response of an HttpRequestResponse in the Target, Proxy or Logger tab.

The sample extension demonstrates the following techniques:

Registering a new ContextMenuItemsProvider.
Creating a JMenuItem.
Adding an action listener to a JMenuItem.
If you right-click in a message editor context, it will use the item from the message editor.
If you right-click on a table item, it will print the request/response for the first selected item.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;

public class MyContextMenuItemsProvider implements ContextMenuItemsProvider
{

private final MontoyaApi api;

public MyContextMenuItemsProvider(MontoyaApi api)
{
this.api = api;
}

@Override
public List<Component> provideMenuItems(ContextMenuEvent event)
{
if (event.isFromTool(ToolType.PROXY, ToolType.TARGET, ToolType.LOGGER))
{
List<Component> menuItemList = new ArrayList<>();

JMenuItem retrieveRequestItem = new JMenuItem("Print request");
JMenuItem retrieveResponseItem = new JMenuItem("Print response");

HttpRequestResponse requestResponse = event.messageEditorRequestResponse().isPresent() ? event.messageEditorRequestResponse().get().requestResponse() : event.selectedRequestResponses().get(0);

retrieveRequestItem.addActionListener(l -> api.logging().logToOutput("Request is:\r\n" + requestResponse.request().toString()));
menuItemList.add(retrieveRequestItem);

if (requestResponse.response() != null)
{
retrieveResponseItem.addActionListener(l -> api.logging().logToOutput("Response is:\r\n" + requestResponse.response().toString()));
menuItemList.add(retrieveResponseItem);
}

return menuItemList;
}

return null;
}
}

import burp.api.montoya.BurpExtension;
import burp.api.montoya.MontoyaApi;

public class ContextMenu implements BurpExtension
{
@Override
public void initialize(MontoyaApi api)
{
api.extension().setName("Context menu extension");

api.userInterface().registerContextMenuItemsProvider(new MyContextMenuItemsProvider(api));
}
}

上面代码是创建右键处理选项的