WeChall - Stop us

Challenge

Noother 写了一个卖 .xyz domain 的 PHP 小站。目标是找到漏洞,不花钱完成购买。

Solution

purchaseDomain()reduceMoney() 之间有约 6 秒间隙(三次 nooth_message() 各 sleep 2 秒)。PHP 默认 ignore_user_abort = false,客户端断开连接后,PHP 在 sleep 间隙检测到中止并终止脚本。利用这个窗口可以让 purchaseDomain() 提交但 reduceMoney() 被跳过。

利用步骤:

  1. 加载余额:?load=balance(+$10,+1 funding)
  2. 等 timeout 结束(45 秒 cooldown)
  3. 发送购买请求,curl 设置 --max-time 12:请求约 12s 后被切断,此时 purchaseDomain() 已执行(domains+1,money 未扣)但 reduceMoney() 未执行
  4. 再等一次 timeout 结束,发一次正常购买(不切断)
  5. 此时 fundings=1,domains=2,条件 fundings < domains 触发,自动解决

关键源码逻辑:

1
2
3
4
noothtable::purchaseDomain($sid);   // domains=domains+1 WHERE money>=price
// ~6s sleep via nooth_message()
noothtable::reduceMoney($sid, $price); // money=money-price
// 随后检查 fundings < domains

注意第二步必须是正常购买——如果第二次也切断,domains 只+1 但 fundings=1,条件仍然 fundings >= domains。只有 purchaseDomain 成功两次而 reduceMoney 只执行一次,才能制造差值。