pwnthem0le

Home Blog About GitHub

pwnthem0le is a Turin-based, hacking students group born out of CyberChallenge 2018. Read more about us!

20 September 2018

noxCTF 2018 - Att3nti0n Writeup

by XxcoralloxX

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

AltText

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. AltText

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). AltText

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.

AltText 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:

for(i=0;i<Len;i++){
if(Key[i]^Mask[i%3]!=checkString[i]){
exit()
}
}

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

the mask:

AltText

the checkString:

AltText

and a few lines of C to perform that XOR.

AltText

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

AltText

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?”

AltText

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

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”.

AltText

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

AltText

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

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. (???)

AltText

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

AltText

And run it… oh.. we broke it? AltText

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.. AltText

But these instructions seem too strange, maybe they are wrong? Well 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: 0x13,0x37,0x73,0x31 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

AltText

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:

AltText

A nice challenge imho :D

XxcoralloxX

tags: reverse  windows  noxCTF2018