https://app.hackthebox.com/challenges/619

Description

After successfully joining the academy, there is a process where you have to log in to eclass in order to access notes in each class and get the current updates for the ongoing prank labs. When you attempt to log in, though, your browser crashes, and all your files get encrypted. This is yet another prank for the newcomers. The only thing provided is the password generator script. Can you crack it, unlock your files, and log in to the spooky platform?

Source

output.txt

Your Password : t*!zGnf#LKO~drVQc@n%oFFZyvhvGZq8zbfXKvE1#*R%uh*$M6c$zrxWedrAENFJB7xz0ps4zh94EwZOnVT9&h
Encrypted Flag : GKLlVVw9uz/QzqKiBPAvdLA+QyRqyctsPJ/tx8Ac2hIUl8/kJaEvHthHUuwFDRCs

server.py

from hashlib import sha256
import string, random
from secret import MASTER_KEY, FLAG
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from base64 import b64encode

ALPHABET = string.ascii_letters + string.digits + '~!@#$%^&*'

def generate_password():
    master_key = int.from_bytes(MASTER_KEY, 'little')
    password = ''

    while master_key:
        bit = master_key & 1
        if bit:
            password += random.choice(ALPHABET[:len(ALPHABET)//2])
        else:
            password += random.choice(ALPHABET[len(ALPHABET)//2:])
        master_key >>= 1

    return password

def main():
    password = generate_password()
    encryption_key = sha256(MASTER_KEY).digest()
    cipher = AES.new(encryption_key, AES.MODE_ECB)
    ciphertext = cipher.encrypt(pad(FLAG, 16))

    with open('output.txt', 'w') as f:
        f.write(f'Your Password : {password}\nEncrypted Flag : {b64encode(ciphertext).decode()}')

if __name__ == '__main__':
    main()

Exploitation

#!/usr/bin/python3
from hashlib import sha256
from Crypto.Cipher import AES
from base64 import b64decode
import string

password = "t*!zGnf#LKO~drVQc@n%oFFZyvhvGZq8zbfXKvE1#*R%uh*$M6c$zrxWedrAENFJB7xz0ps4zh94EwZOnVT9&h"
encrypted_flag = "GKLlVVw9uz/QzqKiBPAvdLA+QyRqyctsPJ/tx8Ac2hIUl8/kJaEvHthHUuwFDRCs"
ALPHABET = string.ascii_letters + string.digits + '~!@#$%^&*'
first_half = ALPHABET[:len(ALPHABET)//2]
second_half = ALPHABET[len(ALPHABET)//2:]
master_key_bits = []
for char in password:
    if char in first_half:
        master_key_bits.append(1)
    else:
        master_key_bits.append(0)
master_key = 0
for bit in reversed(master_key_bits):
    master_key = (master_key << 1) | bit
MASTER_KEY = master_key.to_bytes((master_key.bit_length() + 7) // 8, 'little')
encryption_key = sha256(MASTER_KEY).digest()
cipher = AES.new(encryption_key, AES.MODE_ECB)
ciphertext = b64decode(encrypted_flag)
flag = cipher.decrypt(ciphertext)
print(f"Recovered MASTER_KEY (hex): {MASTER_KEY.hex()}")
print(f"Flag: {flag.decode()}")

Summary

SPG: reconstruct the generator state, derive the AES material, and decrypt the final ciphertext.