利用PNG畫素隱藏PE程式碼:分析PNG Dropper新樣本
概述
本文將主要針對PNG Dropper惡意軟體進行分析,這一惡意軟體是由Turla組織開發和使用的。PNG Dropper在2017年8月被Carbon Black研究人員首次發現。早在2017年,該惡意軟體就被用來分發Snake。但是最近,NCC的研究人員發現了一個帶有新型Payload的樣本,我們在內部將其命名為RegRunnerSvc。
值得注意的是,這種威脅還有其他我們無法獲得的組成部分。其中,有一個第一階段的Dropper,將會投放並安裝PNG Dropper(RegRunnerSvc)。我們非常有必要記錄PNG Dropper的這種新用途。
PNG Dropper
關於PNG Dropper元件的詳細資訊,已經由Carbon Black研究團隊進行了記錄,但為了清晰起見,我們在這裡將對其進行簡要描述,並說明其工作原理。
Dropper的目的是載入並執行隱藏在眾多PNG檔案中的PE檔案。上圖展示了Dropper的資源。在這裡,我們可以看到一個名為“PNG”的二進位制資料的資源項。所有這些資源都有有效的PNG檔案,可以使用任意支援這種檔案格式的影象檢視器開啟,但在開啟後,我們無法看到任何有意義的影象內容。舉例來說,開啟其中的一個檔案,我們只能看到其中的幾個彩色畫素(如下圖放大版本所示)。
PNG檔案使用Microsoft的GDI+庫載入。在下圖中,我們看到其呼叫了LockBits,用於從PNG檔案中讀取畫素資料。畫素資料中的每個位元組代表畫素的RGB值。在每個RGB值中編碼的是來自PE檔案的位元組。之所以沒有形成一個有意義的影象,是因為惡意軟體將資料隱藏在了看似合法的資源之中。
我們通過列舉每個PNG資源,提取其中的畫素資料,並將它們組合在一起,最終獲得到了完整的PE檔案,正是記憶體中的完整PE檔案。然後,Dropper會手動載入PE檔案。對於匯入和重定位的處理過程也大致一致,最後將執行整個PE檔案的入口點,如下圖所示。
RegRunnerSvc
PNG Dropper將從PNG資源中解碼,隨後執行RegRunnerSvc。RegRunnerSvc的目的是從登錄檔中提取加密的Payload,將其載入到記憶體中,然後執行。第一階段的Dropper(我們目前還未獲得)已經將它作為服務安裝,同時執行了一些額外的設定操作。
下圖展現了RegRunnerSvc的入口點。在這裡,我們可以看到對StartServiceCtrlDispatcher的呼叫。在示例中,其服務名稱為WerFaultSvc,顯然是為了使其看上去類似於Windows錯誤報告服務的合法服務而特意選擇的名稱。該服務還可以作為惡意軟體的永續性機制。
在進行服務的功能設定後,惡意軟體開始在登錄檔中查詢資料。通常,登錄檔值的路徑將會作為(可能經過加密或混淆後的)字串,儲存到二進位制檔案中,但有趣的是,這一樣本中並沒有這樣實現。實際上,惡意軟體使用RegEnumKeyExA和RegEnumValueA函式遍歷登錄檔項和值。遍歷從HKEY_LOCAL_MACHINE開始,並採用深度優先的搜尋方式,直至找到資料或結束遍歷為止。另外還有一個有趣的實現細節(如下圖所示),呼叫解密函式的唯一要求是資料的大小為0x200(512)位元組。這一細節並不像它看起來的那麼低效,如果第一階段的Dropper沒有執行其設定操作,那麼解密函式就會迅速退出。很明顯,對於惡意軟體的作者來說,混淆比執行效率更重要。
登錄檔中的資料,包含加密Payload和解密它所需的資料。儘管其包含用於生成金鑰的資料,但卻不包含解密金鑰。該資料自身使用Microsoft CNG庫函式(NCrypt*)實現部分加密。第一階段的Dropper將生成一個解密金鑰,並將其儲存在一個系統預設金鑰儲存提供程式中,在這一樣本中為“Microsoft Software Key Storage Provider”。如果第一階段Dropper未執行,那麼金鑰將不會儲存在儲存提供程式中,並且解密函式將會退出。如果儲存提供程式實際包含金鑰,那麼會解密資料的第一個0x200(512)位元組。該解密資料包含一個標頭,其中包含在二進位制Blob中定位其餘資料所需的資訊。標頭中偏移量及完整描述如下:
0x00 加密資料,用於呼叫BCryptGenerateSymmetricKey()函式;
0x08 加密資料的大小
0x10 IV
0x18 IV的大小
0x20 AES加密資料
0x28 加密資料大小
現在,我們已經完成對標頭的分析,接下來就可以進行第二部分的解密。主要Payload使用AES演算法進行加密。首先,登錄檔中的一大塊資料會被傳遞給BCryptGenerateSymmetricKey函式,隨後建立AES解密金鑰。在生成金鑰並設定解密屬性後,將會對Payload進行解密。再之後,對解密的Payload進行校驗,以確認它是有效的PE檔案。該校驗主要檢查MZ和PE魔術位元組,並檢查PE標頭中的主機體系結構條目。如果校驗通過,就會手動載入檔案(匯入和重定位),並呼叫入口點,如下圖所示。
總結
在本文,我們對Turla組織PNG Dropper的新利用方法有了一定了解。該組織目前正在使用一個新的元件:RegRunnerSvc,該元件從登錄檔中提取加密後的PE檔案,對其進行解密,並執行該檔案。該惡意組織似乎從無檔案惡意軟體(例如Poweliks和Kovter)中獲得了啟發,儘量使惡意軟體在二進位制檔案中留下儘可能少的資訊,導致只留下了沒有進行硬編碼、包含加密資料的登錄檔金鑰的名稱。這也意味著,研究人員將無法提取有用的IoC來進行威脅分析工作。
值得慶幸的是,我們捕獲了這一樣本,至少可以使用Yara規則來對PNG Dropper進行檢測。
作為我們研究的一部分,我們編寫了一個工具,可以從PNG Dropper中提取Payload。目前,為方便大家的使用,我們已經公開發布了這一工具,可以在這裡找到:
ofollow,noindex" target="_blank">https://github.com/nccgroup/Cyber-Defence/tree/master/Scripts/turla_image_decoder
Yara規則
rule turla_png_dropper { meta: author = "Ben Humphrey" description = "Detects the PNG Dropper used by the Turla group" sha256 = "6ed939f59476fd31dc4d99e96136e928fbd88aec0d9c59846092c0e93a3c0e27" strings: $api0 = "GdiplusStartup" $api1 = "GdipAlloc" $api2 = "GdipCreateBitmapFromStreamICM" $api3 = "GdipBitmapLockBits" $api4 = "GdipGetImageWidth" $api5 = "GdipGetImageHeight" $api6 = "GdiplusShutdown" $code32 = { 8B 46 3C// moveax, [esi+3Ch] B9 0B 01 00 00// movecx, 10Bh 66 39 4C 30 18// cmp[eax+esi+18h], cx 8B 44 30 28// moveax, [eax+esi+28h] 6A 00// push0 B9 AF BE AD DE// movecx, 0DEADBEAFh 51// pushecx 51// pushecx 03 C6// addeax, esi 56// pushesi FF D0// call eax } $code64 = { 48 63 43 3C// movsxd rax, dword ptr [rbx+3Ch] B9 0B 01 00 00// mov ecx, 10Bh BA AF BE AD DE// mov edx, 0DEADBEAFh 66 39 4C 18 18// cmp [rax+rbx+18h], cx 8B 44 18 28// mov eax, [rax+rbx+28h] 45 33 C9// xor r9d, r9d 44 8B C2// mov r8d, edx 48 8B CB// mov rcx, rbx 48 03 C3// add rax, rbx FF D0// call rax } condition: (uint16(0) == 0x5A4D and uint16(uint32(0x3c)) == 0x4550) and all of ($api*) and 1 of ($code*) }
rule turla_png_reg_enum_payload { meta: author = "Ben Humphrey" description = "Payload that has most recently been dropped by the Turla PNG Dropper" shas256 = "fea27eb2e939e930c8617dcf64366d1649988f30555f6ee9cd09fe54e4bc22b3" strings: $crypt00 = "Microsoft Software Key Storage Provider" wide $crypt01 = "ChainingModeCBC" wide $crypt02 = "AES" wide condition: (uint16(0) == 0x5A4D and uint16(uint32(0x3c)) == 0x4550) and pe.imports("advapi32.dll", "StartServiceCtrlDispatcherA") and pe.imports("advapi32.dll", "RegEnumValueA") and pe.imports("advapi32.dll", "RegEnumKeyExA") and pe.imports("ncrypt.dll", "NCryptOpenStorageProvider") and pe.imports("ncrypt.dll", "NCryptEnumKeys") and pe.imports("ncrypt.dll", "NCryptOpenKey") and pe.imports("ncrypt.dll", "NCryptDecrypt") and pe.imports("ncrypt.dll", "BCryptGenerateSymmetricKey") and pe.imports("ncrypt.dll", "BCryptGetProperty") and pe.imports("ncrypt.dll", "BCryptDecrypt") and pe.imports("ncrypt.dll", "BCryptEncrypt") and all of them }
IoC
PNG Dropper:
6ed939f59476fd31dc4d99e96136e928fbd88aec0d9c59846092c0e93a3c0e27
在PNG Dropper中的Payload:
fea27eb2e939e930c8617dcf64366d1649988f30555f6ee9cd09fe54e4bc22b
服務:
WerFaultSvc