
# 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}
```