scripting

Nahamcon 2024

Hashes on Hashes on Hashes

Solved by : thewhiteh4t

  • We have a python script server.py and decryption log
  • log contains a fixed pattern :
20/05/2024 15:14:38        Listening for connection...
20/05/2024 15:14:42        Connection received from ('10.10.2.6', 50924)
20/05/2024 15:14:42        Received encrypted message GyseOBdHRQ49Mz1h
20/05/2024 15:14:42        Key loaded for encrypted message
20/05/2024 15:14:42        Key expanded by factor of 1
20/05/2024 15:14:42        Partial message digest is c1d9f50f86825a1a2302ec2449c17196
20/05/2024 15:14:42        Partial message digest is a64cf5823262686e1a28b2245be34ce0
20/05/2024 15:14:42        Partial message digest is 6b6e667a40e816c4da7bb4ab64cbb82b
20/05/2024 15:14:42        Partial message digest is 1824e8e0307cbfdd1993511ab040075c
20/05/2024 15:14:42        Partial message digest is 8b1a9953c4611296a827abf8c47804d7
20/05/2024 15:14:42        Partial message digest is d1a7fb5eab1c16cb4f7cf341cf188c3d
20/05/2024 15:14:42        Partial message digest is d245114cd44bdcd540a014ad78257432
20/05/2024 15:14:42        Partial message digest is fd05d5cc96e2e85fa2dfc2505932cf76
20/05/2024 15:14:42        Partial message digest is cd3719c301dce67f4440f42be83ef6f3
20/05/2024 15:14:42        Partial message digest is ad7fe93595f81645e06239701fbd8084
20/05/2024 15:14:42        Partial message digest is e8ea7a8d1e93e8764a84a0f3df4644de
20/05/2024 15:14:42        Partial message digest is 9d6a2963872077db674a27a39c492e61
20/05/2024 15:14:42        Message fully decrypted, ready to send...
20/05/2024 15:14:42        Decrypted message sent!
  • server.py contains the decrypt function :
def decrypt(encrypted):
    key = open('key.txt').read()
    key = key.strip()
    log.print("Key loaded for encrypted message")

    factor = len(encrypted) // len(key) + 1
    key = key * factor
    log.print(f"Key expanded by factor of {factor}")
    key_bytes = key.encode()

    enc_bytes = base64.b64decode(encrypted)
    dec_bytes = bytearray()

    for i in range(len(enc_bytes)):
        dec_bytes.append(enc_bytes[i] ^ key_bytes[i])
        log.print(f"Partial message digest is {md5(dec_bytes).hexdigest()}")
    decrypted = dec_bytes.decode()
    log.print("Message fully decrypted, ready to send...")
    return decrypted
  • key is read from a file which we do not have
  • key is repeated by factor and the factor value is available in the log
  • key is encoded into bytes
  • encrypted message is base64 decoded
  • each byte of the encrypted message is XORed against one byte of the key based on the index of the encrypted message
  • the decoded byte is appended to a byte array
  • md5sum of the bytearray is calculated which is also available in the log
  • now what we have :
1. encrypted message
2. key factor
3. md5 digest
  • reverse of XOR is XOR, we can bruteforce they single key byte used by calculating md5sum for each combination and comparing it with the md5 present in the log
  • if the md5 matches then we have one correct byte of the key, we can extract full key and decode the messages
  • script :
#!/usr/bin/env python3

import base64
import hashlib

with open('decryption_server.log', 'r') as infile:
        logs = infile.read()


def guess_key_byte(encrypted, digests):
        enc_bytes = base64.b64decode(encrypted)
        dec_bytes = bytearray()
        key_bytes = bytes()

        for i in range(len(enc_bytes)):
                for num in range(256):
                        key_int = enc_bytes[i] ^ num

                        dec_bytes.append(key_int)

                        md5_digest = hashlib.md5(dec_bytes).hexdigest()

                        if md5_digest == digests[i]:
                                key_bytes += bytes([num])
                                break
                        else:
                                dec_bytes = dec_bytes[:-1]
        return key_bytes


chunks = logs.split('Listening for connection...')

for chunk in chunks:
        lines = chunk.split('\n')

        if len(lines) < 4:
                continue

        dec_bytes = bytearray()
        digests = []

        for line in lines:
                if 'Received encrypted message' in line:
                        enc_msg = line.split(' ')[-1]
                if 'Key expanded' in line:
                        key_factor = int(line.split(' ')[-1])
                if 'Partial message' in line:
                        msg_digest = line.split(' ')[-1]
                        digests.append(msg_digest)

        partial_key_bytes = guess_key_byte(enc_msg, digests)
        # print(partial_key_bytes)

        dec_key = partial_key_bytes * key_factor

        dec_key_bytes = dec_key
        enc_bytes = base64.b64decode(enc_msg)
        dec_msg_bytes = bytearray()
        for i in range(len(enc_bytes)):
                dec_msg_bytes.append(enc_bytes[i] ^ dec_key_bytes[i])
        decrypted = dec_msg_bytes.decode()
        print(decrypted)

Published on : 28 May 2024