[红日安全]代码审计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:

  1. in_array()'7shell.php'强制转换为数字7
  2. 数字7在1-24范围内
  3. 绕过安全检查,实现任意文件上传

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 漏洞点

  1. in_array()未启用严格模式
  2. stop_hack()函数过滤不完整
  3. 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. 总结

  1. in_array()默认的弱类型比较可能导致安全绕过
  2. 类型转换问题常出现在文件上传、权限检查、输入验证等场景
  3. 结合SQL注入时危害更大
  4. 修复关键是启用严格模式或确保类型一致性
  5. 防御需要多层次:输入验证、参数化查询、输出编码等

6. 扩展思考

  1. PHP中其他存在弱类型比较问题的函数:array_search()==比较等
  2. 类似漏洞在自动化漏洞扫描中可能被忽略
  3. 开发中应建立安全编码规范,避免此类问题
PHP代码审计:in_ array()函数缺陷与安全风险 1. in_ array()函数基础 1.1 函数定义 in_array() 是PHP中用于检查数组中是否存在某个值的函数,其定义如下: $needle : 要搜索的值 $haystack : 要搜索的数组 $strict : 是否进行严格类型检查(默认为FALSE) 1.2 弱类型比较问题 当 $strict 参数为FALSE(默认值)时, in_array() 会进行弱类型比较,可能导致意外的类型转换: 2. 安全漏洞实例分析 2.1 文件上传绕过案例 原始代码片段: 漏洞利用 : 攻击者可提交 7shell.php 作为文件ID: in_array() 将 '7shell.php' 强制转换为数字7 数字7在1-24范围内 绕过安全检查,实现任意文件上传 2.2 SQL注入案例(Piwigo 2.7.1) 漏洞位于 include/functions_rate.inc.php : $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语句: 3. CTF题目分析 3.1 题目代码 3.2 漏洞点 in_array() 未启用严格模式 stop_hack() 函数过滤不完整 SQL语句直接拼接用户输入 3.3 利用方法 假设users表有5条记录,白名单为 array(1,2,3,4,5) Payload示例 : 由于 in_array() 的弱类型比较: '1 union select 1,flag,3,4 from flag' 被强制转换为数字1 数字1在白名单中 绕过检查,执行SQL注入 4. 修复建议 4.1 启用严格模式 4.2 类型强制转换 4.3 使用正则表达式验证 4.4 参数化查询 对于SQL注入防护: 5. 总结 in_array() 默认的弱类型比较可能导致安全绕过 类型转换问题常出现在文件上传、权限检查、输入验证等场景 结合SQL注入时危害更大 修复关键是启用严格模式或确保类型一致性 防御需要多层次:输入验证、参数化查询、输出编码等 6. 扩展思考 PHP中其他存在弱类型比较问题的函数: array_search() 、 == 比较等 类似漏洞在自动化漏洞扫描中可能被忽略 开发中应建立安全编码规范,避免此类问题