Our mission is to call the libc system() function with "/bin/sh" as the argument. We can do this by calling a gadget that assigns a chosen value to RDI and then jump to the system() libc function.

First, where’s libc?

$ locate libc.so /lib/i386-linux-gnu/libc.so.6 /lib/x86_64-linux-gnu/libc.so.6 /lib32/libc.so.6 /usr/lib/x86_64-linux-gnu/libc.so

My system has a 32-bit and a 64-bit libc. We want the 64-bit one; that’s the second on the list.

Next, what kind of gadgets are available anyway?

$ objdump -d /lib/x86_64-linux-gnu/libc.so.6 | grep -B5 ret

The selection is reasonable, but our quick-and-dirty search only finds intentional snippets of code.

We can do better. In our case, we would very much like to execute:

pop %rdi retq

while the pointer to "/bin/sh" is at the top of the stack. This would assign the pointer to RDI before advancing the stack pointer. The corresponding machine code is the two-byte sequence 0x5f 0xc3, which ought to occur somewhere in libc.

Sadly, I know of no widespread Linux tool that searches a file for a given sequence of bytes; most tools seem oriented towards text files and expect their inputs to be organized with newlines. (I’m reminded of Rob Pike’s "Structural Regular Expressions".)

We settle for an ugly workaround:

$ xxd -c1 -p /lib/x86_64-linux-gnu/libc.so.6 | grep -n -B1 c3 | grep 5f -m1 | awk '{printf"%x

",$1-1}' 22a12

In other words:

Dump the library, one hex code per line. Look for "c3", and print one line of leading context along with the matches. We also print the line numbers. Look for the first "5f" match within the results. As line numbers start from 1 and offsets start from 0, we must subtract 1 to get the latter from the former. Also, we want the address in hexadecimal. Asking Awk to treat the first argument as a number (due to the subtraction) conveniently drops all the characters after the digits, namely the "-5f" that grep outputs.

We’re almost there. If we overwrite the return address with the following sequence:

libc’s address + 0x22a12

address of "/bin/sh"

address of libc’s system() function