Writeup: FlareOn 2022: 011 - the challenge that shall not be named

Task description

1. TLDR

TLDR graph

2. Dane wejściowe

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

Przedmiotem zadania był plik:

11.exe

Zweryfikowałem typ pliku 11.exe:

$ file 11.exe
11.exe: PE32+ executable (console) x86-64, for MS Windows

3. Analiza wstępna

Wczytałem program do IDA. Po krótkiej analizie znalazłem fragment kodu:

pyinstaller

Program był zatem napisany w języku Python i został spakowany do jednego pakietu narzędziem PyInstaller

4. Odpakowanie pakietu

4.1 pyinstxtractor

W celu odpakowania pakietu pobrałem narzędzie pyinstxtractor-ng i je uruchomiłem:

>pyinstxtractor-ng.exe 11.exe
[+] Processing 11.exe
[+] Pyinstaller version: 2.1+
[+] Python version: 3.7
[+] Length of package: 8807847 bytes
[+] Found 80 files in CArchive
[+] Beginning extraction...please standby
[+] Possible entry point: pyiboot01_bootstrap.pyc
[+] Possible entry point: pyi_rth_subprocess.pyc
[+] Possible entry point: pyi_rth_inspect.pyc
[+] Possible entry point: 11.pyc
[+] Found 250 files in PYZ archive
[+] Successfully extracted pyinstaller archive: 11.exe

You can now use a python decompiler on the pyc files within the extracted directory

4.2 uncompyle6

Następnie, w celu dokończenia dekompilacji, uruchomiłem narzędzie uncompyle6:

>uncompyle6 -ro 11.exe_decompiled 11.exe_extracted

Niestety, program był zabezpieczony narzędziem pyarmor

from pytransform import pyarmor
pyarmor(__name__, __file__, b'PYARMOR\x00\x00\x03\x07\x00B\r......\xe8;?\x12S\x16', 2)

5. Deobfuskacja i… odczytanie flagi

Postanowiłem zdeobfuskować projekt, korzystając z PyArmor-Unpacker.

Ze względu na wiadomość na Githubie:

IMPORTANT: USE THE SAME PYTHON VERSION EVERYWHERE,
LOOK AT WHAT THE PROGRAM YOU ARE UNPACKING IS COMPILED WITH.
If you don't you will face issues.

sprawdziłem wersję pythona wykorzystanego przez 11.exe:

$ grep -a python 11.exe
- blibssl-1_1.dll @-F--bpython3.dll @nO9:bpython37.dll0YSWD--bpytransform.pyd ^-6-jbselect.pyd ^--Eibucrtbase.dll0f7-bbunicodedata.pyd0l        QC>
                                                                   %-xbase_library.zip0oL-]-Z&xcertifi\cacert.pem0q-xcertifi\py.typed@q-^
                                                         xcryptography-36.0.1.dist-info\INSTALLER@q-j-Ixcryptography-36.0.1.dist-info\LICENSE@q-=--*xcryptography-36.0.1.dist-info\LICENSE.APACHE@q---xcryptography-36.0.1.dist-info\LICENSE.BSD@q---   -xcryptography-36.0.1.dist-info\LICENSE.PSF@qµ--xcryptography-36.0.1.dist-info\METADATA@q?9>-xcryptography-36.0.1.dist-info\RECORD@q-xcryptography-36.0.1.dist-info\REQUESTED@q--jdxcryptography-36.0.1.dist-info\WHEEL@q-9xcryptography-36.0.1.dist-info\top_level.txt q-Wv-v-zPYZ-00.pyzMEI



-e--S-`3python37.dll

Zatem wykorzystana wersja pythona to 3.7.

Sprawdziłem wersję zainstalowanego interpretera:

>python --version
Python 3.7.9

Spróbowałem uruchomić plik 11.pyc. Niestety próba zakończyła się niepowodzeniem:

>python 11.pyc
Traceback (most recent call last):
  File "<dist\obf\11.py>", line 2, in <module>
  File "<frozen 11>", line 3, in <module>
  File "C:\Python37\lib\crypt.py", line 3, in <module>
    import _crypt
ModuleNotFoundError: No module named '_crypt'

Moduł crypt jest niedostępny dla Windows

Postanowiłem przetestować w jaki sposób wykorzystywana jest ta biblioteka. W tym celu utworzyłem plik crypt.py:

>touch crypt.py

Ponownie spróbowałem uruchomić plik 11.pyc

>python 11.pyc
C:\Python37\lib\site-packages\requests\__init__.py:104: RequestsDependencyWarning: urllib3 (1.26.7) or chardet (5.0.0)/c
harset_normalizer (2.0.9) doesn't match a supported version!
  RequestsDependencyWarning)
Traceback (most recent call last):
  File "<dist\obf\11.py>", line 2, in <module>
  File "<frozen 11>", line 12, in <module>
AttributeError: module 'crypt' has no attribute 'ARC4'

Do pliku crypt.py dopisałem zawartość:

def ARC4(*args, **kwargs):
    print("[+] ### ARC4 ###")
    print(f"[+] {len(args)} args:")
    for arg in args:
        print(f"  [-] {arg}")
    print(f"[+] {len(kwargs.values())} kwargs:")
    for value in kwargs.values():
        print(f"  [-] {value}")
    print("[+] ############")

Po uruchomieniu na standardowym wyjściu pojawiła się zawartość:

>python 11.pyc
C:\Python37\lib\site-packages\requests\__init__.py:104: RequestsDependencyWarning: urllib3 (1.26.7) or chardet (5.0.0)/c
harset_normalizer (2.0.9) doesn't match a supported version!
  RequestsDependencyWarning)
[+] ### ARC4 ###
[+] 1 args:
  [-] b'PyArmor_Pr0tecteth_My_K3y'
[+] 0 kwargs:
[+] ############
Traceback (most recent call last):
  File "<dist\obf\11.py>", line 2, in <module>
  File "<frozen 11>", line 15, in <module>
AttributeError: 'NoneType' object has no attribute 'encrypt'

Nastąpiło odwołanie do atrybutu encrypt - dostarczyłem zatem programowi, to co ten potrzebował:

def print_params(name, *args, **kwargs):
    print("[+] ### {name} ###")
    print(f"[+] {len(args)} args:")
    for arg in args:
        print(f"  [-] {arg}")
    print(f"[+] {len(kwargs.values())} kwargs:")
    for value in kwargs.values():
        print(f"  [-] {value}")
    print("[+] ############")

class ARC4:
    def __init__(*args, **kwargs):
        print_params("ARC4", *args, **kwargs)

    def encrypt(*args, **kwargs):
        print_params("encrypt", *args, **kwargs)

Po uruchomieniu na standardowym wyjściu pojawiła się zawartość:

>python 11.pyc
C:\Python37\lib\site-packages\requests\__init__.py:104: RequestsDependencyWarning: urllib3 (1.26.7) or chardet (5.0.0)/c
harset_normalizer (2.0.9) doesn't match a supported version!
  RequestsDependencyWarning)
[+] ### {name} ###
[+] 2 args:
  [-] <crypt.ARC4 object at 0x00000000006BC808>
  [-] b'PyArmor_Pr0tecteth_My_K3y'
[+] 0 kwargs:
[+] ############
[+] ### {name} ###
[+] 2 args:
  [-] <crypt.ARC4 object at 0x00000000006BC808>
  [-] b'Pyth0n_Prot3ction_tuRn3d_Up_t0_11@flare-on.com'
[+] 0 kwargs:
[+] ############
Traceback (most recent call last):
  File "<dist\obf\11.py>", line 2, in <module>
  File "<frozen 11>", line 15, in <module>
  File "C:\Python37\lib\base64.py", line 58, in b64encode
    encoded = binascii.b2a_base64(s, newline=False)
TypeError: a bytes-like object is required, not 'NoneType'

Zatem flaga to:

Pyth0n_Prot3ction_tuRn3d_Up_t0_11@flare-on.com