VolgaCTF quals 19 – JAC II writeup

This challenge was solved by @R3x and @d3xt3r during the CTF. Writeup by @R3x

The challenge has two files – an Linux 64 bit executable and a encrypted file.

Reversing the executable

Running the executable we notice that it takes two command line arguments. The first argument is the input file and the second is the output file. We noticed that the contents of the input file are encrypted and stored in the output file.

Running the executable in gdb. We saw that it exits without printing anything. This looks like a possible ptrace implementation. Looking into the main function We don’t see anything standing. This leads to the conclusion that the ptrace might have happened before the main function. This leads to a variety of possibilities and the most obvious one being the .init_array section.

Sections named .init, .ctors, .preinit_array, and .init_array are to do with initialization of C/C++ objects, and sections .fini, .fini_array, and .dtors are for tear down.

Taking a look at the .init_array section we saw a lot more functions called than usual. And indeed there was a ptrace function and a ptrace syscall in these functions. So we quickly patched those and we were able to debug the binary.

Now looking into the binary in IDA we see that a lot of functions aren’t properly decompiled. So we do some patching here and there to get the decompilation working properly.

Below is a snapshot of the main function where the input file is actually being modified.

Screenshot 2019-03-31 at 1.34.27 PM.png

Here we noticed that the input_modification_function actually takes the arguments as two sets of four characters from the input and a constant key.

Again some patching inside the input_modification_function actually gave us a proper decompilation.

Below is a snapshot of the input_modification_function. (here sub_401DE6 is a rotate left function)

Screenshot 2019-03-31 at 1.42.49 PM.png

Now we just had to reverse the above function and we can get each four blocks of the flag from the given encrypted flag.

So we wrote a script in python to reverse the same. (CTF pressure so the script is obviously messy)


from pwn import *

keys = [ "6291bda5", "d40cbbbb", "cdb9f3e5", "edbd5140",
"2a716584", "42a476de", "79c7cea9", "48852b0e",
"2a53b9c8", "2984790b", "daaed337", "0245815e",
"014020ae", "3a84aaa9", "84b1fd24", "2766105f",
"1b765e10", "b691adc9", "eb50c850", "264c358b",
"32213a84", "387a7378", "1d7a8a61", "883de7f1",
"2c3bae3b", "6de14ba2"]

ror = lambda val, r_bits, max_bits: \
    ((val & (2**max_bits-1)) >> r_bits%max_bits) | \
    (val << (max_bits-(r_bits%max_bits)) & (2**max_bits-1))

f = open("data.jac2","r")
cont = f.read()

for ctr in xrange(0, len(cont), 8):
    v1 = int(p32(int(cont[ctr:ctr+4].encode('hex'), 16)).encode('hex'), 16)
    v2 = int(p32(int(cont[ctr+4:ctr+8].encode('hex'), 16)).encode('hex'), 16)
    for i in range(12, 0, -1):
        v2 = ror((v2 - int(keys[2 * i + 1], 16)) & 0xffffffff, v1 & 0x1f, 32) ^ v1
        v1 = ror((v1 - int(keys[2 * i], 16)) & 0xffffffff, v2 & 0x1f, 32) ^ v2
    inp1 = (v1 - int(keys[0], 16)) & 0xffffffff
    inp2 = (v2 - int(keys[1], 16)) & 0xffffffff
    print hex(inp1).replace('0x','').decode('hex')[::-1],
    print hex(inp2).replace('0x','').decode('hex')[::-1],

The above script just reversed the algorithm of the input_modification_function. Running it printed out the flag for us.

VolgaCTF{ptr@ce_ant1_r3verse_@ll_in_va1n}

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Blog at WordPress.com.

Up ↑

%d bloggers like this: