August 25, 2026
EHAX RecCTF 2026 • Not What It Seems
DIGITAL FORENSICS • MULTI-LAYER FILE ANALYSIS
By Vrindamalik
2 min read
EHAX RecCTF 2026 — Not What It Seems
When extensions lie: magic bytes, metadata, LSBs, an encrypted QR and two final transformations.
CHALLENGE IN ONE LINE Treat every filename as suspicious, recover two password fragments from metadata and pixel bits, unlock a QR code, then decode and reverse its payload.
This was my favorite multi-layer forensics challenge because every file contributed something different. It initially looked like a folder of ordinary images and notes, but the readme's warning — things are not always what they seem — was a direct instruction to stop trusting appearances.
1. First approach: check the real formats
Opening the images normally did not reveal a flag. I therefore checked their internal signatures rather than relying on the extensions.
file handout/*file handout/*The result showed that report.png was actually a JPEG, vacation.jpg was actually a PNG, and notes.docx was a tiny ZIP container. The filename was only a label; the magic bytes described the real content.
2. Recovering the two password fragments
ExifTool showed an unusual Artist value inside report.png: z3gnqngn. Applying ROT13 converted it to m3tadata.
exiftool handout/report.png
# Artist : z3gnqngn
# ROT13 : m3tadataexiftool handout/report.png
# Artist : z3gnqngn
# ROT13 : m3tadataBecause vacation.jpg was really a PNG, I analysed its least-significant pixel bits. The red channel yielded st3g0_|||END|||, where the marker showed the end of the useful text.
zsteg handout/vacation.jpg
# b1,r,lsb,xy text: "st3g0_|||END|||"zsteg handout/vacation.jpg
# b1,r,lsb,xy text: "st3g0_|||END|||"
Combining the fragments gave the password st3g0_m3tadata. The underscore at the end of st3g0_ made the intended joining order especially clear.
3. Unlocking and scanning the QR
unzip -P 'st3g0_m3tadata' handout/notes.docxunzip -P 'st3g0_m3tadata' handout/notes.docxThe archive contained secret_qr.png. Scanning the extracted QR returned a Base64-looking string.
4. Peeling back the final layers
From Base64 produced a string that already resembled a flag, but backwards. Reversing the text completed the last layer.
printf '%s' 'fXNsM3gxcF9uM2RkMWhfJl9zM3R5Yl9kM3MxdWdzMWR7WEFIRQ==' | base64 -d | rev
printf '%s' 'fXNsM3gxcF9uM2RkMWhfJl9zM3R5Yl9kM3MxdWdzMWR7WEFIRQ==' | base64 -d | rev
Flag
EHAX{d1sgu1s3d_byt3s_&_h1dd3n_p1x3ls}EHAX{d1sgu1s3d_byt3s_&_h1dd3n_p1x3ls}What I learned
The challenge became manageable once I treated it as a chain instead of four unrelated files. File signatures told me which tools were appropriate, metadata and LSBs supplied a password, and the QR delivered the final encoded payload. No individual step was very advanced; preserving the order of the clues was the real skill.
Evidence note
Every figure in this post was built from the original supplied challenge artifact or an exact deterministic decode of it. No AI-generated challenge imagery, account data, email address, username, team token, or session detail is included.
Medium publishing draft • Evidence derived from supplied challenge artifacts