Skip to main content

Hell is haard

Challenge

Content preserved from the original writeup source. Minimal normalization was applied to fit platform format.

Solution

Original Writeup Content (Preserved)

Hell is haard

The challenge shipped a single message.txt file containing 2048 integers. The key observation is that the file is not plaintext; it is a rendered artifact that needs to be visualized and OCR'd.

The most useful approach was:

  1. Load the integers from message.txt.
  2. Render them as a grayscale image in the obvious power-of-two shapes.
  3. Try a few simple transforms such as modulo-256, inversion, thresholding, and contrast adjustments.
  4. Run OCR on the best-looking render.

The strongest OCR result came from the inverted 64 by 32 render with nearest-neighbor scaling. The best read of the banner is:

Secrets leak out if you try to hide

The first chunk is very stable across OCR runs. The tail is noisier, but the line structure and repeated OCR hits support that transcription.

Code

from pathlib import Path
import ast
from PIL import Image, ImageOps
import pytesseract

nums = ast.literal_eval(Path('message.txt').read_text())

# The data fits a 64x32 grayscale image cleanly.
img = Image.new('L', (64, 32))
img.putdata([n % 256 for n in nums])

# Inversion and blocky upscaling preserve the banner-like text best for OCR.
variant = ImageOps.invert(img)
big = variant.resize((variant.width * 40, variant.height * 40), Image.Resampling.NEAREST)

text = pytesseract.image_to_string(
big,
config='--psm 6 --oem 1 -c tessedit_char_whitelist=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
)

print('OCR:', ' '.join(text.split()))

If you want the word boxes instead of the whole-line transcript, this is the same render with OCR metadata:

from pytesseract import Output

data = pytesseract.image_to_data(
big,
config='--psm 6 --oem 1 -c tessedit_char_whitelist=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
output_type=Output.DICT,
)

for i, text in enumerate(data['text']):
if text.strip():
print(i, repr(text), data['conf'][i], (data['left'][i], data['top'][i], data['width'][i], data['height'][i]))

Notes

The same file also reacts well to simple thresholding and contrast changes, which is a strong hint that the original payload is visual rather than textual. The challenge title is consistent with a Haar-style image decode workflow.