[红日安全]代码审计Day5 - escapeshellarg与escapeshellcmd使用不当
字数 1538 2025-08-29 08:32:25
PHP escapeshellarg与escapeshellcmd使用不当漏洞分析
1. 漏洞背景
本文分析PHP中escapeshellarg()与escapeshellcmd()函数同时使用时可能导致的命令注入漏洞,以及相关的邮件函数安全问题。
2. 核心漏洞原理
2.1 mail函数的安全问题
PHP的mail()函数底层调用Linux的sendmail程序发送邮件,其第五个参数additional_parameters可以传递sendmail支持的选项:
-O option=value- 设置队列目录-X logfile- 指定日志文件-f from_email- 指定发件人邮箱
其中-X参数可以指定日志文件路径,如果将日志写入web目录并设置为.php后缀,可能导致代码执行。
2.2 filter_var()的绕过
filter_var($email, FILTER_VALIDATE_EMAIL)用于验证邮箱格式,但存在以下问题:
- 特殊字符必须放在双引号中
- 可以通过转义空格绕过检测
- 通过重叠单引号和双引号欺骗验证
2.3 escapeshellcmd与escapeshellarg的交互问题
当这两个函数一起使用时,可能导致特殊字符逃逸:
escapeshellarg先对单引号转义并添加外层引号escapeshellcmd再对特殊字符转义- 转义字符被解释导致引号逃逸
示例分析:
$input = "127.0.0.1' -v -d a=1";
$arg = escapeshellarg($input); // 结果为:'127.0.0.1'\'' -v -d a=1'
$cmd = escapeshellcmd($arg); // 结果为:'127.0.0.1'\\'' -v -d a=1\'
最终执行的命令相当于:
curl 127.0.0.1\ -v -d a=1'
3. PHPMailer实例分析
3.1 CVE-2016-10033
漏洞原因:
- 未对
$params变量严格过滤 - 当
safe_mode关闭时,mail()函数传入$params参数 $params来自$this->Sender,而setFrom函数中的邮箱验证可绕过
利用Payload:
a( -OQueueDirectory=/tmp -X/var/www/html/x.php )@a.com
3.2 CVE-2016-10045
修复后绕过:
添加了escapeshellcmd函数,但结合mail()底层的escapeshellarg,导致单引号逃逸。
利用Payload:
a'( -OQueueDirectory=/tmp -X/var/www/html/x.php )@a.com
最终执行的参数变为:
'-fa'OQueueDirectory=/tmp -X/var/www/html/test.php \)@a.com\'
3.3 漏洞利用条件
- PHP版本 < 5.2.0
- PHPMailer < 5.2.18 (CVE-2016-10033) 或 < 5.2.20 (CVE-2016-10045)
- PHP未安装PCRE扩展
- safe_mode = false
4. 修复建议
- 避免同时使用
escapeshellcmd()和escapeshellarg()函数 - 对用户输入进行严格验证
- PHPMailer官方修复方案:检测转义字符时不传递
-f参数
5. CTF题目分析
题目代码关键点:
- 使用
parse_url检查URL scheme必须是http或https - 对URL参数先后应用
escapeshellarg和escapeshellcmd - 通过
system("curl " . $url)执行命令
利用思路:
利用escapeshellarg和escapeshellcmd的交互问题构造特殊URL,绕过scheme检查并执行命令。
6. 总结
- PHP邮件函数底层实现存在安全隐患
- 邮箱验证函数可被绕过
- shell转义函数组合使用可能导致参数逃逸
- 实际案例(PHPMailer)展示了漏洞的严重性
- 修复时需要全面考虑函数交互影响
7. 防御措施
- 使用最新版本的PHP和库文件
- 对用户输入实施严格的白名单验证
- 避免不必要的shell命令执行
- 如必须使用shell命令,选择安全的参数传递方式
- 定期进行安全审计,特别是对敏感函数的使用