校对依据:直接解包了你桌面上的
turbo-intruder-all .jar,读了它的META-INF/MANIFEST.MF、内置examples/*.py,以及burp/Scripts.class里内嵌的 Python 运行时(RequestEngine/Engine/queue的真实签名)。 所以下面的参数名、默认值、脚本写法,跟你手上这个版本是一致的,不是照抄官网新版文档。
0. 先搞清楚你这个 jar
| 项 | 值 |
|---|---|
| 文件 | turbo-intruder-all .jar(39.7 MB,fat jar,内置 Jython 2.7.0) |
| 内部版本 | v1.1.0(BurpExtender 里 Loaded Turbo Intruder v1.1.0) |
| 构建时间 | 2020-08-21 |
| 主类 | burp.Fast_httpKt |
| 脚本语法 | Python 2.7(Jython)—— 没有 f-string,print 用语句写法 |
判断:能用,但这是 5 年前的版本。当前官方是 2.x,参数更全(autoContentLength、hostHeader、learnCharsetLength、rateLimit 等)、对 HTTP/2 单包攻击支持更完整。
如果你在新版 Burp(JRE 17/21)上加载报错或脚本跑不动,别修这个 jar,直接去 BApp Store 装新版——省时间。
加载
Burp → Extender → Extensions → Add
Extension type: Java
Select file: turbo-intruder-all .jar
装好后:任意请求 → 右键 → Extensions → Turbo Intruder(或 Send to Turbo Intruder),弹出攻击窗口。
窗口四块
┌─────────────────────────────────────────────┐
│ Request 模板(用 %s 当占位符) [Attack] │
├─────────────────────────────────────────────┤
│ Python 脚本编辑器(queueRequests / handleResponse)│
├─────────────────────────────────────────────┤
│ 结果表:payload | status | length | wordcount | time │
└─────────────────────────────────────────────┘
模板里写 %s 的位置就是载荷插入点;多个 %s 对应 queue() 里传的列表,按顺序填。
1. 最小可用脚本(官方 default.py,已核对)
def queueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint,
concurrentConnections=5,
requestsPerConnection=100,
pipeline=False
)
for i in range(3, 8):
engine.queue(target.req, randstr(i), learn=1)
engine.queue(target.req, target.baseInput, learn=2)
for word in open('/usr/share/dict/words'):
engine.queue(target.req, word.rstrip())
def handleResponse(req, interesting):
if interesting:
table.add(req)
三件事必须记住:
- 只有两个函数会被调用:
queueRequests(target, wordlists)发请求,handleResponse(req, interesting)处理响应。 learn=1/learn=2把响应登记成基线;之后凡与基线不同的响应,interesting=True。这是它比 Burp Intruder 好用的核心。table.add(req)才把这条放进结果表;不 add 就是白跑。
2. API 全表(v1.1.0 真实签名)
RequestEngine 构造参数
RequestEngine(endpoint, callback=None, engine=Engine.THREADED,
concurrentConnections=50, requestsPerConnection=100,
pipeline=False, maxQueueSize=100, timeout=5,
maxRetriesPerRequest=3, readCallback=None, readSize=1024,
resumeSSL=True, autoStart=True)
| 参数 | 默认 | 说明 |
|---|---|---|
endpoint |
— | 必填,target.endpoint 或 'https://host:443' |
engine |
THREADED |
见下表 |
concurrentConnections |
50 | 并发连接数。默认模板里写 5 是保守值 |
requestsPerConnection |
100 | 单连接复用发多少个请求 |
pipeline |
False | True 走 HTTP/1.1 管道;填数字=每 N 个请求读一次 |
maxQueueSize |
100 | 未发出请求的队列上限,内存保护 |
timeout |
5 | 秒,socket 读超时(注意官方新版默认不同) |
maxRetriesPerRequest |
3 | 失败重试次数 |
readCallback / readSize |
None / 1024 | 流式读取回调,可用于"读到 token 就发下一条" |
autoStart |
True | False 时需手动 engine.start() |
resumeSSL |
True | 断点续传 TLS 会话 |
引擎怎么选(关键判断)
class Engine:
BURP = 1 # 走 Burp 自身发包,可见于 Proxy history,慢,但一定能过 Burp 的 HTTP/2 栈
THREADED = 2 # 线程池 + 原生 socket,默认。快,适合 HTTP/1
ASYNC = 3 # 异步原生 socket,HTTP/1
HTTP2 = 4 # 异步 + HTTP/2 多路复用,竞态/单包测试用它
Engine.BURP有硬限制:requestsPerConnection被强制为 1、pipeline 关闭、readCallback不可用(源码里直接 print 提示)。- 做竞态选
HTTP2;做纯爆破选THREADED;要结果落进 Burp Proxy 历史选BURP。
方法与属性
engine.queue(template, payloads=None, learn=0, callback=None, gate=None, label=None)
engine.openGate(gate) # 放行被 gate 挂住的请求
engine.start(timeout=5) # autoStart=False 时手动启动
engine.complete(timeout=-1) # 等队列跑完再返回,竞态脚本必加
engine.userState # dict,跨响应共享状态
req.status # 状态码
req.length # 响应长度
req.wordcount # 单词数(比长度更抗随机噪声)
req.time # 本次请求耗时(秒,浮点)—— 时序攻击靠它
req.response # 完整原始响应字符串
req.label # queue 时打的标签,用于分类处理
req.engine # 反向拿到引擎,访问 userState
req.template # 原始模板
req.words # 本次用的载荷列表
req.request # 实际发出的请求
3. 常用套路(全部来自 jar 内 examples/,可直接抄)
3.1 单参数字典爆破
def queueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint,
concurrentConnections=5,
requestsPerConnection=100,
pipeline=False)
for word in open('pass.txt'):
engine.queue(target.req, word.rstrip())
def handleResponse(req, interesting):
if req.status != 404:
table.add(req)
3.2 多参数笛卡尔积(两个 %s)
for u in open('users.txt'):
for p in open('pass.txt'):
engine.queue(target.req, [u.rstrip(), p.rstrip()])
3.3 递归目录爆破
def handleResponse(req, interesting):
if '404 Not Found' not in req.response:
table.add(req)
for word in open('dirs.txt'):
req.engine.queue(req.template, req.words[0] + '/' + word.rstrip())
3.4 多主机同一套字典
req = '''GET / HTTP/1.1
Host: %s
Connection: keep-alive
'''
engines = {}
for domain in open('domains.txt'):
d = domain.rstrip()
engines[d] = RequestEngine(endpoint='https://' + d + ':443')
for word in open('words.txt'):
for d, engine in engines.items():
engine.queue(req, word.rstrip() + '.' + d)
注意:多主机时统计面板的数字不准,别拿它估算进度。
3.5 限速(防封、防把自家服务打挂)
import time
triedWords = 20 # 每 20 个词
timeSecs = 5 # 停 5 秒
throttleMillisecs = 200
def queueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint,
concurrentConnections=5,
pipeline=False,
engine=Engine.BURP) # BURP 引擎更温和
n = 0
for word in open('words.txt'):
time.sleep(throttleMillisecs / 1000.0)
engine.queue(target.req, word.rstrip())
n += 1
if n == triedWords:
time.sleep(timeSecs)
n = 0
3.6 竞态(同时发,是本工具最值钱的用法)
def queueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint,
concurrentConnections=30,
requestsPerConnection=100,
pipeline=False)
for i in range(30):
engine.queue(target.req, target.baseInput, gate='race1')
engine.openGate('race1') # 非阻塞,把所有被挂住的请求一起放出去
engine.complete(timeout=60) # 等全部回来
def handleResponse(req, interesting):
table.add(req)
gate='race1'的含义:请求发到最后一个字节之前就挂住,openGate一喊一起放。这就是"同时到达"的原理。- 想真正逼近"单包",把引擎换成
engine=Engine.HTTP2(HTTP/2 多路复用后多请求落进同一个 TCP 包)。v1.1.0 有这个引擎,但不如新版成熟,测不出差异就换新版再试。
3.7 时序盲注 / 时间侧信道
def queueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint,
concurrentConnections=1,
requestsPerConnection=100)
engine.userState['base_times'] = []
for i in range(20):
engine.queue(target.req, randstr(i), label='benchmark')
for username in ['test', 'foo', 'admin']:
engine.queue(target.req, username)
def handleResponse(req, interesting):
if req.label == 'benchmark':
req.engine.userState['base_times'].append(req.time)
elif req.time > max(req.engine.userState['base_times']) + 10:
table.add(req)
3.8 边读边发(token 依赖场景)
def queueRequests(target, wordlists):
global engine
engine = RequestEngine(endpoint=target.endpoint,
concurrentConnections=2,
readCallback=handleRead,
readSize=256) # 单次 socket 读的大小
engine.queue(target.req)
def handleRead(data): # data 只是"最后一次读到的内容"
if 'token' in data:
engine.queue('something-using-the-token')
BURP 引擎不支持 readCallback,会直接打印提示。
3.9 无限爆破 / 剪贴板词表
for word in wordlists.clipboard: # 直接吃剪贴板,一行一个
engine.queue(target.req, word)
for word in wordlists.observedWords: # 被动扫描期间见过的词
engine.queue(target.req, word)
seed = 0
while True: # a, b, ... aaa, aab 无限生成
batch = []
seed = wordlists.bruteforce.generate(seed, 5000, batch)
for word in batch:
engine.queue(target.req, word)
4. 结果过滤
def handleResponse(req, interesting):
if interesting: # 与 learn 基线不同
table.add(req)
if req.status == 200 and req.length > 5000:
table.add(req)
if req.label == 'benchmark':
pass # 基线样本不入表
learn=N是分组基线:多个learn=1的响应互相比较,得出"正常长什么样"。- 只按
length判会误报(页面带随机 csrf 值长度会飘),wordcount更稳。 - 结果表右键可以看 request/response 原文,也可以导出。
5. 性能调优
| 目标 | 配置 |
|---|---|
| 单纯要快(HTTP/1) | THREADED,concurrentConnections=50,requestsPerConnection=100 |
| HTTP/2 目标 / 竞态 | HTTP2,concurrentConnections 按目标承受力,30 起步 |
| 不能把目标打挂 | 降 concurrentConnections 到 2~5,加 3.5 的 sleep 限速 |
| 结果要进 Burp 历史 | engine=Engine.BURP(并接受单连接限制) |
| 内存吃紧 | 降 maxQueueSize(默认 100) |
| 目标慢/抖 | 提高 timeout(默认只有 5 秒!) |
6. 坑清单
| 现象 | 原因 | 处理 |
|---|---|---|
Loaded ... v1.1.0 后窗口打不开 / 报错 |
老版本在新 Burp + JRE 17+ 上兼容性差 | 换 BApp Store 新版 |
脚本报 SyntaxError |
用了 Python 3 语法(f-string、print() 混用) |
Jython 2.7,用 % 格式化 |
| 请求发出去了结果表空 | 忘了 table.add(req) |
补上 |
interesting 永远 False |
没做 learn,或基线样本就在噪声里 |
先发 3~7 个 randstr(i) + 1 个 baseInput 建基线 |
| 一条都没回来 | endpoint 与模板里的 Host 不匹配 |
端口/协议对齐 |
Engine.BURP 下并发不生效 |
该引擎强制单连接单请求 | 换 THREADED |
| 大字典跑到一半停 | maxQueueSize 撑满 + 目标超时 |
提 maxQueueSize 和 timeout |
| 拿到 429 / 被封 | 并发过高 | 限速 + 降并发 |
%s 里的特殊字符没编码 |
模板替换是原文拼接 | 自己 urllib.quote() |
7. 蓝队视角:这东西在日志里长什么样
Turbo Intruder 的流量跟 Burp Intruder 有明显区别,适合当检测口径:
1. 单 TCP 连接上复用 100 个请求 → requestsPerConnection 的指纹
2. HTTP/1.1 pipelining:一个连接里请求不等响应连发 → 顺序错乱的请求时间戳
3. 同一毫秒内并发命中同一接口,payload 不同 → 竞态攻击特征(正常业务几乎没有)
4. HTTP/2 单连接上瞬间涌出几十个 stream,时间差 < 1ms → 单包攻击特征
5. 请求节奏完全均匀(无人类点击间隔、无静态资源请求,只打同一个接口)
6. UA/Cookie 固定不变,Referer 缺失,只重复单一参数
落地检测建议:
- 按 (源IP, 目标接口) 做 1 秒窗口聚合:请求数 > 30 且参数各不相同 → 告警
- HTTP/2 统计单连接 stream 数:短时间内 > 20 个并发 stream 且路径相同 → 关注
- 登录/优惠券/提现这类"一次性语义"接口,同一账号在同一秒内出现多次成功 → 竞态告警
- 反向踩点:自家系统用这套脚本自测,能打出来的问题在日志里一定也能看见,
这条链路(自测 → 看日志 → 写规则)比直接抄规则更值钱
边界:这套东西只在授权范围用(靶场、自家资产、有书面授权的项目)。竞态类攻击尤其注意——打 500 次成功 500 次,可能直接把生产数据写乱。
8. 速查:一条命令跑起来
1. Burp 装上 jar → 右键目标请求 → Send to Turbo Intruder
2. 模板把要变的位置改成 %s
3. 粘贴 3.1 或 3.6 的脚本
4. 填并发数、点 Attack
5. 看结果表 → 挑 interesting 的肉眼验证