標籤:

Form-Grabber惡意軟體的詳細分析

介紹

作為Stormshield安全情報團隊的一名新成員,我的第一個任務就是分析這款form-grabber惡意軟體,在這種惡意軟體的幫助下,攻擊者可以利用基於Web瀏覽器的注入方法來竊取目標用戶的密碼。在這篇文章中,我將跟大家詳細介紹這款惡意軟體的技術細節,其中的重點是Web瀏覽器的注入技術。

這款惡意軟體已經有一定「年紀」了,因為從編譯後代碼的時間戳來看,這款惡意軟體早在2012年就已經存在了。但是待會兒等我介紹完之後你就會發現,雖然這款惡意軟體已經「上年紀」了,但它仍然能夠高效地攻擊很多最新版本的瀏覽器(32位模式)。安全研究專家Xylitol已經在VirusTotal平台上傳了一份這款惡意軟體的樣本,但是目前互聯網上還沒有針對這款惡意軟體的詳細分析報告。由於這部分內容的缺失,這種威脅的傳播方法很可能不為人所知,這也是我寫這篇文章的原因。

脫殼

我們所分析的樣本加了兩層殼,第一層是UPX的殼,這個可以輕鬆脫殼。第二層同樣非常簡單,它利用了一種反調試技巧讀取PEB中的『BeingDebugged』標記。除此之外,這裡還實現了一種反混淆技術,即樣本使用了一個1位元組密鑰(0x0F)來進行XOR運算並輸出解密後的PE域(緩衝區使用VirtualAlloc()分配)。在調用了VirtualAlloc()之後,我們可以使用下列指令來識別第二階段的殼是否結束:

push 0x666 ; magic value checked after unpackingnpush ebx ; base address of the unpacked PEncall eax ; leads to the unpacked PE original entry pointn

因此我們可以得知,這款惡意軟體在執行第一個功能時需要接收兩個輸入參數:

脫殼後的PE基地址;

一個可當作密鑰使用的值;

如果這個值不是惡意軟體所定義的(0x666),那麼它就會停止運行。

RC4加密

為了防止逆向分析或其他基於檢測的靜態分析方法,這款惡意軟體使用了RC4演算法來加密字元串。其中被加密的絕大多數都是與Web瀏覽器注入相關的DLL、函數名稱或參數,它們可以使用LoadLibraryA()GetProcAddress()來動態解析導入的代碼庫。在地址data+0x30中有一個結構體數組,其中包含有每一個加密字元串的地址。這個結構體如下代碼所示:

struct rc4_encrypted_string {nconst char *string; // pointer to the encrypted string stored in .rdatanunsigned int length; // length of the stringn}n

因此,為了解密字元串,惡意軟體使用了一個函數來發送結構體數組中加密字元串的個數,並以此來推算其所在地址和長度。在一個IDA Python腳本的幫助下,我們可以輕鬆找到這個函數的交叉引用,並了解到字元串的個數,並執行解密。

運行腳本之後,我們可以發現很多有意思的字元串,例如DLL或函數名等等:

用於解密的RC4密鑰長度為128位,其地址存放於data+0x14。在這個樣本中,其密鑰為:27F56A32B728364FBA109F983D148023。

主要的執行流程

這款惡意軟體的主線程用來執行一個無限循環,然後在循環中枚舉出目標操作系統中正在運行的所有進程,最終找出一個瀏覽器程序並實現線程注入。枚舉過程主要使用了以下幾個Windows API函數:

CreateToolhelp32Snapshot()

Process32FirstW()

Process32NextW()

這款惡意軟體還會尋找任何名字元合以下字元串的進程,並嘗試向其中注入一個線程:

chrome.exe

firefox.exe

opera.exe

iexplorer.exe

WebKit2WebProcess.exe (Safari)

Form-grabber線程注入

一旦其找到了匹配的進程名稱,它便會調用OpenProcess()來獲取目標進程的控制權。接下來,惡意軟體將調用VirtualAlloc()在目標進程的地址空間中分配一個執行的內存區域。這一塊內存區域可以用來存儲當前運行的PE文件副本(使用WriteProcessMemory()實現)。現在,整個PE文件都會被映射到目標進程的地址空間中,最後再調用CreateRemoteThread()來運行注入的線程。

由於這款惡意軟體不會向線程函數傳遞任何的變數,因此遠程線程不需要知道它到底是在哪個進程中運行的。

內聯鉤子

內聯鉤子(Inline Hooking)是一種專門用來攔截函數調用的方法,這種方法可以執行一種旁路函數來訪問原始函數的參數信息。在我們的分析樣本中,它使用了這種內聯鉤子來攔截瀏覽器在發送HTTP請求時所調用的函數,並訪問其中包含的敏感數據,例如用戶名、密碼或信用卡號等等。

為了設置內聯鉤子,這款惡意軟體使用了一個全局結構體來存儲掛鉤函數的信息(存儲在.data域)。這種結構體如下代碼所示:

// Function pointer definition for calling HTTPSendRequestA()ntypedef BOOL (*http_send_request_prototype_t)(n_In_ HINTERNET hRequest,n_In_ LPCTSTR lpszHeaders,n_In_ DWORD dwHeadersLength,n_In_ LPVOID lpOptional,n_In_ DWORD dwOptionalLengthn);n nstruct direct_injection_hook {nhttp_send_request_prototype_t hooked_function; // address of Wininet.dll!HttpSendRequestAnhttp_send_request_prototype_t detour_function; // address of the function written by the authornunsigned int count_saved_bytes; // number of bytes overriden at Wininet.dll!HttpSendRequestAnvoid (*return_to_dll)(void); // address of user-allocated page (RWX) used to execute the originaln// hooked function after execution of the detour functionn} n

下面是用於設置內聯鉤子的函數反編譯版本,代碼位於地址.text+0x40:

掛鉤後的執行流程

當設置好了鉤子之後,如果iexplorer.exe調用了Wininet.dll!HttpSendRequestA,則執行流程如下:

1. 執行Wininet.dll!HttpSendRequestA的第一條指令,並跳轉到旁路函數。

2. 旁路函數訪問已掛鉤函數的參數信息,例如HTTP Payload,並從中提取出敏感數據。

3. 旁路函數調用跳轉函數(return_to_dll),並存儲Wininet.dll!HttpSendRequestA執行過的所有指令,最終跳轉到Wininet.dll!HttpSendRequestA+5然後執行。

4. Wininet.dll!HttpSendRequestA剩下的指令會繼續執行,直到函數返回並執行HTTP請求。

5. 旁路函數運行完之後會返回到原函數,然後調用Wininet.dll!HttpSendRequestA

完整的執行流程請大家參考下面這張圖片:

瀏覽器與掛鉤函數信息

下面這個表格顯示的是瀏覽器可注入的DLL和函數名等信息:

某些函數是在HTTP層運行的,這也就意味著當用戶瀏覽一個HTTPS網站時,函數鉤子在將信息傳遞給TLS層並進行加密之前,它首先拼接出的會是HTTP請求。剩下的操作全部都會在TCP層執行,這也就意味著瀏覽一個HTTPS網站將會導致惡意軟體掛鉤TLS記錄Payload並通過套接字進行發送,而這對於這款惡意軟體來說沒有任何的實際意義。

該惡意軟體基於BaseHTTPServer所創建出的類代碼如下,其主要功能就是捕獲POST方法:

import BaseHTTPServernimport urlparsen nbrowser_mapping = {n0 : chrome.exe,n1 : chrome.exe,n2 : firefox.exe,n3 : opera.exe,n4 : WebKit2WebProcess.exe, # Safarin5 : iexplorer.exen}n nHOST=localhostnPORT=80nXOR_KEY=0x07n nclass FormGrabberHTTPDecoder(BaseHTTPServer.BaseHTTPRequestHandler):n ndef do_POST(self):nrequest_line = self.requestlinencontent_length = int(self.headers[Content-Length])npost_data = self.rfile.read(content_length)ndecoded_data = urlparse.parse_qs(post_data)nmalware_version = decoded_data[v][0]ninjected_browser = browser_mapping[int(decoded_data[t][0])]nusername_hostname = decoded_data[h][0]nhexdumped_post_data = decoded_data[c][0]nxored_post_data = hexdumped_post_data.decode(hex)nunxored_post_data = [chr(ord(c) ^ XOR_KEY) for c in xored_post_data]nunxored_post_data = .join(unxored_post_data)nd1 = (- * 79)nd2 = (* * 79)nprint(Received HTTP request line: {}.format(request_line))nprint(Received HTTP body:n{}n{}n{}.format(d1, post_data, d1))nprint(Malware version: {}.format(malware_version))nprint(Injected browser: {}.format(injected_browser))nprint(Username and Hostname: {}.format(username_hostname))nprint(Intercepted HTTP request:n{}n{}n{}.format(nd1, unxored_post_data, d1))nprint(d2)n nif __name__ == __main__:ns = BaseHTTPServer.HTTPServer((HOST, PORT), FormGrabberHTTPDecoder)ns.serve_forever()n

下面是腳本的輸出樣本,我們嘗試通過facebook.com的身份驗證,測試環境為IE瀏覽器+HTTPS:

瀏覽器測試

因為這款form-grabber惡意軟體在我分析的時候已經存在了五年之久了,所以我們也很想知道為什麼它至今仍然可以攻擊很多最新版本的瀏覽器。實際上在這些年裡,瀏覽器的架構一直都在不斷地升級和改進,而這款惡意軟體所掛鉤的部分函數現在已經不再使用了。下面這個表格所顯示的內容是這款惡意軟體在Windows 7操作系統(SP1,64位)中可以成功攻擊的瀏覽器版本信息:

有意思的是,除了Firefox之外,該惡意軟體所有的函數鉤子都可以有效地對所有最新版本的32位瀏覽器實施攻擊。

總結

這是一款十分精巧的form-grabber型惡意軟體,它使用了一些反調試技術,並對函數調用進行了混淆處理。除此之外,它還使用了RC4演算法來加密函數以及DLL名稱來執行代碼庫的動態導入。眾所周知,內聯鉤子是一種用於攔截函數調用的著名技術,而且對於目前最新版本的瀏覽器來說這種技術仍然是非常有效的。但是,這款惡意軟體的開發者並沒有花時間去優化所有瀏覽器HTTP層的鉤子函數,因此它很有可能無法針對那些通過https來發送的請求進行攔截和攻擊。

額外信息

MD5: cb066c5625aa85957d6b8d4caef4e497

SHA1: bd183265938f81990260d88d3bb6652f5b435be7

SHA256: 9cdb1a336d111fd9fc2451f0bdd883f99756da12156f7e59cca9d63c1c1742ce

VirusTotal的分析報告:【傳送門】


推薦閱讀:

勒索病毒都是怎麼中的?身邊很多連殺毒軟體都不知道怎麼用的人好像都沒中過

TAG:恶意软件 |