Magic Numbers (File Signatures)
Magic numbers — more precisely, file signatures — are the fixed byte sequences at (or near) the start of a file that identify its format. Plain text files have no magic number; binary formats usually do, typically in the first 2–8 bytes. The Unix file(1) utility and its libmagic database are the canonical implementation of signature-based identification; Wikipedia’s list of file signatures is the standard community reference.
Well-known examples:
| Signature (hex) | ASCII | Format |
|---|---|---|
FF D8 FF | ÿØÿ | JPEG image |
89 50 4E 47 0D 0A 1A 0A | ‰PNG␍␊␚␊ | PNG image |
47 49 46 38 37/39 61 | GIF87a / GIF89a | GIF image |
25 50 44 46 2D | %PDF- | PDF document |
50 4B 03 04 | PK␃␄ | ZIP archive (also docx/xlsx/jar/apk) |
7F 45 4C 46 | ␡ELF | ELF executable |
4D 5A | MZ | DOS/PE executable |
1F 8B | — | gzip compressed data |
Offensive use: bypassing upload filters
Many web applications validate uploads by checking the magic number rather than parsing the file. Because text files carry no signature, a script payload can be prepended with a few ASCII characters and then patched in a hex editor to match a trusted format’s signature — for example, starting a PHP file with GIF8 and editing it to 47 49 46 38 (GIF8). The file utility will then report the polyglot as an image.
PHP is unusually forgiving here: the interpreter only executes content inside <?php ... ?> tags and passes everything else through verbatim, so a valid image header can coexist with executable code in one file. Most other languages lack this “interpreted vs. non-interpreted region” split — a stray signature at byte 0 breaks the parser. For those, the fallback is to intercept the upload request (e.g. with Burp) and strip the extra bytes after the filter has seen them, lest the delivered reverse shell be unexecutable.
Workflow:
- Insert four ASCII placeholder characters at the front of the payload.
- Open the file in a hex editor (e.g.
hexeditor,xxdwith-rfor reverse patching) and overwrite the placeholders with the target magic number. - Run
file payload.phpto confirm the signature is now detected as the spoofed type.
Defensive notes
- Signature checks are a hint, not validation. Content-type verification should parse the actual format structure (image decoders, archive walkers) and re-encode where possible.
file/libmagicresults should never be the sole gate for executable-content decisions.
Related: xss-attacks (polyglot payloads), xxd (hex editing on the command line).
Sources
See also
- xxd
- xss-attacks
- zip-bomb — the archive-side cousin: crafted files that abuse parsers rather than spoof formats