$ cat writeup.md…
$ cat writeup.md…
hackthebox
Task: recover an AES-128 key from a remote embedded device that exposes chosen-plaintext power traces over a socket. Solution: apply first-round AES CPA with a Hamming-weight leakage model, recover the key from 800 traces, then submit it to receive the flag.
Project Power Challenge Scenario
The provided artifacts were a Python socket client and a lab layout image. The goal was to recover the embedded device's AES-128 key and use it against the live instance at 154.57.164.74:31688.
At first glance this looked like a remote exploitation challenge, but the supplied interface was not a memory-corruption target. socket_interface.py exposed a much more direct side channel:
1: send a 16-byte plaintext and receive a base64-encoded NumPy power trace2: send a 32-hex-char AES-128 key and receive the flag if the key is correctremote_lab_layout.png clarified the architecture: plaintext is sent to the embedded device, an oscilloscope captures the AES power consumption, and Laptop-2 forwards the trace back over the socket. That makes this a standard AES side-channel problem, not a pwn or reverse challenge.
The useful prior-art match was CTFBase writeup 20260123_0xl4ugh_sca1, which used classic Correlation Power Analysis (CPA) against AES. The right first-round leakage model here was:
HW(SBOX[plaintext[i] XOR key[i]])
CPA works because the real power trace contains samples that correlate with the number of switching bits in this intermediate AES state. For each key-byte guess 0..255, we compute the hypothetical Hamming weights across many chosen plaintexts and measure which guess correlates best with the observed traces. The correct key byte stands out with the highest correlation.
Live collection confirmed that traces decoded as float64 arrays of length 1042, and 800 traces were already enough for a clean recovery. Alternate leakage models and dtype overrides were unnecessary.
socket_interface.py and identify the two menu options: trace oracle and key submission.project_power_solver.py using the Hamming-weight model of SBOX[PT ^ K] for each byte position.800 live traces and plaintexts from the target.2.Minimal run command:
python3 project_power_solver.py \ --host 154.57.164.74 \ --port 31688 \ --count 800 \ --save /Users/sergeyskorobogatov/Projects/Agents/CTF/tasks/hackthebox/project-power/live_traces_800.npz \ --submit
This recovered:
35425203F4BF23C7F93444BF772F2E1FHTB{51d3_ch4nn31_c4n_8234k_3v3n_7h3_m057_53cu23_d3v1c35!@^5%2}Non-needed paths:
float64 decoding was confirmed$ cat /etc/motd
Liked this one?
Pro unlocks every writeup, every flag, and API access. $9/mo.
$ grep --similar