dhakal-bibek/DedupeAI

GitHub: dhakal-bibek/DedupeAI

一款 Burp Suite 扩展,通过去重 HTTP 历史记录、按端口高亮攻击者/受害者流量并提供 IDOR/BOLA 测试工具与 AI 导出桥接,来优化移动端多账号安全测试工作流。

Stars: 3 | Forks: 1

# DedupeAI Burp Suite 扩展(Montoya API),它将嘈杂的 HTTP 历史记录转化为**去重、AI 就绪**的攻击面。它将每个新的代理条目标记为 **UNIQUE** 或 **DUPE**,将唯一的条目流式传输到实时 feed 中,根据监听器端口对攻击者/受害者流量进行颜色编码——一个**基于端口的高亮器**(PwnFox 风格,但以代理监听器端口为键),专为 **Android/iOS** 多账号测试而构建——并通过文件桥将去重后的集合直接交给 **Claude Code / AI**,内置 **IDOR/BOLA** 工具。 ![DedupeAI — 带有攻击者(绿色)/ 受害者(红色)标记和内联 Repeater 的 Dedupe Live feed](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/3da4c591f6155432.png) ## 功能 - **Dedupe(去重)** — 每个 HTTP 历史记录条目都会在 Notes 列中被标记为 `[DEDUPE] UNIQUE` / `[DEDUPE] DUPE xN`(签名可配置)。对 Notes 列进行排序 → 所有唯一的行聚集在一起 → 批量选择并提供给你的扫描器或其他扩展。 - **Dedupe Live 标签页** — 一个始终开启、自动刷新的 feed,*仅*显示唯一的请求,无需手动选择。 - **攻击者 / 受害者标记** — 根据监听器端口注入 `X-AI-Use: attacker|victim`,并按端口**和**判定结果(绿色 / 黄色 / 红色 / 灰色)为行着色,适用于多账号 IDOR/BOLA 测试。 - **IDOR/BOLA 工具** — **Magic Cookie**(使用另一个身份的 session 重放请求)和 **Match & Replace**(交换 object id 并观察意外的 `200` 响应),均可直接在唯一请求 feed 中使用。 - **AI 桥接** — **Save request(s) for AI** 和 **Live export → file** 将唯一的集合镜像到 `~/.burp-dedupe//live-unique.http`,以便 Claude Code 可以读取它(Burp 的 MCP 无法查看自定义扩展窗口,因此文件系统是共享通道)。 - **内联 Repeater** — 无需离开当前视图即可编辑和重新发送任何记录的唯一请求。 - **Send unique to Organizer** — 仅将唯一请求(过滤掉重复项)推送到 Burp Organizer,带有可选的 Header 覆盖。 - **Body Only (Pretty JSON)** — 一个只读的响应查看器标签页(Proxy / Repeater / 任何地方),*仅*显示 body,移除了 JSON XSSI 防护符(`)]}'`, `for(;;);`, `while(1);`),并通过无依赖的重新缩进器对 JSON 进行美化打印;当你选择 **Save request(s) for AI** 时,这种仅包含 body 的美化 JSON 是一个可选选项。 ## 工作原理 - 注册一个 `ProxyResponseHandler`(Montoya)。落入 HTTP 历史记录的每个响应都会被分类。 - 根据请求/响应的可配置部分(method、host、path、param 名称等)计算**签名**。 - 签名是派生自 SHA-256 的 128 位密钥,存储在 `ConcurrentHashMap` 中 — 快速、线程安全、轻量内存。 - 判决结果作为 `[DEDUPE] UNIQUE` 或 `[DEDUPE] DUPE x3` 盖戳到 Notes 列中。该行也会被高亮显示(可选)。高亮颜色取决于去重判决结果**和**监听器端口 — 请参阅下方的矩阵。 ## 端口高亮器(攻击者 / 受害者标记) - 注册一个 `ProxyRequestHandler`,它根据流量到达的**监听器端口**将识别性 Header 注入到流量中 — 非常适合每个账号都通过自己的代理监听器浏览的多账号 (IDOR/BOLA) 测试。 - 行颜色在 `PortHighlightHandler.colorFor(...)` 中集中决定,并由去重处理器(实时)和历史记录重新标记器应用,因此两者保持一致。颜色是**按端口和判决结果**设定的。默认值(在 `PortHighlightHandler.java` 顶部编辑 `PORT_RULES` 并重新构建): | 监听器端口 | Unique | Duplicate | 注入的 Header | |---|---|---|---| | **8082** (攻击者) | 绿色 | 黄色 | `X-AI-Use: attacker` | | **8083** (受害者) | 红色 | 灰色 | `X-AI-Use: victim` | | 任何其他端口 | 黄色 | 灰色 | — | - 因为颜色具有判决感知能力,所以它是在分类之后应用的 — 因此必须打开 "Highlight rows" / "Stamp Notes" 开关才能显示颜色。 ![Burp HTTP 历史记录中的 DEDUPE 判决结果和攻击者/受害者端口标签 — Notes 列中的 [DEDUPE] UNIQUE / DUPE xN,行颜色根据端口和判决结果着色(8082 上的攻击者为绿色/黄色,8083 上的受害者为红色/灰色)](assets/history-verdicts.png) ![DedupeAI 中的多账号 IDOR/BOLA — 攻击者流量(绿色,端口 8082)对受害者(红色,端口 8083),在内联 Repeater 中使用受害者的 session(`X-AI-Use: victim`)重放捕获的请求](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/54d97aaa1e155501.png) ## 构建 需要 JDK 21+。 ``` JAVA_HOME=/opt/homebrew/Cellar/openjdk@21/21.0.9/libexec/openjdk.jdk/Contents/Home \ ./gradlew build ``` 输出:`build/libs/burp-dedupe-0.1.0.jar` ## 在 Burp 中安装 1. Burp → **Extensions** → **Installed** → **Add** 2. Extension type: **Java** 3. 选择 `build/libs/burp-dedupe-0.1.0.jar` 4. 顶部会出现一个新的 **Dedupe** 标签页。 ## 使用方法 1. 打开 **Dedupe** 标签页。 2. 选择一个预设(例如 **Request smuggling**,如果你只关心路径唯一性)。 3. 点击 **Apply** — 这也会重置已见集合,以便判决结果保持一致。 4. 浏览 / 重放流量。新条目将被标记。 5. 在 **HTTP history** 中,点击 **Notes** 列标题进行排序。所有 `[DEDUPE] UNIQUE` 行将聚集在一起。多选 → 发送给你的扫描器 / 扩展。 ## 右键操作(HTTP history / Site map) 选择行,右键点击 → **Dedupe**: - **Show only unique requests** — 打开一个样式类似于 Burp HTTP 历史记录的独立窗口:包含 `# / Host / Method / URL / Status / Length / MIME / Notes` 列,行根据其 Burp **高亮颜色**进行着色(因此 attacker=绿色 / victim=红色 / other=黄色 会保留),**Notes** 列显示 `[DEDUPE] …` 判决结果 + `[attacker]/[victim] port N` 标签,下方有只读的请求/响应查看器。Burp 的 API 无法过滤其自身的历史记录表,因此这里显示去重后的集合。(范围外/静态 `SKIP` 行和已知重复项被排除。) - 这是当前选择的**快照**(在选择行时也可以通过 **Ctrl+9** 访问)。要获取自动更新的视图,请使用 **Dedupe Live** 标签页或 **Live unique window**(见下文)。 - 该表格支持**多选**(Ctrl/Cmd- 或 Shift-点击)。工具栏操作应用于整个选择。 - **Send to Repeater** — 将每个选定的请求发送到新的 Repeater 标签页,**以 method + path 命名**(例如 `GET /test/lasd/something/234`, `POST /sdfsd/dff`),以便轻松区分标签页。(提示:将 [Autorize](https://github.com/Quitten/Autorize) 指向 Repeater 并点击 Send 以运行其 authz 检查。) - **Save request(s) for AI** — 将所有选定的请求**及其响应保存到一个 `.http` 文件中**(每个请求位于其自己的 `####` 部分中,以其 [case manifest](#case-manifest-per-request) 为前缀),供 Claude Code / AI 读取;在保存对话框中选择目标位置。在对话框中勾选 **Responses: body only, pretty JSON**,将每个响应仅写为其 body(剥离 XSSI 防护符,美化打印 JSON)而不是完整的原始响应 — 此选择将被记住。 - **Magic Cookie** — 使用用户提供的 **auth set**(cookies / bearer token / 自定义 Header)重新发送选定的请求。它会剥离请求现有的 `Cookie` 和 `Authorization`(以及你列出的任何 Header),并**仅**使用你提供的凭据发送 — method、path、body 和所有其他 Header 保持不变。你在对话框中输入一次 auth set(每行一个 `Name: value`),它会在窗口和重启后被记住(Montoya preferences);结果会在各自的窗口中打开,以便你比较状态。非常适合相同请求 / 不同身份的 **IDOR/BOLA** 检查(例如,使用受害者的 session 重放攻击者的请求并观察是否返回 `200`)。 - **Match & Replace (IDOR)** — 对选定的请求应用查找/替换后重新发送,作用于 **path/query**、**body** 或 **两者**(文本匹配,或勾选 **regex**)。专为 IDOR/BOLA 构建:交换 object id(例如 `1001`→`1002`)并观察结果,看在另一个身份的值应被拒绝的情况下是否返回 `200`。**仅重新发送实际包含匹配项的请求** — 其余请求将被跳过,因此你只会命中携带该 id 的 endpoint,并且仅更改了 id。Method、Header 和未触及的部分原样发送(`Content-Length` 会自动刷新)。匹配/替换/范围设置会被记住(Montoya preferences)。 - **Clear** — 清空此窗口(收集的行)。在实时窗口中,新的 `[DEDUPE] UNIQUE` 请求之后会继续到达;已清除的行不会重新出现。 - **Filter box** — 根据 **request**(path、query、headers、body)、**response body** 或列(Host / Method / URL / Status / MIME / Notes)中的任何文本进行过滤;默认为纯子字符串匹配,或勾选 **regex** 进行不区分大小写的正则表达式匹配。从扩展中无法实现完整的 Bambda(Java 代码片段)过滤 — Montoya 仅向 Burp 公开 `bambda().importBambda(...)` 来*加载* Bambda,而不是*评估*它 — 因此这是一个快速的文本/正则过滤器。对于真正的 Bambda,请在这些相同的行上使用 Burp 原生的 HTTP-history 过滤栏。 - **Send unique to Organizer** — 仅将唯一请求(过滤掉重复项)发送到 Burp Organizer,可选择应用 Header 覆盖,并打上批次标签。 ## 实时唯一视图 — **Dedupe Live** 标签页(或 Ctrl+9 窗口) 两种进入方式,相同的实时视图 — **无需选择**: - **Dedupe Live** — 一个始终开启的 Burp suite 标签页(位于 **Dedupe** 旁边);扩展加载后它就在那里。 - 在 **HTTP history** / **Site map** 中按 **Ctrl+9** — 在**选中**行(例如 **Ctrl+A**)的情况下,它会在快照窗口中打开*那些*经过去重的请求;在**没有选择**任何内容的情况下,它会在窗口中打开实时视图。(**Dedupe** 标签页上的 **Live unique window ▶** 按钮始终打开实时视图。) 这是一个 HTTP history 风格的视图,它会**自动收集 Notes 中标记了 `[DEDUPE] UNIQUE` 的每个 Proxy HTTP 历史记录条目** — 并且仅收集这些条目。随着你的浏览,新的唯一请求会自行出现(它每秒刷新几次,**增量**扫描历史记录,因此即使历史记录很大也能保持流畅);Burp 已经折叠掉的重复项(`[DEDUPE] DUPE …`)永远不会显示,并且在你打开它的那一刻,历史记录中已有的唯一请求就会被收集。 工具栏对多选的行进行操作:**Send to Repeater**、**In-scope only**(仅保留 URL 在 Target 范围内的行)、**Save request(s) for AI**、**Magic Cookie**、**Match & Replace**、**Clear**、**Live export → file** 和一个 **filter** 框(子字符串或正则表达式)。 **内联 Repeater:** 选择一行以将其加载到表格下方的**可编辑**请求编辑器中,进行微调,然后 **Send ▶** — 或 **Ctrl+Space** / **Cmd+Enter**。响应显示在右侧,带有 status / length / timing 信息,因此你可以修改记录的请求并重新发送,而无需离开视图(它使用p 的 HTTP 客户端,因此它会落入 **Logger**,而不是 Proxy 历史记录)。在 macOS 上,Ctrl+Space 可能保留用于输入源切换 — 请在此处使用 **Cmd+Enter**。 - 它**会重新读取代理处理器已经写入的判决结果** — 它*不会*重新去重。因此请保持**启用判决结果标记**(这就是写入 `[DEDUPE]` note 的操作);如果关闭标记,则不会收集任何内容。 - 它还会提取 **Stamp existing history** 过程在视图已经打开后标记为 `UNIQUE` 的行。 - 为什么需要专用视图:Burp 自己的 HTTP 历史记录已经实时显示了这些 note,但 Montoya API 无法将该表*过滤*为仅显示 `UNIQUE` 行 — 因此此视图实现了这一点。(该标签页在会话期间存在;关闭 Ctrl+9 窗口会停止该窗口的轮询。) ## 导出到文件(用于 Claude Code / AI) Burp 的 MCP server 无法查看自定义扩展窗口,因此为了将去重后的请求交给 AI,我们使用**文件系统**作为共享通道。打开 **Live export → file** 开关后(在实时窗口中默认开启),该窗口将以防抖(debounced)的方式写入到一个稳定的、按项目划分的文件夹: ``` ~/.burp-dedupe// live-unique.http ← every unique request it collects, as it arrives selection.http ← just the rows you currently have selected ``` 该文件夹以**当前 Burp 项目**(`api.project().name()`)命名,因此每次测试都有其专属文件夹。每个条目是请求**和**其响应,位于一个以 `####` 分隔的块中,**以一个 [case manifest](#case-manifest-per-request) 作为前缀**;该文件以单行协议开头,告诉 AI 在处理 payload 之前先阅读清单并解释风险。该开关在**实时窗口中默认开启**(在快照/结果窗口中默认关闭,因此它们不会覆盖文件 — 在那里将其打开以进行一次性操作)。 **工作流:** 打开 **Dedupe Live** 标签页(或 Ctrl+9 窗口)→ 它会填充 `[DEDUPE] UNIQUE` 请求并自动将它们镜像 → 在 **Claude Code** 中:*"读取 `~/.burp-dedupe//live-unique.http`"* 以获取完整的去重集合,或读取 `selection.http` 仅获取你已高亮显示的内容。文件夹路径会在打开时记录到扩展的 **Output** 中,并在每次写入后显示在**状态栏**中。 ### Case manifest(每个请求) 为了让 AI 获得**案例文件,而不是一堆 HTTP 噪声**,每个导出的请求都以 `#` 注释的**清单**作为前缀 — 这是不可跳过的,它位于每个块的前面: 1. **源请求** — method + URL。 2. **身份角色** — `attacker` / `victim`,来自 `X-AI-Use` Header 或 `[attacker]/[victim] port N` 标签。 3. **唯一的原因** — 去重判决结果以及签名基于的内容。 4. **重放命令** — 现成的 `curl` 命令(包含 auth + body)。 5. **预期的安全失败** — IDOR/BOLA 预言机:在*不同*身份下重放应该被拒绝(`401/403/404`);返回另一个身份数据的 `200` 就是漏洞发现。 ``` # --- CASE MANIFEST (read before touching payloads) ------------------------ # 1. Source request : POST https://api-m.paypal.com/v1/tracking/batch/events # 2. Identity role : victim (X-AI-Use: victim, proxy listener port 8083) # 3. Why unique : [DEDUPE] UNIQUE — first request with this signature (method + host + path + # sorted param names + status, per the active preset); its duplicates were folded out. # 4. Replay command : curl -isSk -X POST 'https://api-m.paypal.com/v1/tracking/batch/events' -H 'Cookie: ...' --data-raw '...' # 5. Expected safe : original response 200; replayed under a DIFFERENT identity this should be DENIED — # expect 401/403/404. A 200 returning the other identity's data is the finding. # -------------------------------------------------------------------------- ===== REQUEST ===== POST /v1/tracking/batch/events HTTP/2 ... ``` *清单格式由 [Timur Yessenov (@Timur_Yessenov)](https://x.com/Timur_Yessenov) 建议 — 感谢!* ![磁盘上的 AI 桥接 — ~/.burp-dedupe// 包含 live-unique.http 和 selection.http,每个都是一个 #### 分隔的请求+响应块,准备好供 Claude Code 读取](https://raw.githubusercontent.com/dhakal-bibek/DedupeAI/main/assets/ai-export.png) ## 预设 | 预设 | 视为唯一的判定条件 | |---|---| | Default | method + host + path + 排序后的 param names + status | | Request smuggling | 仅 method + host + path(忽略 params) | | IDOR / Auth | method + host + path(数字 ID 归一化)+ 排序后的 param names | | XSS | method + host + path + 排序后的 query+body param names | | SQLi | method + host + path + 排序后的 param names | | SSRF | method + host + path + query param names | | Open redirect | host + path + query param names(不区分 method) | | SSTI | method + host + path + param names | | Path traversal | method + host + 归一化后的 path + query param names | | Strict | 完整 URL + 所有 params + values + status + content-type | | Custom | 你勾选的任何内容 | ![Dedupe 配置标签页 — 选择一个预设(或勾选单个签名域),设置过滤器和内存上限,粘贴 Header 覆盖,并查看实时统计信息](https://raw.githubusercontent.com/dhakal-bibek/DedupeAI/main/assets/dedupe-config.png) ## 发送唯一请求到 Organizer(右键点击) 主要操作:在 **HTTP history** 中,选择任意数量的行(可以是重复项),右键点击 → **Dedupe → Send unique to Organizer**。扩展程序将会: ![右键点击路径:在 HTTP history 中选择行 → Extensions → Dedupe → Send unique to Organizer(此处选择了 11 行);Dedupe 子菜单还提供了实时窗口和 Ctrl+9 快照](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/42f0f642d7155810.png) 1. 使用当前的签名配置重新计算选择的签名(Notes 列中的标记不是必需的 — 唯一性是实时确定的)。 2. 保留每个签名的第一次出现,丢弃其余的。 3. 如果启用了 **Header overrides**,则通过 `HttpRequest.withUpdatedHeader` / `withAddedHeader` 将它们应用于每个请求。 4. 在后台线程上为每个唯一的、已被覆盖的请求调用 `api.organizer().sendToOrganizer(...)`。 从那里,右键点击 **Organizer → Extensions → …** 中的项目,将它们提供给任何扩展。扩展会读取你交给它的请求字节 — 包括你覆盖的 Header — 即使它是通过原始 socket 分发的(例如 HTTP Request Smuggler、Turbo Intruder),因为源字节正是这些扩展用于攻击采样的内容。 ### Header 覆盖 在 Dedupe 标签页的 **Header overrides** 部分: - 粘贴原始 Header 行(例如 `Cookie: a=1; b=2`, `Authorization: Bearer …`),每行一个。空行和 `#` 注释将被忽略。 - 选择 **Replace if present, add if missing** 或 **Replace only (don't add new headers)**。 - 勾选 **Apply header overrides when sending to Organizer** 并点击 **Apply**。 - 保留的 Header(`Host`, `Content-Length`, `Transfer-Encoding`)将被拒绝,并记录警告。 - 格式错误的行将在扩展日志中按行报告。 ## 注意事项 / 边缘情况 - **现有历史记录可以被追溯标记。** 使用 Dedupe 标签页中的 **"Stamp existing history"** 按钮遍历 `api.proxy().history()` 并就地应用判决结果。或者勾选 **"Auto-stamp existing history when extension loads"** 以在每次加载时自动执行此操作(在重新打开保存的项目时非常有用)。该作业在后台线程上运行,可以取消。在通过之前会重置已见集合,以保持计数一致。 - **更改配置会重置已见集合**,因此你不会在不同的签名规则下得到混合的判决结果。 - **静态资源**(`.css`, `.js`, 图像、字体等)默认会被跳过,以保持已见集合较小。 - **内存上限**:在达到 *Max tracked signatures*(默认 200k)时,将停止添加新密钥,判决结果变为 `OVRF` — 防止在超大型测试中发生 OOM。 - **范围外**:启用 "In-scope only" 以跳过不在 target scope 中的所有内容。 - **路径归一化**(数字 ID → `{n}`,UUID → `{uuid}`,长十六进制 → `{hex}`)在每个预设中都是可选的;针对 IDOR / path traversal 开启它。 - Header 包含:自由文本字段(逗号分隔,小写)— 可用于在 Host Header 攻击中包含 `host` 别名等。 ## 致谢 - AI 导出中每个请求的 **[case manifest](#case-manifest-per-request)** — 源请求、身份角色、唯一的原因、重放命令和预期的安全失败 — 由 **[Timur Yessenov (@Timur_Yessenov)](https://x.com/Timur_Yessenov)** 建议。感谢这个将导出转化为真正案例文件而不是一堆 HTTP 噪声的想法。 - **Body Only (Pretty JSON)** 响应标签页(以及匹配的 Save-for-AI 导出选项)的灵感来自 **[rikeshbaniya](https://github.com/rikeshbaniya)** 同名的 Burp 扩展,在这里使用无依赖的 JSON 重新缩进器重新实现。感谢你的灵感!
标签:AI辅助测试, Burp Suite 插件, HTTP流量分析, JS文件枚举, Web安全, 后台面板检测, 域名枚举, 蓝队分析, 越权测试