Writeup: FlareOn 2021: 004 - myaquaticlife

Task description

1. TLDR

myaquaticlife graph

2. Dane wejściowe

Plik z zadaniem znajduje się tutaj. Hasło: flare.

Przedmiotem zadania plik myaquaticlife.exe

  myaquaticlife.exe

3. Wstępna analiza

Na początku pozyskałem podstawowe informacje o pliku wykonywalnym:

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

Widząc, że program został spakowany packerem UPX, rozpakowałem go:

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. Odzyskanie pliku projektu

Przeanalizowałem plik kilkoma standardowymi narzędziami. Korzystając z narzędzia Resource Hacker ujawniłem, że do zbudowania aplikacji wykorzystano narzędzie Multimedia Builder:

multimedia builder

Rozpocząłem zatem poszukiwania dekompilatora. Postanowiłem wykorzystać projekt MMUnbuilder. W tym cel pobrałem i uruchomiłem wspomniane narzędzie:

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!

W ten sposób pozyskałem plik mbd - projekt Multimedia Builder:

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. Analiza projektu

Analiza projektu ujawniła istnienie i wykorzystanie pliku fathom.dll:

Fathom browser

Pozyskałem podstawowe informacje o nowym pliku wykonywalnym:

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

6. Analiza pliku fathom.dll

Analiza pliku pozwoliła na ustalenie kilku faktów:

  1. Użytkownik wybierając elementy interfejsu użytkownika wybiera słowa z 16-wyrazowego słownika
  2. Wybrane słowa stanowią szyfrogram
  3. Program zawiera zahardkodowany klucz służący do pozyskania tekstu jawnego
  4. Program zawiera oczekiwaną wartość skrótu md5 poprawnego tekstu jawnego

Postanowiłem zatem napisać skrypt znajdujący poprawny tekst jawny:

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. Odczytanie flagi

Uruchomienie powyższego skryptu spowodowało odnalezienie flagi:

s1gn_my_gu357_b00k@flare-on.com