Testing Linux Heap exploits on different Glibc version (with source-level debugging setup)
Recently I am learning about Linux Heap exploitation and I came across some really good Phrack papers and blogs which explained different type of attacks in varying conditions, I have included the link of these blogs and papers in the next section. I also came across an amazing GitHub project How2Heap by shellpish team, this project has the example exploit code for various heap exploitation technique of different versions of Glibc out there in public, which help me to get a better understanding of how those attacks played out. That project also included a script to build Glibc with any version of your choice and test the exploit on that version.
There was a certain limitation to the building and testing of the exploit code in the which is included in the project, I couldn’t set an environment with source-level debugging with. To gain a deeper understanding of these exploitation techniques to inspected memory layout of the various Glibc data structure(chunks, bins and arena) as the exploits were progressing and to see have how manipulation of these data structure affects the control flow of the Glibc internal code. This is what this post will address, how to compile any version of Glibc and setup environment to do source debugging and link that particular version of Glibc with the how2heap sample exploit or any other exploit code.
Below are some of the excellent piece of document which might blow your mind with the depth of thinking these hackers have put in(I will keep updating this section, this is not the whole coverage yet).
- Phrack Glibc Heap Attack Paper - straight from the underground
- Heap Exploitation Blogs
- The method used in the project is to set the LD_PRELOAD env variable to the newly compiled version, with this variable your program will give your Glibc library precedence over default, this method is good to test in standalone exploit code but if you launch gdb with this option, gdb will load the newly compiled version of the due to this gdb can start behaving weird or might get crashed.
- The other thing you need to know is that Glibc is composed of some 200+ binaries that must all match exactly. Two key binaries are /lib/ld-linux.so and /lib/libc.so.6 (but there are many more: libpthread.so.0, libnsl.so.1, etc. etc). If some of these binaries came from different versions of Glibc, you usually get a crash.
All in all, you have to make sure the only your program loads the Glibc you are experimenting with this exact version of libc.so matching with correct ld-linux.so binary.
- Clone the Glibc source from URL git://sourceware.org/git/glibc.git.
- You can use git checkout to checkout to any Glibc version of your choice.
- Create a build directory and go to that directory. Please make a note of this path as it will be used later while compiling. If you are going to compile different version then make a build directory for each version, build_
will be good conversion to follow.
- If you want to disable tcache option then you will have to pass –disable-experimental-malloc option. Build command will look something like this
<glibc source drictory>/configure --prefix=/usr [--disable-experimental-malloc].
makecommand. Don’t do
sudo make installthis might replace your system Glibc file, highly not recommended
Glibc is by default compiled with debug symbol ref so you don’t have to worry about doing any special here.
When the binaries are deployed in the production environment, debug symbols are removed using strip command.
Once you have the compiled Glibc binaries, you can see all these binaries in the build directory, will use this path in the gcc compile command with is as follow.
What are these GCC option ?
Here is a brief explanation of these options straight from the Linux manual man ld
Add a directory to the runtime library search path. This is used when linking an ELF executable with shared objects. All -rpath arguments are concatenated and passed to the runtime linker, which uses them to locate shared objects at runtime. The -rpath option is also used when locating shared objects which are needed by shared objects explicitly included in the link;
Set the name of the dynamic linker. This is only meaningful when generating dynamically linked ELF executables. The default dynamic linker is normally correct; don’t use this unless you know what you are doing.
How do I know which Glibc version is been loading by my program? Lucky there is a method exposed by Glibc library with you can to get the version. Paste the code below in the start of you exploit code to be aware of the version of the Glibc version.
Below are some of the command which will assist you further with source debugging.
|list/l 247||List your source code at line 247|
|list/l myFunc||List your source code of the starting function myFunc|
|list/l hello_world.c:main||check the source main function of this hello_world.c function|
|call myFunc(myArgc)||call function from gdb, useful to invoke function which print debug info|
|print/p myVar||Print the current value of myVar, you can also print most C expressions, e.g. myList[i] + 10, student.name. Note that #defined values don’t work.|
|break/b 36||Set a breakpoint at line 36 of your code.|
|break/b myFunc||Set a breakpoint at the start of the function myFunc in your code.|
|finish||continue the execution till the end of the function|
I use gef plugin for gdb, which makes command-line debugging less painful, gef also has heap analysis plugin which prints the heap data structure(chunks, bins and arena) stored in the program memory at will.
I hope at this point you are all set to do digging into heap exploitation and this setup might also help you in CTF’s. You won’t be able to do exact expression evaluation for some of the code as some of it is lost(#define code) in optimization and pre-processing about 5% of the code or so, nothing of major concern. Happy Hacking.