FLARE On Challenge (2015) #7

This challenge is a .NET application. There are many tools to decompile a .NET application and here I use the ILSpy.

A quick look at the decompile result I found that this application is probably obfuscated by SmartAssembly :
ch7_decomp1

There is a powerful tool named d4dot which can help with the deobfuscation. The tool is easy to use so I will not talk about more details here. After the deobfuscation the code looks much better and let’s go to the Entry Point function at first:
ch7_decomp2

This function is easy to understand, and the most important logic here is to compare your input with a string stored in a variable named “b”. And the string “b” is made up with two parts that generated by two different functions Class3.smethod_0() and Class3.smethod_3(). The code of Class3.smethod_0() is shown as below:
ch7_decomp3

This function does a simple XOR calculation on the array returned by function Class3.smethod_2() and the second arguments passed to this function. Here is the code of function Class3.smethod_2():
ch7_decomp4

This function is interesting, it returns the byte code of method 100663297 as a byte array. So what is method 100663297? If you are not familiar with .NET file format, I recommend you to read the article here at first:
http://www.codeproject.com/Articles/12585/The-NET-File-Format

In short, the 100663297 (0x06000001) is a .NET token which can be split into two parts, the highest 8 bit (0x06) is an index for a MetaData table, and the rest 24 bits (0x000001) is the index of the item in that table. Following is a list of .NET MetaData tables:
ch7_meta

The index 0x06 here represents the MethodDef table. We can use the CFF explorer to view the .NET tables. With this tool we can find that the first item (0x000001) in the MethodDef table is a function named .cctor, and we can also disassemble this function:
ch7_cff

Now that we have the byte code of the function, and we also know the second augments passed to the Class3.smethod_0() (from the decompiled code), we can easily calculate the first part of the string “b”:

bytecode =(0x72, 0x01, 0x00, 0x00, 0x70, 0x26, 0x2A)
arg2 = (31, 100, 116, 97, 0, 84, 69, 21, 115, 97, 109, 29, 79, 68, 21, 104, 115, 104, 21, 84, 78)

bytecode_len = len(bytecode)
out = ''
i = 0

for b in arg2:
    out += chr(b ^ bytecode[i%bytecode_len])
    i+= 1

print out

The string we want is:
ch7_str1

Ok, now we can move to the second part of string “b”, which is generated by function Class3.smethod_3():
ch7_decomp5

This function also straightforward, it concatenates all the CustomAttributeData as a string and then calculates the MD5 hash of it. The CustomAttributeData can be easily read from the .NET decompiler:
ch7_decomp6

However, this is a problem that we don’t know the correct order to put those CustomAttributeData together as a string. Since there are not too many CustomAttributeData, one possible way is to brute-force all the orders. But I will not solve this challenge in this way.

As we already have the first part of the string “b”, when this program compares the string with our input, the string must present in the memory, so why not just search it in the memory?

With this idea I launched this program in a debugger and let it run directly. It will ask us to enter a password:
ch7_output

We can input any password and continue executing the program until it exits. Now open the memory window and search for the first part of the string in Unicode format:
ch7_search

And finally we will  get what we want in the memory:
ch7_key

Provide the correct password to this program we have the email address:
ch7_ans

This entry was posted in CTF and tagged , , , . Bookmark the permalink.