原文: https://exploitbox.io/paper/Pwning-PHP-Mail-Function-For-Fun-And-RCE.html
当在php中使用mail()函数发送一份邮件时,一般是这样的:
<?php $to = "john@localhost"; $subject = "Simple Email"; $headers = "From: mike@localhost"; $body = 'Body of the message'; $sender = "admin@localhost"; mail($to, $subject, $body, $headers, "-f $sender"); ?>php将会执行这样一个execve()的系统调用。
execve("/bin/sh", ["sh", "-c", "/usr/sbin/sendmail -t -i -f admin@localhost"], [/* 24 environment vars */])然后把以下数据传到标准输入
To: john@localhost Subject: Simple Email X-PHP-Originating-Script: 0:simple-send.php From: mike@localhost Body of the message其中-t和-i参数是由PHP自动加上的。-t参数是让sendmail从标准输入中提取出头信息。-i参数可以防止sendmail把.当作输入的结束标志。 -f参数来自于mail()函数调用的第五个参数。 有趣的是,sendmail命令是通过系统的shell(sh)调用得以执行的。如果将未受信任的输入传给了mail()函数的第五个参数,这就给命令注入攻击创造了机会。
如果攻击者能够向mail()函数的第五个参数注入数据,比如通过GET请求将数据传入$sender变量
$sender = $_GET['senders_email']; mail($to, $subject, $body, $headers, "-f $sender");这样,攻击者就可以向php脚本构造这样一个url请求
http://webserver/vulnerable.php?senders_email=attackers@email%20extra_data来达到对/usr/sbin/sendmail命令注入任意数据的目的。然后php的mail()函数就会这样执行。
mail(..., "-f attackers@email extra_data");然后使得sendmail命令这样执行。
/usr/sbin/sendmail t -i -f attackers@email extra_data当然mail()函数还是有其命令转义功能的,通过调用
escapeshellcmd($additional_parameters)函数,使得shell原始字符串注入不得行。 比如把GET的参数设置为
attacker@remote > /tmp/shell_injection # attacker@remote > /tmp/shell_injection并不能创建一个/tmp/shell_injection的文件,因为>字符会被escapeshellcmd()函数转义。然后对sendmail的调用会变成
/usr/sbin/sendmail t -i -f attacker@remote \> /tmp/shell_injection然后攻击者还是可以向sendmail注入额外的命令参数,因为由mail()函数调用的escapeshellcmd()函数默认情况下并没有给$additional_parameters参数打上引号!一方面,这给程序调用者传入更多参数的自由,然而另一方面这给那些没有意识到这个问题的程序猿引入了vulnerability。