Waterbear 是一個已肆虐多年、善於使用模組化惡意程式、並可從遠端新增功能的駭客攻擊行動。此攻擊行動幕後的操控者很可能是 BlackTech 網路間諜集團,該集團主要攻擊東亞的科技公司與政府機關 (特別是台灣,有時也攻擊日本和香港),同時也是某些惡名昭彰的攻擊 (如 PLEAD 和 Shrouded Crossbow) 幕後的黑手。在之前的攻擊當中,我們看到 Waterbear 主要用於橫向移動,並使用檔案載入器來解開及觸發加密的惡意檔案。在大多數情況下,這些惡意檔案都是用來接收並載入更多模組的後門程式。不過在最近一起攻擊中,趨勢科技發現某個 Waterbear 惡意檔案有了全新的用途:藉由 API 攔截 (API hooking) 技巧來隱藏自己的網路活動以免被某資安廠商的產品偵測。根據我們的分析,這是一家亞太地區的資安廠商,而這也正是 BlackTech 集團習慣攻擊的地區。
[延伸閱讀:主要鎖定台灣,專偷機密技術的BlackTech 網路間諜集團] |
由於駭客知道該攔截哪個 API 來避開偵側,因此意味著駭客很可能熟悉該資安產品在客戶端點和網路上蒐集資訊的方式。而且,由於其程式碼採用通用的方式來攔截 API,因此未來很可能只需更換部分程式碼就能讓別的產品也無法偵測 Waterbear。
Waterbear 深入剖析
Waterbear 的惡意程式採用模組化設計,它使用一個 DLL 載入器來解開並執行 RC4 加密的惡意檔案。此惡意檔案通常是第一階段後門程式,負責從外部駭客接收並執行後續的執行檔。像這樣的第一階段後門程式大致可分為兩種:第一種會主動與幕後操縱 (C&C) 伺服器連線,第二種會一直監聽某個連接埠以等候遠端連線。我們發現有些加密檔案的路徑是寫死的,而且不是指向 Windows 的系統目錄 (例如指向資安產品或第三方程式庫的目錄),這表示駭客可能已經預先熟悉了攻擊目標的環境。此外,駭客有時也會將 Waterbear 當成他們已滲透目標系統之後用來長期潛伏於系統內的第二波程式。因為 Waterbear 經常使用內部的 IP 位址為 C&C 伺服器位址,例如:BKDR64_WATERBEAR.ZTGD 這個惡意程式 (雜湊碼b9f3a3b9452a396c3ba0ce4a644dd2b7f494905e820e7b1c6dca2fdcce069361,請參見文末的表格) 就使用 10.0.0.211 為 C&C 伺服器 IP 位址。
典型的 Waterbear 感染過程
圖 1:典型的 Waterbear 感染過程。
如圖 1 所示,Waterbear 的感染過程是從載入一個惡意的 DLL開始。之前我們已見過兩種載入惡意 DLL 的技巧。第一種是篡改某個正常的伺服器應用程式 來匯入並載入惡意 DLL;第二種是採用幽靈 DLL 挾持 (Phantom DLL Hijacking) 與 DLL 側載 (DLL Side Loading) 的方式。有些 Windows 服務會在系統開機時試圖載入一些名稱和路徑都寫死的外部 DLL。然而,如果這類 DLL 是一個老舊的 DLL (也就是 Windows 已終止支援的 DLL) 或是一個第三方 DLL (非 Windows 原始系統的 DLL),駭客就能將惡意 DLL 改名成這個寫死的名稱,接著放在系統載入 DLL 時會搜尋的其中一個目錄內。當惡意 DLL 一旦被載入之後,就會取得與載入 DLL 的服務相同的系統權限。
根據我們近期對 Waterbear 的研究指出,其惡意 DLL 會載入兩個惡意檔案,這兩個檔案所扮演的功能,我們從未在其他 Waterbear 行動當中見過。第一個檔案會將程式碼注入某個資安產品的執行程序當中,藉此隱藏攻擊行動所用到的後門程式。第二個檔案是一個典型的 Waterbear 第一階段後門程式,以下我們先根據分析過程觀察到的某個案例來剖析這個檔案。
訂閱資安趨勢電子報
Waterbear 第一階段後門程式
我們在「%PATH%」環境變數所列的某個資料夾中,看到一個名為「ociw32.dll」的 Waterbear 惡意程式載入器。此 DLL 名稱是「mtxoci.dll」當中寫死的一個名稱,這是 Microsoft 分散式交易協調器 (MSDTC) 服務在開機時會載入的一個 DLL。照正常程序是,mtxoci.dll 會先試圖查看系統登錄機碼「HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSDTC\MTxOCI」底下的「OracleOciLib」數值是否存在。若存在,就讀取該值,並載入該值指定的 DLL。若不存在,mtxoci.dll 就會試圖載入 ociw32.dll 來代替。在我們所研究的受害系統上,其 OracleOciLib 登錄數值已遭刪除 (如圖 2 所示)。因此,MSDTC才會去載入駭客的 ociw32.dll 來執行。
圖 2:受害主機上的系統登錄數值「OracleOciLib」已遭刪除。
註:左邊的圖顯示正常系統上列了幾個 DLL 登錄數值,右邊的圖顯示受害系統上少了一個 DLL 登錄數值。由於「OracleOciLib」這個數值不存在,因此會載入寫死的「ociw32.dll」來代替,所以才會啟動 Waterbear 的惡意 DLL。
當 Waterbear 的惡意 DLL 執行時,會先搜尋某個寫死的路徑是否存在,然後試著解開對應的惡意檔案,該檔案是一段加密過的 shellcode。採用 RC4 加密演算法,並且以一個寫死的檔案路徑來產生解密金鑰。解開的惡意檔案若沒問題,就會將這段 shellcode 注入某個 Windows 服務 (此處為 LanmanServer) 的執行程序 (svchost.exe) 當中。在大多數情況下,此惡意程式碼為第一階段後門程式,主要負責接收第二階段的惡意檔案,也就是連線到 C&C 伺服器,或開啟某個連接埠來等候外部連線,接著載入接收到的執行檔。
第一階段後門程式組態設定
Waterbear 的第一階段後門程式組態設定包含了程式正確執行與外部通訊所需的資訊。
- 位移 0x00,大小 0x10:函式所需的加密 / 解密金鑰
- 位移 0x10,大小 0x04:0x0BB8 (保留)
- 位移 0x14,大小 0x10:版本 (如:0.13、0.14、0.16 等等)
- 位移 0x24,大小 0x10:Mutex 或保留的位元組
- 位移 0x34,大小 0x78:C&C 伺服器位址,以 0xFF 為金鑰進行 XOR 加密。如果後門程式是用來監聽某個連接埠,則此區段填入 0x00。
- 位移 0xAC,大小 0x02:連接埠
- 位移 0xAE,大小 0x5A:保留的位元組。
- 表格:惡意檔案函式位址表。此區塊一開始會填入 0x00,隨後在執行時期會填入資料。
- 表格:函式大小。
- 表格:API 位址表。此區塊一開始會填入 0x00,隨後在執行時期會填入載入的 API 位址。
- 表格:動態 API 載入所需的 API 雜湊碼。
- DLL 名稱清單以及要載入的 API 數量。
圖 3:第一階段後門程式組態設定結構。
Shellcode 惡意檔案的記憶體掃描反制機制
為了避開資安軟體的執行時期記憶體掃描,惡意檔案在執行實際的惡意行為之前會先將所有函式區塊加密。隨後,每當它需要用到某個函式,就會將該函式解密、執行,然後再加密回去,如圖 4 所示。如果某個函式接下來都不會再用到,該函式會由另外一個函式將它的內容攪亂,如圖 6 所示。這個攪亂函式會將指定區塊內的每個位元組填入隨機數值,使區塊內容無法復原。這麼做的目的,是希望進一步避免被某個網路資安軟體所偵測。
圖 4:shellcode 執行過程中的函式解密、執行、加密流程。
圖 5:負責函式區塊加密與解密的函式。
圖 6:負責攪亂函式內容的函式。
Waterbear 手法改變,本質依然不變
我們在研究過程中發現了一個有別於先前其他 Waterbear 感染案例的奇怪情況。這一次,惡意 DLL載入了兩個惡意檔案:第一個出現了我們之前沒看過的行為:利用 API 攔截技巧將程式碼注入了某個資安產品當中以免後門程式被該產品偵測到。第二個則是一個典型的 Waterbear 第一階段後門程式。
圖 7:非典型的 Waterbear 感染過程。
這兩個惡意檔案都經過加密並儲存在受害電腦的磁碟上,並且也都注入同一個服務當中 (此處為 LanmanServer)。我們發現,載入器會試著從磁碟讀取這兩個檔案,將它們解密,然後視下列情況注入執行緒當中:
- 如果磁碟上找不到第一個惡意檔案,載入器就直接終止而不載入第二個檔案。
- 如果第一個惡意檔案成功解開並注入服務當中,第二個檔案也會被載入並注入服務當中,不論第一個執行緒的執行結果如何。
- 在第一個被注入的執行緒當中,如果找不到該資安產品的必要執行檔,該執行緒就會終止並且放棄執行其他的惡意行為。請注意,只有該執行緒本身會終止,原本的服務依然會正常繼續執行。
不論 API 攔截動作是否執行成功,第二個後門程式在成功載入之後仍會正常執行。
利用 API 攔截來躲避偵測
為了隱藏第一階段後門程式的行為 (也就是下載第二個惡意檔案),第一個惡意檔案會使用 API 攔截技巧來干擾 API 函式的執行結果,以避免後門程式的行為被某資安產品所偵測。它會攔截「ZwOpenProcess」和「GetExtendedTcpTable」這個 API 函式來隱藏自己的行為。不過它只會修改資安產品執行程序在記憶體內的函式,因此原本的系統 DLL 仍不受影響。
惡意檔案包含了兩個攻擊步驟的 shellcode。第一步驟的 shellcode 會搜尋該資安產品某個名稱的特定執行程序,然後將第二步驟的 shellcode 注入該執行程序內部。接著,第二步驟的 shellcode 會攔截目標執行程序內的 API 函式。
隱藏執行程序識別碼 (PID)
執行程序識別碼 (也就是 PID) 是儲存在共用記憶體「Global\<computer_name>」當中。如果共用記憶體不存在,惡意程式就會使用第一步驟的 shellcode 所給的 PID。此處惡意程式碼想做的就是隱藏 Waterbear 的後門程式活動不讓資安產品發現。因此,第一步驟的 shellcode 會取得 Windows 服務的 PID (也就是第一步驟 shellcode 和後續後門程式所注入的資安產品執行程序),將該執行程序隱藏起來,然後將其 PID 寫入第二步驟 shellcode。
圖 8:將當前的 PID 寫入第二步驟 shellcode。
攔截 ntdll.dll 中的 ZwOpenProcess 函式
攔截 ZwOpenProcess 函式的目的,是為了防止資安產品存取該執行程序。每當 ZwOpenProcess 被呼叫時,被注入的程式碼就會先核對正要被開啟的執行程序是否為它想要隱藏的其中一個執行程序 (比對 PID)。若是,就修改它所收到的 PID,讓系統開啟另一個 Windows 服務的執行程序。
首先,它會先產生好要被注入的函式,然後將函式加入 ntdll.dll 的末端。此函式包含兩部分 (如圖 9 所示):
- PID 檢查程序。它會檢查 ZwOpenProcess 要開啟的執行程序是否在它要隱藏的執行程序清單當中 (比對 PID)。如果是,就將要被開啟的 PID 改成 Waterbear 載入器一開始寫入的另一個 Windows 服務的 PID。
- 在檢查過 PID 之後,它就繼續執行原本的 ZwOpenProcess 函式並傳回結果。
圖 9:攔截 ZwOpenProcess 函式來檢查並修改函式輸出結果。
其次,它會在原本的 ZwOpenProcess 函式開頭位址寫入「push <ADDRESS> ret」這行程式碼。如此一來,當 ZwOpenProcess 被呼叫時,就會執行被修改過的 ZwOpenProcess 函式。
圖 10:修改過後的 ZwOpenProcess。
攔截 API 函式 ZwOpenProcess 的動作只會在主機上存在著「%temp%\KERNELBASE.dll」這個 DLL 的時候才會執行。這樣的檢查有可能是針對它所要躲避的資安產品所設計的。
攔截 iphlpapi.dll 當中的「GetExtendedTcpTable」和「GetRTTAndHopCount」
接下來要攔截的 API 是「GetExtendedTcpTable」函式。GetExtendedTcpTable 函式的用途是用來取得應用程式可使用的 TCP 端點清單,一些網路相關的指令 (如「netstat」) 經常都會用到。攔截這個函式的目的是要消除某些執行程序的 TCP 端點記錄。為了達到這項目的,它會修改「GetExtendedTcpTable」和「 GetRTTAndHopCount」兩個函式。攔截第二個函式 (GetRTTAndHopCount) 的目的是為了放置要插入程的式碼。
攔截 GetExtendedTcpTable 函式時只會在其開頭寫入一行跳到 GetRTTAndHopCount 的程式碼。GetExtendedTcpTable 函式只有前 5 個位元組的程式碼有改變 (如圖 11 所示)。
圖 11:GetExtendedTcpTable 函式只有前 5 個位元組被修改。
其餘的程式碼都放置在 GetRTTAndHopCount 當中。在程式碼的第一部分,它會先將 [GetRTTAndHopCount +0x3E] 這個返回位址加入堆疊當中,然後執行原本 GetExtendedTcpTable 函式的前四道指令 (在圖 11 當中已經變成了 jump 指令)。之後,就會跳到原本的 GetExtendedTcpTable 來執行,並擷取其回傳的數值。該程式碼顯示在圖 12 當中。
圖 12:GetRTTAndHopCount 當中的第一部分程式碼,它會執行 GetExtendedTcpTable 然後再回到下一個指令。
在 GetExtendedTcpTable 執行過後,執行程序會回到第二部分的程式碼,也就是依序檢查回傳的 TCP 表中的每一筆資料。如果當中有任何 Waterbear 想要隱藏的 PID,它就會移除該筆資料,修改表中的資料筆數,然後繼續往下檢查。最後,它會回傳修改過的 TCP 表。
圖 13:GetRTTAndHopCount 當中的第一部分程式碼,它會執行 GetExtendedTcpTable 然後再回到下一個指令。
與其直接停用上述兩個函式,這種 API 攔截技巧反而更難被發覺,因為被攔截的函式依然照常運作,也照常回傳資料。儘管此案例中被攻擊的執行程序是寫死在第一步驟的 shellcode 中,但其攔截 API的邏輯是通用的,且相同的 shellcode 也可用來攔截其他廠商的產品。
結論
這是我們第一次見到 Waterbear 試圖隱藏其後門程式活動。從產品名稱寫死的情況來看,我們推測駭客對於受害者的環境以及他們所用的資安產品有一定的了解。此外,駭客也可能熟悉資安產品蒐集客戶端點與網路資訊的方法,因此才知道該攔截哪些 API 函式。由於其程式碼採用通用的方式來攔截 API,因此未來很可能只要更換部分程式碼就讓能其他產品也無法偵測 Waterbear 的活動。
手法 | 技巧 | 識別碼 | 說明 |
執行 | 透過載入模組的方式執行 | T1129 | 藉由 shellcode 動態載入 DLL。 |
透過 API 執行 | T1106 | 藉由 shellcode 動態載入 API。 | |
持續潛伏 | API 攔截 | T1179 | 攔截資安產品常用的 API。 |
提升權限 | 執行程序注入 | T1055 | 將解密後的惡意檔案注入「svchost.exe」執行程序當中。 |
API 攔截 | T1179 | 攔截資安產品常用的 API。 | |
躲避防禦 | 二進位碼填充 | T1009 | 填入無意義的資料來躲避防毒掃描。 |
停用資安工具 | T1089 | 注入程式碼的目的是為了躲避特定資安產品。 | |
解密/解碼檔案或資訊 | T1140 | 使用 TROJ_WATERBEAR 來將加密的惡意檔案解開。 | |
執行限制 | T1480 | 專門針對受害者環境中的特定軟體。 | |
DLL 側載 | T1073 | 使用被修改過的合法 DLL 來載入惡意 DLL。 | |
執行程序注入 | T1055 | 將解密後的惡意檔案注入「svchost.exe」執行程序當中。 | |
資料外傳 | 透過幕後操縱 (C&C) 管道將資料外傳 | T1041 | 有可能將蒐集到的資料經由 C&C 管道傳送給駭客。 |
入侵指標 (IoC)
SHA256 雜湊碼 | 趨勢科技命名 |
649675baef92381ffcdfa42e8959015e83c1ab1c7bbfd64635ce5f6f65efd651 | BKDR_WATERBEAR.ZTGF |
3909e837f3a96736947e387a84bb57e57974db9b77fb1d8fa5d808a89f9a401b | TROJ_WATERBEAR.ZTGD |
fcfdd079b5861c0192e559c80e8f393b16ba419186066a21aab0294327ea9e58 | TROJ_WATERBEAR.ZTGJ |
3f26a971e393d7f6ce7bf4416abdbfa1def843a0cf74d8b7bb841ca90f5c9ed9 | TROJ_WATERBEAR.ZTGH |
abb91dfd95d11a232375d6b5cdf94b0f7afb9683fb7af3e50bcecdb2bd6cb035 | TROJ_WATERBEAR.ZTGH |
bda6812c3bbba3c885584d234be353b0a2d1b1cbd29161deab0ef8814ac1e8e1 | TROJ_WATERBEAR.ZTGI |
53402b662679f0bfd08de3abb064930af40ff6c9ec95469ce8489f65796e36c3 | TROJ_WATERBEAR.ZTGH |
f9f6bc637f59ef843bc939cb6be5000da5b9277b972904bf84586ea0a17a6000 | TROJ_WATERBEAR.ZTGI |
3442c076c8824d5da065616063a6520ee1d9385d327779b5465292ac978dec26 | BKDR_WATERBEAR.ZTGD |
7858171120792e5c98cfa75ccde7cba49e62a2aeb32ed62322aae0a80a50f1ea | TROJ64_WATERBEAR.ZTGI |
acb2abc7fb44c2fdea0b65706d1e8b4c0bfb20e4bd4dcee5b95b346a60c6bd31 | BKDR_WATERBEARENC.ZTGF |
b9f3a3b9452a396c3ba0ce4a644dd2b7f494905e820e7b1c6dca2fdcce069361 | BKDR64_WATERBEAR.ZTGD |
7c0d2782a33debb65b488893705e71a001ea06c4eb4fe88571639ed71ac85cdd | BKDR_WATERBEARENC.ZTGH |
c7c7b2270767aaa2d66018894a7425ba6192730b4fe2130d290cd46af5cc0b7b | BKDR_WATERBEARENC.ZTGI |
7532fe7a16ba1db4d5e8d47de04b292d94882920cb672e89a48d07e77ddd0138 | BKDR_WATERBEARENC.ZTGI |
dea5c564c9d961ccf2ed535139fbfca4f1727373504f2972ac92acfaf21da831 | BKDR_WATERBEARENC.ZTGI |
05d0ab2fbeb7e0ba7547afb013d307d32588704daac9c12002a690e5c1cde3a4 | BKDR64_WATERBEARENC.ZTGJ |
39668008deb49a9b9a033fd01e0ea7c5243ad958afd82f79c1665fb73c7cfadf | BKDR_WATERBEARENC.ZTGD |
原文出處:Waterbear is Back, Uses API Hooking to Evade Security Product Detection 作者:Vickie Su、Anita Hsieh 與 Dove Chiu