Files
reverse-skills-max/reverse-skill-repo/skills/field-journal/2026-06-29_burp-mcp-full-test-and-fix.md

142 lines
7.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 2026-06-29 burp-mcp-full 全量测试与修复
## 场景分类
BurpSuite 扩展开发/测试
## 目标概述
对 burp-mcp-full 扩展(Burp Suite Professional MCP Full Control, 63 个工具)做全量运行时可用性测试,发现并修复 3 个 bug + 1 个桥接层竞争条件。
## 完整执行链路
1. 静态验证:检查 Java dispatch 表 / getToolList() / bridge buildToolDefinitions 三处 63 工具一致性
2. 编译:build.bat 自动化 fat-jar 打包(JDK 21, montoya-api 2025.5, gson 2.11.0, nanohttpd 2.3.1)
3. 加载:在 Burp Suite Professional 2026.4.2 中加载扩展,确认 [MCP] Server started
4. 运行时测试:分 5 批通过 node http 客户端直接调用 127.0.0.1:9876:
- 第一批:30 个只读/编解码/查询工具(零副作用)
- 第二批:网络发送类(send_request / repeater / intruder, 目标 scanme.nmap.org)
- 第三批:Intruder 7 变体(attack/async/wordlist/pitchfork/cluster_bomb/battering_ram/with_options, 小范围枚举)
- 第四批:Scope/配置/规则/handler/add_issue/compare
- 第五批:crawl + proxy_clear
5. 发现并修复 3 个 bug,回归验证通过
## 踩坑记录
| 问题 | 原因 | 解决方案 | 耗时 |
|------|------|---------|------|
| `scan()` request_count 恒为 0 | AuditConfiguration 不接受种子 URL,代码漏调 addRequest | 从 url 解析 host/port/路径,构造 GET HttpRequest 喂给 activeAudit.addRequest() | 2h(含验证) |
| `send_to_intruder()` 报 HttpRequest must have an HttpService | 用 HttpRequest.httpRequest(raw) 无 service 重载 | 新增 buildRequestWithService(): 从 Host 头正则解析 host/port/https → HttpService,用 httpRequest(HttpService, raw) 重载 | 20min |
| `set_upstream_proxy()` 缺参数时空指针 NPE | params.get("proxy_host") 返回 null → .getAsString() NPE | 加判空:if (!params.has("proxy_host")) 返回清晰错误 | 5min |
| mcp-bridge.js API 异步竞争条件:4 个快速请求第 4 个丢失响应 | stdin close 时 process.exit(0) 杀死未完成的 HTTP 请求 | pending 计数器+stdinClosed 标志 → 所有请求完成后才 exit | 1h(含 mock 测试) |
| curl HTTP_CODE=000 无法探测端口 | curl 在本机被沙箱禁止 | 改用 node http 模块做探测 | 5min |
| Montoya API Audit 包路径推测错误 | 基于在线 javadoc 推断 Audit 在 scanner 包下 | javap 反编译真实 montoya-api-2025.5.jar 确认在 scanner.audit 包下 | 30min |
| 文件编码问题导致 Edit 工具匹配失败 | UTF-8 with BOM 中文内容在终端显示编码错层 | 改用 Python 做替换,指定 utf-8-sig | 10min |
## 工具链发现
- montoya-api 2025.5 版 Audit 在 `burp.api.montoya.scanner.audit.Audit` (非 scanner.Audit)
- AuditConfiguration 工厂方法不接受种子 URL,种子必须通过 Audit.addRequest(HttpRequest) 喂入
- HttpRequest.httpRequest(raw) 无 service 重载对 Repeater 够用,但 Intruder 要求带 HttpService
- Intruder.sendToIntruder(HttpRequest) 要求 request 必须附加 service
- api.burpSuite().version() 的 major()/minor()/build() 已在 2025.5 中移除 deprecation→removal,需用 buildNumber()/edition()/toString() 替代
- send_request 走 http.sendRequest(),不进 proxy history
- 本机 curl 被沙箱屏蔽,需用 node http 做探测
- IDA MCP 端口非固定 13337(实例间递增),但 Burp MCP 端口通过系统属性/env 可配,端口固定
## 关键代码/命令
### 全量测试脚本模式
```javascript
const http = require('http');
function call(tool, params={}, timeoutMs=30000) {
return new Promise((resolve) => {
const body = JSON.stringify({tool, params});
const req = http.request({hostname:'127.0.0.1',port:9876,path:'/',method:'POST',
headers:{'Content-Type':'application/json','Content-Length':Buffer.byteLength(body)}}, (res)=>{
let d=''; res.on('data',c=>d+=c); res.on('end',()=>{ try{resolve(JSON.parse(d));}catch(e){resolve({__raw:d.slice(0,200)});} });
});
req.on('error', e => resolve({__err: e.message}));
req.on('timeout', () => { req.destroy(); resolve({__timeout:true}); });
req.setTimeout(timeoutMs);
req.write(body); req.end();
});
}
```
### buildRequestWithService (核心修复)
```java
private HttpRequest buildRequestWithService(String rawRequest) {
java.util.regex.Matcher m = java.util.regex.Pattern.compile(
"(?im)^Host:\\s*([^:\r\n]+)(?::(\\d+))?\\s*$").matcher(rawRequest);
if (!m.find()) return HttpRequest.httpRequest(rawRequest);
String host = m.group(1).trim();
boolean isHttps = rawRequest.contains("https://") || rawRequest.contains(":443");
int port = m.group(2) != null ? Integer.parseInt(m.group(2))
: (isHttps ? 443 : 80);
HttpService svc = HttpService.httpService(host, port, isHttps);
return HttpRequest.httpRequest(svc, rawRequest);
}
```
### 桥接层竞争条件修复 (mcp-bridge.js)
```javascript
let pending = 0;
let stdinClosed = false;
rl.on('line', async (line) => { ... pending++; ... finally { pending--; if (stdinClosed && pending === 0) process.exit(0); } });
rl.on('close', () => { stdinClosed = true; if (pending === 0) process.exit(0); });
```
### scan() 种子修复
```java
// 从 URL 构造 GET 种子请求后喂给 audit
java.net.URL u = new java.net.URL(url);
String host = u.getHost();
boolean isHttps = "https".equalsIgnoreCase(u.getProtocol());
int port = u.getPort() > 0 ? u.getPort() : (isHttps ? 443 : 80);
String path = (u.getPath() == null || u.getPath().isEmpty()) ? "/" : u.getPath();
String pathQuery = u.getQuery() != null ? path + "?" + u.getQuery() : path;
HttpService svc = HttpService.httpService(host, port, isHttps);
HttpRequest seedReq = HttpRequest.httpRequest(svc,
"GET " + pathQuery + " HTTP/1.1\r\nHost: " + host + "\r\nConnection: close\r\n\r\n");
activeAudit.addRequest(seedReq);
```
## 对本包的改进建议
- 路由矩阵已覆盖 BurpSuite MCP,无需修改
- `burpsuite-mcp-guide.md` 已追加更新日志(3 个修复 + 桥接层 + 全量验证结果)
- 工具表已更新 Scanner(scan 新增 mode 参数)和 Intruder(send_to_intruder Host header 要求)
- 无需新增 bootstrap 条目(编译脚本 build.bat 已自包含)
- IDA MCP 端口非固定,建议在 MCP 服务管理表中注明
## 可复用的模式/脚本片段
- 63 工具全量可用性测试脚本模式(见上方关键代码)。适用于任何 HTTP-based MCP 扩展的回归测试。
- buildRequestWithService 模式:从 Host 头解析 HttpService。适用于所有 Montoya API 中需要从原始请求构造 HttpRequest + HttpService 的场景。
## 进化动作
- [x] 更新了路由矩阵(路由已覆盖,无需修改)
- [ ] 更新了 tool-index(使用 .template,无需修改)
- [ ] 更新了 bootstrap-manifest(无新工具)
- [x] 更新了子 skill 文档(burpsuite-mcp-guide.md 追加更新日志)
- [x] 新增了 pitfall 记录(本条目)
- [ ] 无需更新
## 环境信息
- OS: Windows 11 Pro for Workstations 10.0.26200
- 工具版本: JDK 21.0.11+10 / Burp Suite Professional 2026.4.2 (20260402000047704)
- 目标平台: montoya-api 2025.5 / gson 2.11.0 / nanohttpd 2.3.1
- 测试目标: scanme.nmap.org (授权测试站点)
## 脱敏要求
测试目标为公开测试站点 scanme.nmap.org,无需脱敏。不含真实域名/IP/Token/用户名。
## 索引同步(提交前最后一步)
写完本日志后,必须同步更新 `_index.md`:
1. 在「按场景分类」对应小节新增一行(含日期、关键词)
2. 更新「累计统计」的计数与"最近更新"日期
---
<!-- [社区贡献] 完成后询问用户是否 PR 到主仓库。流程见 CONTRIBUTE-BACK.md -->