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

I am available for new work
Interested? Feel free to reach