We’re Screwed….Well Not Really, But Things Just Got More Difficult.

Last time we talked about advancing our skills to overcome some modern stack protections that prevent us from injecting shellcode and owning a system.

Like the Title Says

I listed three main protections we are concerned with when it comes to exploiting buffer overflows: ASL, DEP, and Stack Canaries.  These form a pretty powerful combination of protections and kill our exploit techniques we’ve learned so far.  So what do we do?

Getting Some Ideas

Lets look at DEP.  DEP makes the stack non-executable.  For us that means we can’t inject shellcode into the stack and execute it.  The shellcode will be treated as pure data.  So what do we do if we can’t inject code to get what we want?  We have to use what’s already there.  Fortunately for us some people with a lot more experience came up with the idea that we can use the code base of the C Standard Library to help us exploit a program.  That leads us to the return to libc attack.

Return to libc

Here we are going to follow HTAE to get the idea of what’s going on. Lets take a look at the following program:

int main(int argc, char *argv[])
{
    char buffer[5];
    strcpy(buffer, argv[1]);
    return 0;
}

Nothing too complicated is happening here.  We set up a buffer of length 5?  (You may want to look up why the length is that short)  Then we copy the command line argument into the buffer.  Pretty standard.  We then change the ownership to root and change permissions to allow us to run this program as root.

What do we want to do here?  At first glance this program doesn’t look like anything that will do what we want.  The idea is that we want to send execution into the standard C library where there are functions that will allow us to execute commands.  Functions such as system().  Take a look at the man page in the link for system().  The question becomes how do we access the command.

We need to find out where system() is in memory.  So to do that we run a simple program that calls system and does nothing else:

int main() {
    system(); 
}

We don’t get much simpler than that.  Now we run that program through gdb to find out where we are calling system() from.

$ gdb -q ./dummy
Reading symbols from ./dummy...(no debugging symbols found)...done.
(gdb) break main
Breakpoint 1 at 0x8048409
(gdb) run
Starting program: /home/exploit/Hacking/Exploits/dummy 

Breakpoint 1, 0x08048409 in main ()
(gdb) print system
$1 = {<text variable, no debug info>} 0xb7e523e0 <__libc_system>
(gdb) 

Now we see that system is located in libc at 0xb7e523e0.  Then we need to create a command to be given as an argument for system().  We do this by exporting an environment variable that calls a shell and then finding where the environment variable is stored.  We pass both the address of the system() function and the environment variable to our program and what happens?

$ ./vuln `perl -e 'print "ABCD"x2 . "\xe0\x23\xe5\xb7FAKE\xf7\x1d\xcd\xbf"'`
Segmentation fault

According to HTAE that should have worked….

What Should Have Happened?

First off we should have a root shell, but we don’t.  To recap the flow goes as follows:  We have a buffer set up.  We write a dummy program to find out where system() is in the C standard library.  We then export an environment variable to pass the command to system to call a shell.  We then find where the variable will be in memory when we run the program.  All of that combines to finish with calling the program and passing just enough buffer data to get right next to overflow.  Then we pass the addresses of system() and the variable as an argument.  The execution then should have overwritten the return address to call system(     /bin/sh) producing a root shell for our enjoyment and exploitation.  But that didn’t happen.

Conclusion

This is a new type of attack for us, but it’s not advanced enough to overcome all of the protections we are encountering.  I’ve included it for a few reasons.  It gets us thinking from the standpoint of what do we have available now that the old ideas won’t get us what we want.  It gets us thinking about the computer as a whole.  Why do we have to restrict ourselves to the stack or heap?  We have an entire system that may or may not contain attack surfaces we can exploit.  Results matter, not whether we got them by exploiting a buffer overflow or by tricking a user to click on a link.  You also never know.  The system you are approaching could have canaries and ASLR turned off because someone thinks that the overhead isn’t worth the protection.

We aren’t there yet but we are moving forward.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s