Timelord

Author: trupples
Contest: ECSC Romanian Quals 2018

The given dll file contains repeated checks whether the current day is the 25th of december 2018 in the functions at addresses 0x180001170 and 0x180001000. Every time the checks wouldn’t fail a string was built up characer by character.

// inside sub_180001170
GetSystemTime(&SystemTime);
if ( SystemTime.wYear != 2018 )
	return MessageBoxW(0i64, L"You are not the time lord!", L"TimeLord", 0x10u);
mystery_string[3] = '8';
mystery_string[1] = '0';
mystery_string[2] = '1';
mystery_string[0] = '2';
if ( SystemTime.wMonth != 12 )
	return MessageBoxW(0i64, L"You are not the time lord!", L"TimeLord", 0x10u);
mystery_string[5] = '1';
mystery_string[4] = '_';
mystery_string[6] = '2';
if ( SystemTime.wDay != 25 )
	return MessageBoxW(0i64, L"You are not the time lord!", L"TimeLord", 0x10u);
result = (unsigned __int8)sub_180001000();

// which calls sub_180001000:

// ...
if ( *((_DWORD *)BufferPtr + 10) == 2018 && *((_DWORD *)BufferPtr + 9) == 12 && *((_DWORD *)BufferPtr + 8) == 25 )
    {
      mystery_string[9] = '5';
      mystery_string[7] = '_';
      mystery_string[8] = '2';
      mystery_string[10] = '_';
      mystery_string[13] = 'C';
      mystery_string[11] = 'U';
      result = 1;
      mystery_string[12] = 'T';
      return result;
    }
// ...

So without even running it we know that if we were to run it at that date then mystery_string will be “2018_12_25_UTC” without a NULL terminator.

After calling the second function, the first one performs an XOR decryption using mystery_string as the key on the 70 byte long ciphertext at address 0x01800188E0:

[0x77, 0x73, 0x62, 0x7B, 0x24, 0x05, 0x74, 0x1A, 0x74, 0x74, 0x69, 0x60,
0x11, 0x77, 0x77, 0x09, 0x03, 0x7E, 0x19, 0x77, 0x05, 0x66, 0x05, 0x02,
0x6B, 0x11, 0x61, 0x75, 0x00, 0x07, 0x08, 0x08, 0x6A, 0x72, 0x01, 0x1C,
0x02, 0x71, 0x1A, 0x60, 0x61, 0x75, 0x76, 0x08, 0x70, 0x7E, 0x66, 0x06,
0x0A, 0x6F, 0x0B, 0x73, 0x6B, 0x10, 0x66, 0x7B, 0x70, 0x00, 0x00, 0x09,
0x66, 0x08, 0x71, 0x19, 0x05, 0x0D, 0x1A, 0x16, 0x67, 0x3E, 0x00, 0x00]

The script to get the flag is:


ciphertext = [0x77, 0x73, 0x62, 0x7B, 0x24, 0x05, 0x74, 0x1A, 0x74, 0x74, 0x69, 0x60,
0x11, 0x77, 0x77, 0x09, 0x03, 0x7E, 0x19, 0x77, 0x05, 0x66, 0x05, 0x02,
0x6B, 0x11, 0x61, 0x75, 0x00, 0x07, 0x08, 0x08, 0x6A, 0x72, 0x01, 0x1C,
0x02, 0x71, 0x1A, 0x60, 0x61, 0x75, 0x76, 0x08, 0x70, 0x7E, 0x66, 0x06,
0x0A, 0x6F, 0x0B, 0x73, 0x6B, 0x10, 0x66, 0x7B, 0x70, 0x00, 0x00, 0x09,
0x66, 0x08, 0x71, 0x19, 0x05, 0x0D, 0x1A, 0x16, 0x67, 0x3E, 0x00, 0x00]

key = "2018_12_25_UTC"*5	# *5 so that we have 70 characters

flag = ""

for i in range(70):
	flag += chr(ciphertext[i] ^ ord(key[i]))

print(flag)

The flag is ECSC{4FEFA65E4E92FFF79774D5627905C3C0DE556D8AF97809F4E28B01199CF78EC3}