Retrospectiva sobre Log4j, parte 1: Origen de la vulnerabilidad
Cronología
El 24 de noviembre de 2021, el equipo de seguridad en la nube de Alibaba informó de forma privada a la Apache Foundation de que Log4j, la popular biblioteca de registro basada en Java, presentaba una vulnerabilidad importante que podría provocar la filtración de información privada así como la ejecución remota de código (RCE). Esta vulnerabilidad había estado presente desde 2013.
El día siguiente, la Apache Foundation reservó CVE-2021-44228 y comenzó a investigar una solución. En los siguientes 12 días, se introdujeron varios cambios en el código fuente para resolver el problema, y el 9 de diciembre de 2021 se dio a conocer la vulnerabilidad públicamente.
El resultado fue innumerables intentos de ataque que han crecido a una velocidad alarmante desde entonces.
¿Qué es Log4j?
Para comprender realmente la vulnerabilidad, tenemos que entender qué es Log4j. Log4j es una biblioteca que usan de forma generalizada los desarrolladores de la comunidad Java. Proporciona un marco simple pero sólido para el registro de mensajes de error, la información de diagnóstico, etc.
Entre algunas de sus impresionantes funcionalidades se incluye la capacidad de crear registros en varios destinos, incluidos, entre otros, la consola, un archivo, un servidor remoto mediante TCP, Syslog, registros de eventos de NT y el correo electrónico. Además, permite filtrar jerárquicamente los mensajes de registro, los niveles de registro, los diseños personalizados y mucho más.
En resumen, cuenta con un conjunto completo de funciones que la convierten en una biblioteca muy atractiva para los desarrolladores, lo que ha dado lugar a su omnipresencia en todo tipo de elementos, desde aplicaciones web hasta dispositivos integrados.
Búsquedas y anidamiento
Una de las funciones realmente potentes de la Log4j son las búsquedas. Las búsquedas permiten a un desarrollador incorporar variables o expresiones en texto que Log4j evalúa automáticamente antes de presentar el resultado. Por ejemplo, un desarrollador podría escribir este código para el siguiente texto:
"${date:MM-dd-yyyy} Todos los sistemas en buen estado"
Log4j reconoce el patrón ${date:MM-dd-yyyy} como búsqueda de fecha y reemplaza dicha expresión por la fecha actual. Por ejemplo, si la fecha fuera 20 de diciembre de 2021, modificaría el texto de esta forma antes de presentar el resultado:
"12-20-2021 Todos los sistemas en buen estado"
Esto es muy útil para los desarrolladores. Sin esta funcionalidad, tendrían que escribir manualmente el código que busca la fecha, lo convierte en una cadena, lo añade al principio de la línea de registro y, a continuación, presenta el resultado. Y, aunque el código anterior no es muy difícil de escribir, no representa la lógica empresarial principal del software y acaba repitiéndose de un proyecto a otro.
Si se aprovecha la funcionalidad ya codificada en la biblioteca Log4j, los desarrolladores pueden centrarse en la diferenciación que importa a su proyecto y dejar que Log4j se encargue de todas las tareas relacionadas con el registro.
Hay muchos de estos tipos de expresiones de búsqueda compatibles con Log4j. Examinemos dos más que se mencionarán en este artículo: env y lower. env. permite incluir variables de entorno del sistema host en líneas de registro. Por ejemplo, un desarrollador registra este texto:
"El usuario actual es ${env:USER}"
Se mostrará este resultado, siempre que ejecute el software como administrador.
"El usuario actual es Administrador"
A diferencia de env y date, que introducen datos nuevos en el texto, lower se puede usar para manipular la información que ya está presente. Log4j simplemente cambia a minúsculas lo que aparece en la expresión. Con este ejemplo:
"El texto en minúsculas es ${lower:ABCDEFG}"
Se obtendrá esto:
"El texto en minúsculas es abcdefg"
Este ejemplo no parece muy interesante. ¿Por qué no escribe usted mismo en minúsculas la cadena? Su importancia es más evidente cuando vemos que Log4j permite anidar expresiones de búsqueda.
Podemos combinar las dos expresiones anteriores de la siguiente manera:
"El usuario actual en minúsculas es ${lower:${env:USER}}"
Aquí, Log4j evalúa primero la expresión ${env:USER} como Administradory después pasa esa información a lower, lo que dará como resultado administradory, en última instancia, se mostrará lo siguiente:
"El usuario actual en minúsculas es administrador"
JNDI
Aunque date, envy lower son muy interesantes y útiles, esta vulnerabilidad no existiría sin la búsqueda de JNDI. JNDI, o Java Naming and Directory Interface, es un mecanismo integrado de forma nativa en los entornos de desarrollo y ejecución de Java que permite realizar consultas simplificadas en diversos servicios de directorio para obtener información mediante una interfaz común.
Existen muchos tipos diferentes de servicios de directorio compatibles. Por ejemplo, la JNDI es compatible con consultas a servidores DNS para detectar la dirección IP de un host, así como consultas a AD y LDAP para las entradas de directorio. Incluso es compatible con consultas en el propio entorno Java para entradas de entorno, que se pueden considerar opciones de configuración especializadas para el software actual.
La expresión de búsqueda de JNDI de Log4j permite a los desarrolladores acceder a este subsistema increíblemente potente directamente a través de expresiones integradas en el texto. Por ejemplo, si un desarrollador intenta registrar la siguiente cadena:
"El host de correo actual es ${jndi:java:comp/env/mailhost}"
Log4j reconocería la expresión ${jndi:java:comp/env/mailhost} como una búsqueda de JNDI y pasaría la seudoURL de java:comp/env/mailhost al subsistema de la JNDI. La JNDI reconocería este tipo de URL como una consulta para buscar una opción de configuración llamada mailhost para el componente actual.
Imaginemos que está configurado como miservidordecorreo.ejemplo.com. La JNDI pasaría esta información a Log4j, que luego reemplazaría la expresión de búsqueda por miservidordecorreo.ejemplo.com, lo que daría lugar a:
"El host de correo actual es miservidordecorreo.ejemplo.com"
Comprender por qué existe la vulnerabilidad
En resumen, la vulnerabilidad de Log4j de Apache supuso una increíble oportunidad para los atacantes debido a la gran popularidad de la biblioteca y, en concreto, a sus funciones de búsqueda, anidamiento y JNDI. Esta funcionalidad, aunque es muy útil para los desarrolladores, también da lugar a oportunidades para enviar solicitudes que pueden exfiltrar datos o dar lugar a la RCE. Con esta información, ahora podemos comenzar a comprender mejor la vulnerabilidad y cómo se puede atacar el sistema.
Siguiente artículo
En la parte 2 de esta serie, veremos cómo se comenzó a atacar esta vulnerabilidad para lograr la exfiltración de datos y la RCE.