Writeup: FlareOn 2022: 005 - T8

Task description

1. TLDR

TLDR graph

2. Input data

The challenge file is here. Password: flare.

The subjects of the task were PE and pcapng files:

t8.exe
traffic.pcapng

3. Analysis of the pcapng file

I first listed the protocols used:

> tshark -r .\traffic.pcapng -T fields -e frame.protocols | sort | uniq
eth:ethertype:ip:tcp
eth:ethertype:ip:tcp:http:data

I then listed communications using the HTTP protocol:

> tshark -r .\traffic.pcapng -Y "http"
    5   0.000725 192.168.10.15 → 13.13.37.33  HTTP 78 POST / HTTP/1.1
    9   0.016663  13.13.37.33 → 192.168.10.15 HTTP 390 HTTP/1.0 200 OK
   17   0.019410 192.168.10.15 → 13.13.37.33  HTTP 70 POST / HTTP/1.1
   21   0.020672  13.13.37.33 → 192.168.10.15 HTTP 218 HTTP/1.0 200 OK

I extracted two communication sequences (below). Decoding the data using base64 yielded no intelligible results.

3.1. Sequence #1

Retrieved content of the request and response below:

POST / HTTP/1.1
Connection: Keep-Alive
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; 11950)
Content-Length: 24
Host: flare-on.com

y.d.N.8.B.X.q.1.6.R.E.=.

HTTP/1.0 200 OK
Server: Apache On 9 
Date: Tue, 14 Jun 2022 16:14:36 GMT

TdQdBRa1nxGU06dbB27E7SQ7TJ2+cd7zstLXRQcLbmh2nTvDm1p5IfT/Cu0JxShk6tHQBRWwPlo9zA1dISfslkLgGDs41WK12ibWIflqLE4Yq3OYIEnLNjwVHrjL2U4Lu3ms+HQc4nfMWXPgcOHb4fhokk93/AJd5GTuC5z+4YsmgRh1Z90yinLBKB+fmGUyagT6gon/KHmJdvAOQ8nAnl8K/0XG+8zYQbZRwgY6tHvvpfyn9OXCyuct5/cOi8KWgALvVHQWafrp8qB/JtT+t5zmnezQlp3zPL4sj2CJfcUTK5copbZCyHexVD4jJN+LezJEtrDXP1DJNg==

3.2. Sequence # 2

Retrieved content of the request and response below:

POST / HTTP/1.1
Connection: Keep-Alive
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; CLR)
Content-Length: 16
Host: flare-on.com

V.Y.B.U.p.Z.d.G.

HTTP/1.0 200 OK
Server: Apache On 9 
Date: Tue, 14 Jun 2022 16:14:36 GMT

F1KFlZbNGuKQxrTD/ORwudM8S8kKiL5F906YlR8TKd8XrKPeDYZ0HouiBamyQf9/Ns7u3C2UEMLoCA0B8EuZp1FpwnedVjPSdZFjkieYqWzKA7up+LYe9B4dmAUM2lYkmBSqPJYT6nEg27n3X656MMOxNIHt0HsOD0d+

4. Initial analysis of the PE file

I verified the file type t8.exe :

$ file t8.exe
t8.exe: PE32 executable (console) Intel 80386, for MS Windows

Its startup, however, did not indicate any interaction with the user. The process, however, was running all the time….

I analyzed the program with the capa tool:

+------------------------+------------------------------------------------------------------------------------+
| md5                    | fc5051e15de9ad7fbeeded225f8e7997                                                   |
| sha1                   | d68eede38c42fc26d7f0385c1f717f889fb3bcea                                           |
| sha256                 | 06144f641616519805b7cb6f215347967a9f01da50aa83aa155d5bacaffcbdf8                   |
| path                   | t8.exe                                                                             |
+------------------------+------------------------------------------------------------------------------------+

+------------------------+------------------------------------------------------------------------------------+
| ATT&CK Tactic          | ATT&CK Technique                                                                   |
|------------------------+------------------------------------------------------------------------------------|
| DEFENSE EVASION        | Obfuscated Files or Information [T1027]                                            |
| DISCOVERY              | System Information Discovery [T1082]                                               |
| EXECUTION              | Command and Scripting Interpreter [T1059]                                          |
|                        | Shared Modules [T1129]                                                             |
+------------------------+------------------------------------------------------------------------------------+

+-----------------------------+-------------------------------------------------------------------------------+
| MBC Objective               | MBC Behavior                                                                  |
|-----------------------------+-------------------------------------------------------------------------------|
| COMMUNICATION               | HTTP Communication::Create Request [C0002.012]                                |
|                             | HTTP Communication::Get Response [C0002.017]                                  |
|                             | HTTP Communication::WinHTTP [C0002.008]                                       |
| CRYPTOGRAPHY                | Encrypt Data::RC4 [C0027.009]                                                 |
|                             | Encryption Key::RC4 KSA [C0028.002]                                           |
|                             | Generate Pseudo-random Sequence::RC4 PRGA [C0021.004]                         |
| DATA                        | Check String [C0019]                                                          |
|                             | Encoding::Base64 [C0026.001]                                                  |
|                             | Encoding::XOR [C0026.002]                                                     |
|                             | Non-Cryptographic Hash::FNV [C0030.005]                                       |
| DEFENSE EVASION             | Obfuscated Files or Information::Encoding-Standard Algorithm [E1027.m02]      |
| FILE SYSTEM                 | Write File [C0052]                                                            |
| MEMORY                      | Allocate Memory [C0007]                                                       |
| OPERATING SYSTEM            | Environment Variable::Set Variable [C0034.001]                                |
| PROCESS                     | Allocate Thread Local Storage [C0040]                                         |
|                             | Set Thread Local Storage Value [C0041]                                        |
|                             | Terminate Process [C0018]                                                     |
+-----------------------------+-------------------------------------------------------------------------------+

+------------------------------------------------------+------------------------------------------------------+
| CAPABILITY                                           | NAMESPACE                                            |
|------------------------------------------------------+------------------------------------------------------|
| initialize WinHTTP library                           | communication/http                                   |
| prepare HTTP request                                 | communication/http/client                            |
| receive HTTP response                                | communication/http/client                            |
| encode data using Base64 (2 matches)                 | data-manipulation/encoding/base64                    |
| reference Base64 string                              | data-manipulation/encoding/base64                    |
| encode data using XOR (2 matches)                    | data-manipulation/encoding/xor                       |
| encrypt data using RC4 KSA                           | data-manipulation/encryption/rc4                     |
| encrypt data using RC4 PRGA                          | data-manipulation/encryption/rc4                     |
| hash data using fnv                                  | data-manipulation/hashing/fnv                        |
| hash data with MD5                                   | data-manipulation/hashing/md5                        |
| contain a resource (.rsrc) section                   | executable/pe/section/rsrc                           |
| accept command line arguments                        | host-interaction/cli                                 |
| query environment variable                           | host-interaction/environment-variable                |
| set environment variable                             | host-interaction/environment-variable                |
| write file (5 matches)                               | host-interaction/file-system/write                   |
| print debug messages (2 matches)                     | host-interaction/log/debug/write-event               |
| allocate thread local storage (2 matches)            | host-interaction/process                             |
| get thread local storage value (2 matches)           | host-interaction/process                             |
| set thread local storage value (2 matches)           | host-interaction/process                             |
| allocate RWX memory                                  | host-interaction/process/inject                      |
| terminate process (3 matches)                        | host-interaction/process/terminate                   |
| terminate process via fastfail (7 matches)           | host-interaction/process/terminate                   |
| access PEB ldr_data                                  | linking/runtime-linking                              |
| link function at runtime (2 matches)                 | linking/runtime-linking                              |
| link many functions at runtime                       | linking/runtime-linking                              |
| parse PE header (4 matches)                          | load-code/pe                                         |
+------------------------------------------------------+------------------------------------------------------+

So I expected to run shellcode, network interaction, encryption, MD5 hashing, and base64

I loaded the program into the IDA environment

5. Code analysis

At the beginning of the analysis I noticed a loop call with the Sleep function, This was one of the first activities after the main function was started.

I made a patch of the jz conditional jump statement:

loop-jz-before-patch

per jmp unconditional jump instruction:

loop-jz-after-patch

Then … I noticed an import of the KERNEL32.OutputDebugStringW function. After running the program, before its operation was completed, the program actually logged the function names.

debugview

I then noticed a number of imported functions related to establishing http connections:

http-actions

At the same time, I disclosed a suspicious piece of code that was running code from a newly allocated memory area:

shellcode-run

So I prepared a configuration file for the tiny_tracer tool:

kernel32;LoadLibraryW;1
kernel32;LoadLibraryA;1
kernel32;GetProcAddress;2
advapi32;RegQueryValueW;3
kernel32;CreateFileW;6
kernel32;CreateProcessInternalW;12
winhttp;WinHttpQueryDataAvailable;2
winhttp;WinHttpReceiveResponse;2
winhttp;WinHttpOpen;5
winhttp;WinHttpReadData;4
winhttp;WinHttpOpenRequest;7
winhttp;WinHttpCloseHandle;3
winhttp;WinHttpSendRequest;7
winhttp;WinHttpConnect;4
urlmon;ObtainUserAgentString;3

Armed with the knowledge I gained, I proceeded with a static analysis of the code. In doing so, I determined the following facts:

  1. the program was building a string that was used to generate the key
  2. the string always had 8 characters: a fixed beginning “F09” followed by 5 digits (which were probably chosen pseudo-randomly)
  3. the generated “seed” (after encoding using UTF-16LE) was the input for the MD5 algorithm.
  4. the result of the hash function (after encoding using UTF-16LE) was the key, which was used to encrypt the “ahoy” string (encoded using UTF-16LE)
  5. the ciphertext encoded using base64 was sent to the HTTP server.
  6. the received response was base64 encoded and encrypted with the same key.

6. Key recovery

So I decided to develop a code that would determine the correct seed and key. A brute-force search of the space generated by the 5 digits was sufficient:

import itertools
import string
import malduck

from pprint import pprint

expected_b64 = b"ydN8BXq16RE="
known_seed="FO913390"
seed_prefix = "FO9"


plaintext = "ahoy".encode("UTF-16LE")

for c in itertools.product(string.digits, repeat=len(known_seed)-len(seed_prefix)):
    seed_cand = seed_prefix +''.join(c)
    seed_cand_w = seed_cand.encode("UTF-16LE")
    seed_cand_hash = malduck.md5(seed_cand_w).hex()
    key = seed_cand_hash.encode("UTF-16LE")
    ciphertext = malduck.rc4(key,plaintext)
    curr_b64 = malduck.base64.encode(ciphertext)
    if curr_b64 == expected_b64:
        break

print(f"seed_cand: {seed_cand}")
print(f"seed_cand_hash: {seed_cand_hash}")
print(f"key: {key}")
print(f"curr_b64: {curr_b64}")

After a split second, I saw the answer:

seed_cand: FO911950
seed_cand_hash: a5c6993299429aa7b900211d4a279848
key: b'a\x005\x00c\x006\x009\x009\x003\x002\x009\x009\x004\x002\x009\x00a\x00a\x007\x00b\x009\x000\x000\x002\x001\x001\x00d\x004\x00a\x002\x007\x009\x008\x004\x008\x00'
curr_b64: b'ydN8BXq16RE='

I then decided to decrypt the message recovered from the pcapng file:

message_1_ciphertext = "TdQdBRa1nxGU06dbB27E7SQ7TJ2+cd7zstLXRQcLbmh2nTvDm1p5IfT/Cu0JxShk6tHQBRWwPlo9zA1dISfslkLgGDs41WK12ibWIflqLE4Yq3OYIEnLNjwVHrjL2U4Lu3ms+HQc4nfMWXPgcOHb4fhokk93/AJd5GTuC5z+4YsmgRh1Z90yinLBKB+fmGUyagT6gon/KHmJdvAOQ8nAnl8K/0XG+8zYQbZRwgY6tHvvpfyn9OXCyuct5/cOi8KWgALvVHQWafrp8qB/JtT+t5zmnezQlp3zPL4sj2CJfcUTK5copbZCyHexVD4jJN+LezJEtrDXP1DJNg=="
message_1_plaintext = malduck.rc4(key, malduck.base64.decode(message_1_ciphertext))

Unfortunately, I didn’t notice anything special on the standard output, which realistically at that moment would have allowed to read the flag.

7. Reading the flag

I then ran the program and, under the control of the debugger, changed the string in memory that forms the basis for determining the key. Next, I prepared the substituted http server. To do this, I used fakedns and the code for a simple http server that generated a response with the ciphertext:

import BaseHTTPServer

class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):

    def do_POST(self):
        print("Responding on POST")
        content = "TdQdBRa1nxGU06dbB27E7SQ7TJ2+cd7zstLXRQcLbmh2nTvDm1p5IfT/Cu0JxShk6tHQBRWwPlo9zA1dISfslkLgGDs41WK12ibWIflqLE4Yq3OYIEnLNjwVHrjL2U4Lu3ms+HQc4nfMWXPgcOHb4fhokk93/AJd5GTuC5z+4YsmgRh1Z90yinLBKB+fmGUyagT6gon/KHmJdvAOQ8nAnl8K/0XG+8zYQbZRwgY6tHvvpfyn9OXCyuct5/cOi8KWgALvVHQWafrp8qB/JtT+t5zmnezQlp3zPL4sj2CJfcUTK5copbZCyHexVD4jJN+LezJEtrDXP1DJNg=="
        self.send_response(200)
        self.send_header("Content-Length", str(len(content)))
        self.end_headers()
        self.wfile.write(content)

if __name__ == '__main__':
    serverAddress = ('', 80)
    server = BaseHTTPServer.HTTPServer(serverAddress, RequestHandler)
    server.serve_forever()

Going through the program’s functions and substituting the string that is the “seed” a few more times, I saw a flag prefix in memory:

shellcode-run

Thus, the flag is:

i_s33_you_m00n@flare-on.com