# PyBonHash
In this challenge we're given two files: * `hash.txt`: a file containing the hex encoded hash* `pybonhash.cpython-36.pyc`: a compiled version of the python script responsible of the hashing
unlike assembly, python byte code can be decompiled with precision, meaning that the decompiled script is (almost)identical to the original script, after a quick google search, i found a decompiler called [uncompyle6](https://github.com/rocky/python-uncompyle6/), it worked perfectly and yielded this script:```pythonimport string, sys, hashlib, binasciifrom Crypto.Cipher import AESfrom flag import key
if not len(key) == 42:    raise AssertionErrorelse:    data = open(sys.argv[1], 'rb').read()    assert len(data) >= 191FIBOFFSET = 4919MAXFIBSIZE = len(key) + len(data) + FIBOFFSET
def fibseq(n):    out = [     0, 1]    for i in range(2, n):        out += [out[(i - 1)] + out[(i - 2)]]
    return out
FIB = fibseq(MAXFIBSIZE)i = 0output = ''while i < len(data):    data1 = data[(FIB[i] % len(data))]    key1 = key[((i + FIB[(FIBOFFSET + i)]) % len(key))]    i += 1    data2 = data[(FIB[i] % len(data))]    key2 = key[((i + FIB[(FIBOFFSET + i)]) % len(key))]    i += 1    tohash = bytes([data1, data2])    toencrypt = hashlib.md5(tohash).hexdigest()    thiskey = bytes([key1, key2]) * 16    cipher = AES.new(thiskey, AES.MODE_ECB)    enc = cipher.encrypt(toencrypt)    output += binascii.hexlify(enc).decode('ascii')
print(output)```
looking at the script, we can easily understarnd how the hashing process is done:1. the `hashing key` has a fixed length of 422. data length >= 1913. it generates a Fibonacci sequence of `MAXFIBSIZE` terms where `MAXFIBSIZE == 4961 + len(data)`4. it loops `range(0, len(data), 2)` times, doing the following:    1. choose two bytes from the data with the following positions:    ```python    FIB[i] % len(data), (FIB[i + 1] % len(data))    ```    2. choose two bytes from the key with the following positions:    ```python    (i + FIB[FIBOFFSET + i]) % 42, (i + 1 + FIB[FIBOFFSET + i + 1]) % 42    ```    3. hash the concat of the two data bytes using md5    4. create an encryption key that is the concat of the two key bytes repeated 16 times    5. encrypts the hex encoded md5 hash using AES in ECB mode
now, we know that the encrypted data is hex encoded strings, and we know that the encryption key is composed of two bytes, so we'll use this to forge our attack, we'll take each 16-bytes block of the final hash, try to decrypt it with one of the possible keys, and take the ones that yield a valid hex encoded string, after we got all the encryption keys, we'll re-order the key bytes using the positions in each block by replicating the bytes selection process in the original script. Here's the final script:```python#!/usr/bin/python2
from Crypto.Cipher import AESfrom hashlib import md5
def fibseq(n):    out = [0, 1]    for i in range(2, n):        out += [out[(i - 1)] + out[(i - 2)]]    return out
FIBOFFSET = 4919
with open('hash.txt', 'r') as f:    hash = f.read().rstrip().decode('hex')
possible_keys = []
for i in range(256):    for j in range(256):        possible_keys.append((chr(i) + chr(j)) * 16)
blocks = [hash[i: i + 32] for i in range(0, len(hash), 32)]key_blocks = []
for n, block in enumerate(blocks):    for thiskey in possible_keys:        cipher = AES.new(thiskey, AES.MODE_ECB)        tmp = cipher.decrypt(block)
        try:            tmp.decode('hex')            print (tmp, thiskey, n)            key_blocks.append(thiskey[:2])            break        except:            pass
len_data = len(blocks) * 2MAXFIBSIZE = 42 + len_data + FIBOFFSETFIB = fibseq(MAXFIBSIZE)
key = ''key_positions = []for i in range(0, len_data, 2):    key_positions.append(((i + FIB[FIBOFFSET + i]) % 42, (i + 1 + FIB[FIBOFFSET + i + 1]) % 42))
for i in range(42):    for n, pos in enumerate(key_positions):        if i == pos[0]:            p = 0            break        elif i == pos[1]:            p = 1            break    key += key_blocks[n][p]
print(key)```the flag is: `midnight{xwJjPw4Vp0Zl19xIdaNuz6zTeMQ1wlNP}`
it was a pretty easy challenge, but fun nonetheless.