OK this is a bad pun to a rather nice movie. You may already have heard of the
magic gadget that exists to rule them all, more seriously, a gadget located in
the libc that executes a shell by itself. The problem is that depending on the
Linux distribution and the version of the libc, it might be located at
different places and have different instructions. Therefore we can’t just
search for a sequence of bytes. In this blog post, I propose a rather easy and
lightweight method of finding it with Radare 2. Happy hunting!
I won’t write yet another post about useful Radare2 commands. There
are already useful ones such as Techorganic’s Radare 2 in 0x1E
minutes, which shows its use while reversing a binary. I’ll
just show how I search for the magic gadget.
Radare 2 usually comes packaged in many Linux distributions. There are also
pre-built binaries for Windows, OS X and mobile platforms. In their
download page, the developers encourage to always use the latest git
version, because it is a rapidly evolving project and a lot of
contributions are added on a daily basis. As an example, the version of Radare2
found in the Kali repositories is almost a year old.
For the sake of completeness of that post, I’ll just explain the commands that
will be used.
When I want to analyze a binary I tend to always launch Radare2 with the -A
option to automatically launch the analysis of all referenced code:
The ? command is used to get help. It can be added to any commands to
get specific help on that command:
To look for a string inside a binary the / command can be used:
To search for cross-references to a specific address the command axt is used.
Some might think that it is barbaric and impossible to remember such a command
name. My idea is to see Radare2 as a tree of commands and each letter in a
command is used to select a branch. In the above command we have a, x and
t. Let’s have a look at the corresponding help information:
The pd N command is used to print (p) dissassembly (d) for N
instructions. There are some more subcommands but they won’t be used here:
If no address is given, it will print at the current address that is shown in
To print at (@) a selected address, we can either provide it as an argument
or change the current address:
The address selection applies to all function that can operate on an address, such as axt.
It is possible to filter the output of a command (sort of a grep) with a ~:
Now that we know a few commands, let the hunt begin. Basically the magic gadget
is a all-in-one gadget that invoke the execvesyscall
with /bin/sh as its first argument. The man pages shows that:
execve takes three arguments
filename: a pointer to /bin/sh for the magic gadget
argv: a pointer to an array of arguments
envp: a pointer to an array of environment variables
syscall are invoked with the following registers used to pass arguments:
rax: the number corresponding to the syscall (59 or 0x3b for execve)
rdi: the first argument (filename)
rsi: the second argument
rdx: the third argument
Basically the magic gadget has to do the following actions (not especially in that order):
load the address of /bin/sh in the rdi register
set the rsi and rdx registers
either call execve or set the rax register and execute the syscall instruction
Let’s start by looking for /bin/sh:
Now that we know the address, we can look for references that loads it into rdi:
Let’s have a look at those addresses:
We might be in the middle of the magic gadget because we already have rdi and
rdx registers set and the call to execve. Only rsi register is missing
and we need an instruction that will load something into rax, let’s have a
look at few instructions above:
That’s it we have found the magic gadget:
The address 0x000d605e is the offset of the magic gadget. To have the real
address one has to find the base address at which the libc is loaded (e.g. by
using vmmap in GDB).
If you are curious and want to see what is done by the function execve:
We can see that rax is set with 59 followed by the syscall instruction.
That example showed to magic gadget of the latest libc available in Arch Linux (glibc 2.23-1).
Here it is for the latest Ubuntu 14.04 (libc6 2.19-0ubuntu6.7):