# Trend Micro CTF 2015: Analysis - Defensive 200
----------## Challenge details| Contest        | Challenge     | Category  | Points ||:---------------|:--------------|:----------|-------:|| Trend Micro CTF 2015 | Analysis - Defensive 200 | Reversing |    200 |
**Description:**>*Category: Analysis-defensive*>>*Points: 200*>>*Capture the flag by analyzing the file. (pass: TMCTF2015)*
----------## Write-up
[We are given an archive](challenge/AnalyzeThis.zip) containing a Windows 32-bit Portable Executable (PE) binary:
```bash$ file AnalyzeThis.exeAnalyzeThis.exe; PE32 executable for MS Windows (GUI) Intel 80386 32-bit```
We load up the binary in IDA and start by statically reverse-engineering the core functionality (renaming function names and variables as well) which gives us the following pseudo-code:
```cint __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd){  int result; // eax@2  int portnum; // [sp+0h] [bp-10h]@5  int bufLen; // [sp+4h] [bp-Ch]@1  LPCSTR lpszServerName; // [sp+8h] [bp-8h]@5  char *c2_buffer; // [sp+Ch] [bp-4h]@4
  bufLen = 4;  if ( check_compname() )  {    if ( decrypt_mystery_buffer() && get_data_from_url((LPCSTR)(url_data + 4), (int)&c2_buffer, (int)&bufLen) )    {      if ( get_hostname_and_port(c2_buffer, bufLen, (int)&lpszServerName, (int)&portnum) )      {        do_core(lpszServerName, portnum);        free((void *)lpszServerName);      }    }    result = 0;  }  else  {    result = -1;  }  return result;}```
The main routine starts by calling the function which we renamed as *check_compname*:
```csigned int check_compname(){  signed int v1; // [sp+0h] [bp-120h]@1  DWORD nSize; // [sp+4h] [bp-11Ch]@1  CHAR computername; // [sp+8h] [bp-118h]@1  char v4; // [sp+9h] [bp-117h]@1  char *encoded_name; // [sp+118h] [bp-8h]@1  char *decoded_name; // [sp+11Ch] [bp-4h]@1
  v1 = 0;  computername = 0;  memset(&v4, 0, 0x103u);  encoded_name = "544e45574a3736383d365a4e";  nSize = 260;  GetComputerNameA(&computername, &nSize);  decoded_name = (char *)decode_string(encoded_name);  if ( !strcmp(&computername, decoded_name) )    v1 = 1;  free(decoded_name);  return v1;}```
This function retrieves the local computer name and compares it against the decoded result of *"544e45574a3736383d365a4e"*. The *decode_string* function can be written in python as:
```pythondef decode_string(a1):  v4 = len(a1)  v5 = 48  v6 = 120  v11 = ""  if(v4 % 2 == 0):    for i in xrange(v4 >> 1):      v7 = a1[2*i]      v8 = a1[2*i + 1]      s = chr(48)+chr(120)+a1[2*i]+a1[2*i+1]      v1 = int(s, 16)      v11 += "%c" % (v1-i)
  return v11```
Which gives us the target PC name of *"TMCTF2015-PC"*. If the executable is executed on a PC bearing this name the function *decrypt_myster_buffer* is executed which retrieves the computer name and feeds it to a sequence of routines manipulating an (as of yet) 'mystery buffer'. The decryption functionality looks as follows:
```cint __cdecl decryption_routine(int key, __int16 keylen, int ciphertext, unsigned __int16 ciphertext_len){  char keystream; // [sp+0h] [bp-110h]@1
  func1(key, keylen, (int)&keystream);  return func2(ciphertext, ciphertext_len, (int)&keystream);}
int __cdecl func1(int a1, __int16 a2, int a3){  int result; // eax@4  char v4; // ST0A_1@6  unsigned __int8 v5; // [sp+Bh] [bp-9h]@1  unsigned __int16 i; // [sp+Ch] [bp-8h]@1  unsigned __int16 j; // [sp+Ch] [bp-8h]@4  unsigned __int8 v8; // [sp+13h] [bp-1h]@1
  v8 = 0;  v5 = 0;  *(_BYTE *)(a3 + 256) = 0;  *(_BYTE *)(a3 + 257) = 0;  for ( i = 0; (signed int)i < 256; ++i )    *(_BYTE *)(a3 + i) = i;  result = 0;  for ( j = 0; (signed int)j < 256; ++j )  {    v5 += *(_BYTE *)(a3 + j) + *(_BYTE *)(a1 + v8);    v4 = *(_BYTE *)(a3 + j);    *(_BYTE *)(a3 + j) = *(_BYTE *)(a3 + v5);    result = v5;    *(_BYTE *)(a3 + v5) = v4;    LOBYTE(result) = v8++ + 1;    if ( v8 == a2 )      v8 = 0;  }  return result;}
int __cdecl func2(int a1, unsigned int a2, int a3){  char v3; // ST0D_1@3  int result; // eax@4  unsigned int i; // [sp+4h] [bp-Ch]@1  unsigned __int8 v6; // [sp+Eh] [bp-2h]@1  unsigned __int8 v7; // [sp+Fh] [bp-1h]@1
  v6 = *(_BYTE *)(a3 + 256);  v7 = *(_BYTE *)(a3 + 257);  for ( i = 0; i < a2; ++i )  {    ++v6;    v7 += *(_BYTE *)(a3 + v6);    v3 = *(_BYTE *)(a3 + v6);    *(_BYTE *)(a3 + v6) = *(_BYTE *)(a3 + v7);    *(_BYTE *)(a3 + v7) = v3;    *(_BYTE *)(i + a1) ^= *(_BYTE *)(a3 + (unsigned __int8)(*(_BYTE *)(a3 + v7) + *(_BYTE *)(a3 + v6)));  }  *(_BYTE *)(a3 + 256) = v6;  result = a3;  *(_BYTE *)(a3 + 257) = v7;  return result;}```
Inspection of the above routines reveals the algorithm to be RC4 (with *func1* being the RC4 key scheduling algorithm and *func2* being the Pseudo-Random Number Generator (PRNG) that generates RC4's keystream) thus revealing *decrypt_mystery_buffer* to work as follows: 
```csigned int decrypt_mystery_buffer(){  __int16 cnamelen; // ax@2  signed int v2; // [sp+0h] [bp-118h]@1  DWORD nSize; // [sp+4h] [bp-114h]@1  CHAR computername; // [sp+8h] [bp-110h]@1  char v5; // [sp+9h] [bp-10Fh]@1
  v2 = 0;  computername = 0;  memset(&v5, 0, 0x103u);  nSize = 260;  if ( !url_data )  {    GetComputerNameA(&computername, &nSize);    cnamelen = strlen(&computername);    do_rc4_decrypt((int)&computername, cnamelen, (int)&mysterybuffer, 0x1CCu);    url_data = (int)&mysterybuffer;    if ( mysterybuffer == 0x35313032 )          // if(mysterbuffer[:4] == "2015")      v2 = 1;  }  return v2;}```
So we decrypt the myster buffer using RC4 with the key "TMCTF2015-PC" which yields the following buffer:
```2015http://ctfquest.trendmicro.co.jp:13106/126ac9f6149081eb0e97c2e939eaad52/top.html                                                <font color="#FEFEFE">                                    </font>                    /e45c2dc8d9e5b215ea141f2f609100f9/notify.php    TMCTF2015-13106                                                 `Ω      key.bin```
The next function executed is *get_data_from_url*:
```cint __cdecl get_data_from_url(LPCSTR url, int buffer, int bytesRead){  void *v3; // ST1C_4@1  signed int v5; // [sp+4h] [bp-124h]@1  void *lpBuffer; // [sp+8h] [bp-120h]@3  HANDLE hFile; // [sp+Ch] [bp-11Ch]@4  DWORD nNumberOfBytesToRead; // [sp+10h] [bp-118h]@2  CHAR downloadpath; // [sp+18h] [bp-110h]@1  DWORD NumberOfBytesRead; // [sp+124h] [bp-4h]@5
  v5 = 0;  *(_DWORD *)buffer = 0;  *(_DWORD *)bytesRead = 0;  GetTempPathA(0x104u, &downloadpath);  v3 = decode_string("746e65776a3736383d377e787c");// tmctf2015.tmp  _snprintf(&downloadpath, 0x104u, "%s%s", &downloadpath, v3);  free(v3);  if ( !URLDownloadToFileA(0, url, &downloadpath, 0, 0) )  {    nNumberOfBytesToRead = get_file_size(&downloadpath);    if ( nNumberOfBytesToRead != -1 )    {      lpBuffer = malloc(nNumberOfBytesToRead);      if ( lpBuffer )      {        hFile = CreateFileA(&downloadpath, 0x80000000, 0, 0, 3u, 0, 0);        if ( hFile != (HANDLE)-1 )        {          ReadFile(hFile, lpBuffer, nNumberOfBytesToRead, &NumberOfBytesRead, 0);          CloseHandle(hFile);          *(_DWORD *)buffer = lpBuffer;          *(_DWORD *)bytesRead = nNumberOfBytesToRead;          v5 = 1;        }        if ( !v5 )          free(lpBuffer);      }    }  }  return v5;}```
This function connects to *http://ctfquest.trendmicro.co.jp:13106/126ac9f6149081eb0e97c2e939eaad52/top.html*, reads the HTML and extracts (using function *get_hostname_and_port*) the first token between tags:
```html<font color="#FEFEFE">...</font>```
If we navigate to that URL we are presented with a decoy blogging site:
![alt site](site.png)
Which hides tokens in its HTML:
```html<div class="post-text">    Summer is hot. I do not like summer. <font color="#FEFEFE">6c706564706d757a7c8542434445</font>  </div>      </div>       <div class="post-entry" id="2015092401">  <div class="post-header">    <span>      Posted On: Sep 24, 2015    </span>    <span> Winter    </span>  </div>  <div class="post-text">    Winter is cold. I like winter. <font color="#FEFEFE">63756874796a797b367d7c707a717b78738381417784448188954b54504d4e</font>  </div>      </div>       <div class="post-entry">  <div class="post-header">    <span>      Posted On: Sep 23, 2015    </span>    <span> My first post    </span>  </div>  <div class="post-text">    Hello Blog! <font color="#FEFEFE">313339313433363539853b3d3f4143</font>  </div>      </div>```
Decoding the tokens using the *decode_string* function yields the following:
```localhost|8888ctfquest.trendmicro.co.jp|19400127.0.0.1|12345```
Which are typical *servername|port* configuration entries for malware Command & Control servers.
The final function execute is *do_core*:
```cvoid __cdecl do_core(LPCSTR lpszServerName, __int16 portnum){  signed int dothing; // [sp+4h] [bp-11Ch]@1  signed int status; // [sp+Ch] [bp-114h]@1  int v4; // [sp+10h] [bp-110h]@7  LPCVOID lpBuffer; // [sp+14h] [bp-10Ch]@13  char Buffer; // [sp+18h] [bp-108h]@7  char v7[254]; // [sp+1Ah] [bp-106h]@13  char cmd; // [sp+11Fh] [bp-1h]@1
  dothing = 1;  status = 0;  cmd = 0;  if ( lpszServerName && portnum )  {    while ( dothing )    {      if ( get_file_size((LPCSTR)(url_data + 396)) == 35 )// filesize("key.bin") == 35      {        ++*(_DWORD *)(url_data + 392);        if ( !(*(_DWORD *)(url_data + 392) % 0xAu) )          status = 1;      }      v4 = 256;      if ( get_keyfile(lpszServerName, portnum, status, &Buffer, (int)&v4) )      {        if ( v4 )        {          cmd = extract_cmd((int)&Buffer, v4);          switch ( cmd )          {            case 0x4B:                          // K              lpBuffer = &v7[Buffer];              write_key_bin(&v7[Buffer], v4 - (&v7[Buffer] - &Buffer));              break;            case 0x53:                          // S              do_mutex_stuff();              break;            case 0x54:                          // T              dothing = 0;              break;          }        }        status = 0;        Sleep(*(_DWORD *)(url_data + 388));     // sleep(60000)      }    }  }}```
This routine checks for the existence of "key.bin" on the machine and if it exists (and is exactly 35 bytes in size) increments a counter. If the counter is a multiple of 10 the *status* variable is set to 1. Next the *get_keyfile* function is executed which connects to the server and port extracted from the decoy blog and sets a particular cookie value (encoding the status variable) and user agent to retrieve a keyfile from the Command & Control server:
```int __cdecl get_keyfile(LPCSTR lpszServerName, __int16 portnum, int status, LPVOID dstBuffer, int a5){  HINTERNET hConnect; // [sp+0h] [bp-F4h]@2  unsigned int v7; // [sp+4h] [bp-F0h]@1  signed int v8; // [sp+8h] [bp-ECh]@1  char getparams; // [sp+Ch] [bp-E8h]@1  char v10; // [sp+Dh] [bp-E7h]@1  char *cookieheader; // [sp+4Ch] [bp-A8h]@4  HINTERNET hInternet; // [sp+50h] [bp-A4h]@1  CHAR szHeaders; // [sp+54h] [bp-A0h]@1  char v14; // [sp+55h] [bp-9Fh]@1  char *v15; // [sp+D8h] [bp-1Ch]@1  HINTERNET hRequest; // [sp+DCh] [bp-18h]@3  char *reqparam; // [sp+E0h] [bp-14h]@4  void *v18; // [sp+E4h] [bp-10h]@4  DWORD dwNumberOfBytesRead; // [sp+E8h] [bp-Ch]@6  unsigned int v20; // [sp+ECh] [bp-8h]@1  char *v21; // [sp+F0h] [bp-4h]@1
  v8 = 0;  v7 = 0;  getparams = 0;  memset(&v10, 0, 0x3Fu);  szHeaders = 0;  memset(&v14, 0, 0x7Fu);  v15 = "673278367138713a81462f6f";             // g1v3m3k3y=%d  v21 = "4370716e6d6a40272d7c1715";             // Cookie: %s  v20 = *(_DWORD *)a5;  *(_DWORD *)a5 = 0;  hInternet = InternetOpenA((LPCSTR)(url_data + 324), 0, 0, 0, 0);// user agent: TMCTF2015-13106  if ( hInternet )  {    hConnect = InternetConnectA(hInternet, lpszServerName, portnum, 0, 0, 3u, 0, 0);    if ( hConnect )    {                                           // GET /e45c2dc8d9e5b215ea141f2f609100f9/notify.php      hRequest = HttpOpenRequestA(hConnect, "GET", (LPCSTR)(url_data + 260), "HTTP/1.0", 0, 0, 0x80000u, 0);      if ( hRequest )      {        reqparam = (char *)decode_string(v15);        _snprintf(&getparams, 0x3Fu, reqparam, status);        free(reqparam);        v18 = get_cookie(&getparams);        cookieheader = (char *)decode_string(v21);        _snprintf(&szHeaders, 0x80u, cookieheader, v18);        free(v18);        free(cookieheader);        HttpAddRequestHeadersA(hRequest, &szHeaders, 0xFFFFFFFF, 0xA0000000);        if ( HttpSendRequestA(hRequest, 0, 0, 0, 0) )        {          while ( v7 <= v20 )          {            if ( InternetReadFile(hRequest, dstBuffer, v20 - v7, &dwNumberOfBytesRead) )            {              if ( !dwNumberOfBytesRead )              {                v8 = 1;                *(_DWORD *)a5 = v7;                break;              }              dstBuffer = (char *)dstBuffer + dwNumberOfBytesRead;              v7 += dwNumberOfBytesRead;            }          }        }        InternetCloseHandle(hRequest);      }      InternetCloseHandle(hConnect);    }    InternetCloseHandle(hInternet);  }  return v8;}```
We can see that there are 2 actions that can be undertaken after data has been retrieved from the Command & Control server:
```cint __cdecl write_key_bin(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite){  signed int v3; // [sp+0h] [bp-Ch]@1  DWORD NumberOfBytesWritten; // [sp+4h] [bp-8h]@2  HANDLE hFile; // [sp+8h] [bp-4h]@1
  v3 = 0;  hFile = CreateFileA((LPCSTR)(url_data + 396), 0x40000000u, 0, 0, 2u, 0x80u, 0);// openfile(key.bin)  if ( hFile != (HANDLE)-1 )  {    WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, &NumberOfBytesWritten, 0);    CloseHandle(hFile);    v3 = 1;  }  return v3;}
int do_mutex_stuff(){  DWORD nNumberOfBytesToRead; // [sp+4h] [bp-14h]@1  HANDLE hFile; // [sp+8h] [bp-10h]@1  void *lpBuffer; // [sp+Ch] [bp-Ch]@3  HANDLE hObject; // [sp+10h] [bp-8h]@4  DWORD NumberOfBytesRead; // [sp+14h] [bp-4h]@4
  nNumberOfBytesToRead = get_file_size((LPCSTR)(url_data + 396));// filesize(key.bin)  hFile = CreateFileA((LPCSTR)(url_data + 396), 0x80000000, 0, 0, 3u, 0, 0);// open(key.bin)  if ( hFile != (HANDLE)-1 && nNumberOfBytesToRead == 35 )  {    lpBuffer = malloc(35u);    if ( lpBuffer )    {      ReadFile(hFile, lpBuffer, 35u, &NumberOfBytesRead, 0);      extract_mutex(Name, 35, lpBuffer, 35);      hObject = CreateMutexA(0, 0, Name);      if ( hObject && GetLastError() == 183 )      {        CloseHandle(hObject);        ExitProcess(0x47414C46u);      }      free(lpBuffer);    }    CloseHandle(hFile);  }  return 0;}```
The *write_key_bin* function seems to extract keying data from the response and write it to the *"key.bin"* file. The *do_mutex_stuff* function reads 35 bytes from the key file, applies the *extract_mutex* function to a constant *Name* buffer and obtains a mutex name value which it then proceeds to set. We assume it is the mutex name we are supposed to obtain as a flag value.
Given that we have neither *keyfile.bin* nor will the connection succeed (since it attempts to connect to localhost) we connect to *ctfquest.trendmicro.co.jp|19400* ourselves with user-agent *TMCTF2015-13106* and cookie set to *get_cookie("g1v3m3k3y=1")* and make a GET request to */e45c2dc8d9e5b215ea141f2f609100f9/notify.php* using the following (very dirty) code:
```c#include <stdio.h>#include <stdlib.h>#include <wininet.h>
int main(int argc, unsigned char** argv){    char getParams[0x40] = {0};    char szHeaders[0x81] = {0};    char* cookieVal = "673278367138713a81463b"; // g1v3m3k3y=1    int status = 0;    DWORD readBytes = 0;    DWORD bufSZ = 256;    unsigned char buffer[257] = {0};    DWORD dwNumberOfBytesRead = 0;    DWORD a5 = 0;    unsigned char* dstBuffer = (unsigned char*)buffer;
    HANDLE hInternet = InternetOpenA((LPCSTR)"TMCTF2015-13106", 0, 0, 0, 0);    if(hInternet)    {        HANDLE hConnect = InternetConnectA(hInternet, (LPCSTR)"ctfquest.trendmicro.co.jp", 19400, 0, 0, 3, 0, 0);        if(hConnect)        {            HANDLE hRequest = HttpOpenRequestA(hConnect, "GET", (LPCSTR)"/e45c2dc8d9e5b215ea141f2f609100f9/notify.php", "HTTP/1.0", 0, 0, 0x80000, 0);            if(hRequest)            {                snprintf(getParams, 0x3F, "g1v3m3k3y=%d", status);                snprintf(szHeaders, 0x80, "Cookie: %s\r\n", cookieVal);
                HttpAddRequestHeadersA(hRequest, &szHeaders, 0xFFFFFFFF, 0xA0000000);
                if(HttpSendRequestA(hRequest, 0, 0, 0, 0))                {                    printf("[*] Reading server response...\n");
                    while(readBytes <= bufSZ)                    {                        if( InternetReadFile(hRequest, dstBuffer, bufSZ - readBytes, &dwNumberOfBytesRead) )                        {                            if( !dwNumberOfBytesRead )                            {                                a5 = readBytes;                                break;                            }
                            dstBuffer = (unsigned char*)(dstBuffer + dwNumberOfBytesRead);                            readBytes += dwNumberOfBytesRead;                        }                    }
                    printf("[+] Read (%d) bytes\n", a5);
                    printf("[+] Data buffer: [");
                    DWORD kl = a5 - ((unsigned char*)&buffer[2 + buffer[0]] - (unsigned char*)&buffer);                    DWORD i;
                    printf("[+] Key: [");
                    for(i = 0; i < kl; i++)                    {                        printf("%02x", ((unsigned char*)(&buffer[2 + buffer[0]]))[i]);                    }
                    printf("]\n");                }            }        }    }
  return 0;}```
Which gave us the key buffer:
```6381b943696db16f13f84ac7176049a9f74025bd779eae5b22a1617423b66e5bf207f6```
The *extract_mutex* function is a simple repeating-key XOR application of the key to the encrypted mutex name buffer:
```pythondef extract_mutex(mutex_buf, mutex_len, key_buf, key_len):  res = ""  for i in xrange(mutex_len):    res += chr(ord(mutex_buf[i]) ^ ord(key_buf[i % key_len]))  return res
mutex_buf = "\x37\xCC\xFA\x17\x2F\x16\xFC\x39\x2B\x82\x12\xBD\x51\x06\x04\xEF\xCF\x72\x7D\xC7\x25\xF8\xE0\x0D\x1A\x91\x39\x0D\x4B\xD0\x23\x3C\xCF\x3A\x8B"
key_buf = "6381b943696db16f13f84ac7176049a9f74025bd779eae5b22a1617423b66e5bf207f6".decode('hex')
assert(len(mutex_buf) == len(key_buf) == 35)mutex = extract_mutex(mutex_buf, len(mutex_buf), key_buf, len(key_buf))print "[+]Mutex: [%s]\n" % mutex```
Execution of which gives us:
```bash$ ./getmutex.py[+]Mutex: [TMCTF{MV8zXzFfMF82XzRfNV80XyhfMg==}]```