forensicsfreeeasy

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/
zip_password_extractionpdf_hidden_text_extractionpdf_polyglot_extractionimagemagick_swirl_reversaltrailing_data_analysis

$ 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 -list returns nothing
  • No attachments: pdfdetach -list shows 0 embedded files
  • Hidden text: pdftotext extracts 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