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
从这里就可以看出上述第四个要求的原因, 如果开启了safe_mode, 则不会向mail函数传递第5个参数
接下来跟踪变量$params
变量$params
来自于$this->Sender
继续跟踪:
变量$this->Sender
是通过setFrom
函数的第一个参数进行设置的
在之前, 函数对$address
是进行有效性判断的, 接下来进入这个地址有效性判断的函数中去看看
从这段代码我们能知道, 如果php version < 5.2.0
and no pcre
, 则$patternselect = 'noregex'
继续往下看
当$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 | vulnerables@ -OQueueDirectory=/tmp -X/www/backdoor.php |
至于另一个-O参数, 在某些环境下需要
比如我搭的环境, 用的是debian, 默认情况下会出现can not chdir(/var/spool/mqueue-client/): Permission denied
, 然后问了下p神, 他搭的环境用的是ubuntu, 不会报这个错误
这是由于权限设置的问题, 研究了下
1 | $ ls -lF /var/spool |
就不会出现这个错误了, 但是这就不是默认环境, 而是配置后的环境
之后发现如果加上-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 | <?php |
昨晚我研究出了两张种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 | php> var_dump(escapeshellarg("a'( -OQueueDirectory=/tmp -X/tmp/backdoor.php )@a.com")) |
然后带入sendmail
1 | $ sendmail -f'a'\''( -OQueueDirectory=/tmp -X/tmp/backdoor2.php )@a.com' |
发现并跑不起来, 日志文件也没成功写入
但是传入mail函数中, 却能成功写入日志文件
之后对mail.c源码进行了研究, 发现:
在mail函数中, 对参数使用php_escape_shell_cmd
进行处理
我们可以进行测试下:
1 | # test.php |
得到:
1 | $ php test.php |
发现sendmail能成功写入日志文件, 虽然会报一些错, 但无伤大雅, 数据能写到日志文件中
从上面我们可以得到是escapeshellarg
和 escapeshellcmd
函数一起处理参数, 导致的问题
同理: Roundcube也存在该问题
Other
之后会对各大cms进行分析, 就目前分析过的两个Joomla和Wordpress来看, 并不是特别好利用
- Joomla中有phpmailer模块, 但是实际代码中却并未使用该模块
- Wordpress实际代码中使用了该模块, 而且还是5.2.14版本的, 但是设置参数的地方只有管理员能设置, 既然是管理员了, 要getshell又何必用这中麻烦的方法
所以感觉该漏洞在我眼中目前看来只能算个中危吧, 因为并没有发现非常棒的实际利用场景
参考
- https://github.com/opsxcq/exploit-CVE-2016-10033
- https://linux.die.net/man/8/sendmail.sendmail
- https://www.leavesongs.com/PENETRATION/how-to-analyze-long-regex.html
- https://www.leavesongs.com/PENETRATION/PHPMailer-CVE-2016-10033.html
- https://github.com/php/php-src/blob/452dcf12ae3376a3cdb47490c51aadb0651a2a73/ext/standard/mail.c
- 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
phpmailer RCE 分析