大約在一個(gè)月前,Shadow Brokers(影子經(jīng)紀(jì)人)泄露了方程式組織(為NSA效力的黑客組織)的軟件FuzzBunch,一個(gè)類似于Metasploit的利用框架。這個(gè)框架中有幾個(gè)針對(duì)Windows的未認(rèn)證的遠(yuǎn)程利用(如EternalBlue, EternalRomance和 EternalSynergy)。很多利用的漏洞在MS17-010中被修復(fù)了,它可能是近十年來(lái)最關(guān)鍵的Windows補(bǔ)丁。
提示:你能使用我的MS17-010 Metasploit auxiliary module來(lái)掃描你網(wǎng)絡(luò)中沒(méi)有打補(bǔ)丁的系統(tǒng)。如果沒(méi)有安裝補(bǔ)丁,還會(huì)檢查是否感染DoublePulsar。
0x01 介紹
DoublePulsar是FuzzBunch中SMB和RDP利用中使用的主要的payload。下面分析是在Windows Server 2008 R2 SP1 x64上使用EternalBlue SMBv1/SMBv2 exploit完成的。
Shellcode基本上執(zhí)行了下面幾個(gè)步驟:
步驟0:判斷x86還是x64。
步驟1: 從KPCR中定位IDT,從第一個(gè)中斷處理反向遍歷找到ntoskrnl.exe的基址(DOS MZ頭)。
步驟2:讀取ntoskrnl.exe的導(dǎo)出目錄,并使用哈希(和應(yīng)用層shellcode類似)來(lái)找到ExAllocatePool/ExFreePool/ZwQuerySystemInformation函數(shù)地址。
步驟3:使用枚舉值SystemQueryModuleInformation調(diào)用ZwQuerySystemInformation,得到一個(gè)加載驅(qū)動(dòng)的列表。通過(guò)這個(gè)定位到Srv.sys,一個(gè)SMB驅(qū)動(dòng)。
步驟4:將位于SrvTransaction2DispatchTable[14]的SrvTransactionNotImplemented()函數(shù)指針指向自己的hook函數(shù)。
步驟5:使用輔助的DoublePulsar payload(如注入dll),hook函數(shù)檢查是否正確運(yùn)行并分配一個(gè)可執(zhí)行的緩沖區(qū)來(lái)運(yùn)行原始的shellcode。所有的其他請(qǐng)求直接轉(zhuǎn)發(fā)給原始的SrvTransactionNotImplemented()函數(shù)。"Burning" DoublePulsar不會(huì)完全擦除內(nèi)存中hook函數(shù),只是休眠它。
在利用后,你能看到缺少SrvTransaction2DispatchTable符號(hào)。在這里應(yīng)該有兩個(gè)處理程序與SrvTransactionNotImplemented符號(hào)。這是DoublePulsar后門(數(shù)組索引14):

我真的很好奇這個(gè)payload,在Countercept的DLL注入代碼分析之外沒(méi)有看到很多它的細(xì)節(jié)。但是我很好奇初始SMB后門是如何安裝的,這也是本文的內(nèi)容。
使用IA32_LSTAR系統(tǒng)調(diào)用MSR(0xc000082)和包含F(xiàn)EFE的Srv.sys的區(qū)域的EternalBlue利用中有一些有趣的設(shè)置,但是我將專注于原始的DoublePulsar的方法…很像EXTRABACON shellcode,這個(gè)非常狡猾并不只是產(chǎn)生一個(gè)shell。
0x02 shellcode詳細(xì)分析
在shadow brokers的轉(zhuǎn)儲(chǔ)中你能找到DoublePulsar.exe和EternalBlue.exe。當(dāng)你使用FuzzBunch中的DoublePulsar,有個(gè)選項(xiàng)是將它的shellcode輸出到一個(gè)文件中。我們還發(fā)現(xiàn)EternalBlue.exe包含了它自己的payload。
步驟0:判斷CPU架構(gòu)
主payload非常大,因?yàn)樗瑇86和x64的shellcode。前面一些字節(jié)使用操作碼技巧來(lái)決定正確的架構(gòu)(參考我之前的文章匯編架構(gòu)檢測(cè))。
下面是x86頭幾個(gè)字節(jié)。

你該注意到inc eax意思是je指令不執(zhí)行。接著是一個(gè)call和pop,獲取正確的指令指針。
下面是x64的:

其中inc eax由rex替換。因此zf標(biāo)志寄存器由xor eax,eax操作設(shè)置。因?yàn)閤64有RIP相對(duì)尋址,不需要獲取RIP寄存器。
X86的payload和x64的基本一樣,所以這里只關(guān)注x64。
由于NOP在x64中一個(gè)真正的NOP,我使用16進(jìn)制編輯器用CC CC(int 3)覆寫40 90。中斷3是調(diào)試器的軟件斷點(diǎn)。

現(xiàn)在執(zhí)行利用,我們附加的內(nèi)核調(diào)試器將自動(dòng)斷點(diǎn)在shellcode開始執(zhí)行處。
步驟1:找到ntoskrnl.exe的基址
一旦shellcode判斷是在x64上面運(yùn)行,它將開始搜索ntoskrnl.exe的基地址。代碼片段如下:

相當(dāng)簡(jiǎn)單的代碼。在用戶模式下,x64的GS段包含線程信息塊(TIB),其保存了進(jìn)程環(huán)境塊(PEB),該結(jié)構(gòu)包含了當(dāng)前運(yùn)行進(jìn)程的各種信息。在內(nèi)核模式中,這個(gè)段寄存器包含內(nèi)核進(jìn)程控制區(qū)(KPCR),其中偏移0處包含當(dāng)前進(jìn)程的PEB。
該代碼獲取KPCR的偏移0x38處,是IdtBase并包含一個(gè)KIDTENTRY64結(jié)構(gòu)的指針。在x86中很熟悉,能知道這是中斷描述符表。
在KIDTENTRY64的偏移4,你能得到中斷處理的函數(shù)指針,其代碼定義在ntoskrnl.exe中。從那里按頁(yè)大小(0x1000)增長(zhǎng)反向搜索內(nèi)存中.exe的DOS MZ頭(cmp bx,0x5a4d)。
步驟2:定位必要的函數(shù)指針
一旦你知道了PE文件的MZ頭的位置,你能定位到導(dǎo)出目錄,并得到你想要的函數(shù)的相對(duì)虛擬地址。用戶層的shellcode一直能做到這個(gè),通常是找到ntdll.dll和kernel32.dll的一些必要的函數(shù)。只需要和用戶層shellcode一樣,ring0 shellcode也使用哈希算法代替硬編碼字符串,以便找到必要的函數(shù)。
下面是要找的函數(shù):
ZwQuerySystemInformation
ExAllocatePool
ExFreePool
ExAllocatePool能用來(lái)創(chuàng)建可執(zhí)行內(nèi)存區(qū)域,并且ExFreePool能用來(lái)清理內(nèi)存區(qū)域。這些是重要的,因此shellcode能為它的hook函數(shù)和其他函數(shù)分配空間。ZwQuerySystemInformation在下一步中是重要的。
步驟3:定位SMB驅(qū)動(dòng)Srv.sys
使用SystemQueryModuleInformation(0xb)調(diào)用ZwQuerySystemInformation能實(shí)現(xiàn)。得到所有加載的驅(qū)動(dòng)的列表。

Shellcode在這個(gè)列表中搜索兩個(gè)不同的哈希,定位到Srv.sys,這是SMB運(yùn)行的主要驅(qū)動(dòng)。

過(guò)程和用戶層一樣,通過(guò)PEB->Ldr得到,遍歷搜索加載的DLL。這里要查找的是SMB驅(qū)動(dòng)。
步驟4:Patch SMB的trans2派遣表
現(xiàn)在DoublePulsar已經(jīng)有了主要的SMB驅(qū)動(dòng),它遍歷.sys的PE節(jié),直到找到.data節(jié)。

.data節(jié)中通常是全局讀寫內(nèi)存,在這里存儲(chǔ)著SrvTransaction2DispatchTable,一個(gè)處理不同的SMB任務(wù)的函數(shù)指針數(shù)組。
Shellcode分配一些內(nèi)存并實(shí)現(xiàn)函數(shù)hook。

接下來(lái)shellcode存儲(chǔ)派遣函數(shù)SrvTransactionNotImplemented()的函數(shù)指針(以便能在hook函數(shù)中調(diào)用)。然后使用hook覆蓋SrvTransaction2DispatchTable中的這個(gè)成員。

后門完成了。現(xiàn)在它返回到它自己的調(diào)用棧,并做一些小的清理操作。
步驟5:發(fā)送“Knock”和原始的shellcode
當(dāng)DoublePulsar發(fā)送了指定的“knock”請(qǐng)求(被視為不可靠的SMB調(diào)用),派遣表調(diào)用hook的假的SrvTransactionNotImpletemented()函數(shù)。能觀察到奇怪的行為:正常的SMB響應(yīng)MultiplexID必須匹配SMB請(qǐng)求的MultiplexID,但是增加了delta作為一個(gè)狀態(tài)碼。
操作能夠隱身,在Wireshark中沒(méi)有合適的解析。

狀態(tài)碼(通過(guò)MultiplexID delta):
0x10 = 成功
0x20 = 不可靠的參數(shù)
0x30 = 分配失敗
操作列表:
0x23 = ping
0xc8 = exec
0x77 = kill
你能使用下面的算法得到操作碼:

反之,你能使用這個(gè)算法制作包,其中k是隨機(jī)生成的:

在一個(gè)Trans2 SESSION_SETUP請(qǐng)求中發(fā)送一個(gè)ping操作將得到一個(gè)響應(yīng),其中包含需要為exec請(qǐng)求計(jì)算的XOR密鑰的一部分。
“XOR密鑰”的算法是:

更多的shellcode能使用Trans2 SESSION_SETUP請(qǐng)求和exec操作發(fā)送。使用XOR密鑰作為基本流密碼,一次性在數(shù)據(jù)包4096字節(jié)的“數(shù)據(jù)payload”部分中發(fā)送。后門將分配一塊可執(zhí)行內(nèi)存區(qū)域,解密復(fù)制shellcode并運(yùn)行。注入dll的payload能注入你想要的DLL。
我們能看見hook被安裝在SrvTransaction2DispatchTable+0x70 (112/8 = index 14)處:

全部的匯編在這里。
0x03 總結(jié)
這是一個(gè)復(fù)雜的多平臺(tái)的SMB后門。它是一個(gè)非常酷的payload,因?yàn)槟隳芨腥疽粋(gè)系統(tǒng),駐留,并能在你想要的時(shí)候做更多的事。它在系統(tǒng)中找到了一個(gè)很好的隱藏位置,并且不會(huì)觸PatchGuard。
通常我們只能在本地漏洞利用看到內(nèi)核shellcode,因?yàn)樗鼤?huì)變換進(jìn)程令牌以便提權(quán)。然而,微軟在內(nèi)核中做了很多網(wǎng)絡(luò)相關(guān)的事,例如Srv.sys和HTTP.sys。所描述的技術(shù)在很多方式完全符合遠(yuǎn)程利用中用戶模式的shellcode的操作方式。
當(dāng)它移植到Metasploit中,我可能不會(huì)逐字節(jié)復(fù)制,而是跳過(guò)后門的想法。它不是最安全的,因?yàn)樗辉偈敲孛埽魏稳硕伎梢允褂媚愕暮箝T。
下面是可以代替做的事:
1. 和DoublePulsar相同的方式獲得ntoskrnl.exe地址,并讀取導(dǎo)出目錄獲得必要的函數(shù)。
2. 啟動(dòng)一個(gè)隱藏的進(jìn)程(如notepad.exe)
3. 使用Meterpreter payload插入APC
4. 恢復(fù)進(jìn)程,退出內(nèi)核
5. ???
6. 收獲
|