Writeup: FlareOn 2021: 004 - myaquaticlife

Task description

1. TLDR

myaquaticlife graph

2. Input data

The challenge file is here. Hasło: flare.

The available files is:

  myaquaticlife.exe

3. File analysis

At first I acquired basic information about the executable file:

remnux@remnux:~/RE/04$ file myaquaticlife.exe 
myaquaticlife.exe: PE32 executable (GUI) Intel 80386, for MS Windows, UPX compressed

Seeing that the program was packaged with the UPX packer, I unpacked it:

remnux@remnux:~/RE/04$ upx -d myaquaticlife.exe -o myaquaticlife-unpacked.exe 
                       Ultimate Packer for eXecutables
                          Copyright (C) 1996 - 2020
UPX 3.96        Markus Oberhumer, Laszlo Molnar & John Reiser   Jan 23rd 2020

        File size         Ratio      Format      Name
   --------------------   ------   -----------   -----------
   3154103 <-   2389687   75.76%    win32/pe     myaquaticlife-unpacked.exe

Unpacked 1 file.

4. Retrieving the project file

I analyzed the file with several standard tools. Using the Resource Hacker tool, I revealed that the Multimedia Builder tool was used to build the application:

multimedia builder

Therefore, I began my search for a decompiler. I decided to use the MMUnbuilder project. For this purpose, I downloaded and launched the mentioned tool:

remnux@remnux:~/RE/04$ git clone https://github.com/qprotex/MMUnbuilder.git
Cloning into 'MMUnbuilder'...
remote: Enumerating objects: 14, done.
remote: Counting objects: 100% (1/1), done.
remote: Total 14 (delta 0), reused 0 (delta 0), pack-reused 13
Unpacking objects: 100% (14/14), done.


remnux@remnux:~/RE/04$ python MMUnbuilder/MMUnbuilder.py -u myaquaticlife-unpacked.exe
 
MMUnbuilder - v0.1
Programmed by Miguel Febres - http://www.q-protex.com

[+] Opening myaquaticlife-unpacked.exe
[+] Checking size...
[+] Overlay data found in the end of PE file!
[+] Checking if overlay data is from Multimedia Builder...
[+] Multimedia Builder format version 30 found!
[+] Checking if data is compiled with security layer...
[+] Security Layer not found!
[+] Saving project...
[+] Work done!

This is how I obtained the mbd file - Multimedia Builder project file:

remnux@remnux:~/RE/04$ xxd myaquaticlife-unpacked.mbd  | head
00000000: 0b4d 4d42 7569 6c64 6572 3330 0000 0000  .MMBuilder30....
00000010: 0100 0000 0000 0000 0000 0000 0000 0000  ................
00000020: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000030: 0000 0000 0000 0000 2457 6861 7427 7320  ........$What's 
00000040: 796f 7572 2066 6176 6f72 6974 6520 6171  your favorite aq
00000050: 7561 7469 6320 616e 696d 616c 3f01 0000  uatic animal?...
00000060: 0000 0000 0000 0000 0000 0000 0000 0200  ................
00000070: 0000 0650 6167 6520 311e 0000 0000 0000  ...Page 1.......
00000080: 0000 0100 0000 0000 0000 0000 0000 ffff  ................
00000090: ff00 0000 0000 0059 0000 1300 0000 0000  .......Y........

5. Project analysis

Analysis of the project revealed the existence and use of the fathom.dll file:

Fathom browser

I acquired basic information about the new executable file:

remnux@remnux:~/RE/04$ file fathom.dll 
fathom.dll: PE32 executable (DLL) (GUI) Intel 80386, for MS Windows

6. Analysis of the fathom.dll file

The analysis of the file made it possible to determine several facts:

  1. The user, when selecting user interface elements, selects words from a 16-word dictionary
  2. The selected words constitute a ciphertext
  3. The program contains a hardcoded key used to obtain the plaintext
  4. The program contains the expected md5 hash value of the correct plaintext

So I decided to write a script that finds the correct plain text:

from pprint import pprint
import itertools
import hashlib
import binascii

flotsam = ["PXopvM", "BGgsuhn", "DFWEyEW"]
lagan = ["GTXI", "GTYAKlwER", "BAJkR", "QICMX", "rOPFG"]
jetsam = ["HwdwAZ", "newaui", "SLdkv"]
derelict = ["LSZvYSFHW", "yXQsGB", "MZZWP", "LDNCVYU", "RTYXAc"]
wordlists = [flotsam, lagan, jetsam, derelict]
wordlists = []
wordlists.extend(flotsam)
wordlists.extend(lagan)
wordlists.extend(jetsam)
wordlists.extend(derelict)


expected_hash = "6c5215b12a10e936f8de1e42083ba184"


def calc(input_1, input_2):
    
    encrypted = "00A8A3FCD1A79DD2BA8F8F87A4E4CBF9" + "169E81F938E5AF9F909A96A3A9A42596"
    encrypted = binascii.unhexlify(encrypted)[::-1]
    input_1 = ''.join(input_1) * 30
    input_2 = ''.join(input_2) * 30
    i=0
    plaintext = []
    for c in encrypted:
        p = ((c ^ ord(input_1[i])) - ord(input_2[i]) & 0xFF)
        plaintext.append(chr(p))
        i=i+1 
    
    plaintext = ''.join(plaintext)
    
    plaintext_hex = ''.join("{:02x}".format(ord(c)) for c in plaintext)
    plaintext_hex = plaintext_hex[:-2]
    hash_object = hashlib.md5(binascii.unhexlify(plaintext_hex))
    md5_hash = hash_object.hexdigest()
    
    return md5_hash,plaintext

for i in range(1,10):
    for combination in itertools.product(wordlists, repeat = i) :
        for x in range(1,len(combination)):
            input_1 = combination[:x]
            input_2 = combination[x:]
            md5_hash,plaintext = calc(input_1, input_2)
            if md5_hash.startswith(expected_hash):
                pprint(plaintext)
                exit()

7. Reading the flag

Running the above script found the flag:

s1gn_my_gu357_b00k@flare-on.com