WeChall - PHP 0815

Challenge

一个有 SQL 注入漏洞的 PHP 脚本,in_array() 白名单检查可被绕过。要求提供最短的修复(least effort fix)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
$whitelist = array(1, 2, 3);
if (false === ($show = isset($_GET['show']) ? $_GET['show'] : false)) {
die('MISSING PARAMETER; USE foo.bar?show=[1-3]');
}
elseif (in_array($show, $whitelist)){
$query = "SELECT 1 FROM `table` WHERE `id`=$show";
echo 'Query: '.htmlspecialchars($query, ENT_QUOTES).'<br/>';
die('SHOWING NUMBER '.htmlspecialchars($show, ENT_QUOTES));
}
else {
die('HACKER NONONO');
}
?>

Solution

漏洞分析: in_array() 默认使用 loose comparison(==)。白名单是整数 1, 2, 3,而输入 "1 union select 1" 通过 == 比较时会先转为整数:"1 union select 1" == 1 → true。因此 whitelist 检查被绕过,$show 仍然带着完整注入字符串进入 SQL 查询。

最短修复:

挑战要求「least effort」——在代码的某个逻辑位置增加最少字符来修复漏洞。

有两种 2 字符的方案:

  • 1* — 将 SQL 改为 WHERE \id`=1*\(show`,在 SQL 层面做乘法运算强制 `\)show` 转为数字
  • -0 — 将 SQL 改为 WHERE \id`=$show-0`,减法运算同样强制转为数字

两种都只增加 2 个字符,比 (int)$show(4 字符)或 in_array($show, $whitelist, true)(6 字符)更短。

漏洞页面接受 answer 字段提交,cmd=Fix+It,不需要 CSRF token。

1*