noxCTF 2018 - Att3nti0n Writeup

This is a windows executable, let’s start looking at what it does.


So, it looks like a key-checker, let’s see what IDA think about it.

Let’s investigate

Here we have the main. As usual, on the left, the program ends if there aren’t enough arguments (1).
On the right, the function Y2hlY2tLZXk it’s called, to check our input. Very standard.

Now, let’s have a look at the check function, conveniently renamed.

The check function?

Here, we note that the function is recursive

test al, al
add [ebp+arg_0], 1
mov eax, [ebp+arg_0]
mov [esp], eax
call CheckFun

checks if we are at the end of the string, if yes, it returns,

else it calls itself adding 1 at the address of the string (the next char).

Ok, but what it does?
there’s a bigger block of instruction which is the main part of the function, we need to take a closer look. Slowly.

Here what’s going on:

I’m going to name

“Key” the password provided by the user (which is ebp+arg_0)

“Mask” the string contained in the variable a2V5QXJy

“checkString” the string contained in the variable c29tZUtleQ_

1 - 2) The address Key is moved to EAX, then it’s value is moved to ECX.

3) The index variable i is moved into EAX.

4) a logic and between EAX (index i) and 3 is performed. The result will be the 3 lower bits of EAX (i % 3)

5) Mask[i%3] moved into EAX

6) EAX XOR with our Key (remember that this function is recursive, here we have 1 char of our Key).

6.5) This result is moved into EDX

7-8-9-10) checkString[i] moved into EAX

11) taking lower part of EAX

12) comparing it with EDX ( the result of Key[i] XOR MASK[i%3]).

Long story short, this kind of check is made:


okay, we can fairly easily find which is the right key doing this operation in the opposite way, we only need:

the mask:


the checkString:


and a few lines of C to perform that XOR.


And voilà, easy peas… oh.. no…


The Cake was a lie

Ok, a big breath and let’s start again..
Looking at the rest of the program, we can find another function: c2VjcmV0RnVuY3Rpb24
and this is it:

Several bytes are moved into two “Strings maybe?”


Some of them are “checked”, and if all the checks are correct, some memory is allocated:

Then a for through one of the two string is performed (on the right) and on the left, we can see “Your flag is %s”.


Okay okay, so let’s patch the program, we want it to call this function, instead of the “Fake check”.


Still not working.
Debugging with gdb we can see that some checks fail.
Let’s have a look at them:

They are quite simple, but strange, the value inside that memory address is moved only once and never used before the check. So it seems deliberately wrong. (???)


Then what about trying to patch them? I’m going to change that 4 bytes to the value they should be.


And run it… oh.. we broke it?

Losing hope

Ok.. let’s see with gdb..
At some point, after the for loop, but before the printf of the flag, a call to EAX is performed..

But these instructions seem too strange, maybe they are wrong?
Push Ebp
Mov Ebp, Esp
it’s quite common after a call.. maybe this first part is correct?
Looking back to ida, we can have a better look at that call.
the address is lpAddress which is the memory allocated after the check..

Let’s put on our thinking caps

Remember the “fake function”?
Ok, it uses a mask of 4 bytes to decode some data.
which is interesting, since we also patched 4 bytes to make the program proceeds..

the old values was:
0x46 0xbe 0x96 0x51

the new is:
0x55 0x89 0xe5 0x60

a xor between those 4 gives us:
which is the Mask of the fake function!

At last

Now we do what we did in the fake function, let’s take all the bytes from the second string (the one executed by the call).
and use the script made for the old function


And our output is:
55 89 e5 60 31 c0 be 44 33 22 11 bf dd cc bb aa ac 84 c0 74 5 34 17 aa eb f6 61 89 ec 5d c3

(Spoiler c3 is a return, great!)

One last effort

Now we patch all the bytes and running the program one last time we get:


A nice challenge imho :D