ZeroDays CTF 2018 – “Whatta Man” Challenge

The “Whatta Man” challenge under the “Reverse Engineering” category of the ZeroDays Capture the Flag 2018 event got me quite confused probably because I got intimidated by those system calls presented in the debugger. So to start with, the challenge description went as follows:

OK ladies lets hear it for Khal Drogo

First was the need to check what the file was:

Another 64-bit ELF here which means the debugger has to be 64-bit too! Apart from doing the initial investigation on the file format, doing the “strings” command to extract strings in the executable gave an output of:

Looking at the above picture doesn’t give us any flag so the next step would be running the program to get an idea of how it works before using a debugger to do some assembly language review:

Great! It’s asking for a passcode. So by typing in the command “gdb ./KhalDrogo”, GDB should load the executable for debugging:

Next is finding out potential functions that we could look into but nothing stood out except of course the main function.

By typing in the command “disas main”, GDB dumps the assembly instructions and this is where the real analysis begins. (Please note that I am using the intel assembly format for this write-up. By default, GDB uses the AT&T assembly format so to change this to intel, type in “set disassembly-flavor intel”)

The concern here starts at <+9> because the previous lines are just some memory adjustment instructions.

0x0000555555554c93 <+9>: movabs rax,0x3231323132313231
0x0000555555554c9d <+19>: movabs rdx,0x323132313231
0x0000555555554ca7 <+29>: mov    QWORD PTR [rbp-0x30],rax
0x0000555555554cab <+33>: mov    QWORD PTR [rbp-0x28],rdx
0x0000555555554caf <+37>: mov    BYTE PTR [rbp-0x20],0x0
0x0000555555554cb3 <+41>: movabs rax,0x73560970035e0464
0x0000555555554cbd <+51>: movabs rdx,0x3533787009470365
0x0000555555554cc7 <+61>: mov    QWORD PTR [rbp-0x50],rax
0x0000555555554ccb <+65>: mov    QWORD PTR [rbp-0x48],rdx
0x0000555555554ccf <+69>: mov    BYTE PTR [rbp-0x40],0x0

At line +9, rax gets the literal value of 0x3231323132313231 and rdx gets 0x323132313231 in the next instruction. The following two instructions basically put rax and rdx in the stack together with the “mov BYTE PTR [rbp-0x20],0x0” instruction which simply puts a null character (“\0”) after the placement of rdx.

 At line +41, rax gets the literal value of 0x73560970035e0464 and rdx gets 0x3533787009470365 in the next instruction. The following two instructions basically put rax and rdx in the stack together with the “mov BYTE PTR [rbp-0x40],0x0” instruction which again, simply puts a null character (“\0”) after the placement of rdx in the memory.

After placing the bytes above in the stack, the program calls functions like “cout” through the stream libraries (as seen starting in line +92). Since the program was asking for a “passcode” when it was executed in its normal state, line +118 in the disassembled code points to this “passcode” input. Once the input function happens, the next instruction appears to check if the length of the input is 16 (0x10 in hex) as seen in line +138.

Obviously, if the input string doesn’t have a length of 16, the program will jump to main+370 and you’ll realize that’s were the exit is. The next instructions somehow show a loop where the counter is stored in the stack (rbp-0x14).

Also notice in line +166 “movzx ebx,BYTE PTR [rbp+rax*1-0x30]”, the data stored in the stack specifically the one that is stored in the -0x30 index (refer to the excel screenshot) is being placed in the ebx register and later being xor’d with the passcode input (line +195). The result is then placed in the edx register.

At this point, we have this formula:

(Input Passcode) XOR (Data stored in rbp-0x30) = edx

Further analysis show that each of the xor’d character is now placed in the stack starting in index -0x60 as seen in line +204. In line +232, these characters are being retrieved and stored in edx while eax now holds the characters stored in the stack from index -0x50 (refer to the excel screenshot). Once characters are placed in eax, it gets subtracted by 2 (line +253) and gets compared to the xor’d output currently stored in edx:

This means, we get another equation:

Data stored in rbp-0x50 = eax
eax – 0x02 = edx (This was derived from line +256 because the condition has to be met so the program can proceed)

With these in mind, a final equation can be summarized to:

eax – 0x02 = (Input Passcode) XOR (Data stored in rbp-0x30)

Since eax holds the data stored in rbp-0x50,

(Data stored in rbp-0x50) – 0x02 = (Input Passcode) XOR (Data stored in rbp-0x30)

Exclusive OR’s logic on the other hand can simply be reversed by applying the operation unto itself.

Example: 50 xor y = 05
If we xor 05 with 50, we are able to derive y.
50 xor 05 = 55

When going back to the original equation to check, 50 xor y = 05:

50 xor 55 is definitely 05 so if we xor this data [(Data stored in rbp-0x50) – 0x02] with (Data stored in rbp-0x30), we should get the passcode!

I have automated this through a C# program:

The output is: S0m3_5eCR3t5_D13Now to check if the passcode is correct, enter it in the KhalDrogo program:

The flag is: ZD2018{S0m3_5eCR3t5_D13}

One Comment

Leave a Reply

Your email address will not be published. Required fields are marked *