Bugs_Bunny CTF 2017 - Maze Runner - Rev400 Writeup

Hello,

I solved the task by statically analyzing the given program. The goal was to pass 2 checks, isValid() and ValidAgAin().

If you import the binary to IDApro, you get the Call Graph of isValid() Function :



It looks hard to reverse-engineer it but it is really simple. The function is obfuscated since there is a lot of unnecessary checks and fake tests.

The check algorithm controls the execution flow based on Finite-State Machine model.

To solve the function we have to find the correct input which leads the execution to the correct final state, the node/state which returns 1 and avoid states returning 0 result.

The EAX register holds the current state value. The initial state value is 0x4DC7551E. The question is what is the following correct state ? I mean what will be the transition if EAX register is equal to  0x4DC7551E ?

We can just take the disassembly and search for 0x4DC7551E value.


As we can see from the above disassembly if the state is equal to 0x4DC7551E than the input character (held by DL register) at current index held by RDI register is checked against a set of candidate characters (0x48, 0x35, 0x77, 0x22 ..).

After several fuzzing attempts, I figured out that we need to pass only the first check (cmp dl, 0x48) and ignore the remaining one. This means that the first flag char is 'H'. Than the control is transferred to  loc_402B37.


The next state is 0x2C5928F3. We ask the same question: what will be the following state if 0x2C5928F3 state is reached ? We search again for 0x2C5928F3.


To reach the state the second input character is tested against 0x65 ,0x4F, 0x59..and as we said we should focus only on the first check. Thus, the second flag char is 'e' and so on and so forth !

0x4DC7551E  -> 0x48  ->  'H'
0x2C5928F3   -> 0x65  ->  'e'
0xEFCD27A9 -> 0x72  ->  'r'
0x707CE1DD -> 0x65  ->  'e'
0x0A4E69255 -> 0x2d  ->  '-' <- You should pay intention that the check is made using JNZ instead of JZ

And the first par of the flag is revealed ! "Here-"

The next state is 0x69241B56. To reach this state a new check mechanism is introduced.


The first 2 instructions in the disassembly above checks if the following char is number or not. Giving any number at this level is fine.  Remember that always we need to pas the first check !

The next states are:
0x7F202C0Ah  -> 1
0x9958FF9Bh  ->  1
0x56A7CE11h  -> 1
0x78AB8DFCh -> -

And so on and so forth !

The input Here-1111-Is-My-5EcreT-11-HH should pass the first test.

IsValid() accepts many solutions, just change numeric values.

IsValidAgAin() is made to make the program accepts only one input.

Decompile the function. Note I removed many unnecessary checks !




Conclusion drawn from the above code:
The flag length is 28
Chars at index 23 and 24 must  '4'
Chars at index 5,6,7 and 8 must '1'
Char at index 0 must be equal to 'H'

The flag is  Here-1111-Is-My-5EcreT-44-HH

The following video contains detailed steps !





That's all :)