Skip to content

That PNG Is Also a ZIP and Your Gateway Only Checked the Magic Bytes

PNG ZIP Polyglot Files: Build, Abuse, Detect (Lab How-To)

That PNG Is Also a ZIP and Your Gateway Only Checked the Magic Bytes

file(1) says PNG. PIL opens it. your users see a sloth. unzip also opens it and extracts stage.sh. same bytes. two parsers. one of them works for the attacker. welcome to polyglots, the format bug that keeps paying rent.

Lab only. we build a PNG+ZIP polyglot from a local avatar and a harmless echo script. do not email polyglot payloads at people. use this to test whether your mail gateway, chat upload filter, or “allow images” policy is lying to you about what it inspected.

how a file can be two things

PNG is a chunked format. decoders read IHDR, IDAT, IEND and stop caring. ZIP finders scan from the end for the End Of Central Directory (PK\\x05\\x06) and walk backward. append a ZIP archive after a valid PNG’s IEND and you get a file that is a legal image and a legal zip. GIF89a+ZIP, PDF+ZIP, JPEG+ZIP are the same family of insults.

Kali terminal building a PNG plus ZIP polyglot with Python zipfile appended to a PNG.
Step 1: append a ZIP (with stage.sh) to a real PNG.
Kali terminal showing file(1) reports PNG while unzip -l lists the embedded stage.sh.
Step 2: file(1) says PNG. unzip lists the payload. both are correct.
Kali terminal downloading the polyglot and extracting stage.sh with unzip.
Step 3: implant path. fetch image, unzip, run. email said it was safe.
Kali terminal detecting PNG magic and ZIP EOCD in the same file as POLYGLOT.
Step 4: one detector. png header + zip EOCD = ticket.

why defenders care

  • content filters that trust the first magic bytes will classify the file as an image and skip archive inspection.
  • users are told “it’s just a png” and will open / save it without suspicion.
  • second-stage loaders love this: the download looks clean in the proxy MIME column.
  • build pipelines and design tools can be abused the same way (asset folders that are also zip bombs or stage drops).

detections that fit on a sticky note

  1. yara / python: uint32(0) == 0x89504E47 and PK\\x05\\x06 somewhere in the file.
  2. same idea for GIF89a, %PDF, JPEG SOI + ZIP EOCD.
  3. gateway policy: re-encode images on ingest (destroys trailing polyglot data) or unpack-and-scan with an archive engine regardless of declared MIME.
  4. alert when a process does Image.open / equivalent and also treats the same path as a zip within a short window.
honesty check: polyglots are a parser-differential problem. “we block .zip” does nothing if the filename is avatar.png. fix the inspection, not the extension cosplay.

sloth take

formats are social contracts between parsers. attackers forge contracts. if your security tool only reads the greeting at the front of the file, it is doing customer service, not malware analysis. check the end of the file. check both parsers. or keep collecting polyglots in your abuse mailbox and calling them “weird images.”