在 ai 辅助下开发的一个小工具,主要功能就是从 js 中正则匹配 url 路径并进行 fuzz 测试

链接:https://github.com/ALe1293528/bp_JsFuzz

功能测试:

官方的api接口说明地址:

https://portswigger.github.io/burp-extensions-montoya-api/javadoc/index.html

在新版本的 api 中加入了 MontoyaApi ,这极大简化了插件开发的过程

burp.api.montoya

包含两个类

BurpExtension:所有插件必须实现该接口,内置有Burp插件初始化方法

Burp 会自动检测并加载所有继承了BurpExtension的类

MontoyaApi:Burp通过该接口传给插件一些可以在Burp中执行的方法,内置有访问Burp各个模块的方法

代码结构

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
JsFuzzExtension              ← 插件入口(Montoya BurpExtension)

├── core/ ← 接口发现
│ ├── JsLinkFinder ← 正则提取 JS 中的链接/API
│ └── PassiveJsScanner ← 被动扫描钩子,串起整条流水线

├── security/ ← 安全测试流水线
│ ├── ApiSecurityManager ← 调度器(线程池 + 去重 + 编排)
│ ├── ApiAliveChecker ← 存活检测
│ ├── UnauthorizedScanner ← 未授权/IDOR/敏感数据
│ ├── RiskEngine ← 风险评分
│ └── HttpHelper ← Montoya HTTP 客户端薄封装

├── fuzz/
│ └── ApiFuzzEngine ← 九类 Fuzz 策略 + 401/403 绕过

├── model/ ← 数据模型
│ ├── ApiEndpoint ← 一个接口 + 所有测试结果
│ ├── FuzzAttempt ← 一次 fuzz 请求记录(含原始报文)
│ └── RiskLevel ← Low/Medium/High/Critical 枚举

├── util/
│ ├── UrlNormalizer ← 相对 URL → 绝对 URL
│ └── LruCache ← 有界 LRU 去重缓存

└── ui/ ← Swing 界面
├── MainUI ← 顶层两个 Tab
├── LinkFinderPanel ← "Main" 标签:站点→文件/路径
├── ApiSecurityPanel ← "API Security" 标签:结果表 + 报文查看器
├── ApiTableModel ← 接口结果表模型
├── FuzzAttemptTableModel ← fuzz 尝试表模型
└── Exporter ← CSV / JSON 导出

JsFuzzExension

作为入口类,主要功能为创建 ui 和扫描器

core 接口发现

JsLinkFinder

在这个类中主要就是实现的 https://github.com/InitRoot/BurpJSLinkFinder 的功能

一部分通过 LinkFinder 中的正则匹配

1
2
3
4
5
6
7
8
9
10
11
12
private static final Pattern LINKFINDER = Pattern.compile(
"(?:\"|')(" +
"((?:[a-zA-Z]{1,10}://|//)[^\"'/]{1,}\\.[a-zA-Z]{2,}[^\"']{0,})" +
"|" +
"((?:/|\\.\\./|\\./)[^\"'><,;| *()(%$^/\\\\\\[\\]][^\"'><,;|()]{1,})" +
"|" +
"([a-zA-Z0-9_\\-/]{1,}/[a-zA-Z0-9_\\-/.]{1,}\\.(?:[a-zA-Z]{1,4}|action)(?:[?|/][^\"|']{0,}|))" +
"|" +
"([a-zA-Z0-9_\\-/]{1,}/[a-zA-Z0-9_\\-/]{3,}(?:[?|#][^\"|']{0,}|))" +
"|" +
"([a-zA-Z0-9_\\-]{1,}\\.(?:php|asp|aspx|jsp|json|action|html|js|txt|xml)(?:\\?[^\"|']{0,}|))" +
")(?:\"|')");

另外又加入了一些正则

1
2
3
4
5
6
7
- FETCH → fetch('...'),方法 GET
- AXIOS → axios.get/post/...('...'),方法取自动词;AXIOS_CONFIG → axios({url:...})
- XHR_OPEN → .open('POST', '...'),方法取第一个参数
- JQUERY → $.ajax/get/post/load/getJSON;$.post 推断为 POST,其余 GET
- GRAPHQL → 含 graphql 的路径,方法 POST
- WEBSOCKET → ws:///wss://
- REST_PATH + REST_FEATURES → 命中 /api/ /v1/ /admin/ /pay/ 等特征的路径

PassiveJsScanner

被动扫描钩子,实现 Montoya ScanCheck

  1. 过滤:只处理 URL 含 .js、且不在排除列表里的响应
  2. ui.linkFinder().recordSite(url) 把这个 JS 站点登记到左侧列表
  3. finder.extractAll(body) 提取所有链接
  4. 对每条链接:
  • 用 UrlNormalizer 补全成绝对 URL
  • 分别加进 UI 的 Paths 框和 Files 框(addFilename 从链接里截文件名)
  • 若是 http(s) 接口 → 构造 ApiEndpoint,security.submit(ep, …) 丢进安全流水线,回调里刷新 UI 行
  1. consolidateIssues 同名同 URL 的 issue 只保留一个,避免重复刷屏

security

ApiSecurityManager

主要负责线程管理和去重

ApiAliveChecker

存活检测,先发 HEAD;若失败或返回 405(很多服务器拒绝 HEAD)则回退 GET。然后按 classify() 分类:200–399=Alive / 404=Dead / 其余=Unknown

UnauthorizedScanner

  • 未授权:去掉 Authorization/Cookie/JWT 等认证头重发。查看返回包状态码和大小是否有差别
  • IDOR / 越权:URL 里若有 uid/userId/id=数字,尝试 原值+1 / -1 / 一个哈希随机值
  • 敏感数据:响应包里若出现 token/password/secret/apikey/admin 等关键字则在 fuzz 摘要中标出

Fuzz

所有策略:

# 策略 内容
1 HTTP 方法 换 GET / POST / PUT / DELETE / OPTIONS / HEAD
2/3/4 边界参数 数字边界 0 / -1 / 2147483647,字符串 '"../AAAA...,空参数
5/6 JSON 体 {"id":null}{"admin":true}{"isAdmin":true}
7 参数污染 id=1&id=2
8 伪造 IP 头 X-Forwarded-For: 127.0.0.1
9 Content-Type 切换 application/json / application/x-www-form-urlencoded / multipart/form-data / text/plain
10 401/403 绕过 仅当基线请求被拦截时触发

model

重要的就是 RiskLevel 枚举权重

ui

ui 用 ai 写的,也没什么好说的