Post

HackTheBox Hybrid Unifier Writeup

Explore the basics of cybersecurity in the Hybrid Unifier Challenge on Hack The Box. This easy-level Challenge introduces encryption reversal and file handling concepts in a clear and accessible way, perfect for beginners.

Proof of Concept (PoC)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import requests
from hashlib import sha256
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from base64 import b64encode, b64decode
import os
import json

BASE_URL = "http://94.237.63.109:56751/api"

def generate_keypair(g, p):
    a = int.from_bytes(os.urandom(48), 'big') % (p - 1) + 1
    A = pow(g, a, p)
    return a, A

def init_session(client_public_key):
    payload = {"client_public_key": int(client_public_key)}
    response = requests.post(f"{BASE_URL}/init-session", json=payload)
    if response.status_code == 200:
        data = response.json()
        server_public_key = int(data['server_public_key'], 16)
        return server_public_key
    else:
        print("Error in init_session:", response.status_code, response.text)
        return None

def compute_session_key(a, server_public_key, p):
    shared_secret = pow(server_public_key, a, p)
    return sha256(str(shared_secret).encode()).digest()

def decrypt_challenge(session_key, encrypted_challenge):
    encrypted_data = b64decode(encrypted_challenge)
    iv, encrypted = encrypted_data[:16], encrypted_data[16:]
    cipher = AES.new(session_key, AES.MODE_CBC, iv)
    return unpad(cipher.decrypt(encrypted), AES.block_size)

def get_dh_params():
    response = requests.post(f"{BASE_URL}/request-session-parameters")
    if response.status_code == 200:
        params = response.json()
        return int(params['g'], 16), int(params['p'], 16)
    else:
        print("Error fetching DH parameters:", response.status_code, response.text)
        return None, None

def main():
    print("[+] Requesting DH parameters...")
    g, p = get_dh_params()
    if g is None or p is None:
        print("[-] Failed to get DH parameters")
        return
    print(f"[+] Received g: {g}, p: {p}")
    print("[+] Generating keypair...")
    a, client_public_key = generate_keypair(g, p)
    print("[+] Initializing session...")
    server_public_key = init_session(client_public_key)
    if server_public_key is None:
        print("[-] Failed to initialize session")
        return
    print(f"[+] Received server public key: {server_public_key}")
    print("[+] Computing session key...")
    session_key = compute_session_key(a, server_public_key, p)
    print("[+] Requesting challenge...")
    response = requests.post(f"{BASE_URL}/request-challenge")
    if response.status_code != 200:
        print("[-] Failed to get challenge:", response.status_code, response.text)
        return
    encrypted_challenge = response.json()['encrypted_challenge']
    challenge = decrypt_challenge(session_key, encrypted_challenge)
    challenge_hash = sha256(challenge).hexdigest()
    print("[+] Challenge decrypted and hashed")
    print("[+] Requesting flag...")
    iv = os.urandom(16)
    cipher = AES.new(session_key, AES.MODE_CBC, iv)
    encrypted_packet = iv + cipher.encrypt(pad(b'flag', 16))
    packet_data = b64encode(encrypted_packet).decode()
    response = requests.post(f"{BASE_URL}/dashboard",  json={"challenge": challenge_hash,  "packet_data": packet_data})
    if response.status_code == 200:
        encrypted_flag = b64decode(response.json()['packet_data'])
        flag = decrypt_challenge(session_key, response.json()['packet_data'])
        print("[+] Flag:", flag.decode())
    else:
        print("[-] Error during flag retrieval:", response.status_code, response.text)

if __name__ == "__main__":
    main()

Summary

Hybrid Unifier employs Diffie-Hellman for generating a shared session key and AES-CBC encryption for securely exchanging data. The client and server negotiate a shared key, which the client then uses to decrypt a challenge, hash the result, and respond. Upon successful authentication, the server provides an encrypted flag, which the client decrypts using the shared session key, revealing the flag.

This post is licensed under CC BY 4.0 by the author.