前言

这是一道经典的 PHP 代码审计题。题目来自 BUUCTF / CTF² 平台的 [极客大挑战 2019]BuyFlag,主要考察 is_numeric 绕过、松散比较,以及用数组绕过长度校验。记录一下完整解题过程。

题目信息

  • 平台:BUUCTF(CTF²)
  • 类型:WEB
  • 目标:花掉 100000000 money,买到 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!!!

pay.php 页面

查看页面源码,底部 HTML 注释直接泄露了 password 的校验逻辑:

1
2
3
4
5
6
7
8
9
~~~post money and password~~~
if (isset($_POST['password'])) {
$password = $_POST['password'];
if (is_numeric($password)) {
echo "password can't be number</br>";
}elseif ($password == 404) {
echo "Password Right!</br>";
}
}

漏洞分析

结合页面提示与回显,程序依次校验三件事:

  1. 是不是 CUIT 学生 —— 回显 you are Cuiter,由 Cookie user=1 控制;
  2. 密码是否正确 —— 需满足 is_numeric($password) === false 且 $password == 404;
  3. 钱够不够 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
2
3
4
curl -s -X POST 'http://<target>/pay.php' \
-H 'Cookie: user=1' \
-d 'password=404 ' \
-d 'money[]=100000000'

服务器返回(本题 flag 为动态生成,此处略去具体值):

1
you are CuiterPassword Right!CTF2{************-****-****-****-************}

成功拿到 flag

Flag

本题 flag 为动态生成(每次环境不同),成功利用后服务器会返回形如 CTF2{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} 的字符串,此处不再贴出具体值。

总结

  • is_numeric() 与松散比较 == 的差异 —— 用 404(尾部空格)绕过;
  • 身份 / 权限判断藏在 Cookie 里 —— 尝试 user=1;
  • 长度 / 正则类校验对数组入参失效 —— 用 money[]=... 绕过。

参考

  • BUUCTF:[极客大挑战 2019]BuyFlag