Flare-on 2021: Challenge 2 - known
The next challenge of the Flare-on 2021 is called "known".
Description
In this challenge, we have one executable called UnlockYourFiles.exe and a directory with a few files in different formats, all with a ".encrypted" extension:
Executing "UnlockYourFiles.exe" will open the console, waiting for the user to enter the decryption key to decrypt all encrypted files inside the "Files" directory:
So the target is to find that decryption key.
Solution
We will start analyzing the executable file UnlockYourFiles.exe by using a disassembly tool IDA.
The program starts at the entry point which prints the text above, and then reads the input and executes function sub_401370, passing the buffer (which contains the input) as argument:
Inside this function, the argument arg_0 contains the user input.
It sets the directory to "Files" (which means that the directory and the executable must be in the same location) and iterates through the files with the file extension ".encrypted" (the sub_4010c0 will be called if an error occurs):
After getting the handler for the first file, the program will iterate over all the files (with the ".encrypted" extension) performing functions sub_401030 and then sub_401220.
Looking for the decryption process, the next function sub_401220 gets the 2 files' names (the current file and the file name from sub_401030) and arg_0 - which is the user input (the decryption key).
Inside sub_401220, the function opens the encrypted file with read privileges and creates the decrypted file with write privileges:
Then, it reads 8 bytes (each iteration until the end of the file) from the encrypted file:
And performs the decryption (function sub_4011F0) and writes it to the decrypted file:
The function sub_4011F0 gets 2 arguments - the buffer which contains 8 bytes of the encrypted data and "arg_8" which is the decryption key input by the user.
Finally, the decryption algorithm inside sub_4011F0.
The algorithm iterates 8 times and performs the next operations for each byte from the decryption key and the encrypted data (arg_0 is the encrypted data and arg_4 is the decryption key):
For each index in arg_0 and arg_4 respectively, perform the operations in the red rectangle:
To summarize, the formula is:
ROL(encrypted_data[i] ^ decryption_key[i], i) - i = decrypted_data[i]
for each iteration (= i) from 0 to 7.
Since we need to find the decryption_key (which is 8 bytes long) by finding 8 bytes of encrypted_data and 8 bytes of the decrypted_data respectively - we can reverse the formula and find the decryption_key.
Back to the encrypted files in the "Files" directory, we can notice that a PNG file was encrypted too.
PNG has 8 bytes constant header - 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A.
We can use those values as the decrypted_data and check for the encrypted PNG constant header (with HxD):
We will use those values as the encryped_data.
Reversing the formula:
ROL(encrypted_data[i] ^ decryption_key[i], i) - i = decrypted_data[i] ==>
ROL(encryped_data[i] ^ decryption_key[i], i) = decrypted_data[i] + i ==>
encrypted_data[i] ^ decryption_key[i] = ROR(decrypted_data[i] + i, i) ==>
decryption_key[i] = ROR(decrypted_data[i] + i, i) ^ encrypted_data
A python script to calculate it all:
encrypted_data = b'\xC7\xC7\x25\x1D\x63\x0D\xF3\x56'
decrypted_data = b'\x89\x50\x4E\x47\x0D\x0A\x1A\x0A'
def calc_decryption_key(i: int):
byte_to_rotate = decrypted_data[i] + i # the reverse of SUB
byte_after_rotate = (byte_to_rotate >> i) | (byte_to_rotate << (8 - i)) & 0xFF # the reverse of ROL
return byte_after_rotate ^ encrypted_data[i] # the reverse of XOR
decryption_key = bytes([calc_decryption_key(i) for i in range(8)])
print(decryption_key)
The output is:
b'No1Trust'
Insert the decryption key:
And the files are decrypted successfully!
The flag for this challenge is inside the "critical_data.txt" file: