FLARE On Challenge (2015) #9

This challenge contains a Windows Portable Executable file in a very small size (4,608 bytes), typically, this kind of files is written in Assembly Lagrange. If you load this file into IDA, you may notice that the file is badly obfuscated and hard to analyze statically. But if you look at the Strings (Shift + F12), you may find some interesting code located at 0x00401000:
ch9_disass1

Those code looks very similar to challenge #1 and challenge #2, so how about executing this program in a debugger and putting a breakpoint at 0x00401000? Unfortunately, the breakpoint here will not being hit. Eh… how about putting a breakpoint on the API it may calls like WriteFile() or ReadFile()? Badly, it seems cannot work either. But if you are not give up, you will finally find that a breakpoint on GetStdHandle() will eventually interrupt the execution of this program. That’s a good thing! Let’s execute this program step by step after hit the second GetStdHandle(). After several instructions, I am surprised that the program actually calls the API WriteFile():
ch9_dbg1

So why our previous breakpoint on WriteFile() did not work? When I look at the breakpoints lists, I realized that it is because the debugger “play a joke” on me:
ch9_dbg2

The breakpoint here is set on the WriteFile() function from module Kernelbase.dll, however, the WriteFile() function being called at real time comes from module kernel32.dll:
ch9_dbg3

Understand this, now we can put a breakpoint on the ReadFile() function in the kernel32.dll and it will hit as expected. After provides some fake input to the ReadFile() function, I continue executing this program on single steps. And finally, it comes to the interesting part:
ch9_dbg4

If you execute the code from here step by step, you will find that although the code is badly obfuscated, the verification logic is easy to understand: firstly, it will initialize a table on the stack, and retrieve an index from this table, and then it will use this index to retrieve a second index from the same table. Next, it will use the second index to retrieve a byte from that table and XOR it with the relevant byte of our input data. After this, it will use the second index to retrieve another byte from that table and do a left rotation with the XOR result. And finally it will compare the rotate result with a third byte retrieved from that table.

If you cannot understand the algorithm clearly through my description, the following Python script may help:

table  = '\xCC\xA9\x6D\x77\x0A\xF2\x4E\x58\xC1\x8A\x2F\x9F\xD8\x6C\x58\x43'
table += '\xF9\x1D\xC8\x92\x1F\x5C\xC3\x98\xC7\xF8\xD7\x03\xB0\x8A\x3C\xE7'
table += '\x1F\x1A\xCD\x02\x13\xF6\x07\x73\xF2\x33\xC8\xF0\xBA\xC2\xCC\xB8'
table += '\x80\xF0\x48\x77\xF9\x9A\x50\x55\xDC\x01\xE1\xEB\x16\x5A\x6B\xC6'
table += '\xC3\x0E\x8E\x27\x5D\xC3\xF4\x4E\x06\x42\xBC\xF2\x5D\x56\x30\x2E'
table += '\x19\x53\x53\x66\xD2\xF9\x03\xCF\x12\x06\x17\x1A\x0A\x0D\x02\x1E'
table += '\x16\x10\x1F\x09\x23\x0F\x14\x25\x1D\x03\x19\x21\x0B\x28\x13\x00'
table += '\x26\x08\x1B\x0C\x04\x27\x24\x1C\x01\x22\x18\x20\x11\x15\x05\x0E'
table += '\x07\x2A\x2B\x2C\xAC\xBE\xF5\x4E\x75\xBC\x87\xB8\x16\x67\x6B\x5C'
table += '\xFA\xF1\xF9\x93\xF2\xD4\xF8\x23\xB9\xC8\x11\x7E\xCA\x56\xD6\x1B'
table += '\x0A\xDA\x6E\xB5\x01\xC1\x55\x9B\xB8\x61\xCE\x4C\x6E\xBC\xEE\x08'
table += '\xF4\x64\x15\x8C\x65\x60\xE2\x1B\x8E\x40\x4A\x34\x45\xE3\x96\x4C'
table += '\xEB\xC9\x0D\xEB\x8E\x67\x26\xEF\x32\x46\xB5\xBD\xB2\xE6\x9F\xFF'
table += '\xF1\x74\xEF\xA8\x46\xC4\x60\x39\x65\x31\xAB\x9F\x01\x00\x00\x00'

def ror(n, c):
    c = c % 8
    t1 = (n >> c) & 0xff
    t2 = (n << (8-c)) & 0xff
    return t1 | t2

out = ''
for i in range(0, 41):
    index1 = ord(table[i+0x58])
    index2 = ord(table[index1+0x58])
    ch1 = ord(table[index2+0xB0])
    ch2 = ord(table[index2+0x84])
    ch3 = ord(table[index2+0x2C])
    out += chr(ror(ch3, ch2) ^ ch1)

print out

Run this script we can get the following result:
ch9_ans

Posted in CTF | Tagged , , , | Comments Off on FLARE On Challenge (2015) #9

FLARE On Challenge (2015) #8

When you open this challenge directly in IDA, you may as disappointed as me, there is only a few code available at the Entry Point and they seems do nothing useful:
ch8_disass1

However, if you open this file in a text editor, you may find the secret: there are a lot of Base64-like strings inside this file:
ch8_text

After decodes those strings, you can have a PNG file looks like below:
ch8_png

The first time I saw this picture, I believe that some information must be hidden into it. After Googling, I found a wonderful tool named Stegsolve which can help with analyzing the hidden information in a picture.

If you are not familiar with Steganography, I recommend you to read the following Wiki page:
https://en.wikipedia.org/wiki/Steganography

One famous approach to hide information into a picture is to store each bit of the information into the least significant bit (LSB) of the 8-bit color value of each pixel (24-bit bitmap). So let’s use the Stegsolve to extract this information, and the extracted data looks like below:
ch8_extract

At the first glance, there seems no useful inforamtion. However, if you are very familiar with the Windows Portable Executable file format, you may find some similarities if you compare the extracted binary data with a PE file:
ch8_cmp

Now we can guess that the information hidden in this picture is actually an encrypted PE file and let’s see if we can decrypted it. From the comparison above, we can at least know two things:
1. The file seems encrypted by a byte-by-byte encryption algorithm.
2. Some special bytes like 0x00 and 0xFF seems keep the same after encryption.

Next, let’s assume the first two bytes are the magic string “MZ” and the name of the first section is “.text” so that we can compare those bytes to see how they get encrypted:
ch8_cmpbytes

What’s your finding here? Yes, the ciphertext only reverse the bit order of the plaintext! Now we can write a Python script to decrypt the file:

def bit_reverse(byte):
    out = 0
    for i in range(0, 8):
        out += (byte & 0x01)
        out = (out << 1)
        byte = (byte >> 1)
    out = (out >> 1)
    return out

data = ''
for ch in open('gdssagh.bin', 'rb').read():
    data += chr(bit_reverse(ord(ch)))

open('gdssagh.out.exe', 'wb').write(data)
print 'Result written to file gdssagh.out.exe.'

And run the decrypted file we can get the email address:
ch8_ans

Posted in CTF | Tagged , , , | Comments Off on FLARE On Challenge (2015) #8

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

Posted in CTF | Tagged , , , | Comments Off on FLARE On Challenge (2015) #7

FLARE On Challenge (2015) #6

This challenge is an Android application. There are a lot of tools can be used to analyze Android application and the JEB Decompiler is my favorite one. Let’s open this challenge in JEB and look at the Manifest file at first:
ch6_manifest

The Manifest gives us many information and the most important are the two Activity: com.flareon.flare.MainActivity and com.flareon.flare.ValidateActivity.

Let’s see what will the MainActivity do:
ch6_decomp1

The functionality looks simple: it reads the input and stores it as an extra data named com.flare_on.flare.MESSAGE, and then it launches the ValidateActivity. So we move to the ValidateActivity:
ch6_decomp2

The ValidateActivity will retrieve the extra data stored in the com.flare_on.flare.MESSAGE, then verify if it is an ASCII string, if so it will pass this string to a function named “validate”, if not it will set the text “No”. So what does the function validate() do? From the keyword “native” in the function definition we can know that this is actually a native function which could exist in a native library. If you decompress the APK file with a decompression tool like 7-zip you may notice that there is a folder named lib and inside this folder there is an interesting file named libvalidate.so, from the file name we can guess that this one should be the file we want. So let’s disassemble it in IDA. From the Entry Point List (Ctrl + E) we can see a function named Java_com_flareon_flare_ValidateActivity_validate, which is interesting:
ch6_disass1

A quick navigate on this function we can find that there are two strings “That’s it!” and “No” present at the end of this function:
ch6_disass2

Those strings confirm that this function is what we need, so the next thing to do is no more than read the disassembly code to understand the functionality of this function. In short, this function will verify if the length of the input string is equal to or less than 46 at first, then it will convert two adjacent bytes of the input string to a 16-bit WORD (e.g. if two adjacent bytes are 0x11 and 0x22, they will be converted to 0x1122), and next, it will calculate the remainder of the WORD by dividing each 16-bit WORD in a table (I call it mod_table) located at address 0x00002214, if the remainder is zero, it will increase the relevant byte in another table (I call it reminder_table) by 1, and use the dividing result as a new DWORD to calculate the remainder until the dividing result equal to or less than 1. And finally it will compare the reminder_table with a hard-coded table (I call it key_table) to see if they are match. The following pseudo code may help you understand the flow:

if (input.length > 46)
    return "No"

result = 0
for (i = 0, table_index = 0; i <= input.length; i += 2, table_index++)
{
    n = (input[i] << 8) | input[i+1]

    j = 0
    while (j < 0xD94)
    {
        while ((n % mod_table[j]) == 0)
        {
            reminder_table[table_index][j] += 1
            n = n / mod_table[j]
            if (n <= 1)
                goto label_next
        }
        j++
    }
label_next:
    if (reminder_table[table_index] == key_table[table_index])
    {
        result += 1
    }
}

if (result == 0x17)
    return "That's it!"

return "No"

Obviously, this algorithm can be easily reversed, the following IDA Python script can be used to calculate the correct input:

from idaapi import *
import struct

mod_table = 0x00002214
key_tables = 0x00005004
key_tables_len = 0x17
key_table_len = 0xD94
out_str = ''

for i in range(0, key_tables_len):
    key_table = Dword(key_tables + i*4)
    out = 1
    for j in range(0, key_table_len):
        index = Word(key_table + j*2)
        if index != 0:
            num = Word(mod_table + j*2)
            out = out * (num ** index)
    out_str += struct.pack('<H', out)[::-1]

print out_str

And the answer is:
ch6_ans

Posted in CTF | Tagged , , , | Comments Off on FLARE On Challenge (2015) #6

FLARE On Challenge (2015) #5

This challenge is an easy one. It contains two files, one is a Windows Portable Executable file and another one is a PCAP file. Let’s look at the PCAP file at first:
ch5_pcap1

In the PCAP file we can see a series of HTTP traffics, each of them only POST 4 characters to a localhost server and the server will response with “1”:
ch5_pcap2

There is no more information we can find from the PCAP file, so let’s move to the executable.

The functionality of the executable file whose name is sender is really simple. Firstly, it will read some data from a file named key.txt:
ch5_disass1

Next, the data read from the key.txt will be encrypted by a function located at address 0x00401250:
ch5_disass2

The encryption algorithm is easy to understand: it adds the string “flarebearstare” to the data read from key.txt byte by byte.

After the encryption, the encrypted data will be encoded by Base64 algorithm with a custom character set:
ch5_disass4

And finally, the data will be split into 4 bytes strings and send out to the server:
ch5_disass5

So our task is easy, just assemble the 4 bytes strings in the PCAP file and then do a reverse calculation on the assembled string, the following Python script can help with the reversing:

import string
import base64

def base64_decode(s):
    table = string.maketrans(
      string.lowercase + string.uppercase + string.digits + "+/",
      string.uppercase + string.lowercase + string.digits + "+/"
    )
    s = s.translate(table)
    return base64.b64decode(s)

enc_data = 'UDYs1D7bNmdE1o3g5ms1V6RrYCVvODJF1DpxKTxAJ9xuZW=='
key_str = 'flarebearstare'
key_len = len(key_str)

b64_str = base64_decode(enc_data)
out_str = ''
i = 0

for ch in b64_str:
    out_str += chr((ord(ch) - ord(key_str[i % key_len])) & 0xff)
    i += 1

print out_str

And the answer is:
ch5_ans

Posted in CTF | Tagged , , , | Comments Off on FLARE On Challenge (2015) #5