Intro
Every year, FireEye holds a challenge called flare-on. For a couple of years, I participated and tried to solve them. This year I have decided to write my solutions on my blog. This year I could only solve 8 challenges. During this process, I got great help from many people and I also helped a couple of people. It was a great experience. I hope I can participate next year as well.
Challenge 1
The first one was very basic.
function checkCreds() {
if (username.value == "Admin" && atob(password.value) == "goldenticket")
{
var key = atob(encoded_key);
var flag = "";
for (let i = 0; i < key.length; i++)
{
flag += String.fromCharCode(key.charCodeAt(i) ^ password.value.charCodeAt(i % password.value.length))
}
}
So if we use Admin
as a username and Z29sZGVudGlja2V0
as a password(goldenticket encoded as base64 string ) the first flag appears.
enter_the_funhouse@flare-on.com
Challenge 2
When we open the unlock.exe file it asks for a password. We need to find the password to decrypt all the files. Let’s decompile the exe file and see what is happening.
BOOL __cdecl sub_401220(LPCSTR lpFileName, LPCSTR a2, int a3)
{
DWORD v3; // eax
char Buffer; // [esp+0h] [ebp-18h]
DWORD NumberOfBytesWritten; // [esp+8h] [ebp-10h]
HANDLE hFile; // [esp+Ch] [ebp-Ch]
HANDLE hObject; // [esp+10h] [ebp-8h]
DWORD NumberOfBytesRead; // [esp+14h] [ebp-4h]
hFile = CreateFileA(lpFileName, 0x80000000, 1u, 0, 3u, 0x80u, 0);
if ( hFile == (HANDLE)-1 )
LogError((void *)lpFileName);
hObject = CreateFileA(a2, 0x40000000u, 0, 0, 2u, 0x80u, 0);
if ( hObject == (HANDLE)-1 )
LogError((void *)a2);
while ( 1 )
{
if ( !ReadFile(hFile, &Buffer, 8u, &NumberOfBytesRead, 0) )
LogError((void *)lpFileName);
if ( !NumberOfBytesRead )
break;
sub_4011F0((int)&Buffer, a3);
if ( !WriteFile(hObject, &Buffer, NumberOfBytesRead, &NumberOfBytesWritten, 0) )
LogError((void *)a2);
}
CloseHandle(hObject);
CloseHandle(hFile)
v3 = sub_401000(lpFileName);
NumberOfBytesRead = v3;
a2[v3 - 10] = 10;
WriteConsoleA(hConsoleOutput, lpFileName, NumberOfBytesRead, 0, 0);
WriteConsoleA(hConsoleOutput, asc_403760, 4u, 0, 0);
return WriteConsoleA(hConsoleOutput, a2, NumberOfBytesRead - 9, 0, 0);
We see that it reads the file 8 bytes at a time and it sends this buffer to the following function. The first parameter is the buffer second parameter is the key.
char __cdecl sub_4011F0(int a1, int a2)
{
int i; // ecx
char result; // al
for ( i = 0; (char)i < 8; LOBYTE(i) = i + 1 )
{
result = __ROL1__(*(_BYTE *)(i + a2) ^ *(_BYTE *)(i + a1), i) - i;
*(_BYTE *)(i + a1) = result;
}
return result;
}
So the point of this challenge is finding the key so that we can decrypt the files. If we check the algorithm, there is a step after 8 bytes. So if we can have a plaintext with 8 bytes and with an encrypted file, we can recover the key. We check the files and we see that there is a PNG file named capa.png.encrypted
. PNG files have a predefined header which is
0x89,0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A
We see that the encrypted PNG file has a header with the following bytes
0xC7,0xC7,0x25,0x1D,0x63,0x0D,0xF3,0x56
Let’s reverse the algorithm
png_header = bytearray([0x89,0x50,0x4E,0x47, 0x0D, 0x0A, 0x1A, 0x0A])
encrypted = bytearray([0xC7,0xC7,0x25,0x1D,0x63,0x0D,0xF3,0x56])
def ROR(data, shift, size=32):
shift %= size
body = data >> shift
remains = (data << (size - shift)) - (body << size)
return (body + remains)
result = ''
for i in range(len(png_header)):
key = png_header[i]
key += i % 0xFF
key = ROR(key,i) % 0xFF
key = key ^ encrypted[i]
result += chr(key)
print(result)
So if we run this script, we find the key as No1Trust
If you run the UnlockYourFiles.exe and use this password, it will decrypt all the files. If you check the contents of critical_data.txt, you will get the flag
You_Have_Awakened_Me_Too_Soon_EXE@flare-on.com
Flare-On 2021 Write-ups