1. 疑问与原理解析
疑问:代码中使用了 set_token(),每次登录失败都会刷新 Token,并且验证逻辑是在后端进行的 (if($token == $_SESSION['token']))。既然 Token 是动态随机的,且每次只能用一次,为什么还能爆破?
原理 :这种机制虽然有效地防止了 多线程并发爆破 (因为 Token 是一次性的,线程 A 用了,线程 B 的就废了)。但是,它 无法防止单线程的递归爆破。
因为服务器为了让正常用户能继续尝试登录,必须在 响应包 的 HTML 表单中返回一个新的 Token:

<input type="hidden" name="token" value="s8798df7s98d7f98s7df..." />
攻击工具可以模拟浏览器的行为:“看一眼上次回包里的新 Token,把它填进这次的请求包里”。
2. 渗透测试过程 (Burp 高级操作)
这一关不能用普通的 Intruder 模式,必须配置 递归提取 (Recursive Grep)。
第一步:抓包与模式选择
- 随便输入账号 test、密码 test,抓包。
- 发送到 Intruder。
- Attack Type (攻击模式):必须选择 Pitchfork (草叉模式,一一对应 (多对多并行),请求总数取决于最短的那一个 Payload 列表的行数)。

第二步:设置变量位置
我们需要标记两个位置:
password的值。token的值。
示例:
password=§test§&token=§38649789...§
第三步:配置 Payload (重头戏)
Payload Set 1 (对应 password):
- Type:
Simple list - Load: 载入密码字典。

Payload Set 2 (对应 token):
- Payload Type: 选择 Recursive Grep (递归 grep)。
- 它的作用是:“拿上一次请求的响应结果,作为下一次请求的 Payload。”
- BP 的普通模式是一股脑发包,或者并发发包,它不知道每次请求需要带上一次服务器给的新 Token,导致所有请求失效。
- 使用了 Recursive Grep 之后:
- 配置:

第四步:设置提取规则 (Settings 选项卡)
切到 Settings 选项卡,找到 Grep – Extract (Recursive Grep 提取规则) 区域。
- 勾选
Extract the following items from responses。 - 点击 Add。
- Burp 会弹出一个框,点击 Refetch response,去 Response 响应包里选。找到那行
<input type="hidden" name="token" value="..." />。 - 选中
value引号里面的那串 Token 字符串。 - Burp 会自动生成正则表达式。点击 OK。
- 回到 Payloads 选项卡,确认 Payload Set 2 已经自动关联了这个提取规则。


第五步:设置单线程 (至关重要!)
因为 Token 是一次一换的,第 2 个请求必须等第 1 个请求拿到 Token 才能发。
- 在 Resource Pool (资源池) 选项卡中。
- 创建一个新的资源池。
- Maximum concurrent requests (最大并发请求数):设置为 1。

第六步:开始攻击
点击 Start Attack。会发现攻击速度比以前慢(因为是单线程),但 Token 每次都在变,且每次都能成功绕过 Token 校验,看好对应关系,会发现下个包中的 token 值,就是上个包中的 token 返回值,直到爆破出正确密码。

3. 代码审计
查看源码 bf_token.php:
// 后端验证
if($token == $_SESSION['token']){// ... 验证账号密码 ...} else {$html.= '<p> csrf token error</p>';}
// 漏洞点:在验证结束后,生成了新的 Token,并且在后续的 HTML 中输出了。set_token();
// ...
<input type="hidden" name="token" value="<?php echo $_SESSION['token'];?>" />
结论 :
Token 机制本身主要用于防御 CSRF(跨站请求伪造),它的设计初衷并不是为了防御 暴力破解 。
虽然它客观上增加了爆破的难度(强制单线程,降低速度),但并没有从根本上解决暴力破解的问题。
4. 修复方案 (防爆破的正确姿势)
既然 Token 防不住,那怎么防爆破?
- 验证码:加一个图形验证码(Token 是机器看不见的,但验证码需要图像识别)。
- 账号锁定:连续失败 5 次,锁定账号 30 分钟。
- IP 风控:同一 IP 请求频率过高,直接封禁。
- 延时响应:每次失败后,sleep(2) 两秒再返回结果,拖慢爆破速度。