« Home | Using socketNinja.pl with the Metasploit Framework... » | About the body Onload Internet Explorer Vunerabili... » | Obfuscating The Mozilla Recent Firefox DOS » | Obfuscating Web Pages » | Optomizer.pl » 

Thursday, January 05, 2006

Bypassing Windows DEP

So, we were talking about how the concept of making user data (such as portions of the heap, and the stack) non-executable could stop an attacker from being able to execute their shellcode. The gist of it is that the stack, and also any user data should be in sections of memory that are marked as non-executable. Thus, even if you can do a buffer overflow and get control of the EIP, you (in theory) should not be able to get your shellcode to execute since it is in a page of memory that is marked as non-executable. But, in fact, you often can…

I mentioned that there is a way around this. The technique used is called “return into libc”. It is also sometimes called “arc Injection”. See http://en.wikipedia.org/wiki/Ret2libc. Also see http://www.awprofessional.com/articles/article.asp?p=430402&seqNum=7 You put the parameters for a command on the stack, and then you put the address of some function into the EIP, and control jumps into that function and begins executing code. This code is already in some DLL or shared library that is loaded into memory and marked as executable. When the program jumps into that code, it will POP its arguments off the stack and perform that function.

So, what kind of functions would be good to jump into? In UNIX traditionally you want to jump into functions provided by libc, since that should be available on every system. In Linux, a useful command to jmp into is “system” which allows you to execute a command passed as a string.

It looks like this:

int system(const char *cmd);

In Windows, it is a bit more complex, but there are several functions that might be useful.

For example, one technique that was used in the rpcexec.c exploit called functions to allocate memory, copy the shellcode into a new page, and then mark the page as executable.

* addr1=(unsigned long)GetProcAddress(h1,"NtAllocateVirtualMemory");
* addr2=(unsigned long)GetProcAddress(h2,"memcpy");
* addr3=(unsigned long)GetProcAddress(h1,"NtProtectVirtualMemory");

They even provided some C source code to find these addresses:

* to get new offsets use this:
* ------------------------------
* #include <windows.h>
* #include <stdio.h>
* int main()
* {
* HANDLE h1,h2;
* unsigned long addr1,addr2,addr3,addr4;
* h1=LoadLibrary("ntdll.dll");
* h2=LoadLibrary("MSVCRT.dll");
* addr1=(unsigned long)GetProcAddress(h1,"NtAllocateVirtualMemory");
* addr2=(unsigned long)GetProcAddress(h2,"memcpy");
* addr3=(unsigned long)GetProcAddress(h1,"NtProtectVirtualMemory");
* for (addr4=addr1;addr4<addr1+0xffff;addr4++)
* {
* if (!memcmp((void*)addr4,"\xc9\xc3",2)) break;
* }
* printf("0x%x 0x%x 0x%x 0x%x\n",addr1,addr2,addr3,addr4);
* return 0;
* }
* -----------------------------
* to get the last offset use a standard rpc dcom exploit with the last
* \x90\x90 before the shellcode replaced with \xcd\x21. run the exploit
* and read the drwatson logs. substract 0xA5 from the fault address.

Another technique, described in http://www.uninformed.org/?v=2&a=4&t=txt involves turning of DEP for your process by passing control of the code into several carefully chosen places in actual DLLs.

I think what complicates matters for Windows is the fact that most Intel hardware does not have the capability to perform hardware enforced DEP.

Here is a presentation that discusses many of the stack protection schemes out there: http://www.blackhat.com/presentations/bh-usa-04/bh-us-04-silberman/bh-us-04-silberman-paper.pdf

In conclusion, making the stack and portions of the heap non-executable raises the bar for expoits, but does not make them impossible. It is not some kind of magic bullet.

E-mail this post

Remenber me (?)

All personal information that you provide here will be governed by the Privacy Policy of Blogger.com. More...

Add a comment