Monday, August 13, 2007

F-Secure Khallenge '07 @ Assembly,Helsinki Finland

Well lately I have nothing really useful to post so I guess I'll post about F-Secure's Assembly Challenge 2007.

Binaries can be downloaded from http://www.f-secure.com/security_center/asm.html

Here are among the few tools which could prove useful

Ascii-hex-dec-bin converter
Ollydbg

Question 1 :
This here is a classic example of 'If you don't know how to get pass this, don't bother already!'
But for enlightenment's sake I'll post with clues on how to pass this level. Don't get me wrong, I'm not trying to discourage anyone from proceeding with this challenge(s) but it's simply a phrase to illustrate how dead simple this binary is. I will list out the steps.

1) Run the executable.

2) What did you realize
- Looks like a console program (duh)
- It has some input streams --> a key
- Seems to authenticate something . At some point it has to compare something, be it a constant, encrypted string or something else.
- It outputs a string right after it authenticates.

3) From the way I look at it, there are several ways with solving this challenge. If you're using Ollydbg like me, a noteworthy thing to do would probably be checking out string constants...

- Okay looking for strings probably wasn't as helpful, but definitely yield something interesting. If you look closely enough you could see something along the lines of
"Congratulations,!Please send an email to ThisIs%s@khallenge.com x0Dx0A"
- From here we know the string is not visible but has a memory buffer holding the remainder of the string we want to extract which is probably %s string identifier.

4) Now, you can either trace the program from start or ... Since we already know it's receiving some input and storing it in the buffer at some point, let's just hit f9 on ollydbg and run it till it waits for user input.

5) At this point, the program should keep running and wait for user input. You might want to hit f-12 now to stop ollydebug while you input an arbitrary value into the input field and wait for the values to pop up on your memory. Upon keying in your arbitrary string (which is 'aaaa' in my case) and hitting enter on your console where you input, you should see you are now in ntdll's memory section. What you might want to do is hit alt-f9 and let ollydbg execute till user code.

6) From here on you might want to hit f8 all the way till you see something like
690010BF 68 10330069 PUSH FSC_Leve.69003310 ; /s2 = "Asm07REC"
690010C4 68 A0310069 PUSH FSC_Leve.690031A0 ; |s1 = "aaaa"
690010C9 FF15 88200069 CALL DWORD PTR DS:[<&MSVCR71._stricmp>]

At this point i think the key is a dead giveaway. But assuming you don't want to re-run the program you could always

i ) change the memory location to which it stores the buffer for scanf and modify that memory location.
ii) Switch the zero flag on
690010D4 |. /75 1D JNZ SHORT FSC_Leve.690010F3
So that it doesn't take the jump and goes into the part where we saw the string "Congratulations ...."


Question 2 :

One interesting point here is the way the anti debugging code was done. Some people might not even realize there is some form of anti-debugger in this piece of code. To start off I will Illustrate some concepts of this program as far as my understanding goes.

The way the anti debugger in this binary was coded utilizes the TLS (Thread Local Storage) method so as to prevent debuggers like ollydbg (If i'm not mistaken ring-3 debuggers) to only have a break point on the entry point of the main program which can be referenced from OpenRCE's PE File Format Graph which is labeled as a DWORD : AddressOfEntryPoint in the _IMAGE_OPTIONAL_HEADER.

The TLS structure however is located in _IMAGE_TLS_DIRECTORY_. If your computation was correct, the TLS address location should be in 004070CC.
Based on that we refer to the _IMAGE_TLS_DIRECTORY_ and if we looked at the 4th Double Word in the struct, we should see a PIMAGE_TLS_CALLBACK *AddressOfCallBacks.
So from there we have to compute 4 DWORD locations from the offset of 0x4070cc which is the value 0x004070F0.
We then turn our attention to the memory location 0x004070F0 which is the value 0x004070A4.
And then... we look at the memory location 0x004070A4 in the disassembler window. Voila! Looks like some code in ere.

Here is the code dump for the TLS callback function.
004070A4 837C24 08 01 CMP DWORD PTR SS:[ESP+8],1
004070A9 75 1E JNZ SHORT FSC_Leve.004070C9
004070AB 50 PUSH EAX
004070AC 64:A1 18000000 MOV EAX,DWORD PTR FS:[18]
004070B2 8B40 30 MOV EAX,DWORD PTR DS:[EAX+30]
004070B5 0FB740 02 MOVZX EAX,WORD PTR DS:[EAX+2]
004070B9 83F8 00 CMP EAX,0
004070BC 0F94C0 SETE AL
004070BF 6BC0 08 IMUL EAX,EAX,8
004070C2 2805 BD634000 SUB BYTE PTR DS:[4063BD],AL
004070C8 58 POP EAX
004070C9 C3 RETN

If you know your way around kernel32's API you should be able to quickly identify that from the memory address functions 004070AC - 004070B5 are excerpts of code taken from kernel32.IsDebuggerPresent. What it does then is checks if there is a debugger attached to the program from the Process Environment Block (PEB) flag and then Subtracts 8 From the memory location 4063BD if there is no debugger present.

At this point you might want to already change memory location 0x4063BD with the value FFFFAF99 to FFFFAF91 to fool the binary into thinking you don't have an attached debugger.

Now let's go back to the main function of the program. We can tell that this binary is packed with UPX. So we scroll down right to the last operand at
004063BC .- E9 99AFFFFF JMP FSC_Leve.0040135A

Hit f4 to execute till that memory location 004063BC and hit f7 again to step into that jump.

We could then immediately see we have
00401352 33DB XOR EBX,EBX
00401354 68 5A134000 PUSH FSC_Leve.0040135A
00401359 C3 RETN

Zero-ing out EBX will then have later repercussions to the program yielding out proper results instead of fuzzy incorrect ones.
That said let's execute it further.

We can see later at memory address
0040137D FF25 5C304000 JMP DWORD PTR DS:[40305C]
There is a direct jump to Kernel32.GetCommandLineA to parse the execution parameter for this binary. We could almost tell that the outcome of this binary is reliant on input parameters.

Long story short at
004011EC 35 6D562855 XOR EAX,5528566D

we could see it XOR's the hex equivalent of your ascii input parameter with the mask 5528566D which results in the value 6578652E.

The anti debugging part earlier which will affect the outcome is then demonstrated here with this particular instruction

004011F1 30FC XOR AH,BH

At this point if your EBX is not zero-ed out, you will get a pseudorandomly XOR-ed AH which will affect the third character of your whole input parameter. Which is why some people out there are wondering why their 3rd input parameter is always changing.

Execute it further and you will realize you will get answer which is

Congratulation!
Please send an e-mail to LuckyNumberIs_30503343_FSC@khallenge.com
30503343 being the hex equivalent of your ascii input parameter.

The last solution will be posted sometime soon when I gather enough energy to blog it up. However it won't be as straight forward as the first two so I will not spend too much time on trivial and simple methodologies and concepts but focus more on the challenge at hand.

1 comment:

Unknown said...

I thought it was illegal to post solutions.... lolz but good work =)