La extensión miente: identifica archivos por sus magic bytes
Renombras factura.pdf.exe a factura.pdf y el icono cambia. El fichero, no. La extensión es solo una etiqueta que el sistema operativo usa para decidir con qué programa abrirlo: no dice nada sobre lo que hay dentro. Un analista no se fía de ella. Se fía de los magic bytes.
Qué son los magic bytes
Casi todos los formatos de fichero empiezan por una firma fija en sus primeros bytes: una marca que dice «soy un PNG», «soy un PDF». Es como el ADN del archivo. Da igual cómo lo llames: si empieza por %PDF-, es un PDF; si empieza por MZ, es un ejecutable de Windows.
PNG 89 50 4E 47 0D 0A 1A 0A ‰PNG␍␊␚␊
JPEG FF D8 FF ÿØÿ
GIF 47 49 46 38 GIF8
PDF 25 50 44 46 2D %PDF-
ZIP 50 4B 03 04 PK··
GZIP 1F 8B
ELF 7F 45 4C 46 ·ELF (binario Linux)
PE 4D 5A MZ (ejecutable Windows)
PHP 3C 3F 70 68 70 <?php
La extensión es una etiqueta, no el contenido
Hay tres cosas que la gente confunde con «el tipo del fichero», y las tres se pueden falsear:
- La extensión (
.jpg): la eliges tú. Windows además la oculta por defecto, así quefoto.jpg.exese ve comofoto.jpg. Es la doble extensión, un clásico del phishing. - El
Content-Typeque manda el navegador al subir: lo pone el cliente, así que un atacante lo cambia a su gusto. - El icono: lo pinta el sistema a partir de la extensión. Puro maquillaje.
La firma, en cambio, está dentro del fichero. Para cambiarla de verdad hay que reconstruir el archivo, no solo renombrarlo.
Dónde te muerde esto
Subida de archivos
Un formulario que solo valida la extensión o el Content-Type es un coladero. El atacante sube una webshell con nombre inocente:
shell.php → se renombra a shell.jpg
Content-Type: image/jpeg (falso, lo pone el atacante)
Y para saltarse validaciones que sí miran la firma, se usa un políglota: un fichero válido como imagen y como código. Empieza con una cabecera GIF real y esconde PHP detrás:
GIF89a;<?php system($_GET['c']); ?>
Para el validador «empieza por GIF8, es una imagen». Para el intérprete de PHP, es código ejecutable.
Forense y CTF
Al revés que el atacante, aquí tú descubres lo escondido. Un gatito.jpg que no abre como imagen y que en hex empieza por PK es en realidad un ZIP con algo dentro. Un PNG con datos pegados después del marcador de fin. Es pan de cada día en los retos de forense y esteganografía.
<?php.Los contenedores que empiezan por «PK»
Un detalle que despista mucho: un montón de formatos modernos son, por dentro, ficheros ZIP. Todos empiezan por 50 4B 03 04 (PK··):
.docx .xlsx .pptx (Office)
.apk .jar (Android / Java)
.epub (libros)
.odt (LibreOffice)
Así que si una firma dice «ZIP» pero el nombre es informe.docx, no hay contradicción: renómbralo a .zip, ábrelo y verás su estructura interna (XML, imágenes, classes.dex…). Media investigación de un APK empieza aquí.
Cómo comprobarlo tú mismo
En Linux/macOS tienes dos comandos de bolsillo:
# Ver los primeros bytes en hexadecimal + ASCII
hexdump -C sospechoso.jpg | head
# Preguntar al sistema por el tipo real (usa la firma, no la extensión)
file sospechoso.jpg
# → sospechoso.jpg: PHP script, ASCII text
Ese file que te contradice la extensión es justo la señal que buscas. Y si no tienes terminal a mano, el identificador de arriba hace lo mismo desde el navegador.
Defensa: si tu app recibe archivos
- Valida por firma, no por extensión ni
Content-Type. Comprueba los magic bytes en el servidor contra una lista blanca de formatos permitidos. - Renombra al guardar. Genera tú el nombre y la extensión a partir del tipo detectado; nunca uses el que envió el usuario.
- Sirve las subidas fuera de la webroot o desde un dominio sin ejecución de código, para que un
.phpcolado nunca se interprete. - Cuidado con los contenedores: «es un ZIP válido» no es «es seguro». Un
.docxo un.apkson ZIP con contenido activo.
En resumen
- ✅ La extensión, el icono y el
Content-Typelos controla quien crea el fichero: no son prueba de nada. - ✅ Los magic bytes (los primeros bytes) son la firma real del formato.
- ✅ Ataque: disfrazar un ejecutable o una webshell de imagen (doble extensión, políglotas).
- ✅ Forense/CTF: destapar lo que se esconde tras una extensión falsa.
- ✅ Defensa: validar por firma en el servidor y no confiar nunca en la extensión.
La próxima vez que veas un .jpg que pesa 4 MB y no abre, ya sabes por dónde empezar: mírale los primeros bytes.