![_f6aabe9d-ee37-436a-ab38-70eba69fb787](https://hackmd.io/_uploads/BJY0o8zET.jpg =600x600) # Snake-Oil Writeup We get a file, after doing a strings command on it, we can see that its compiled with pyinstaller. The first thing we want to do is to dissaseble the executable so we can extract the pyc data and find something interesting. ## Dissassemble ```bash= Documents/CTF/huntress/snakeoil/pyinstxtractor# python pyinstxtractor.py snake-oil [+] Processing snake-oil [+] Pyinstaller version: 2.1+ [+] Python version: 3.9 [+] Length of package: 13435879 bytes [+] Found 963 files in CArchive [+] Beginning extraction...please standby [+] Possible entry point: pyiboot01_bootstrap.pyc [+] Possible entry point: pyi_rth_pkgutil.pyc [+] Possible entry point: pyi_rth_multiprocessing.pyc [+] Possible entry point: pyi_rth_inspect.pyc [+] Possible entry point: pyi_rth__tkinter.pyc [+] Possible entry point: pyi_rth_pkgres.pyc [+] Possible entry point: brain-melt.pyc [!] Warning: This script is running in a different Python version than the one used to build the executable. [!] Please run this script in Python 3.9 to prevent extraction errors during unmarshalling [!] Skipping pyz extraction [+] Successfully extracted pyinstaller archive: snake-oil You can now use a python decompiler on the pyc files within the extracted directory ``` ## Extraction after we extract the data we se a file named brain-melt.pyc which is a python binary. If we run a strings on this we will se the data and some ofuscated code + assembly. interesting. so the apporach here is to use ***pydisasm*** ths you can install with: ```bash= pip install pyinstaller write root@kali:~/Documents/CTF/huntress/snakeoil/pyinstxtractor# pydisasm --help Usage: pydisasm [OPTIONS] FILES... Disassembles a Python bytecode file. We handle bytecode for virtually every release of Python and some releases of PyPy. The version of Python in the bytecode doesn't have to be the same version as the Python interpreter used to run this program. For example, you can disassemble Python 3.6.9 bytecode from Python 2.7.15 and vice versa. Options: -F, --format [xasm|bytes|classic|extended|extended-bytes|header] -S, --show-source / --no-show-source Intersperse Python source text from linecache if available. --version Show the version and exit. --help Show this message and exit. ``` so we run the command ```bash= root@kali:~/Documents/CTF/huntress/snakeoil/pyinstxtractor# pydisasm brain- melt.pyc >> brain-melt_decomp.txt ``` when we saved the decompiled byte code to assembly we can se an important code block. ```asm= # Method Name: deobfuscate # Filename: brain-melt.py # Argument count: 0 # Position-only argument count: 0 # Keyword-only arguments: 0 # Number of locals: 4 # Stack size: 6 # Flags: 0x00000043 (NOFREE | NEWLOCALS | OPTIMIZED) # First Line: 16 # Constants: # 0: None # 1: '2ec7627d{galf' # 2: -1 # 3: 'NjIwM2I1Y2M2OWY0' # 4: 'ascii' # 5: 'UTF8' # 6: '\x17*\x07`BC\x14*R@\x14^*' # 7: 'uKeVuzwIexplW' # Names: # 0: str # 1: base64 # 2: b64decode # 3: encode # 4: decrypt # Varnames: # part1, part2, part3, key # Local variables: # 0: part1 # 1: part2 # 2: part3 # 3: key 17: 0 LOAD_CONST ('2ec7627d{galf') 2 LOAD_CONST (None) 4 LOAD_CONST (None) 6 LOAD_CONST (-1) 8 BUILD_SLICE 3 10 BINARY_SUBSCR 12 STORE_FAST (part1) 18: 14 LOAD_GLOBAL (str) 16 LOAD_GLOBAL (base64) 18 LOAD_METHOD (b64decode) 20 LOAD_CONST ('NjIwM2I1Y2M2OWY0') 22 LOAD_METHOD (encode) 24 LOAD_CONST ('ascii') 26 CALL_METHOD (1 positional argument) 28 CALL_METHOD (1 positional argument) 30 LOAD_CONST ('UTF8') 32 CALL_FUNCTION (2 positional arguments) 34 STORE_FAST (part2) 19: 36 LOAD_GLOBAL (decrypt) 38 LOAD_CONST ('\x17*\x07`BC\x14*R@\x14^*') 40 LOAD_CONST ('uKeVuzwIexplW') 42 CALL_FUNCTION (2 positional arguments) 44 STORE_FAST (part3) 21: 46 LOAD_FAST (part1) 48 LOAD_FAST (part2) 50 BINARY_ADD 52 LOAD_FAST (part3) 54 BINARY_ADD 56 STORE_FAST (key) 22: 58 LOAD_FAST (key) 60 RETURN_VALUE ``` ***Block 17** has a flag in reverse that one: ```bash! echo "strings" | rev ``` ***Block 18*** has parts of the flag in base64 ***Block 19*** Has parts in ***XOR*** ## Decryption The most practical part was to make a script that runs all the keys and decyrpts them all together. ```python import base64 def fnXorDecrypt(strValue, strKey): # XOR decryption. Assumes both value and key are strings. strDecrypted = ''.join([chr(ord(c) ^ ord(k)) for c, k in zip(strValue, strKey)]) return strDecrypted def fnRetrieveValues(): # For part1 block 17: strPart1 = '2ec7627d{galf'[::-1] # Reversing the string # For part2 for block 18: strEncodedValue = 'NjIwM2I1Y2M2OWY0'.encode('ascii') byDecodedValue = base64.b64decode(strEncodedValue) strPart2 = byDecodedValue.decode('UTF8') # For part3 for block 19: strPart3 = fnXorDecrypt('\x17*\x07`BC\x14*R@\x14^*', 'uKeVuzwIexplW') # Combine parts to get the key strKey = strPart1 + strPart2 + strPart3 return { 'part1': strPart1, 'part2': strPart2, 'part3': strPart3, 'key': strKey } dictValues = fnRetrieveValues() for strName, strValue in dictValues.items(): print(f"{strName}: {strValue}") ``` to when we run the script we get the flags ```bash! root@kali:~/Documents/CTF/huntress/snakeoil/pyinstxtractor# python flag.py part1: flag{d7267ce2 part2: 6203b5cc69f4 part3: bab679cc78d2} key: flag{d7267ce26203b5cc69f4bab679cc78d2} ```