[红日安全]代码审计Day16 - 深入理解$_REQUESTS数组
字数 1391 2025-08-18 11:37:46
深入理解PHP中的$_REQUEST数组与安全审计
1. $_REQUEST数组基础
1.1 $_REQUEST数组的定义
$_REQUEST是PHP中的一个超全局数组,它包含了$_GET、$_POST和$_COOKIE数据的合集。但需要注意以下几点:
- 数据是复制过去的,不是引用
- 默认情况下不包含
$_FILES信息 - 数据顺序和覆盖规则由
php.ini中的request_order或variables_order决定
1.2 $_REQUEST与过滤问题
常见的安全问题是开发者只过滤了$_GET、$_POST或$_COOKIE,但却使用了$_REQUEST中的数据,导致过滤被绕过。
示例漏洞代码:
function cleanInput($data) {
return (int)$data;
}
$id = cleanInput($_GET['id']); // 过滤GET参数
$mode = $_REQUEST['mode']; // 但使用未过滤的REQUEST参数
2. 实际案例分析
2.1 示例1:FTP命令注入
漏洞代码:
$mode = $_REQUEST['mode']; // 直接从REQUEST获取未过滤的数据
ftp_login($conn, $ftp_user, $ftp_pass);
ftp_raw($conn, "MODE $mode"); // 直接拼接未过滤的数据
攻击payload:
?mode=1%0a%0dDELETE%20test.file
漏洞原理:
- 程序过滤了GET/POST/COOKIE数据,但使用了REQUEST数据
- 通过CRLF注入(
%0a%0d)可以在FTP命令中注入新命令 - 最终可执行删除文件等恶意操作
2.2 示例2:WordPress插件XSS漏洞
漏洞代码:
function render_tab3() {
$tab = $this->get_current_tab(); // 获取过滤后的tab值
echo '<div class="aiowps_ad_intro">'.$_REQUEST['tab'].'</div>'; // 但输出未过滤的REQUEST值
}
攻击payload:
POST /wp-admin/admin.php?page=aiowpsec&tab=tab3
tab="><script>alert(1)</script>
漏洞原理:
- 插件有过滤函数处理
$tab变量 - 但直接输出
$_REQUEST['tab']导致XSS - 由于
request_order设置为"GP",POST值会覆盖GET值
3. $_REQUEST相关配置
3.1 request_order配置
php.ini中的request_order决定了$_REQUEST数组中变量的来源和顺序:
- 默认值:通常为"GP" (GET和POST)
- 可能的值:G, P, C, 或其组合(如"GPC")
- 顺序从左到右,后面的会覆盖前面的同名变量
示例:
request_order = "GP" # 先GET后POST,POST会覆盖GET
3.2 variables_order
当request_order未设置时,会使用variables_order的值来决定$_REQUEST的内容。
4. 安全防护措施
4.1 最佳实践
- **避免直接使用\(_REQUEST**:明确使用`\)_GET
、\(_POST`或`\)_COOKIE` - 统一过滤:如果必须使用
$_REQUEST,确保所有来源都经过相同过滤 - 输出编码:输出前使用
htmlentities()等函数进行编码
4.2 修复方案
错误方式:
$input = $_REQUEST['input'];
正确方式:
// 方案1:明确来源
$input = $_POST['input'] ?? $_GET['input'] ?? '';
// 方案2:统一过滤
function cleanInput($data) {
// 实现过滤逻辑
}
$input = cleanInput($_REQUEST['input']);
// 方案3:输出编码
echo htmlentities($input, ENT_QUOTES, 'UTF-8');
5. 相关CTF题目分析
5.1 题目概述
题目提供了一个SSRF(Server Side Request Forgery)漏洞场景,要求访问本地flag.php获取flag。
关键代码:
function check_inner_ip($url) {
// 检查是否为内网IP
return ip2long('127.0.0.0')>>24 == $int_ip>>24
|| ip2long('10.0.0.0')>>24 == $int_ip>>24
|| ip2long('172.16.0.0')>>20 == $int_ip>>20
|| ip2long('192.168.0.0')>>16 == $int_ip>>16
|| ip2long('0.0.0.0')>>24 == $int_ip>>24;
}
function safe_request_url($url) {
if (check_inner_ip($url)) {
echo $url.' is inner ip';
} else {
// 发起请求
}
}
5.2 解题思路
- 需要绕过内网IP检测
- 利用URL解析差异或特殊协议
- 可能的解法:
- 使用
0代替127.0.0.1(如http://0/flag.php) - 使用域名重定向
- 利用DNS解析特性
- 使用
6. 总结
$_REQUEST数组是安全审计中常被忽视的风险点- 确保过滤逻辑覆盖所有数据来源
- 明确变量来源比使用
$_REQUEST更安全 - 输出前必须进行适当的编码处理
- 理解
request_order和variables_order的影响
通过深入理解$_REQUEST的特性和相关安全问题,可以在代码审计和开发过程中有效避免此类漏洞。