Friday, October 30, 2015

Solving the 2015 FLARE On RE Contest - Challenge #1

After my last post on disassembling control flow structures, a colleague of mine mentioned that I should participate in the 2016 FLARE On challenge next year. Due to work and life obligations I have not had the opportunity to partake in the previous 2 contests but I figured now would be a good time to get some practice in and prepare for 2016. I am by no means an expert and this is very much a learning exercise for me, one that I intend to document and share. I'll be doing a series of posts (when I find time) over the next few months documenting my progress.

The FLARE On contest is an annual capture-the-flag style reverse engineering competition from FireEye. If you'd like to follow along you can download the materials here. Each challenge involves assessing a sample with the sole intent of finding a key (an e-mail address).

Challenge #1
The first file is a self-extracting zip and will dump an executable into a specified directory with the name "i_am_happy_you_are_to_playing_the_flareon_challenge.exe". It's a long and oddly named file. I'll assume the intentional grammatical deficiencies are for comedic purposes and don't have any greater significance, for now :)

Before executing this file lets check out the import table to get an idea of what it does. It's only 2KB in size so it is clearly a small application with very limited functionality.
Pretty standard stuff here, no notable cryptography or networking related libraries. This binary appears setup to take some input and that's about all.

When we run the file this hypothesis is confirmed. The application prints two strings, prompts the user for input, checks if it is the correct value, and then prints a string depending on whether the user input the secret key. I tried entering a variety of answers that included special characters and lengthy input but could not generate an alternate error message.
At this point I elected to fire up IDA and take a peek at the disassembled routines. Before analyzing the main function though, lets review the raw hex and look for some of the strings that we observed during interactive program execution.
My first observation here is that after the 'You are failure' string we see  24 characters that appear mutated and are followed by some null values. Let's keep this in mind and take a peak at the application entry point.
Our application is initialized and GetStdHandle is called. This function retrieves a handle to the specified standard device (standard input, standard output, standard error). User input is taken and written to the memory offset for variable 'byte_402158'. Now we enter the core logic of the application.
The first routine takes the first low order byte (x86 is little-endian and the AL register is 8 bits) from the ECX register and moves it into AL. A bit-wise XOR operation is then performed against the AL register and the hex value '7D'. The result is then compared to a value stored at the memory offset of variable 'byte_402140'. If the values do not match then we get the error message. However, if the value does match then ECX is incremented and the XOR comparison occurs again. It iterates through this loop 0x18 times. In decimal this is 24 loops, which interestingly is the length of the mutated character we noted earlier. The memory offset referenced by variable 'byte_402140' is the location of this suspicious string as well.

At this point there is enough evidence indicating that the mutated characters are in fact the secret key. I thought about writing a program to XOR each byte at that offset by 0x7D but got lazy and used the Python interpreter.

Once you have computed each value, assemble the string and convert the hexadecimal values to ASCII.

Well that certainly looks like an email address. Sure enough, when we enter this as our key value it is successful.

Ta-da! This first challenge was fairly straightforward and didn't take long at all but I assume the difficulty level will ramp up quite quickly.

Monday, October 5, 2015

Disassembling Loops and Control Structures in x86

One of the first topics we discussed focused on understanding how function calls and stack frames are represented in assembly languages. I wanted to follow up on that as we haven't posted on this subject matter since then. Both this post and my prior one are geared towards those with an interest in learning more about assembly and have only introductory level knowledge.

Although most of the worlds developers have long since ascended or are in the process of moving to high-level and very-high-level languages, a subset of industries and disciplines still necessitate a heavy focus on low-level languages. The cyber-security industry is a prime example in that both defenders and attackers, to some degree, work intimately with dis-assemblers and debuggers.

On the offensive side of the equation developers focus on writing memory efficient shellcode in assembly to interact with operating system application programming interfaces in order to exploit a system. Exploit developers may also dis-assemble and debug an application in assembly to gain a better understanding of it's internal structure so as to identify weaknesses. Dis-assembly and debugging is core to the 'hacker' ethos in that it is the mechanism by which one seeks to explore and understand the inner workings of an application or object.

But this process cuts both ways. Defenders spend a great deal of time dis-assembling and debugging malware to understand how it works and what impact it may or will have on a system. Moreover, fuzzing, dis-assembly, and debugging of legitimate applications is often done with altruistic intention and leads to more secure software.

For many tier-1 and tier-2 security analysts, crossing the bridge to a research position is difficult in that it requires significant familiarity with assembly language concepts. I don't often meet a lot of computer science graduates who are fluent in IA32. Most entrants to the security field find themselves working in various security applications for a couple of years unless they score an entry level threat research or junior A/V analyst position. These are more niche areas so the opportunities are not as common.
I mentioned in my previous post that I think one of the best ways to understand assembly is by training the eye to recognize assembly routines that translate to common high-level language functionality. The Intel 64 Architecture Manual isn't a particularly thrilling read and I don't spend all day writing programs in NASM, so for me, coding in C++ and then disassembling an executable was a quick way to build visual fluency. It is much easier if you can visually recognize a particular pattern and immediately know what it is doing instead of picking your way through every operation when viewing an application in IDA or Ollydbg. Legibility is obviously much more natural in high-level languages and so this takes some practice. I wanted to go through a few examples in this post.

Loops and Conditional Statements
Loops and conditional statements are one of the first concepts a programmer will learn and are found in all programs of moderate complexity. A loop is an iterative or repetitive task designed to carry out some action until a specific condition is met. Loops can be expressed in a number of different ways depending on the logical scenario. It is normal to encounter:
  • If-Then Statements
  • For Loops
  • While Loops
  • Do-While Loops
  • Infinite Loops
It's important to understand that all of these loop functions rely on a similar underlying conditional decision making process. A For-Loop contains an initialized variable, a comparative statement, an iterative counter, and an action that is performed. These shared characteristics become more apparent when such a process is dis-assembled. 

Control Flow
We utilize control flow statements to modify the orderly execution of an application. Control flow commands allow us to move non-sequentially around an application, branching out and executing different routines based on required conditions. High-level languages address a lot of the minutiae relating to the management of this process. When we dis-assemble loops and conditional statements we see that variables, comparators and control flow commands are at the core of these components.

Consider the following example:
for (int i=0; i < 10; i++){
     cout << "Hello";
Can be expressed as:
int i = 0;
cout << "Hello";
To implement this functionality in IA32 we utilize the compare (CMP) and (JMP) statements, along with registers, and stored values on the stack.

Let's walk through the prior example. At function loc_415F00 we see:
mov [ebp + i] , 0
jmp short loc_415F0F
First we move the value of 0 into the value 'i' which is referenced as an offset from the EBP register. Think of EBP as the base value from which all variables can be accessed inside functions or the application entry point. This is essentially our variable initialization (declaration would occur in the .BSS or .DATA segments of the PE file).

Now at function loc_415F0F we find:
cmp [ebp + i] , 0Ah
jge short loc_415F30
We see a comparison command that compares the current value of 'i' (which was just set to 0) to 0Ah. The 'h' indicates this value is expressed in hexadecimal and when translated to decimal we know this is the number 10.

The second command is an example of a conditional jump. The JMP command is an unconditional jump in that there is no requirement for it execute a jump. If EIP points at this command it will execute and redirect control flow. A conditional jump requires that a certain criteria is met before it redirects EIP. In our example the command can be interpreted as saying point EIP to the address of loc_415F30 if the second operand (0Ah) is greater than or equal to (JGE) the first operand (our variable 'i'). These commands represent our comparative statement.

We can then proceed to function loc_415F30:
mov eax, [ebp + i]
add eax, 1
mov [ebp + i], eax
jmp loc_415F0F
This set of instructions comprise the iteration required by a For-Loop. The value of 'i' (0) is moved into the register EAX which is then incremented by 1 and then pushed back into the memory offset of our variable 'i'. We then jump back to loc_415F0F so that our comparison and iteration occurs until the CMP statement sees that [ebp + i] is greater than or equal to 0Ah. When this condition is satisfied the program will skip the conditional branch and EIP will move to the instruction following the jump statement.

The popular dis-assembler IDA does a great job of visually representing this process as seen below:
The thick blue line represents the For-Loop. The red line indicates the that the required condition was not met while oppositely the green line implies that it was satisfied. Similar sequences may not be as legible in a debugger.

While this is not the most advanced material I hope that it serves to clarify the subject and help you in your journey!