Phase Madness
Phase Madness
Platform: HackTheBox | Category: Cryptography | Type: Challenge | Difficulty: Medium | OS: NA | Author: D3v0o0Nu11 | Date: 2026-02-01 | Status: Solved Techniques: basis_transformation, phase_recovery, quantum_state_tomography
Summary
Server: 83.136.251.105:37930
Recon
Port scan
bash read-only • copy allowednmap -p- -sV -sC <TARGET> --min-rate 1000 -Pn
| Port | Service | Version | Notes |
|---|---|---|---|
| <PORT> | <SVC> | <VER> | <notes> |
Enumeration highlights
- Event:
HackTheBox| ID:20260201_hackthebox_phase_madness - Tags: quantum, qiskit, phase_encoding, state_tomography
- Indicators: quantum circuit, RX/RY/RZ gates, phase encoding, qiskit, qubit measurement
- Source:
20260201_hackthebox_phase_madness.md
Foothold
Vulnerability / Misconfiguration
- basis_transformation
- phase_recovery
- quantum_state_tomography
bash read-only • copy allowed<command>
Exploitation
- See original writeup content for detailed exploitation.
Privilege Escalation
Enumeration
bash read-only • copy allowedsudo -l find / -perm -4000 2>/dev/null getcap -r / 2>/dev/null cat /etc/crontab ps aux
Exploitation
- N/A for challenge-type writeup; see exploitation above.
- Flag obtained via challenge solve.
bash read-only • copy allowed<command>
Flags
| Flag | Location | Value |
|---|---|---|
| flag | REDACTED |
Key Takeaways / Lessons
- basis_transformation
- phase_recovery
- quantum_state_tomography
- Tags: quantum, qiskit, phase_encoding, state_tomography
Original Writeup
<details><summary>Click to expand original content</summary>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:HthenRZ(θ)— Hadamard + rotation around Z axis
The server allows:
- Selecting a qubit to measure
- Adding additional gates before measurement
- 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)), thenbyte = θ × 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 read-only • copy allowed#!/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.
</details>signed by XESXOR