淺談變形PHP webshell檢測
一、變形webshell
webshell比如eval($_POST[])大家都耳熟能詳,近幾年在常見的webshell基礎上衍生了很多變種,加大了檢測難度,下面先看幾個從網(wǎng)上摘取的樣本:
1、無ascii碼和數(shù)字的webshell

2、隱藏關鍵字

3、編碼 + 隱藏關鍵字

從目前已經(jīng)公開的樣本來看,變形的php webshell都是采取了隱藏關鍵字(eval、system等)的方法來躲避查殺。有一位monyer同學寫過一篇webshell的檢測文章,他把webshell拆分為下面的結(jié)構(gòu),執(zhí)行數(shù)據(jù)和數(shù)據(jù)傳遞,檢測思路是:以小括號為界限,匹配執(zhí)行數(shù)據(jù)部分是否命中收集的樣本的關鍵字。這種思路很好,個人覺得有兩處不足:
1、需要人工維護收集新樣本。
2、誤報量不可預估。

再看這個結(jié)構(gòu),變形的webshell無非是隱藏了執(zhí)行數(shù)據(jù)部分或者數(shù)據(jù)傳遞部分,不過無論怎么變形本質(zhì)上還是去調(diào)用eval、調(diào)用system、exec等命令執(zhí)行函數(shù),殺毒軟件通過異常行為來檢測木馬病毒,比如開機自啟動,這種思想同樣也可以用在webshell的檢測中。獲取行為數(shù)據(jù)是第一步。
二、PHP HOOK
這里我們只需要一些敏感的行為數(shù)據(jù),比如eval、system的調(diào)用。實現(xiàn)方法很簡單,hook這些php函數(shù)或語法結(jié)構(gòu),這里通過php擴展來實現(xiàn)hook。下面以eval和system來簡要概述下hook的方法。
Eval是一個語法結(jié)構(gòu),調(diào)用eval最終會調(diào)用php內(nèi)核的zend_compile_string函數(shù),hook eval的只需要重寫zend_complie_string函數(shù)即可,流程如下:

System是php的一個內(nèi)部函數(shù),php代碼是轉(zhuǎn)化為opcode(指令)來執(zhí)行,函數(shù)調(diào)用的指令是ZEND_DO_FCALL,風雪之隅大牛在taint擴展(詳見參考二)就是通過重載ZEND_DO_FCALL的方法實現(xiàn)了。因為我們并不需要hook每個內(nèi)部函數(shù),所以這里介紹另外一種方法,流程如下:

上報的數(shù)據(jù)寫在一個日志文件中,包括文件名、調(diào)用函數(shù)名、代碼在文件的行數(shù)。日志結(jié)構(gòu)和內(nèi)容如下:

附件中有eval、system函數(shù)hook實現(xiàn)的demo,具體細節(jié)可以查看代碼。demo只在php-5.3.6上測試過,不兼容之處忘見諒。
三、檢測
變形webshell分為兩大類,下面依次說明一下檢測邏輯。
1、執(zhí)行數(shù)據(jù)隱藏
一個正常的程序員如果使用eval、system是不會刻意的轉(zhuǎn)換隱藏的,如果發(fā)現(xiàn)某個函數(shù)執(zhí)行了,代碼中卻找不到這個函數(shù)名,我們認為這是一個異常行為。以下面這個變形為例

比如黑客傳入?yún)?shù)nonalpha.php?_=system&__=whoami執(zhí)行了一條命令,日志會記錄

我們在后端取nonalpha.php文件的第7行內(nèi)容匹配system(字符串,如果沒找到,則認為是一個變形webshell。
2、數(shù)據(jù)傳遞隱藏
先看下面這個例子

這個webshell通過編碼的referer來傳遞攻擊載荷,利用日志文件記錄到的文件名和行數(shù)把代碼上報到后端,和后端svn中的代碼做對比,如果不一致,則認為是一個webshell。
四、不足
web承受著大量的訪問請求,增加的php擴展的性能和穩(wěn)定性是一個嚴峻的考驗,另外在服務器比較多的公司還存在一個推廣和部署成本。




















