Skip to content

Commit b8ffa5d

Browse files
author
githubnull
committed
refactor: 模块化拆分Burp插件代码,提取对话框和辅助类
- SqlmapContextMenuProvider: 1218行 -> 228行 - BurpExtender: 1233行 -> 269行 - PresetConfigPanel: 1222行 -> 603行 新增模块化类: - dialogs/InjectionPointDialog - 注入点标记对话框 - dialogs/ConfigSelectionDialog - 配置选择对话框 - dialogs/SessionHeaderDialog - 会话Header配置对话框 - dialogs/HeaderRuleDialog - Header规则配置对话框 - dialogs/TextLineNumber - 行号显示组件 - dialogs/JsonUtils - JSON工具类 - dialogs/HeaderConstants - Header常量定义 - panels/ConfigImportExportHelper - 配置导入导出辅助类 - panels/PresetConfigDialog - 预设配置编辑对话框 两端(Montoya API/Legacy API)同步实现
1 parent f53d0a1 commit b8ffa5d

22 files changed

Lines changed: 4061 additions & 3332 deletions

src/burpEx/legacy-api/src/main/java/com/sqlmapwebui/burp/BurpExtender.java

Lines changed: 23 additions & 986 deletions
Large diffs are not rendered by default.
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
package com.sqlmapwebui.burp.dialogs;
2+
3+
import burp.*;
4+
import com.sqlmapwebui.burp.ConfigManager;
5+
import com.sqlmapwebui.burp.ScanConfig;
6+
import com.sqlmapwebui.burp.SqlmapApiClient;
7+
import com.sqlmapwebui.burp.SqlmapUITab;
8+
9+
import javax.swing.*;
10+
import java.awt.*;
11+
import java.io.PrintWriter;
12+
import java.util.ArrayList;
13+
import java.util.List;
14+
import java.util.Map;
15+
16+
/**
17+
* 配置选择对话框 - Legacy API版本
18+
*/
19+
public class ConfigSelectionDialog {
20+
21+
private final IBurpExtenderCallbacks callbacks;
22+
private final IExtensionHelpers helpers;
23+
private final SqlmapApiClient apiClient;
24+
private final ConfigManager configManager;
25+
private final SqlmapUITab uiTab;
26+
private final PrintWriter stdout;
27+
private final PrintWriter stderr;
28+
29+
public ConfigSelectionDialog(IBurpExtenderCallbacks callbacks, SqlmapApiClient apiClient,
30+
ConfigManager configManager, SqlmapUITab uiTab) {
31+
this.callbacks = callbacks;
32+
this.helpers = callbacks.getHelpers();
33+
this.apiClient = apiClient;
34+
this.configManager = configManager;
35+
this.uiTab = uiTab;
36+
this.stdout = new PrintWriter(callbacks.getStdout(), true);
37+
this.stderr = new PrintWriter(callbacks.getStderr(), true);
38+
}
39+
40+
/**
41+
* 显示配置选择对话框
42+
*/
43+
public void show(IHttpRequestResponse requestResponse) {
44+
JDialog dialog = new JDialog((Frame) null, "选择扫描配置", true);
45+
dialog.setLayout(new BorderLayout(10, 10));
46+
dialog.setSize(500, 400);
47+
dialog.setLocationRelativeTo(null);
48+
49+
JPanel contentPanel = new JPanel(new BorderLayout(10, 10));
50+
contentPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
51+
52+
// 配置选择列表
53+
DefaultListModel<ConfigManager.ConfigOption> listModel = new DefaultListModel<>();
54+
for (ConfigManager.ConfigOption option : configManager.getAllConfigOptions()) {
55+
listModel.addElement(option);
56+
}
57+
58+
JList<ConfigManager.ConfigOption> configList = new JList<>(listModel);
59+
configList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
60+
configList.setCellRenderer(new ConfigOptionRenderer());
61+
configList.setSelectedIndex(0);
62+
63+
JScrollPane listScrollPane = new JScrollPane(configList);
64+
listScrollPane.setBorder(BorderFactory.createTitledBorder("选择配置"));
65+
contentPanel.add(listScrollPane, BorderLayout.CENTER);
66+
67+
// 配置预览
68+
JTextArea previewArea = new JTextArea(6, 40);
69+
previewArea.setEditable(false);
70+
previewArea.setFont(new Font("Monospaced", Font.PLAIN, 11));
71+
JScrollPane previewScrollPane = new JScrollPane(previewArea);
72+
previewScrollPane.setBorder(BorderFactory.createTitledBorder("配置预览"));
73+
contentPanel.add(previewScrollPane, BorderLayout.SOUTH);
74+
75+
// 选择变化时更新预览
76+
configList.addListSelectionListener(e -> {
77+
ConfigManager.ConfigOption selected = configList.getSelectedValue();
78+
if (selected != null && !selected.isSeparator() && selected.getConfig() != null) {
79+
ScanConfig config = selected.getConfig();
80+
previewArea.setText(String.format(
81+
"名称: %s\n描述: %s\nLevel: %d, Risk: %d\nDBMS: %s\nTechnique: %s\nBatch: %s",
82+
config.getName(),
83+
config.getDescription() != null ? config.getDescription() : "-",
84+
config.getLevel(), config.getRisk(),
85+
config.getDbms().isEmpty() ? "自动检测" : config.getDbms(),
86+
config.getTechnique().isEmpty() ? "全部" : config.getTechnique(),
87+
config.isBatch() ? "是" : "否"
88+
));
89+
}
90+
});
91+
configList.setSelectedIndex(0);
92+
93+
dialog.add(contentPanel, BorderLayout.CENTER);
94+
95+
// 按钮
96+
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
97+
98+
JButton sendButton = new JButton("发送扫描");
99+
sendButton.addActionListener(e -> {
100+
ConfigManager.ConfigOption selected = configList.getSelectedValue();
101+
if (selected != null && !selected.isSeparator() && selected.getConfig() != null) {
102+
sendRequestToBackend(requestResponse, selected.getConfig());
103+
dialog.dispose();
104+
} else {
105+
JOptionPane.showMessageDialog(dialog, "请选择一个有效的配置",
106+
"提示", JOptionPane.WARNING_MESSAGE);
107+
}
108+
});
109+
buttonPanel.add(sendButton);
110+
111+
JButton cancelButton = new JButton("取消");
112+
cancelButton.addActionListener(e -> dialog.dispose());
113+
buttonPanel.add(cancelButton);
114+
115+
dialog.add(buttonPanel, BorderLayout.SOUTH);
116+
dialog.setVisible(true);
117+
}
118+
119+
/**
120+
* 配置选项渲染器
121+
*/
122+
private static class ConfigOptionRenderer extends DefaultListCellRenderer {
123+
@Override
124+
public Component getListCellRendererComponent(JList<?> list, Object value,
125+
int index, boolean isSelected, boolean cellHasFocus) {
126+
super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
127+
128+
if (value instanceof ConfigManager.ConfigOption) {
129+
ConfigManager.ConfigOption option = (ConfigManager.ConfigOption) value;
130+
if (option.isSeparator()) {
131+
setEnabled(false);
132+
setBackground(new Color(240, 240, 240));
133+
setForeground(Color.GRAY);
134+
} else {
135+
setEnabled(true);
136+
}
137+
}
138+
return this;
139+
}
140+
}
141+
142+
/**
143+
* 发送请求到后端
144+
*/
145+
private void sendRequestToBackend(IHttpRequestResponse requestResponse, ScanConfig config) {
146+
try {
147+
IRequestInfo requestInfo = helpers.analyzeRequest(requestResponse);
148+
java.net.URL urlObj = requestInfo.getUrl();
149+
String url = urlObj.toString();
150+
String host = urlObj.getHost();
151+
152+
byte[] requestBytes = requestResponse.getRequest();
153+
String requestText = new String(requestBytes);
154+
155+
// 解析headers和body
156+
List<String> headersList = new ArrayList<>();
157+
String body = "";
158+
159+
int bodyOffset = requestInfo.getBodyOffset();
160+
if (bodyOffset > 0 && bodyOffset < requestBytes.length) {
161+
body = new String(requestBytes, bodyOffset, requestBytes.length - bodyOffset);
162+
}
163+
164+
for (String header : requestInfo.getHeaders()) {
165+
headersList.add(header);
166+
}
167+
168+
// 构建JSON payload
169+
StringBuilder headersJson = new StringBuilder("[");
170+
for (int i = 0; i < headersList.size(); i++) {
171+
headersJson.append("\"").append(JsonUtils.escapeJson(headersList.get(i))).append("\"");
172+
if (i < headersList.size() - 1) headersJson.append(",");
173+
}
174+
headersJson.append("]");
175+
176+
// 构建options
177+
Map<String, Object> options = config.toOptionsMap();
178+
StringBuilder optionsJson = new StringBuilder("{");
179+
boolean first = true;
180+
for (Map.Entry<String, Object> entry : options.entrySet()) {
181+
if (!first) optionsJson.append(",");
182+
first = false;
183+
optionsJson.append("\"").append(entry.getKey()).append("\":");
184+
if (entry.getValue() instanceof String) {
185+
optionsJson.append("\"").append(JsonUtils.escapeJson((String)entry.getValue())).append("\"");
186+
} else if (entry.getValue() instanceof Boolean) {
187+
optionsJson.append(entry.getValue());
188+
} else {
189+
optionsJson.append(entry.getValue());
190+
}
191+
}
192+
optionsJson.append("}");
193+
194+
String jsonPayload = String.format(
195+
"{\"scanUrl\":\"%s\",\"host\":\"%s\",\"headers\":%s,\"body\":\"%s\",\"options\":%s}",
196+
JsonUtils.escapeJson(url),
197+
JsonUtils.escapeJson(host),
198+
headersJson.toString(),
199+
JsonUtils.escapeJson(body),
200+
optionsJson.toString()
201+
);
202+
203+
// 异步发送到后端
204+
new Thread(() -> {
205+
try {
206+
String response = apiClient.sendTask(jsonPayload);
207+
208+
configManager.addToHistory(config);
209+
210+
SwingUtilities.invokeLater(() -> {
211+
uiTab.appendLog("[+] 请求已发送: " + url);
212+
uiTab.appendLog(" 使用配置: " + config.getName());
213+
uiTab.appendLog(" 响应: " + response);
214+
});
215+
216+
stdout.println("[+] Task created for: " + url);
217+
218+
} catch (Exception e) {
219+
SwingUtilities.invokeLater(() -> {
220+
uiTab.appendLog("[-] 发送请求失败: " + e.getMessage());
221+
});
222+
stderr.println("[-] Error: " + e.getMessage());
223+
}
224+
}).start();
225+
226+
} catch (Exception e) {
227+
uiTab.appendLog("[-] 处理请求失败: " + e.getMessage());
228+
stderr.println("[-] Error: " + e.getMessage());
229+
}
230+
}
231+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.sqlmapwebui.burp.dialogs;
2+
3+
import java.util.Arrays;
4+
import java.util.HashSet;
5+
import java.util.Set;
6+
7+
/**
8+
* Header常量定义
9+
*/
10+
public class HeaderConstants {
11+
12+
/**
13+
* 常见的会话相关Header名称(不区分大小写匹配)
14+
*/
15+
public static final Set<String> COMMON_SESSION_HEADERS = new HashSet<>(Arrays.asList(
16+
"cookie", "authorization", "x-auth-token", "x-access-token", "x-api-key",
17+
"x-csrf-token", "x-xsrf-token", "session-token", "bearer", "token",
18+
"x-session-id", "x-session-token", "x-user-token", "x-request-id",
19+
"x-correlation-id", "x-trace-id"
20+
));
21+
22+
/**
23+
* 检查是否为常见会话Header
24+
*/
25+
public static boolean isCommonSessionHeader(String headerName) {
26+
return headerName != null && COMMON_SESSION_HEADERS.contains(headerName.toLowerCase());
27+
}
28+
}

0 commit comments

Comments
 (0)