WeChall - Time to Reset
Challenge
提交 admin@wechall.net 的 password reset token。Token
绑定 session,源码公开。
Solution
漏洞分析
源码(?highlight=christmas)暴露了 token 生成逻辑:
1 | // 每次请求(GET 或 POST)都重新播种 |
种子 = time() + rand(0, 100),仅 101 种可能。CSRF
token(32 字符)是种子后的首次 32 次 rand()
输出,直接暴露在页面中。
页面中的两个 token
挑战页面包含两个 hidden input:
csrf(32 字符)— 位于 password reset form 内右键 → 查看页面源代码,搜索1
2
3<tr><td colspan="3">
<input type="hidden" name="csrf" value="5faruVeXQSpw78BPrkYpJqPqmmJfKXdI" />
</td>name="csrf"即可找到。gwf3_csrf(8 字符)— 位于 solution form 内,用于提交答案1
<input type="hidden" name="gwf3_csrf" value="eIt0IMws" />
破解流程
关键:用来破解读取的不是 GET 页面的 CSRF,而是 POST
请求返回页面的 CSRF。因为每次请求 PHP 都重新
srand(time()+rand(0,100)),token 和页面 CSRF
在同一个种子下连续生成(32 + 16 次 rand 调用)。必须先 POST reset 触发
token 生成,再用响应页面中的新 CSRF 推导同一种子下的 token。
Step 1 — GET 页面,提取 CSRF 和 gwf3_csrf
1 | curl -sk --max-time 15 -D /tmp/ttr_headers.txt \ |
输出: 1
lGYstQosLkv6kYxtH6Ftvj6GAjEEMklq
用同样的方式提取 gwf3_csrf: 1
grep -oP 'name="gwf3_csrf"\s*value="\K[^"]+'
Step 2 — POST password reset,触发 token 生成
1 | curl -sk --max-time 15 -D /tmp/ttr_headers2.txt \ |
响应中会包含 msg_mail_sent
提示,以及一个全新的
csrf(同一请求中生成的): 1
<input type="hidden" name="csrf" value="7MkocZHPcc6rkDkGVaSRVltE1ONJH5zM" />
Step 3 — 从响应头获取服务器时间
1 | grep -i '^date:' /tmp/ttr_headers2.txt |
转换为 epoch:1781352811
Step 4 — PHP 离线暴力搜索种子
1 |
|
执行: 1
2
3php brute_force.php
# SEED=1781352853
# TOKEN=XfmLddQ4n1NuBpUD
搜索空间仅 101(偏移量)× 7(±3 秒)= 707 种组合,毫秒级出结果。
Step 5 — 提交预测的 token
1 | curl -sk --max-time 15 \ |