The extension is a suggestion
Windows decides how to open a file from its extension. Email gateways, users and a surprising number of upload forms do the same. But the extension is just part of the filename, and anyone can rename payload.exe to invoice.pdf.
The content of a file is harder to fake. Most binary formats start with a fixed sequence of bytes, a file signature or magic number, so that parsers can check they are reading the right thing. The Unix file command, libmagic, and most DFIR tools identify files this way. When the extension and the magic bytes disagree, you have found something worth a second look.
Signatures you should recognise on sight
You do not need to memorise hundreds. These cover most of what turns up in phishing, malware triage and forensics:
| Format | Hex at offset 0 | ASCII view | Notes |
|---|---|---|---|
| Windows PE (EXE, DLL, SYS) | 4D 5A |
MZ |
The PE\0\0 header sits at the offset stored at 0x3C |
| ELF | 7F 45 4C 46 |
.ELF |
Linux and many IoT binaries |
| Mach-O (64-bit) | CF FA ED FE |
Little-endian on disk | |
| Universal / Java class | CA FE BA BE |
Shared by Mach-O fat binaries and Java classes, check further | |
25 50 44 46 2D |
%PDF- |
Readers tolerate it a little after offset 0 | |
| ZIP (and OOXML, JAR, APK) | 50 4B 03 04 |
PK.. |
50 4B 05 06 is an empty archive |
| OLE2 / CFB (legacy .doc, .xls, .msi) | D0 CF 11 E0 A1 B1 1A E1 |
Old Office and MSI installers | |
| RTF | 7B 5C 72 74 66 |
{\rtf |
Common exploit carrier |
| gzip | 1F 8B |
||
| 7-Zip | 37 7A BC AF 27 1C |
7z..'. |
|
| RAR | 52 61 72 21 1A 07 |
Rar!.. |
Followed by 00 (v4) or 01 00 (v5) |
| PNG | 89 50 4E 47 0D 0A 1A 0A |
.PNG.... |
|
| JPEG | FF D8 FF |
Ends with FF D9 |
|
| GIF | 47 49 46 38 37 61 / 39 61 |
GIF87a / GIF89a |
|
| Windows shortcut (LNK) | 4C 00 00 00 01 14 02 00 |
L... |
Header size 0x4C then the shell link CLSID |
| ISO 9660 | 43 44 30 30 31 at 0x8001 |
CD001 |
Not at offset 0, see below |
The file signatures tool is a quick reference for these and many more, and the MIME types cheat sheet maps formats to the Content-Type values you will see in mail and web logs.
Checking a header from the command line is one line:
xxd -l 16 suspicious.pdf
# 00000000: 4d5a 9000 0300 0000 0400 0000 ffff 0000 MZ..............
file suspicious.pdf
# suspicious.pdf: PE32+ executable (GUI) x86-64, for MS Windows
That "PDF" is a Windows executable.
Extension spoofing tricks
Renaming is the crude version. Attackers have several better tricks to make the displayed name lie:
- Double extensions.
invoice.pdf.exeshows asinvoice.pdfwhen Explorer hides known extensions, which is the default. - Right-to-left override. The Unicode character
U+202Ereverses the display order of what follows, soinvoice_[RLO]fdp.exerenders asinvoice_exe.pdf. - Padding with spaces.
report.pdf .exepushes the real extension out of view in narrow columns. - Icon spoofing. A PE file can embed any icon, including a PDF or Word icon.
- Less familiar executable extensions.
.scr,.pif,.com,.cpl,.hta,.js,.vbs,.wsf,.lnk,.iso,.imgare all capable of running code or delivering it, and users rarely recognise them.
The defence is the same in every case: identify by content, then decide. Mail gateways and upload handlers should check magic bytes and reject mismatches; analysts should run file (or equivalent) before trusting a name.
Containers: when the signature is just the wrapper
Many modern formats are containers, which means the magic bytes tell you the wrapper, not what is inside.
OOXML is a ZIP
.docx, .xlsx and .pptx files start with PK\x03\x04 because they are ZIP archives of XML parts. A ZIP signature on a .docx is normal; what matters is the contents:
unzip -l invoice.docx
# [Content_Types].xml
# word/document.xml
# word/_rels/document.xml.rels
# word/vbaProject.bin <- macros (normally only in .docm)
Things worth checking inside an OOXML file: vbaProject.bin (macros), external relationship targets in .rels files (remote template injection), embedded OLE objects, and unexpected executables in media/. For spreadsheets, the XLSX inspector surfaces these parts without opening the file in Excel.
Legacy .doc and .xls are OLE2 containers (D0 CF 11 E0). A file named .docx that starts with D0 CF 11 E0 is mislabelled, which is a common way to get an old macro document past a filter that only expects OOXML.
ISO, IMG and LNK
After Microsoft started blocking macros in files from the internet by default in 2022, many campaigns shifted to disk images and shortcuts. The pattern: an .iso or .img (sometimes inside a ZIP) contains an .lnk that runs a script or DLL also inside the image.
- ISO 9660 images have their identifier
CD001at offset0x8001(the first 32 KB is a system area that may be empty). Tools that only read the first few bytes will miss it, so check that offset explicitly. - LNK files start with the header size
4C 00 00 00followed by a fixed CLSID. Parse them with a dedicated LNK parser to see the target path, arguments, working directory and sometimes the original machine's metadata. The arguments field is where thecmd /corpowershell -encchain lives.
Disk images also historically mattered for Mark-of-the-Web: files extracted from a mounted image did not carry the internet-zone marker, which weakened SmartScreen and Office protections. Microsoft addressed this in late 2022 updates, but unpatched systems and other container formats keep the technique alive.
Do not double-click to "see what's inside". Mounting an ISO or opening a container on your workstation is enough to run an auto-executing payload or hand a shortcut to a curious user. List and extract contents with command-line tools inside an isolated analysis VM.
Polyglots: one file, two valid types
A polyglot is a file that is valid in two formats at once. They exist because parsers look in different places:
- ZIP readers find the central directory at the end of the file, so data can be prepended to a ZIP and it still opens.
- PDF readers tolerate leading junk before
%PDF-. - Image formats like JPEG and GIF stop parsing at their end marker and ignore trailing data.
So a file can start with valid GIF bytes, display as an image, and still be a working ZIP or script. Attackers use polyglots to pass upload filters ("it's a valid image") and to hide second stages. Defensive takeaways:
- Check both ends of a file, not just the header: is there data after the JPEG
FF D9end marker or the PNGIENDchunk? - Run a tool that scans for embedded signatures throughout the file (for example
binwalk), not just at offset 0. - When a file "opens fine" in one viewer, that is not evidence it is only that type.
Carving: recovering files without a filesystem
When the filesystem metadata is gone (deleted files, unallocated space, memory dumps, packet captures), you can still find files by their signatures. Carving scans raw data for headers, then for footers or a plausible length, and extracts what lies between.
# Scan a disk image for embedded file signatures
binwalk disk.img
# Signature-based carving with common open-source tools
foremost -i disk.img -o carved/
photorec disk.img
Carving works best for formats with clear headers and footers (JPEG, PNG, PDF) and worst for fragmented files, since it assumes contiguous data. Expect false positives: a two-byte signature like MZ appears by chance in any large data set, so validate carved PE files by checking for PE\0\0 at the offset stored at 0x3C.
Once you have carved or extracted a binary, hash it with the hash generator and look it up on /hash/. If an exact hash finds nothing, similarity hashing often does: see fuzzy hashing with ssdeep, TLSH and imphash.
A triage routine for unknown files
For every attachment or artifact that crosses your desk:
- Read the first 16 bytes (
xxd -l 16) and compare against the signatures reference. Does it match the extension? - Run
filefor a second opinion, and check known non-zero offsets (ISO at0x8001). - If it is a container, list contents before extracting. Look for macros, external relationships, LNKs, scripts and executables.
- Check the tail for appended data and scan for embedded signatures.
- Hash and look up the file and anything extracted from it.
- Record the true type in your case notes, not the claimed one.
The phishing email analysis guide shows where this routine fits into a full attachment triage.
Takeaways
- Extensions are labels; magic bytes are evidence. Block or flag mismatches at mail gateways and upload handlers.
- Know a dozen signatures by heart:
MZ,%PDF-,PK\x03\x04,D0 CF 11 E0,{\rtf,7F ELF,1F 8B, PNG and JPEG. - Containers hide their contents. OOXML is ZIP, legacy Office is OLE2, ISO identifies itself at
0x8001, LNK hides commands in its arguments. - Polyglots exist. Check the tail and scan the whole file, not just offset 0.
- Carving needs validation. Short signatures match by accident; confirm with deeper structure.
Trust what the bytes say. The filename was written by the attacker.