Binary Exploitation Automation with Radare2
2020-06-10
Binary Exploitation Automation with Radare2
Before I dive into describing my process I want to write a little disclaimer;
This post is by no means a complete guide to automate any kind of practical exploitation of binaries in the real world. This is simply to describe something I learned a while back but never really got around posting anything about it, and you never know, there might still be people interested in parts of this process.
This is something that has been laying around for quite some time and is by no means some kind of super advanced or creative way of doing this (build stuff in your backyard for fun).
ROP Exploitation
This post will not go into the technical details of ROP (Return Oriented Programming), there are a lot of people and posts about this technique, written by people that can do these explanations way better than I could ever. I will however bless you with some awesome resources regarding the topic:
ret2win32
For whoever that is interested in learning ROP, but doesn’t know where to start: ROP Emporium
ROP Emporium is a website that learns you all about ROP, how to exploit it, and even provides you with some tools that are described in the beginner’s guide on the website. The ret2win32 is one of the first challenges they provide on the website to get your feet wet, this same binary is the one that I used to familiarize myself with the ways to try and exploit it in an automated fashion with radare2.
Initial Information
With the target in sight I started off walking the usual path, gathering some information about the binary so I know what I’m dealing with:
As can be seen in the above output, the NX bit is set which means that the stack will not be executable.
We start off with radare2 in debugging mode, set a breakpoint at main, and continue execution. You could of course do some static information gathering first, I’m more of the struggle-as-you-learn kinda person;
Everything still works, let’s analyze the functions;
Oh my, a function with the name ‘pwnme’? Let’s look at this a little bit closer:
Because I want to keep this post on the short side I will just describe what is in there, and you will have to take my word for it that I’m talking the truth (or don’t and do the ret2win thingy).
This function also holds the print statement and takes the input with fgets
at 0x0804864e
the fgets
function is responsible for reading the user input and storing it in memory, by overwriting certain values we can overwrite EIP with our own value.
Way of the Automation
Normally we would assimilate the right information to construct our payload and return into the function that we want to return in to complete the challenge.
My take on these kind of binaries in particular, where no special input values are needed to validate the call to this function is to write a simple script that is able to leverage the radare2 framework to attempt all the different addresses of the functions as return address, which can be extracted with the afl
command.
The thought process I have can be described as follows:
The script takes a buffer which is used to crash the program;
With the pwn library a unique pattern is created that is used to locate the offset of the crash;
The EIP value is extracted when the program crashes and correlated against the pwn pattern to locate the offset;
The addresses of the different functions in the program are being retrieved
The functions starting with
sym.imp.
are not used because these are debug symbols referring to addresses related to the system calls (in this specific binary, but also in most other binaries that are loaded in radare2, see radare2 flags;
The brute force starts checking every function address, using this as a return value which is added to the pattern of garbage that is used to generate a crash;
To execute the program with this pattern the radare2 profile option is being used to store the pattern and use this pattern the moment the program asks for user input. This is done with the radare2 debug profile because normally the stdout would be redirected to that process, the profile ensures that this output is piped to the radare2 process of the user;
A search for the string
flag
is being done on the output after executing the function, if it holds this value it will output the program’s output;
radare2 profile
The above steps are actually quite simple, however it took me a little while to automate the process of accepting the user supplied value given through stdin, to be used as the buffer to be used to overflow the stack.
This is why the radare2 profile is created (somewhat) dynamically by writing the contents to the profile.rr2
which in turn gets read when the debug mode is entered. So for everyone that was reading this wondering how, the following code snippet shows you how:
Conclusion
I created a little Python script which you can find here (only works for x86 for now, also only tested on ret2win32).
As you can see in below image I probably spend more time on the colors and output than the script itself, overall it was a fun weekend project and I got a good grade with it for one of my university’s courses;
Again, not anything new, groundbreaking or advanced, but for the people that read the whole thing; thank you!
Stay safe in these weird times, spend time with friends and family etc. etc.
Last updated