← Back to Writeups
HTBMediumCrypto

Phase Madness

XESXOR9/10/20263 min read
#crypto#htb#medium#basis_transformation#phase_recovery#quantum_state_tomography

Phase Madness

Platform: HackTheBox | Category: Crypto | Type: Challenge | Difficulty: Medium | OS: NA | Author: XESXOR | Date: 2026-02-01 | Status: Solved Techniques: basis_transformation, phase_recovery, quantum_state_tomography

Summary

Server: 83.136.251.105:37930

Phase Madness — HackTheBox

Description

"Qubitrix doesn't store data the way others do. Deep within its core, every secret stays in a silent quantum spiral, beyond classical reach. Engineers swore it was flawless — yet something in its design hums and breathes. To them, madness. To us, clarity."

Server: 83.136.251.105:37930

Analysis

The server uses Qiskit to encode the flag into quantum states. Each byte of the flag is converted to a rotation angle (byte * π/180 radians) and applied to the corresponding qubit:

  • Position i % 3 == 0: RX(θ) — rotation around X axis
  • Position i % 3 == 1: RY(θ) — rotation around Y axis
  • Position i % 3 == 2: H then RZ(θ) — Hadamard + rotation around Z axis

The server allows:

  1. Selecting a qubit to measure
  2. Adding additional gates before measurement
  3. Receiving results of 100,000 measurements

Solution

Recovery Mathematics

For RX and RY gates: After applying RX(θ) or RY(θ) to |0⟩:

  • State: cos(θ/2)|0⟩ ± sin(θ/2)|1⟩
  • Probability of |1⟩: P(1) = sin²(θ/2)
  • Recovery: θ = 2·arcsin(√P(1)), then byte = θ × 180/π

For RZ gates (after H): After H·RZ(θ)|0⟩:

  • State: (e^{-iθ/2}|0⟩ + e^{iθ/2}|1⟩)/√2
  • Direct measurement in Z-basis gives 50/50 (phase is hidden!)
  • Solution: apply RY(-90°) before measurement to switch to X-basis
  • This converts phase information into amplitude: P(1) = sin²(θ/2)

Solver

python
#!/usr/bin/env python3
"""
Phase Madness Solver - HackTheBox
Quantum state tomography attack on phase-encoded flag
"""
from pwn import *
import json
import math

HOST = "83.136.251.105"
PORT = 37930

def get_measurement(r, qubit, instructions=""):
    """Send measurement request and get results"""
    r.recvuntil(b"Specify the qubit index you want to measure : ")
    r.sendline(str(qubit).encode())
    r.recvuntil(b"Specify the instructions : ")
    r.sendline(instructions.encode())
    return json.loads(r.recvline().decode().strip())

def prob_one(result):
    """Calculate probability of measuring |1⟩"""
    total = sum(result.values())
    return result.get("1", 0) / total if total > 0 else 0

def recover_byte(r, qubit):
    """Recover a single byte from qubit measurement"""
    pos_in_group = qubit % 3
    
    if pos_in_group == 0:  # RX gate
        result = get_measurement(r, qubit, "")
    elif pos_in_group == 1:  # RY gate
        result = get_measurement(r, qubit, "")
    else:  # RZ gate (after H) - need basis transformation
        # Apply RY(-90) to measure in X-basis and reveal phase
        result = get_measurement(r, qubit, f"RY:-90,{qubit}")
    
    p1 = prob_one(result)
    
    # Recover angle from probability
    # P(1) = sin²(θ/2) → θ = 2·arcsin(√P(1))
    theta = 2 * math.asin(math.sqrt(min(p1, 1.0)))
    byte_val = round(theta * 180 / math.pi)
    
    return byte_val

def main():
    flag_len = 79  # Determined by probing
    flag = []
    
    r = remote(HOST, PORT)
    
    for i in range(flag_len):
        try:
            byte_val = recover_byte(r, i)
            char = chr(byte_val) if 32 <= byte_val <= 126 else '?'
            flag.append(char)
            print(f"Qubit {i:2d}: {byte_val:3d} -> '{char}'")
        except Exception as e:
            print(f"Error at qubit {i}: {e}")
            flag.append('?')
    
    print(f"\nFlag: {''.join(flag)}")
    r.close()

if __name__ == "__main__":
    main()

Theory

Quantum Rotation Gates

| Gate | Matrix | Effect on |0⟩ | |------|---------|-----------| | RX(θ) | [[cos(θ/2), -i·sin(θ/2)], [-i·sin(θ/2), cos(θ/2)]] | cos(θ/2)|0⟩ - i·sin(θ/2)|1⟩ | | RY(θ) | [[cos(θ/2), -sin(θ/2)], [sin(θ/2), cos(θ/2)]] | cos(θ/2)|0⟩ + sin(θ/2)|1⟩ | | RZ(θ) | [[e^{-iθ/2}, 0], [0, e^{iθ/2}]] | e^{-iθ/2}|0⟩ (phase only) |

Why RZ Requires Special Handling

RZ on |0⟩ gives only a global phase — measurement always yields |0⟩. But after H: H|0⟩ = (|0⟩ + |1⟩)/√2 Then RZ: (e^{-iθ/2}|0⟩ + e^{iθ/2}|1⟩)/√2

The phase is now relative! By applying RY(-π/2), we rotate the state so that the phase difference becomes an amplitude difference, which can be measured.