摘要:在我們向廠商提交漏洞,發布了相關的漏洞分析文章后,由于內聯函數導致的類似安全問題在其他的應用程序中陸續曝出。淺析的函數自帶了一個內聯函數用于在應用程序中發送電子郵件。
前言
在我們 挖掘PHP應用程序漏洞 的過程中,我們向著名的Webmail服務提供商 Roundcube 提交了一個遠程命令執行漏洞( CVE-2016-9920 )。該漏洞允許攻擊者通過利用Roundcube接口發送一個精心構造的電子郵件從而在目標系統上執行任意命令。在我們向廠商提交漏洞,發布了相關的漏洞分析文章后,由于PHP內聯函數mail()導致的類似安全問題在其他的PHP應用程序中陸續曝出。在這篇文章中,我們將分析一下這些漏洞的共同點,那些安全補丁仍然存在問題,以及如何安全的使用mail()函數。
淺析PHP的mail()函數
PHP自帶了一個內聯函數mail()用于在PHP應用程序中發送電子郵件。開發者可以通過使用以下五個參數來配置郵件發送。
http://php.net/manual/en/func...
bool mail( string $to, string $subject, string $message [, string $additional_headers [, string $additional_parameters ]]
這個函數的前三個參數這里就不細說了,因為這些參數一般情況下不會受到注入攻擊的影響。但是,值得關注的一點是,如果$to參數由用戶控制控制的話,那么其可以向任意電子郵件地址發送垃圾郵件。
郵件頭注入
在這篇文章中我們重點分析后兩個參數。第四個參數$additional_headers的主要功能是規定額外電子郵件報頭。比如From、Reply-To、Cc以及Bcc。由于郵件報頭由CRLF換行符rn分隔。當用戶輸入可以控制第四個參數,攻擊者可以使用這些字符(rn)來增加其他的郵件報頭。這種攻擊方式稱為電子郵件頭注入(或短電子郵件注入)。這種攻擊可以通過向郵件頭注入CC:或BCC:字段造成發送多封垃圾郵件。值得注意的是,某些郵件程序會自動將n替換為rn。
為什么沒有正確處理mail()函數的第5個參數會引發安全問題
為了在PHP中使用mail()函數,必須配置一個電子郵件程序或服務器。在php.ini配置文件中可以使用以下兩個選項:
1.配置PHP連接的SMTP服務器的主機名和端口
2.配置PHP用作郵件傳輸代理(MTA)的郵件程序文件路徑
當PHP配置了第二個選項時,調用mail()函數的將導致執行配置的MTA(郵件傳輸代理)程序。盡管PHP內部可以調用escapeshellcmd()函數防止惡意用戶注入其他的shell命令,mail()函數的第5個參數$additional_parameters允許向MTA(郵件傳輸代理)中添加新的程序參數。因此,攻擊者可以在一些MTA中附加程序標志,啟用創建一個用戶可控內容的文件。
漏洞演示代碼
mail("myfriend@example.com", "subject", "message", "", "-f" . $_GET["from"]);
在上述代碼中存在一個遠程命令執行漏洞,這個問題容易被沒有安全意識的開發人員忽略。GET參數完全由用戶控制,攻擊者可以利用該處輸入向郵件程序傳遞其他額外的參數。舉例來說,在發送郵件的過程中可以使用-O參數來配置發送郵件的選項,使用-X參數可以指定日志文件的位置。
概念性驗證(PoC)
example@example.com -OQueueDirectory=/tmp -X/var/www/html/rce.php
這個PoC的功能是在Web目錄中生成一個PHP webshell。該文件(rce.php)包含受到PHP代碼污染的日志信息。因此,當訪問rce.php文件時,攻擊者能夠在Web服務器上執行任意PHP代碼。讀者可以在 我們的發布的文章 和 這里 找到更多關于如何利用這個漏洞的相關信息。
最新相關的安全漏洞
在許多現實世界的應用程序中,有很多由于mail()函數的第五個參數使用不當引發的安全問題。最近發現以下廣受關注的PHP應用程序受到此類漏洞的影響(多數漏洞由Dawid Golunski發現)。
由于一些廣泛使用的Web應用程序(如 Wordpress, Joomla和 Drupal)部分模塊基于以上庫開發,所以也會受到該類漏洞的影響。
為什么escapeshellarg()函數沒有那么安全?
PHP提供了 escapeshellcmd() 和 escapeshellarg() 函數用來過濾用戶的輸入,防止惡意攻擊者執行其他的系統命令或參數。直觀來講,下面的PHP語句看起來很安全,并且防止了-param1參數的中斷:
system(escapeshellcmd("./program -param1 ". escapeshellarg( $_GET["arg"] )));
然而,當此程序有其他可利用參數時,那么這行代碼就是不安全的。攻擊者可以通過注入"foobar" -param2 payload "來突破-param1參數的限制。當用戶的輸入經過兩個escapeshell*函數的處理,以下字符串將到達system()函數。
./program -param1 "foobar""" -param2 payload "
從最終系統執行的命令可以看出,兩個嵌套的轉義函數混淆了引用并允許附加另一個參數param2。
PHP的mail()函數在內部使用escapeshellcmd()函數過濾傳入的參數,以防止命令注入攻擊。這正是為什么escapeshellarg()函數不會阻止mail()函數的第5個參數的攻擊。 Roundcube和 PHPMailer的開發人員率先發布了針對該漏洞的補丁。
為什么FILTER_VALIDATE_EMAIL是不安全的?
另一種直接的方法是使用PHP的電子郵件過濾器(email filter),以確保在mail()函數的第5個參數中只使用有效的電子郵件地址。
filter_var($email, FILTER_VALIDATE_EMAIL)
但是,并不是所有可能存在安全問題的字符串都會被該過濾器過濾。它允許使用嵌入雙引號的轉義的空格。
由于函數底層實現正則表達式的原因,filter_var()沒有對輸入正確的過濾,導致構造的payload被帶入執行。
"a."" -OQueueDirectory=%0D=eval($_GET[c])?> -X/var/www/html/"@a.php
對于上文給出的url編碼輸入,filter_var()函數返回true,將該payload識別為有效的郵件格式。
當開發人員使用該函數驗證電子郵件格式作為唯一的安全驗證措施,此時仍然是可以被攻擊者利用的:與我們之前的攻擊方式類似,在PHP程序發送郵件時,我們精心構造的惡意“電子郵件地址”會將將PHP webshell生成在Web服務根目錄下。
=eval($_GET[c])?>/): No such file or directory
切記,filter_var()不適合用于對用戶輸入內容的過濾,因為它對部分字符串的驗證是不嚴格的。
如何安全的使用mail()函數
仔細分析應用程序中傳入mail()函數的參數,滿足以下條件:
$to 除非可以預期用戶的輸入內容,否則不直接使用用戶輸入
$subject 可以安全的使用
$message 可以安全的使用
$additional_headers 過濾r、n字符
$additional_parameters 禁止用戶輸入
事實上,當把用戶的輸入作為shell指令執行時,沒有什么辦法可以保證系統的安全性,千萬不要去考驗你的運氣。
如果在開發您的應用程序過程中第5個參數一定要由用戶控制,你可以使用電子郵件過濾器(email filter)將用戶輸入的合法數據限制為最小字符集,即使它違反了RFC合規性。我們建議不要信任任何轉義或引用程序,因為據歷史資料表示 這些功能是存在安全問題的,特別是在不同環境中使用時,可能還會暴露出其他安全隱患。Paul Buonopane研究出了另一種方法去解決這個問題,可以在 這里找到。
總結
許多PHP應用程序都有向其用戶發送電子郵件的功能,例如提醒和通知。 雖然電子郵件頭注入是眾所周知的安全問題,但是當開發人員使用mail()函數時,往往會忽視不正當的使用有可能導致遠程命令執行漏洞。 在這篇文章中,我們主要分析了mail()函數的第5個參數使用不當可能存在的安全風險,以及如何防范這種問題,防止服務器受到攻擊。
本文由甲爪cpa聯盟(www.jiazhua.com)整理編輯!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/22903.html
摘要:背景項目中通過遠程調用服務框架調用了許多其它的服務其中有一個服務需要升級其升級不是版本上的升級而是整個服務重新取了一個名字使用的也是全新的包但是調用的方法沒有改變因此在升級時只是在調用服務類中修改了調用地址和調用返回實體由改為該中返回該調用 背景 項目中通過遠程調用服務框架調用了許多其它的服務,其中有一個服務wx/subscribe/contract/CircleService 需要升...
摘要:但是在這個判斷的情況下,則會很神奇的發現打印出來了,說明此時為,為什么呢因為這里執行了一個對象到布爾值的轉換故返回。 ????之前做項目的時候,總會處理各式各樣的數據,來進行繪圖。但是當后臺返回一個空數組的時候,頁面中并不會顯示沒有數據的圖。代碼如下: var arr = [] if(arr){console.log(124)}else{console.log(無數據)} 我明明判斷了...
摘要:除非使用了分塊編碼,否則首部就是帶有實體主體的報文必須使用的。 背景 新項目上線, 發現一個奇怪的BUG, 請求接口有很小的概率返回400 Bad Request,拿到日志記錄的請求的參數于POSTMAN中測試請求接口, 發現能夠正常響應. 排查過程 首先服務器能夠正常響應400 Bad Request, 排除接口故障問題. 對比日志過程中發現 { hello:world ...
摘要:項目組長給我看了一道面試別人的面試題。打鐵趁熱,再來一道題來加深下理解。作者以樂之名本文原創,有不當的地方歡迎指出。 showImg(https://segmentfault.com/img/bVbur0z?w=600&h=400); 剛入職新公司,屬于公司萌新一枚,一天下午對著屏幕看代碼架構時。BI項目組長給我看了一道面試別人的JS面試題。 雖然答對了,但把理由說錯了,照樣不及格。 ...
摘要:在群里討論,然后得出了這幾種寫法,感覺是層層遞進,想了想,最后選擇發布成文章大頭兒子小頭爸爸叫去吃飯大頭兒子小頭爸爸叫去吃飯大頭兒子小頭爸爸叫去吃飯吃完了背小頭兒子回去正在牽著的手正在吃給所有對象擴展一個繼承的方法繼承爸爸要繼承人的功能正在 在群里討論JavaScript,然后得出了這幾種寫法,感覺是層層遞進,想了想,最后選擇發布成文章 ({ baby : 大頭兒子, ...
閱讀 2418·2021-11-16 11:44
閱讀 852·2021-09-10 11:16
閱讀 2228·2019-08-30 15:54
閱讀 1057·2019-08-30 15:53
閱讀 1900·2019-08-30 13:00
閱讀 620·2019-08-29 17:07
閱讀 3514·2019-08-29 16:39
閱讀 3138·2019-08-29 13:30