I'm writing a return to libc attack for my systems security class. First, the vulnerable code:
//vuln.c
#include <stdio.h>
#include <stdlib.h>
int loadconfig(void){
char buf[1024];
sprintf(buf, "%s/.config", getenv("HOME"));
return 0;
}
int main(int argc, char **argv){
loadconfig();
return 0;
}
I want to use a return to libc attack. Compiling and debugging the program:
$ gcc -g -fno-stack-protector -o vuln vuln.c
$ gdb vuln
(gdb) break loadconfig
(gdb) run
Reached breakpoint blah blah blah.
(gdb) p $ebp
$1 = (void *) 0xbfffefb0
(gdb) p system
$2 = {<text variable, no debug info>} 0x0016db20 <system>
(gdb) p exit
$3 = {<text variable, no debug info>} 0x001639e0 <exit>
(gdb) x/2000s $esp
...
0xbffff5af: "SHELL=/bin/bash"
To execute the attack, I want to overflow the buffer into loadconfig
's return address (aka $esp+4
), replacing it with the return address for system
, then the return address for exit
(since system
expects a real return address), then the command name (the address of SHELL=/bin/bash
plus 6, to trim the SHELL=
part). This should be possible by crafting a $HOME
environment variable of 1024 characters of crap, then the little-endian address of system
, exit
, and /bin/bash
.
However, with every computer I've tried, system
gets loaded at an address that starts with 0x00, which will null terminate the string that sprintf
is reading and stop the attack dead. Is there some way to force libc
to load elsewhere in memory, or am I misinterpreting the attack?
For reference, I'm running an Ubuntu Server 11.10 virtual machine in VirtualBox (Windows host), with gcc
version 4.6.1 and gdb
version 7.3-2011.08. edit: ASLR is disabled, and I compiled with -fno-stack-protector
to remove the canary. Since I'm not executing anything from the stack, I don't need to execstack
it.