Table of Contents
Flare-On Challenge is an annual reverse engineering and hacking challenge created by the cybersecurity company
FireEye. It is designed to test the skills and knowledge of participants in various areas of cybersecurity, such as malware analysis, cryptography, network analysis, and exploit development. The challenge typically consists of a series of increasingly difficult levels, with each level presenting a unique set of challenges that must be solved in order to progress to the next level.
I will present my analysis and solution for the first challenge of the 2015
Flare-On challenge. I advise you to use the article if you are stuck or if you have already done the challenge, otherwise do it by yourself, it is the most formative.
Look at the challenge #
Before we start solving the challenge we can look at what it looks like and what we have to do.
As you can see the goal of the challenge is to find the valid password. This already gives us an idea of what we will have to look for during the reverse engineering.
Recon of the PE file #
Since this is the first challenge in the series, it is likely to be the easiest. Still, it is interesting to see if the executable is packed. To check we will use
Detect It Easy to see if the software detects a packer and take a look at the
entropy of the
PE file data.
Detect It Easy tells us that the challenge is a
PE32 file, which allows us to choose the right version of
IDA, and we learn that the file is not packed (which seems normal, we are only at the first challenge) by analyzing the
Code Analysis #
Now that we know that the file is not packaged and that we know its architecture we can start to analyse the challenge code. So first I load the
PE file into
As you can see, there is very little code, only one function exists. The code can be split into 3 parts: first, requesting the password and retrieving the password entered by the user, then checking the validity of the password and finally displaying the error or success message. We will first focus on the recovery of the password and then reverse engineer the password check to find the valid password.
Password retrieval and display #
In this first part we will analyse how the program retrieves the password and how it displays messages in the console. Below, you can see the part that comes to ask for the password and retrieves it.
You can see that the program uses the functions
ReadFile, I will detail their use and with which parameters they are called.
The first function to be called is the
GetStdHandle function. This function is part of
WINAPI and retrieves a handle to the specified standard device (standard input, standard output or standard error). You can find the documentation for the function here.
This function has only one parameter and this parameter can only have 3 values :
UINT32) : this is the value corresponding to the standard console input and retrieves the text entered by the user.
UINT32) : this is the value corresponding to the standard console output and is used to display text in the console.
UINT32) : this is the value corresponding to the standard console error and is used to display error in the console.
HANDLE retrieved after calling the
GetStdHandle function will be used to write a message in the console or to retrieve the text entered by the user.
To be able to write to the console, you need to call the
GetStdHandle function with the
(DWORD)-11 parameter to retrieve the
HANDLE corresponding to the console output. Then use the
WriteFile function to write to the terminal output buffer. We can therefore deduce that
[ebp+hFile] corresponds to the
HANDLE of the console output.
What we are interested in is how the password is retrieved. To retrieve the text entered by the user in the console, we need to call the
GetStdHandle function with parameter
HANDLE returned by the function corresponds to the standard console input; to retrieve the contents of the standard input buffer, we use the
ReadFile function. A quick analysis of the parameters passed to the
ReadFile function reveals the number of characters read by the
ReadFile function, i.e.
0x32, which is equal to
50 in decimal. We can also see the
HANDLE passed to the function, which is stored at
[ebp+var_c], and finally, what interests us most, the buffer containing the password that has just been read is at address
Password verification #
Now that we’ve analysed how the program retrieves the password and where the password is stored, we can move on to analysing password verification.
As you can see, the code used to check the password is relatively short. First,
ecx is set to
0 with the instruction
xor ecx, ecx, which may seem to indicate the use of a loop. Next, the password character entered by the user at the index of
ecx is loaded into the
al register, then xored with the value
0x7D and finally compared with a character at the index of
ecx present in a buffer at address
It would therefore appear that the correct password is in the buffer at address
0x40107B, but this has been xored, so the operation will have to be reversed to recover the correct password.
Finally, in the second part of the password check, we can see that if the comparison is correct,
ecx is incremented and compared with the value
24), which seems to correspond to the size of the password.
Password recovery #
Now we know that the xored password is in the buffer at address
0x40107B and that it was xored with the key
0x7D. With all this information we can create a small Python script that will allow us to recover the password in clear text. Since the reverse operation of the
XOR is the
XOR itself, we simply need to xor the characters in the buffer with the key
0x7D to recover the password in clear.
def xor_data(data, key): result =  for byte in data: result.append(byte ^ key) return result def bytes_to_string(data): return ''.join(chr(byte) for byte in data) data = [0x1F, 0x8, 0x13, 0x13, 0x4, 0x22, 0x0E, 0x11, 0x4D, 0x0D, 0x18, 0x3D, 0x1B, 0x11, 0x1C, 0x0F, 0x18, 0x50, 0x12, 0x13, 0x53, 0x1E, 0x12, 0x10] key = 0x7D result = xor_data(data, key) result_string = bytes_to_string(result) print(result_string)
We were able to recover the correct password and successfully complete the challenge.