Writeup: FlareOn 2021: 004 - myaquaticlife
1. TLDR
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:
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:
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:
- The user, when selecting user interface elements, selects words from a 16-word dictionary
- The selected words constitute a ciphertext
- The program contains a hardcoded key used to obtain the plaintext
- 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