友情提示: 本文分析的是真實樣本,請各位實驗時千萬千萬不要在物理機上操作,務必使用虛擬機器,並斷開網絡連接。
友情提示: 本文分析的是真實樣本,請各位實驗時千萬千萬不要在物理機上操作,務必使用虛擬機器,並斷開網絡連接。
1. 目的寫這篇文章的目的是想簡單介紹一下Flash樣本分析的流程,以及一些分析Flash樣本常用的工具包括自己寫的小程式。本文涉及的內容包括:Flash檔案的選取、結構查看、ActionScript的反彙編和反編譯、ActionScript中shellcode的定位和選取、shellcode調試。本文不會涉及對漏洞成因進行分析調試的相關內容。
2. 使用的樣本本文中使用是一個利用CVE-2012-0754漏洞的Flash樣本,還算是比較新的Flash漏洞樣本。樣本來源是:ContagioDump這裡向大家推薦一下這個blog,該blog經常會放出一些最新的病毒樣本,仔細挖掘的話還能找到一些樣本的合集,非常有用。不過國內應該無法直接訪問,需要翻牆先。懶得翻牆的同學,我把樣本打包傳到附件裏了,可以直接下載附件。
3. 從Doc中選取Flash文件下載樣本解壓後,原始樣本在original資料夾中,名為“Iran's Oil and Nuclear Situation.doc”。等等,不是Flash樣本嗎,怎麼是doc檔案?你可能在想LZ是不是發錯連結了。其實真正的Flash樣本是嵌在這個doc檔案中的,這種手法並不是第一次被使用了,當年CVE-2010-0609(沒記錯的話)樣本也是嵌在Excel檔案裏流出的。打開word檔案的話最後會有一隻貌似熊(??)的謎樣生物對你說“Hi~”,LZ覺得好詭異。。。
打開word檔案的話最後會有一隻貌似熊(??)的謎樣生物對你說“Hi~”,LZ覺得好詭異。。。
用16進制編輯器打開word檔案,可以看到該檔案是OLE SS格式的Office檔案,這種情況下,一般直接蒐索字串“FWS”(未壓縮的SWF頭部特徵)和“CWS”(壓縮過的SWF頭部特徵)就可以定位其中的Flash檔案。
我寫了一個python小腳本,用來從Office檔案中選取內嵌的Flash檔案,名為extract_swf.py,使用管道如下:
Code:
本例中我們這樣使用:
Code:
輸出如下:
Code:
可以看到選取出來的Flash檔案被命名為“Iran's Oil and Nuclear Situation.doc__offset_0x2e08.swf=”,這個就是真正樣本檔案了。
4. 使用SWF Investigator查看Flash檔案資訊
下麵要重點介紹的是Adobe Lab發佈的一款名為SWF Investigator的工具。功能十分强大,可以查看Flash檔案結構、反彙編ActionScript、編譯ActionScript、直接運行flash、甚至可以用來Fuzz Flash檔案。是不是有點心動了呢,猛擊如下連結下載吧:[下載SWF Investigator]使用SWF Investigator時需要先安裝Adobe AIR,可以從這裡下載:[下載Adobe AIR] 將前面選取出來的SWF文件拖到SWF Investigator中,就可以查看各種資訊了。點擊“Tag View”可以查看各個標籤,其中DoABC2標籤中包含ActionScript 3.0位元組碼。選中DoABC2標籤後,可以在右側視窗中看到反匯編後的ActionScript程式碼,下圖中一連串的pushint…writeInt其實是在做heap spray。直接看位元組碼有點吃力,這時我們需要一個ActionScript 3.0的反編譯工具。
使用SWF Investigator時需要先安裝Adobe AIR,可以從這裡下載:[下載Adobe AIR] 將前面選取出來的SWF文件拖到SWF Investigator中,就可以查看各種資訊了。點擊“Tag View”可以查看各個標籤,其中DoABC2標籤中包含ActionScript 3.0位元組碼。選中DoABC2標籤後,可以在右側視窗中看到反匯編後的ActionScript程式碼,下圖中一連串的pushint…writeInt其實是在做heap spray。
直接看位元組碼有點吃力,這時我們需要一個ActionScript 3.0的反編譯工具。
5. 反編譯ActionScript腳本
這裡使用的工具是AS3 Sorcerer,下載地址為:http://www.as3sorcerer.com/。也可以使用Sothink Flash Decompiler,不過這兩款都是商務軟體。免費軟件的話可以試試HP的SWF Scan,效果還可以,但是有時會反編譯出錯誤的原始程式碼。將前面選取出的SWF文件拖入AS3 Sorcerer,可以看到反編譯後的源碼。附件中的CVE-2012-0754.as3包含完整的原始程式碼。ActionScript 3.0和JavaScript都基於ECMA標準,基本上能看懂JavaScript的樣本就能看懂ActionScript的樣本。
將前面選取出的SWF文件拖入AS3 Sorcerer,可以看到反編譯後的源碼。附件中的CVE-2012-0754.as3包含完整的原始程式碼。ActionScript 3.0和JavaScript都基於ECMA標準,基本上能看懂JavaScript的樣本就能看懂ActionScript的樣本。
通過分析原始程式碼可以看出,這裡的_local2變數中包含shellcode數據。_loca2寫入shellcode的流程如下:1.首先定義_local2,類型為為ByteArray(位元組數組)2.使用一系列的writeInt函數調用寫入數據3.調用自定義的Encrypt2函數解密出真正的shellcode。相關程式碼整理如下:
Code:
下麵我們需要選取出解密後的shellcode數據,有如下選擇:1.讀懂整個邏輯包括Encrypt2函數,使用自己熟悉的程式設計語言還原整個邏輯,得到shellcode數據。這種方法的缺點在於,如果shellcode生成邏輯非常複雜,還原成其他語言的難度會很大。2.直接執行相應的ActionScript,列印出shellcode數據這裡我們將介紹第二種方法。
1.讀懂整個邏輯包括Encrypt2函數,使用自己熟悉的程式設計語言還原整個邏輯,得到shellcode數據。這種方法的缺點在於,如果shellcode生成邏輯非常複雜,還原成其他語言的難度會很大。
2.直接執行相應的ActionScript,列印出shellcode數據
這裡我們將介紹第二種方法。
6. 使用SWF Investigator編譯執行ActionScriptSWF Investigator包含了而一個很强大的工具叫AS3 Compiler,可以編譯和執行ActionScript 3.0腳本。選中選單中的Utilities => AS3 Compiler就可以調出這個工具。下麵我們開始準備要運行的腳本,首先加入如下程式碼:
下麵我們開始準備要運行的腳本,首先加入如下程式碼:
Code:
public function Bin2HexString(arr:ByteArray):String{ var str =“”; var len = arr.length; var i = 0; while(i < len){ var b = arr[i]; str += HexChr[(b >> 4)& 0xf]; str += HexChr[b & 0xf]; i ++; } return str;}
上面的程式碼定義了一個用於將位元組數組的數據轉化成16進制編碼(hex encode)字串的函數。下一步需要把和_local2相關的程式碼和Encrypt2函數的程式碼複製進來,注意去掉Encrypt2函數定義中的“static”内容。最後加入如下程式碼來列印出_local2中的數據:
Code:
完整的程式碼在附件中的compile.txt中,大家可以自行查看。將完整的程式碼拷貝到AS3 Compiler左邊的源碼視窗中,點擊compile進行編譯,再點擊Run運行,就可以在右邊的輸出視窗中看到shellcode的16進制編碼數據了:
7. 調試shellcode將前面輸出地shellcode字串在轉換成二進位數據(附件中的sc.bin),就可以開始調試了。調試shellcode大家各有各的工具和方法,我使用的是自己寫的一個名為ShellcodeDbg小工具。用什麼工具調無所謂,唯一要注意的是,在調試檔案類shellcode時需要在調試行程中先打開原始檔案,並保留這個原始檔案的控制碼,理由接下來會說明。將OllyDbg設定為即時調試器,運行ShellcodeDbg.exe “sc.bin” “Iran's Oil and Nuclear Situation.doc”,會有一個Int3中斷點命中,喚起OD。跳過這個Int3中斷點後,單步幾下,最後一個jmp eax會跳到shellcode程式碼出。Shellcode一開始無非是解密,獲取API地址等例行公事,接著可以看到這樣一個迴圈:
用什麼工具調無所謂,唯一要注意的是,在調試檔案類shellcode時需要在調試行程中先打開原始檔案,並保留這個原始檔案的控制碼,理由接下來會說明。
將OllyDbg設定為即時調試器,運行ShellcodeDbg.exe “sc.bin” “Iran's Oil and Nuclear Situation.doc”,會有一個Int3中斷點命中,喚起OD。跳過這個Int3中斷點後,單步幾下,最後一個jmp eax會跳到shellcode程式碼出。Shellcode一開始無非是解密,獲取API地址等例行公事,接著可以看到這樣一個迴圈:
Code:
上述程式碼迴圈測試檔案控制碼值(從4開始),並使用對應控制碼值來調用GetFileSize,並查看返回的size是不是等於01a06c(原始doc檔案的大小),找到了合適的控制碼才會繼續運行。這是檔案類樣本shellcode的常見行為,因為很多時候原始檔案中包含進一步的shellcode或者PE檔案數據,shellcode需要從中選取這些數據。這就是為什麼我們一開始講要打開並保留一個原始檔案控制碼的理由了。shellcode之後的程式碼,以及隨後生成的PE檔案的行為這裡就不講了,有興趣的同學自己玩吧。
shellcode之後的程式碼,以及隨後生成的PE檔案的行為這裡就不講了,有興趣的同學自己玩吧。
最後是本文中用到的相關檔包括原始樣本,解壓密碼為: infected