Solution to Warsaw Honeynet Project Workshop Conference official Crackme

Here is my solution, official one is available at http://www.cert.pl/news/8300/langswitch_lang/en

Crackme available at http://www.cert.pl/news/8253/langswitch_lang/en

Directly from the main page of the challenge: “We created a special file to which a total of 10 flags are somehow related. All of them are easily recognizable once you find them, because they are of the form flag{xxx}, where xxx is a string made of ASCII printable characters excluding whitespaces.“

Ok, I have a file and I have to look for all these flags inside it!

The crackme is an exe file, protected by Upx.

ThisWasEasyToFind!

My first approach was to use a resource related tool: Resource Hacker. With few clicks I got my first flag: “ThisWasEasyToFind!”.

It was really easy indeed!

PNGdoesNotHaveExif,ButStilIIsFun

Looking at the image you can see the red ellipse, there’s a typo error but it doesn’t matter because it’s a new hint for an hidden flag. Resource hacker is unable to show the picture, it shows an error box with an advice about a possible compression of the resource. Trying the same thing with the unpacked crackme I got the same result, and I decided to inspect the two pictures with an hex editor:

In both case, the header doesn’t reveal recognizable image header, but the one on the left has an interesting bytes sequence: “7zXZ”. 7-Zip will open XZ file, it’s a PNG image and the header contains a new flag:

Seems like the image was created with GIMP and the flag is: “PNGdoesNotHaveExif,ButStilIIsFun”.

JPEGalsoHasAFlag

Opening the image I got a surprise:

Another flag, “JPEGalsoHasAFlag”, the image was really interesting. A doubt remains, why jpeg and not png? Maybe it’s just an hint for those who didn’t see the image header at first. Anyway, it doesn’t matter.

DOSisPower

With the opened hex editor I decided to inspect the original and unpacked executables. There is an interesting thing inside the DOS Stub, the classic “This program cannot be run in DOS mode” phrase is not present this time. So, the only thing to do is to disasm (16 bit of course) the little snippet of 64 bytes starting from offset 0x40 of the executable:

Old school trick for sure! It’s a decryption routine, the real message is xor encrypted and is located at offset 0x22: {00 0A 0D 06 1C 3F 0B 1C 3A 1A 23 3F 18 12 17 0F}.

A simple idc script will reveal the hidden message:

#include static main() { auto x; auto i; x = 0x66; i = 0; while (i < 0x10) { x = x ^ Byte(0x22 + i); Message("%c", x); i++; } }

The new flag is: “flag{DOSisPower}”.

RussianFlagItIs

Ok, I’m not able to get any other information from the hex editor, time to run the executable. A message box appears:

The first time I run the program I didn’t notice the oddity included in the box. Well, once your eyes capture it you are on the path to the new flag! The caption of the box has a particular syntax, two words and one of them is inside ‘{‘, ‘}’ parenthesis. Time to inspect the code:

401FED mov [esp+28h+var_1C], 10h 401FF5 mov [esp+28h+var_20], offset unk_466128 ; The caption 401FFD mov [esp+28h+var_24], offset aThereAreNoFlag ; "There are no flags here for you!" 402005 mov [esp+28h+var_28], 0 40200C call MessageBoxW

The caption is not a direct string but a sequence of bytes: 44 04 3B 04 30 04 33 04… These are the unicode codes for Cyrillic alphabet. i.e:

0x0444 is ф

0x043B is л

As soon as you have the complete conversion in Cyrillic (“флаг{РуссианФлагИтИс} “) you can use an online translator to view the new flag: “flag{RussianFlagItIs}” (I hope the translation is right…). Ok, I’m at half path, I need 5 more flags to complete the journey.

HowToFindStringsInPEYouKnow

Near the message box there’s a suspicious string: “ZmxhZ3tIb3dUb0ZpbmRTdHJpbmdzSW5QRVlvdUtub3d9Cg==”. His nature is pretty clear (look at the end of the string: ‘==’), base64 encoding was used. Here’s the proof: trying to decode that string I obtain the new flag: “flag{HowToFindStringsInPEYouKnow}”

YouKnowHowToDebugCode!

To find out the last four flags you have to get your hands inside the crackme code. Browsing throught the imported functions I have found an unusual entry, OutputDebugStringA. The function is called inside the code at 0x401770. The routine has 3 parts: message initialization, message decryption and OutputDebugStringA of the message. The message is created with a series of bytes except the last 8:

39 47 47 46|0A 06 44 53|6A 1F 30 5C|6E 4E 06 0B| 9GGF#DSj#0

N## 44 62 44 13|2A 4C 65 4E|15 3A 0A 5B|00 63 68 61| DbD#*LeN#:[ cha 6E 67 65 6D|65 00 ngeme

“changeme”, that’s an hint!

The decryption scheme is pretty simple, the first 5 bytes of the message are xored (byte by byte) with the first 5 bytes of the key “changeme”, the next 5 bytes of the message are xored with the first bytes of the key “changeme” and so on until 0x00 bytes is not reached. Pay attention because only the first 5 bytes of the key are used. The decrypted message is used as a parameter for OutputDebugStringA. The idea is to obtain the flag message, and it’s an easy task because the first 5 bytes of a general flag message are “flag{“. So, you have 5 bytes of the encrypted message (39, 47, 47, 46, 0A), 5 of the decrypted message (“flag{“) and you can find the 5 bytes of the key: 5f, 2b, 26, 21, 71. Here is the obtained flag: “flag{YouKnowHowToDebugCode!}”.

HaveNoFear,ConsoleFlagIsHere!

Another suspicious import inside the crackme is CreateToolHelp32Snapshot. We all know what it does and it deserves a deeper investigation because it’s used to show a new flag. The function at 0x401B42 is used to find a specific process: “cmd.exe”. The process should be running when you start the crackme, otherwise you won’t see the flag. The flag’s message is decrypted at runtime but you don’t need to study anything else, just look inside cmd console:

VeryGoodHardDriveName

The call that follows the one used to check cmd.exe contains the ninth flag, it starts from 0x401D78. Again, the right message is decrypted at runtime using a key of four bytes obtained by the result of crc32(GetVolumeInformationA). The crypted string begins with “E2 B1 A6 47..” hex values. The bytes of the crc32 value are used one by one inside the xor decryption. To find out the right crc32 value we got an help from the crackme itself, look at the final part of this call:

401F15 MOVZX EAX,BYTE PTR SS:[EBP-2C] 401F19 CMP AL,'f' 401F1B JNE SHORT 00401F65 401F1D MOVZX EAX,BYTE PTR SS:[EBP-2B] 401F21 CMP AL,'l' 401F23 JNE SHORT 00401F65 401F25 MOVZX EAX,BYTE PTR SS:[EBP-2A] 401F29 CMP AL,'a' 401F2B JNE SHORT 00401F65 401F2D MOVZX EAX,BYTE PTR SS:[EBP-29] 401F31 CMP AL,'g' 401F33 JNE SHORT 00401F65 401F35 MOVZX EAX,BYTE PTR SS:[EBP-28] 401F39 CMP AL,'{' 401F3B JNE SHORT 00401F65 401F3D MOV DWORD PTR SS:[ESP+0C],40 401F45 MOV DWORD PTR SS:[ESP+8],00466072 ; ASCII "Congratulations!" 401F4D LEA EAX,[EBP-2C] 401F50 MOV DWORD PTR SS:[ESP+4],EAX ; Decrypted message 401F54 MOV DWORD PTR SS:[ESP],0 401F5B CALL ; Jump to USER32.MessageBoxA

This is the check for the first five bytes of the decrypted message, but in order to obtain the right crc32 value I need the first four checks only.

E2 ^ 66 = 84

b1 ^ 6c = dd

a6 ^ 61 = c7

47 ^ 67 = 20

The crc32 value of 0x20c7dd84 is the right key for the current decryption and the new flag is “flag{VeryGoodHardDriveName}”.

RC4EncryptionIsFun!!!1

The last flag finally! To get the starting hint for this last flag I checked the output provided by Procmon, the crackme creates a system file named “decode.py” inside temp folder. It’s not a system file of course, it’s a Python script and here is the content of it:

from Crypto.Cipher import ARC4 from base64 import b64decode import sys obj = ARC4.new(sys.argv[1][:5]) text = b64decode('LNLyv86npNDGrMxHrbpzHGoueiX3d3SPOmIZAg==') text = obj.decrypt(text) print text

Base64 plus RC4 decryption. Again, the printed text is somehow related to the flag message, so I know the first 5 chars of the text atleast: “flag{“. I didn’t waste my time trying to find a quick approach to the problem, I simply use one of the most stupid brute force approach. It returns more than one key but I was lucky to find the right one in a reasonable time. Here is the script:

from Crypto.Cipher import ARC4 alphabet = range(32,127) def checkKey(key): obj = ARC4.new(key) text = obj.encrypt('flag') if (text[0] == '\x2c'): if (text[1] == '\xd2'): if (text[2] == '\xf2'): if (text[3] == '\xbf'): print 'Key: ' + key def iterate(position, baseString): for char in alphabet: if (position < 4): iterate(position+1, baseString + "%c" % char) checkKey(baseString + "%c" % char) iterate(0, "")

The right obtained key is “Oi01_” and the final flag is “flag{RC4EncryptionIsFun!!!1}”

It was a fun challenge, thanks to Cert Polska!