在PHP應用程序開發(fā)中不正當使用mail()函數(shù)引發(fā)的血案
一、前言
在我們挖掘PHP應用程序漏洞的過程中,我們向著名的Webmail服務提供商Roundcube提交了一個遠程命令執(zhí)行漏洞(CVE-2016-9920)。該漏洞允許攻擊者通過利用Roundcube接口發(fā)送一個精心構(gòu)造的電子郵件從而在目標系統(tǒng)上執(zhí)行任意命令。在我們向廠商提交漏洞,發(fā)布了相關(guān)的漏洞分析文章后,由于PHP內(nèi)聯(lián)函數(shù)mail()導致的類似安全問題在其他的PHP應用程序中陸續(xù)曝出。在這篇文章中,我們將分析一下這些漏洞的共同點,那些安全補丁仍然存在問題,以及如何安全的使用mail()函數(shù)。
二、淺析PHP的mail()函數(shù)
PHP自帶了一個內(nèi)聯(lián)函數(shù)mail()用于在PHP應用程序中發(fā)送電子郵件。開發(fā)者可以通過使用以下五個參數(shù)來配置郵件發(fā)送。
http://php.net/manual/en/function.mail.php
- bool mail(
- string $to,
- string $subject,
- string $message [,
- string $additional_headers [,
- string $additional_parameters ]]
- )
這個函數(shù)的前三個參數(shù)這里就不細說了,因為這些參數(shù)一般情況下不會受到注入攻擊的影響。但是,值得關(guān)注的一點是,如果$to參數(shù)由用戶控制控制的話,那么其可以向任意電子郵件地址發(fā)送垃圾郵件。
三、郵件頭注入
在這篇文章中我們重點分析后兩個參數(shù)。第四個參數(shù)$additional_headers的主要功能是規(guī)定額外電子郵件報頭。比如From、Reply-To、Cc以及Bcc。由于郵件報頭由CRLF換行符\r\n分隔。當用戶輸入可以控制第四個參數(shù),攻擊者可以使用這些字符(\r\n)來增加其他的郵件報頭。這種攻擊方式稱為電子郵件頭注入(或短電子郵件注入)。這種攻擊可以通過向郵件頭注入CC:或BCC:字段造成發(fā)送多封垃圾郵件。值得注意的是,某些郵件程序會自動將\n替換為\r\n。
四、為什么沒有正確處理mail()函數(shù)的第5個參數(shù)會引發(fā)安全問題
為了在PHP中使用mail()函數(shù),必須配置一個電子郵件程序或服務器。在php.ini配置文件中可以使用以下兩個選項:
- 配置PHP連接的SMTP服務器的主機名和端口
- 配置PHP用作郵件傳輸代理(MTA)的郵件程序文件路徑
當PHP配置了第二個選項時,調(diào)用mail()函數(shù)的將導致執(zhí)行配置的MTA(郵件傳輸代理)程序。盡管PHP內(nèi)部可以調(diào)用escapeshellcmd()函數(shù)防止惡意用戶注入其他的shell命令,mail()函數(shù)的第5個參數(shù)$additional_parameters允許向MTA(郵件傳輸代理)中添加新的程序參數(shù)。因此,攻擊者可以在一些MTA中附加程序標志,啟用創(chuàng)建一個用戶可控內(nèi)容的文件。
1. 漏洞演示代碼
- mail("myfriend@example.com", "subject", "message", "", "-f" . $_GET['from']);
在上述代碼中存在一個遠程命令執(zhí)行漏洞,這個問題容易被沒有安全意識的開發(fā)人員忽略。GET參數(shù)完全由用戶控制,攻擊者可以利用該處輸入向郵件程序傳遞其他額外的參數(shù)。舉例來說,在發(fā)送郵件的過程中可以使用-O參數(shù)來配置發(fā)送郵件的選項,使用-X參數(shù)可以指定日志文件的位置。
2. 概念性驗證(PoC)
- example@example.com -OQueueDirectory=/tmp -X/var/www/html/rce.php
這個PoC的功能是在Web目錄中生成一個PHP webshell。該文件(rce.php)包含受到PHP代碼污染的日志信息。因此,當訪問rce.php文件時,攻擊者能夠在Web服務器上執(zhí)行任意PHP代碼。讀者可以在我們的發(fā)布的文章和這里找到更多關(guān)于如何利用這個漏洞的相關(guān)信息。
五、最新相關(guān)的安全漏洞
在許多現(xiàn)實世界的應用程序中,有很多由于mail()函數(shù)的第五個參數(shù)使用不當引發(fā)的安全問題。最近發(fā)現(xiàn)以下廣受關(guān)注的PHP應用程序受到此類漏洞的影響(多數(shù)漏洞由Dawid Golunski發(fā)現(xiàn))。
對應參考鏈接:CVE-2016-9920、Discussion、CVE-2016-10033、CVE-2016-10034、CVE-2016-10074、CVE-2017-7692
由于一些廣泛使用的Web應用程序(如Wordpress,Joomla和Drupal)部分模塊基于以上庫開發(fā),所以也會受到該類漏洞的影響。
五、為什么escapeshellarg()函數(shù)沒有那么安全?
PHP提供了escapeshellcmd()和escapeshellarg()函數(shù)用來過濾用戶的輸入,防止惡意攻擊者執(zhí)行其他的系統(tǒng)命令或參數(shù)。直觀來講,下面的PHP語句看起來很安全,并且防止了-param1參數(shù)的中斷:
- system(escapeshellcmd("./program -param1 ". escapeshellarg( $_GET['arg'] )));
然而,當此程序有其他可利用參數(shù)時,那么這行代碼就是不安全的。攻擊者可以通過注入"foobar' -param2 payload "來突破-param1參數(shù)的限制。當用戶的輸入經(jīng)過兩個escapeshell*函數(shù)的處理,以下字符串將到達system()函數(shù)。
- ./program -param1 'foobar'\\'' -param2 payload \'
從最終系統(tǒng)執(zhí)行的命令可以看出,兩個嵌套的轉(zhuǎn)義函數(shù)混淆了引用并允許附加另一個參數(shù)param2。
PHP的mail()函數(shù)在內(nèi)部使用escapeshellcmd()函數(shù)過濾傳入的參數(shù),以防止命令注入攻擊。這正是為什么escapeshellarg()函數(shù)不會阻止mail()函數(shù)的第5個參數(shù)的攻擊。Roundcube和PHPMailer的開發(fā)人員率先發(fā)布了針對該漏洞的補丁。
六、為什么FILTER_VALIDATE_EMAIL是不安全的?
另一種直接的方法是使用PHP的電子郵件過濾器(email filter),以確保在mail()函數(shù)的第5個參數(shù)中只使用有效的電子郵件地址。
- filter_var($email, FILTER_VALIDATE_EMAIL)
但是,并不是所有可能存在安全問題的字符串都會被該過濾器過濾。它允許使用嵌入雙引號的轉(zhuǎn)義的空格。
由于函數(shù)底層實現(xiàn)正則表達式的原因,filter_var()沒有對輸入正確的過濾,導致構(gòu)造的payload被帶入執(zhí)行。
- 'a."'\ -OQueueDirectory=\%0D<?=eval($_GET[c])?>\ -X/var/www/html/"@a.php
對于上文給出的url編碼輸入,filter_var()函數(shù)返回true,將該payload識別為有效的郵件格式。
當開發(fā)人員使用該函數(shù)驗證電子郵件格式作為唯一的安全驗證措施,此時仍然是可以被攻擊者利用的:與我們之前的攻擊方式類似,在PHP程序發(fā)送郵件時,我們精心構(gòu)造的惡意“電子郵件地址”會將將PHP webshell生成在Web服務根目錄下。
- <?=eval($_GET[c])?>\/): No such file or directory
切記,filter_var()不適合用于對用戶輸入內(nèi)容的過濾,因為它對部分字符串的驗證是不嚴格的。
七、如何安全的使用mail()函數(shù)
仔細分析應用程序中傳入mail()函數(shù)的參數(shù),滿足以下條件:
1. $to 除非可以預期用戶的輸入內(nèi)容,否則不直接使用用戶輸入
2. $subject 可以安全的使用
3. $message 可以安全的使用
4. $additional_headers 過濾\r、\n字符
5. $additional_parameters 禁止用戶輸入
事實上,當把用戶的輸入作為shell指令執(zhí)行時,沒有什么辦法可以保證系統(tǒng)的安全性,千萬不要去考驗你的運氣。
如果在開發(fā)您的應用程序過程中第5個參數(shù)一定要由用戶控制,你可以使用電子郵件過濾器(email filter)將用戶輸入的合法數(shù)據(jù)限制為最小字符集,即使它違反了RFC合規(guī)性。我們建議不要信任任何轉(zhuǎn)義或引用程序,因為據(jù)歷史資料表示這些功能是存在安全問題的,特別是在不同環(huán)境中使用時,可能還會暴露出其他安全隱患。Paul Buonopane研究出了另一種方法去解決這個問題,可以在這里找到。
八、總結(jié)
許多PHP應用程序都有向其用戶發(fā)送電子郵件的功能,例如提醒和通知。雖然電子郵件頭注入是眾所周知的安全問題,但是當開發(fā)人員使用mail()函數(shù)時,往往會忽視不正當?shù)氖褂糜锌赡軐е逻h程命令執(zhí)行漏洞。在這篇文章中,我們主要分析了mail()函數(shù)的第5個參數(shù)使用不當可能存在的安全風險,以及如何防范這種問題,防止服務器受到攻擊。