Malwarebytes released their second crackme last week coded by @hasherezade . This crackme has multiple levels and the flag is of the format flag{…..}. Here’s the link to the crackme.

 

LEVEL 1

At Level 1, the crackme asks to enter login information. Now, taking a brief look at the crackme in IDA reveals that it expands %temp% and drops some files in temp dir with a name of “_MEI + ProcessId + 2 ” and starts a child process. Taking a look at the contents of the files in the temp directory it is clear that the crackme is a python executable. The crackme creates a child process and after taking a look at the modules loaded by the process, we can confirm that executable infact uses python.

         

It is possible to extract the python script from executable and we are gonna use PyInstaller Extractor and Uncompyle6 . Using PyInstaller Extractor we extract the files and get the main python file named “another“. This file is a pyc file without the header, So we will prepend the 8 byte pyc header (“03 F3 0D 0A 00 00 00 00“) to the file. After this we are ready to decompile, and Uncompyle6 provides us with the decompiled python script used by the crackme.

Going through the extracted script, it is pretty easy to find that the login username is “hackerman”  and the password hash is compared with MD5 hash “42f749ade7f9e195bf475f37a44cafcb“. The hash is pretty common and a simple google search reveals that it is “Password123”. 

              

Now, the application expects a PIN and this is where things got a bit interesting for me. The application uses the entered PIN as seed for random module and then generates a string of 32 characters containing only numbers. The MD5 of this string is compared with “fb4b322c518e9f6a52af906e32aee955“. Initially, what my thought was that random is totally “random” so i was a bit confused here. After some searching, I found that random is actually not “random” and same seed produces same values every time. So, now everything was clear and I moved on to bruteforcing the PIN and generate the 32 length string according to the crackme and comparing the hash of generated string with  “fb4b322c518e9f6a52af906e32aee955“. After bruteforcing, I found out that the PIN is “9667” which helped me to clear the first level.

 

LEVEL 2

The string (key) generated in last step is used as AES key to decrypt the encrypted URL. The key is “95104475352405197696005814181948“. The decrypted link is “https://i.imgur.com/dTHXed7.png“, this image is downloaded. The Image is decrypted at runtime using “get_encoded_data()” and result is a DLL. The DLL is mapped into memory using VirtualAlloc with “PAGE_EXECUTE_READWRITE” memory protection attribute. After this, the DLL is executed from 3rd byte.

                        

Once you have the decoded dll, its pretty easy to analyze. The DLL enumerates all top level windows using “EnumWindow” and passes a callback function. This Callback function uses “SendMessage” with MSG param as “WM_GETTEXT” which retrieves the text in the window. First of all, it is checked if the text contains “Notepad” and “secret_console“. If there is match, then for that Window all Child windows are enumerated using “EnumChildWindows“. Now for all child windows too, there is a callback function which uses “SendMessage” to retrieve the text and matches it with “dump_the_key“. What i did here was, I opened Notepad and saved a file as secret_console which caused both “Notepad” and “secret_console” to appear in title bar. This fulfilled the first condition and after this typing “dump_the_key” inside the window did the job. Once “dump_the_key” is matched, “actxprxy.dll”  is loaded and the memory protection is changed to “PAGE_READWRITE”  and a base64 encoded string is written in this region. This marks the completion of Level 2.

 

LEVEL 3

For Level 3, we are back to another.py script extracted earlier. The crackme asks for 3 color values (R,G,B) for this level. Taking a look at the script there seems no hint for these values so we proceed further. Next, the previously written base64 encoded string is decoded and is decompressed using zlib. The decoded data and three R, G, B values (converted into a string) are passed to “dexor_data” function.

From the name of function and taking a look inside the function it is clear the decoded data (decompressed by zlib) is xor’ed by 3 byte key. Looking further, We come to know that after dexor’ing this data is executed using “exec” from python. This provides a hint that there are only ASCII characters in dexor’ed data that are used in python code and further greatly reduces the number of combinations for bruteforcing. So after this, I divided into three parts according to algorithm from “dexor_data” function and bruteforced for single byte key. This provided me with possible three color values in which there were only ASCII characters. For R these were 128 and 131, For G these were 0 and 4 and For B the only value was 128. As we can see from the following result that first combination produces valid python code therefore 128, 0, 128 is the correct combination.

So, after inputting 128, 0, 128 we get the flag and have solved the crackme successfully. The flag is “flag{“Things are not always what they seem; the first appearance deceives many; the intelligence of a few perceives what has been carefully hidden.” – Phaedrus}“.

Thanks for reading.

 

UPDATE:

Contest Summary – https://blog.malwarebytes.com/malwarebytes-news/2018/05/malwarebytes-crackme-2-contest-summary/

Categories: CrackmeWriteups