Writeup: FlareOn 2021: 004 - myaquaticlife
1. TLDR
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:
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:
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:
- Użytkownik wybierając elementy interfejsu użytkownika wybiera słowa z 16-wyrazowego słownika
- Wybrane słowa stanowią szyfrogram
- Program zawiera zahardkodowany klucz służący do pozyskania tekstu jawnego
- 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