Invisible Ink
tjctf
Task: 638KB PDF polyglot file with hidden text, appended ZIP archive, and swirl-distorted PNG image. Solution: extract hidden password via pdftotext, carve ZIP from PDF trailing data, decrypt archive, reverse ImageMagick swirl distortion to read flag.
$ ls tags/ techniques/
$ cat /etc/rate-limit
Rate limit reached (20 reads/hour per IP). Showing preview only — full content returns at the next hour roll-over.
Invisible Ink — TJCTF 2026
Description
Check out this cool PDF I found... I wonder if there's anything hidden inside!
A 638KB PDF file (chall.pdf) is provided. The goal is to find a hidden flag. The file is suspiciously large for a 2-page text-only document, hinting at embedded data.
Analysis
Stage 1: PDF Reconnaissance
The PDF has 2 pages, created with "Skia/PDF m149 Google Docs Renderer". Key observations:
- File size: 638KB — far too large for a text-only PDF (actual PDF structure is only ~31KB)
- No embedded images:
pdfimages -listreturns nothing - No attachments:
pdfdetach -listshows 0 embedded files - Hidden text:
pdftotextextracts text not visible in the PDF viewer, including a poem about CTFs and crucially a password
pdftotext chall.pdf -
The extracted text includes:
- A decoy message: "There's nothing here lol why are you looking"
- A poem about CTF challenges
- A password string:
DBf8nEBgwRhZ
Stage 2: Polyglot Detection — ZIP After PDF EOF
The PDF structure ends at ~31KB with the %%EOF marker, but the file continues for another ~607KB. Examining the trailing bytes reveals a PK (ZIP) magic header immediately after EOF:
with open('chall.pdf', 'rb') as f: data = f.read() # Find the last %%EOF marker eof_pos = data.rfind(b'%%EOF') trailing = data[eof_pos + 6:] # skip %%EOF\n # Write the trailing ZIP data with open('hidden.zip', 'wb') as f: f.write(trailing)
The carved ZIP archive is 606KB and contains a single password-protected file: original_distorted.png.
Stage 3: ZIP Extraction
Using the password discovered in the PDF hidden text:
unzip -P "DBf8nEBgwRhZ" hidden.zip
This extracts original_distorted.png — a 1920×1080 RGB PNG image.
Stage 4: Image Analysis
...
$ grep --similar
Similar writeups
- [forensics][Pro]100 Pages— taipanbyte
- [misc][Pro]TeXyC— ASIS CTF
- [stego][Pro]SomeText— taipanbyte
- [stego][Pro]Warmup— hackerlab
- [forensics][free]Unfinished File— tjctf