Tutorial de Binwalk: cómo analizar y extraer firmware y ficheros ocultos paso a paso
Guía práctica de Binwalk: escaneo de firmas, extracción recursiva, entropía, carving con dd, exploración del SquashFS y uso en retos CTF de forense.
Este tutorial de Binwalk es un recorrido práctico, de principio a fin, por el análisis de un firmware: desde el primer escaneo de firmas hasta explorar el sistema de archivos extraído en busca de configuraciones y credenciales. También verás cómo interpretar la entropía, cómo extraer datos a mano con dd cuando la extracción automática falla y cómo aplicar todo esto a los retos de forense de los CTF. Si solo buscas qué es la herramienta y cómo instalarla, tienes la ficha resumida de Binwalk; aquí vamos a ensuciarnos las manos.
Marco legal y ético: trabaja solo con firmware de dispositivos que te pertenecen, con imágenes públicas que el propio fabricante o proyecto distribuye (por ejemplo, OpenWrt o la descarga oficial de actualización de tu router) o con ficheros de retos CTF. Analizar un firmware para entenderlo es investigación; usar lo que encuentres contra equipos ajenos no lo es.
Qué es una imagen de firmware (y por qué Binwalk es tan útil)
El firmware de un router, una cámara IP o un enchufe inteligente casi nunca es un único programa. Normalmente es un fichero .bin que concatena varias piezas una detrás de otra:
- Una cabecera del cargador de arranque, muy a menudo en formato uImage de U-Boot, que indica la arquitectura, el tamaño y la compresión de lo que viene detrás.
- El kernel de Linux, comprimido (LZMA y gzip son lo más habitual).
- El sistema de archivos raíz (rootfs), típicamente SquashFS, aunque también aparecen JFFS2, UBIFS o CramFS en equipos más antiguos.
- A veces, particiones de configuración, firmas digitales o simple relleno con bytes
0xFF.
No hay un índice que diga dónde empieza cada parte. Binwalk resuelve justo eso: recorre el fichero buscando firmas (números mágicos y estructuras de cabecera conocidas) y te devuelve un mapa con el desplazamiento de cada componente. Con ese mapa puedes extraer, descomprimir y analizar cada pieza por separado.
Preparar el laboratorio
Lo más cómodo es trabajar en una máquina virtual con Kali o cualquier Debian/Ubuntu (si estás empezando, mira la guía de Kali Linux para principiantes). Además de Binwalk, instala las utilidades que usa por debajo para extraer formatos:
sudo apt update
sudo apt install binwalk squashfs-tools p7zip-full cpio mtd-utils
Para formatos menos comunes necesitarás extractores adicionales que no siempre vienen empaquetados: sasquatch (SquashFS modificado por fabricantes), jefferson (JFFS2) y ubi_reader (UBI/UBIFS). Los veremos en la sección de problemas.
Una nota sobre versiones: casi toda la documentación y los tutoriales que circulan se escribieron para Binwalk v2 (Python). La v3 es una reescritura en Rust, mucho más rápida, que mantiene las opciones básicas (-e, -M, -E, -C) pero cambia o elimina otras. En este tutorial usamos la sintaxis de la v2; si tienes la v3, comprueba cada opción con binwalk --help antes de dar nada por hecho.
Paso 1: reconocimiento con file, strings y xxd
Antes de lanzar Binwalk, dedica un minuto a mirar el fichero con herramientas básicas. Te dan contexto y te ayudan a detectar errores de interpretación más tarde.
file firmware.bin
ls -l firmware.bin
xxd firmware.bin | head -n 5
strings -n 8 firmware.bin | head -n 40
file solo mira el principio del fichero, así que a menudo dirá simplemente data o reconocerá la cabecera u-boot. xxd te enseña los primeros bytes: una cabecera uImage empieza por la firma 27 05 19 56. Y strings suele revelar el nombre del modelo, la versión del firmware y la de U-Boot o del kernel, datos muy útiles para buscar después información pública sobre ese dispositivo.
Paso 2: escaneo de firmas
binwalk firmware.bin
Una salida típica de un router doméstico con procesador MIPS se parece a esto (simplificada y con valores ilustrativos):
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
0 0x0 uImage header, header size: 64 bytes, ... OS: Linux,
CPU: MIPS, image type: OS Kernel Image,
compression type: lzma, image name: "Linux Kernel Image"
64 0x40 LZMA compressed data, properties: 0x5D,
dictionary size: 8388608 bytes, ...
1310784 0x140040 Squashfs filesystem, little endian, version 4.0,
compression:xz, size: 2850000 bytes, 812 inodes, ...
Cómo leerla:
- uImage header en 0x0: confirma que el arranque lo gestiona U-Boot y te dice la arquitectura (MIPS, ARM...). La necesitarás más adelante para analizar binarios.
- LZMA en 0x40: justo después de los 64 bytes de cabecera empieza el kernel comprimido.
- Squashfs en 0x140040: aquí está lo interesante, el sistema de archivos con los programas, scripts y configuración del dispositivo.
Fíjate en que los desplazamientos encajan entre sí: el kernel ocupa desde 0x40 hasta poco antes del SquashFS. Cuando las piezas no encajan (firmas en medio de otros componentes, tamaños imposibles), es señal de falsos positivos.
Paso 3: extracción automática y recursiva
binwalk -e firmware.bin
La opción -e extrae y descomprime todo lo que reconoce. En la v2 el resultado aparece en _firmware.bin.extracted/, con ficheros nombrados por su desplazamiento en hexadecimal (40, 40.7z, 140040.squashfs) y, si todo va bien, una carpeta squashfs-root/ ya desempaquetada.
Cuando hay capas dentro de capas (un tar dentro de un gzip que contiene otra imagen), usa el modo recursivo:
binwalk -Me firmware.bin
-M (de matryoshka) vuelve a escanear cada fichero extraído. En la v2 puedes limitar la profundidad con -d y elegir el directorio de salida con -C. Ojo: en firmwares grandes la recursión puede generar cientos de ficheros y ocupar mucho disco.
Desde la v2.3, si ejecutas la extracción como root, Binwalk se niega por seguridad (los extractores externos procesan datos no confiables). Lo correcto es ejecutarlo como usuario normal; la opción --run-as=root existe solo para cuando sabes lo que haces.
Paso 4: análisis de entropía para encontrar datos comprimidos o cifrados
binwalk -E firmware.bin
La entropía mide lo "aleatorios" que parecen los datos, en una escala de 0 a 1. Interpretarla es más útil de lo que parece:
| Patrón de entropía | Qué suele significar |
|---|---|
| Cerca de 0 | Relleno (0x00 o 0xFF), zonas vacías de la flash. |
| Entre 0,3 y 0,7, irregular | Código sin comprimir, texto, tablas. |
| Meseta plana cercana a 1 con firmas conocidas | Datos comprimidos (LZMA, xz, gzip). Normal. |
| Meseta plana cercana a 1 en todo el fichero y sin firmas | Probablemente cifrado u ofuscado. |
En la v2, -E muestra los "bordes" de subida y bajada de entropía y genera un gráfico; con -N evitas el gráfico y te quedas solo con el texto. Combinarlo con el escaneo de firmas (binwalk -B -E firmware.bin) te permite comprobar si cada meseta de entropía alta coincide con una firma de compresión. Si encuentras una región de entropía alta que ninguna firma explica, ahí hay algo que Binwalk no conoce: un formato propietario, una partición cifrada o datos que conviene examinar a mano.
Un firmware cifrado de principio a fin no se puede "romper" con Binwalk. Las vías habituales son buscar una versión anterior sin cifrar, analizar el firmware de transición que algunos fabricantes publican para migrar al formato cifrado o, en tu propio dispositivo, leer directamente el chip de memoria flash.
Paso 5: identificar la arquitectura con el escaneo de opcodes
binwalk -A firmware.bin
En la v2, -A busca patrones típicos de instrucciones (por ejemplo, prólogos de función) de arquitecturas comunes como ARM, MIPS, PowerPC o x86. Es útil cuando no hay cabecera uImage que te diga la CPU, por ejemplo en firmwares de microcontroladores o en blobs sueltos. Si ves cientos de coincidencias de "MIPSEL instructions" y casi ninguna de otras arquitecturas, ya sabes qué procesador elegir al cargarlo en un desensamblador. Esta opción no está garantizada en la v3, así que compruébalo en tu versión.
Paso 6: extracción manual con dd
A veces -e falla o extrae algo corrupto. Como Binwalk ya te ha dado el desplazamiento, puedes recortar tú mismo el fragmento (carving). Con los valores del ejemplo anterior:
dd if=firmware.bin of=rootfs.sqsh bs=1 skip=1310784 count=2850000
file rootfs.sqsh
unsquashfs -d rootfs rootfs.sqsh
bs=1 es lento con ficheros grandes. Con GNU dd puedes usar bloques grandes y seguir indicando bytes exactos:
dd if=firmware.bin of=rootfs.sqsh bs=4M skip=1310784 count=2850000 iflag=skip_bytes,count_bytes
Si no conoces el tamaño exacto, recorta desde el desplazamiento hasta el final del fichero; la mayoría de descompresores ignoran los bytes sobrantes. Después confirma con file que la cabecera es la esperada.
Paso 7: explorar el sistema de archivos extraído
Con el squashfs-root/ delante tienes, en la práctica, el disco duro del dispositivo. Aquí es donde realmente se aprende cómo funciona por dentro. Un orden de revisión que funciona bien:
Usuarios y contraseñas
cd _firmware.bin.extracted/squashfs-root
cat etc/passwd etc/shadow 2>/dev/null
Busca cuentas con un hash de contraseña fijo dentro de la imagen: significa que todos los dispositivos de ese modelo comparten la misma contraseña de fábrica para esa cuenta.
Arranque y servicios
cat etc/inittab
ls etc/init.d/ etc/rc.d/ 2>/dev/null
grep -rn "telnetd\|dropbear\|httpd" etc/ 2>/dev/null
Los scripts de arranque te dicen qué servicios se levantan: un telnetd activo por defecto o una consola de depuración son hallazgos clásicos.
Secretos hardcodeados
grep -rniE "passw(or)?d|secret|api[_-]?key|token" etc/ www/ usr/ 2>/dev/null | head -n 50
grep -rl "BEGIN .*PRIVATE KEY" . 2>/dev/null
find . -name "*.pem" -o -name "*.key" -o -name "*.crt"
Claves privadas TLS o SSH incluidas en la imagen, credenciales de servicios en la nube o contraseñas en scripts CGI aparecen con más frecuencia de la que debería. Si lo encuentras en un producto comercial, lo responsable es notificarlo al fabricante (divulgación coordinada), no publicarlo.
Interfaz web y binarios
ls www/ usr/www/ 2>/dev/null
file bin/busybox usr/sbin/*
strings -n 6 bin/busybox | grep -i "busybox v"
file te confirma la arquitectura (por ejemplo, ELF 32-bit MSB executable, MIPS) y strings la versión de BusyBox u otros componentes, que puedes cotejar con vulnerabilidades públicas. Los binarios propios del fabricante (el servidor web, los CGI) son los candidatos para un análisis a fondo con Ghidra. Si quieres ejecutar alguno sin el hardware, qemu-user-static permite lanzar binarios de otra arquitectura apuntando a la raíz extraída, por ejemplo qemu-mips-static -L . ./bin/busybox.
Binwalk en retos CTF de forense y esteganografía
En los CTF el patrón más habitual es un fichero que esconde otro concatenado al final. El flujo de trabajo:
file reto.png
binwalk reto.png
xxd reto.png | tail -n 20
binwalk -e reto.png
Un PNG termina en el bloque IEND y un JPEG en los bytes FF D9. Si xxd muestra datos después de esa marca, o Binwalk detecta un Zip archive data a mitad del fichero, ya tienes la pista. Si el ZIP está protegido, vuelve a la imagen: los metadatos (exiftool), strings y el propio enunciado suelen esconder la contraseña. Para decodificar lo que salga (Base64, hexadecimal, XOR...), CyberChef es la navaja suiza.
Saber qué no es sospechoso te ahorra mucho tiempo:
- En un PNG, Binwalk casi siempre muestra Zlib compressed data: es normal, los datos de la imagen (bloques IDAT) van comprimidos con zlib.
- En un JPEG con EXIF puede aparecer un segundo JPEG image data: suele ser la miniatura que incrusta la cámara.
- Un PDF está lleno de flujos zlib; eso, por sí solo, tampoco indica nada oculto.
Binwalk solo detecta ficheros incrustados o concatenados. Si el mensaje está oculto en los bits menos significativos de los píxeles (LSB), necesitarás herramientas específicas como zsteg o steghide.
Problemas frecuentes y cómo resolverlos
Detecta el SquashFS pero no lo extrae
Es el problema número uno. Muchos fabricantes usaron versiones modificadas de SquashFS (variantes antiguas de LZMA, firmas alteradas) que unsquashfs no entiende. La solución habitual es sasquatch, un unsquashfs parcheado para esas variantes; con él instalado, Binwalk lo usa automáticamente. Recorta el fragmento con dd y pruébalo también a mano para ver el mensaje de error real.
JFFS2, UBI y otros formatos
Si el escaneo muestra JFFS2 filesystem, instala jefferson; si muestra UBI image, usa ubi_reader. Sin estos extractores, Binwalk identifica el formato pero deja el fichero sin desempaquetar, a veces sin un aviso claro.
Falsos positivos
Algunas firmas son muy cortas y aparecen por pura casualidad dentro de datos comprimidos: cabeceras LZMA con tamaños absurdos, certificados que no lo son, tablas de símbolos de VxWorks en un firmware Linux... Desconfía cuando la firma cae dentro de una región que ya pertenece a otro componente o cuando los tamaños no tienen sentido. En la v2 puedes acotar el escaneo con -y (incluir solo ciertas firmas) o -x (excluirlas), por ejemplo binwalk -y squashfs firmware.bin.
Ninguna firma reconocible
Revisa la entropía. Si es alta y plana, probablemente está cifrado (ver paso 4). Si es baja o irregular, puede que el fichero use una cabecera propietaria: busca cadenas con strings, compara con otras versiones del mismo firmware y prueba a extraer desde el primer desplazamiento donde los datos tengan sentido.
Chuleta rápida (sintaxis v2)
| Comando | Para qué |
|---|---|
binwalk fw.bin | Escaneo de firmas (mapa del fichero) |
binwalk -e fw.bin | Extraer lo reconocido |
binwalk -Me fw.bin | Extracción recursiva |
binwalk -e -C salida/ fw.bin | Elegir el directorio de salida |
binwalk -E -N fw.bin | Entropía en texto, sin gráfico |
binwalk -A fw.bin | Buscar opcodes para deducir la arquitectura |
binwalk -y squashfs fw.bin | Mostrar solo las firmas que coincidan con un filtro |
Siguientes pasos
Una buena forma de practicar sin riesgos es descargar la imagen oficial de OpenWrt para cualquier router, o la actualización que publica el fabricante de tu propio equipo, y repetir todos los pasos: mapa de firmas, entropía, extracción, dd manual y revisión del rootfs. Cuando te sientas cómodo, salta a los binarios con Ghidra. Y si prefieres aprender forense y análisis de ficheros con retos guiados y progresivos, tienes la Academia de Hackers en Acción.