【BUUCTF】WEB-刷题记录-[极客大挑战 2019]BuyFlag
前言
这是一道经典的 PHP 代码审计题。题目来自 BUUCTF / CTF² 平台的 [极客大挑战 2019]BuyFlag,主要考察 is_numeric 绕过、松散比较,以及用数组绕过长度校验。记录一下完整解题过程。
题目信息
- 平台:BUUCTF(CTF²)
- 类型:WEB
- 目标:花掉
100000000money,买到 flag
信息收集
首页菜单里有 Home / PayFlag,进入 pay.php:
Flag need your 100000000 money
If you want to buy the FLAG:
You must be a student from CUIT!!!
You must be answer the correct password!!!
查看页面源码,底部 HTML 注释直接泄露了 password 的校验逻辑:
1 | ~~~post money and password~~~ |
漏洞分析
结合页面提示与回显,程序依次校验三件事:
- 是不是 CUIT 学生 —— 回显
you are Cuiter,由 Cookieuser=1控制; - 密码是否正确 —— 需满足
is_numeric($password) === false且$password == 404; - 钱够不够 100000000 —— 且对入参长度有限制(回显
Nember lenth is too long)。
1)password:is_numeric + 松散比较绕过
404是纯数字,会被is_numeric拦下;- 在
404后面加一个空格得到"404 ":is_numeric("404 ")为 false(带空白不算合法数字),而"404 " == 404因为松散比较会先转成数字,等于 404 为 true。 - 因此
password=404(注意末尾有一个空格)即可通过校验。
视 PHP 版本不同,
404%00、404.0等写法也可能生效。
2)身份:Cookie: user=1
服务端通过 Cookie 判断是否为 CUIT 学生,把它设为 1 即可。
3)money:用数组绕过长度限制
- 直接提交
money=100000000(9 位数)会触发长度限制,回显Nember lenth is too long; - 尝试科学计数法
1e8,长度虽然短,但服务端按整型处理导致比较失败,回显you have not enough money,loser~; - 关键一步:把
money以数组形式提交money[]=100000000。此时strlen()无法对数组取长度(返回 null / 触发告警),长度校验被绕过,同时该值在比较中也被放行,直接输出 flag。
这是 PHP 里常见的技巧:凡是
strlen/is_numeric/ 正则等“针对字符串”的校验,传入数组往往会让校验函数失效。
解题步骤
一条请求即可拿下:
1 | curl -s -X POST 'http://<target>/pay.php' \ |
服务器返回(本题 flag 为动态生成,此处略去具体值):
1 | you are CuiterPassword Right!CTF2{************-****-****-****-************} |
Flag
本题 flag 为动态生成(每次环境不同),成功利用后服务器会返回形如 CTF2{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} 的字符串,此处不再贴出具体值。
总结
is_numeric()与松散比较==的差异 —— 用404(尾部空格)绕过;- 身份 / 权限判断藏在 Cookie 里 —— 尝试
user=1; - 长度 / 正则类校验对数组入参失效 —— 用
money[]=...绕过。
参考
- BUUCTF:[极客大挑战 2019]BuyFlag
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 末心的小博客!











![【BUUCTF】WEB-刷题记录-[极客大挑战 2019]BuyFlag](/../attachments/image-20261014052001111.png)
