Skip to main content

Hell_is_haard

Challenge

Imported from local notes.md.

Solution

Original Notes

Hell_is_haard

Challenge Summary

  • Given: a single file, message.txt, containing 2048 integers.
  • Goal: recover the hidden flag from the convoluted message.
  • Constraints: live CTF challenge, flag accepted by the platform was lowercase udctf{...} for this challenge.

Initial Recon / Triage

  • Observations: the title strongly suggested a Haar transform. The input length was 2048 = 2^11, which fits a recursive wavelet-style encoding.
  • File identification: starting_files/message.txt is a Python-style list of signed integers.
  • Entry points: test inverse Haar layouts first, then inspect whether any residual error is structured rather than random.

Hypotheses & Approach

  • Hypothesis 1: the ciphertext was produced by a recursive half-split Haar transform and needed an inverse decode.
  • Hypothesis 2: if the decode looked close but not exact, the remaining error would likely live in the low-frequency coefficients and shift whole regions of plaintext at once.

Execution Steps (Reproducible)

Stage 1

Commands:

cd /root/bluehens2026CTF/Hell_is_haard
python3 artifacts/solve.py

Results:

  • The best candidate came from the recursive half-split inverse Haar decode.
  • The first 512 bytes decoded perfectly into a Longfellow translation of Dante's Inferno, Canto IX.
  • The remaining bytes were not random noise. They were the same passage shifted by constant offsets over large blocks, which meant the coarse coefficients were still wrong.

Stage 2

Commands:

cd /root/bluehens2026CTF/Hell_is_haard
python3 artifacts/recover_exact.py

Results:

  • Comparing the decoded text against the normalized Gutenberg source showed exact block deltas of 0, 91, and 45 for the first three 512-byte regions.

  • Mapping those region offsets back through the forward Haar transform identified the coarse-coefficient correction.

  • After applying that correction, the text recovered almost exactly and exposed the inserted flag in the final region:

    This is udctf{h3lp_1t5_c0ld_d0wn_h3r3}; She who is weeping on the right, Alecto;

  • Live validation against the CTFd API confirmed the accepted flag was lowercase.

Stage 3

Commands:

python3 - <<'PY'
import requests
url = 'https://bluehens.ctfd.io/api/v1/challenges/attempt'
headers = {
'Authorization': 'Token ctfd_a8b34b5ad483685d7a9766b48cc00d5912f78707cd241ef656a60b03604b35d8',
'Content-Type': 'application/json',
}
flag = 'udctf{h3lp_1t5_c0ld_d0wn_h3r3}'
print(requests.post(url, headers=headers, json={'challenge_id': 41, 'submission': flag}, timeout=20).json())
PY

Results:

  • The platform returned correct for udctf{h3lp_1t5_c0ld_d0wn_h3r3}.

Artifacts Produced

  • artifacts/solve.py: inverse-Haar candidate testing.
  • artifacts/probe_rounding.py: showed the main ambiguity was not per-fraction rounding.
  • artifacts/compare_gutenberg.py: aligned the recovered plaintext with Dante Canto IX.
  • artifacts/analyze_blocks.py: showed that later quarters differed by constant offsets.
  • artifacts/recover_exact.py: derived the coarse correction and exposed the flag insertion.
  • artifacts/decoded_best.txt: best initial plaintext candidate.
  • artifacts/gutenberg_source_segment.txt: normalized source segment used for alignment.
  • artifacts/redecoded_exact.txt: corrected plaintext reconstruction containing the flag.

Flag

udctf{h3lp_1t5_c0ld_d0wn_h3r3}