Site icon Sophos News

Dentro del código: cómo funciona el exploit Log4Shell

La vulnerabilidad crítica en la utilidad de registro basada en Java Log4j de Apache (CVE-2021-44228) se ha denominado la “vulnerabilidad más crítica de la última década”. También conocida como Log4Shell, la falla ha obligado a los desarrolladores de muchos productos de software a enviar actualizaciones o mitigaciones a los clientes. Y los mantenedores de Log4j han publicado dos nuevas versiones desde que se descubrió el error: la segunda elimina por completo la característica que hizo posible el exploit en primer lugar.

Como señalamos anteriormente, Log4Shell es una explotación de la función de “sustitución de mensajes” de Log4j, que permitió la modificación programática de los registros de eventos insertando cadenas que requieren contenido externo. El código que admitía esta función permitía “búsquedas” mediante las URL de la Interfaz de directorio y nombres de Java (JNDI).

Esta característica, sin darse cuenta, hizo posible que un atacante insertara texto con URL JNDI maliciosas incrustadas en solicitudes de software utilizando Log4j: URL que provocaban que el registrador cargara y ejecutara un código remoto. Para comprender mejor cuán peligrosos son los exploits de esta función, analizaremos el código que lo hace posible.

Cómo funciona el registro de Log4j

Log4j genera eventos de registro usando TTCCLayout: información de tiempo, hilo, categoría y contexto. De forma predeterminada, utiliza el siguiente patrón:

  %r [%t] %-5p %c %x - %m%n

Aquí,% r muestra el tiempo transcurrido en milisegundos desde que se inició el programa; % t es el hilo,% p es la prioridad del evento,% c es la categoría,% x es el contexto de diagnóstico anidado asociado con el hilo que genera el evento y% m es para los mensajes proporcionados por la aplicación asociados con el evento. Es este campo final donde entra en juego nuestra vulnerabilidad.

La vulnerabilidad se puede aprovechar cuando se llama a la función “logger.error ()” con un parámetro de mensaje que incluye una URL JNDI (“jndi: dns: //”, “jndi: ldap: //”, o cualquiera de los otros Interfaces definidas por JNDI discutidas en nuestra publicación anterior). Cuando se pasa esa URL, se llamará a una “búsqueda” de JNDI que puede llevar a la ejecución remota de código.

Para replicar la vulnerabilidad, analizamos una de las muchas pruebas de concepto que se han publicado, que replica cuántas aplicaciones interactúan con Log4j. En el código para logger / src / main / java / logger / App.java en este PoC, podemos ver que llama a logger.error () con un parámetro de mensaje:

package logger;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.logger;

public class App {
    private static final Logger logger = LogManager.getLogger(App.class);
    public static void main(String[] args) {
        String msg = (args.length > 0 ? args [0] : "");
        logger.error(msg);
    }
}

Para fines de depuración, cambiamos el mensaje a una URL de prueba que usa DNS con JNDI (construido con la herramienta Interactsh) para pasarlo como parámetro a la función “logger.error ()” y recorrimos el programa:

Podemos ver que después de llamar al método “logger.error ()” desde la clase “AbstractLogger” con una URL diseñada, se llama a otro método que es “logMessage”:

El método log.message crea un objeto de mensaje con la URL proporcionada:

A continuación, llama a “processLogEvent” de la clase “LoggerConfig”, para registrar el evento:

Luego llama al método “append” de la clase “AbstractOutputStreamAppender”, que agrega el mensaje al registro:

 

Donde pasa la maldad

Esto, a su vez, llama al método “directEncodeEvent”:

El método directEncodeEvent, a su vez, llama al método “getLayout (). Encode”, que formatea el mensaje de registro y agrega el parámetro proporcionado, que en este caso es la URL del exploit de prueba:

Luego crea un nuevo objeto “StringBuilder”:

StringBuilder llama al método “formato” de la clase “MessagePatternConvert” y analiza la URL proporcionada, busca “$” y “{” para identificar la URL:

A continuación, intenta identificar varios nombres y valores separados por “:” o “-“:

Luego llama al método “resolveVariable” de la clase “StrSubstitutor” que identificará las Variables, puede ser cualquiera de los siguientes:

{date, java, marker, ctx, lower, upper, jndi, main, jvmrunargs, sys, env, log4j}

Luego, el código llama al método “lookup” de la clase “Interpolator” que verificará el servicio asociado con la variable (en este caso, “jndi”):

Al encontrar “jndi”, llama al método “lookup” de la clase “jndiManager”, que evalúa el valor del recurso JNDI:

 

Después de eso, llama a “getURLOrDefaultInitCtx” de la clase “IntialContext”. Aquí es donde crea la solicitud que se enviará a la interfaz JNDI para recuperar el contexto, según la URL proporcionada. Aquí es donde el exploit comienza a hacer efecto. En este caso, la URL es para DNS:

En el caso de una URL de DNS, cuando se activa, podemos ver una consulta de DNS a la URL proporcionada con Wireshark:

(Esta es una URL de prueba y no es realmente maliciosa)

Si la URL es “jndi: ldap: //”, llama a otro método de la clase “ldapURLConext” para comprobar si la URL tiene “queryComponents”:

Después de eso, llama al método “lookup” en la clase “ldapURLContext”, la variable “name” aquí contiene la URL ldap:

Esto a su vez se conecta con el ldap “ proporcionado:

Luego, se llamará al método “flushBuffer” desde la clase “OutputStreamManager”, aquí “buf” contiene los datos devueltos desde el servidor LDAP, en este caso, el “mmm …”. cadena que vemos a continuación:

Al observar la captura de paquetes en Wireshark, vemos que la solicitud tiene los siguientes bytes:

 

Estos son los datos serializados y esto será mostrado por el cliente como podemos ver a continuación, lo que muestra que la vulnerabilidad fue explotada, observe la cadena “[principal] ERROR logger .App” en el mensaje seguida de datos:

La solución está en

Todo esto fue posible porque en todas las versiones de Log4j 2 hasta la versión 2.14 (excluyendo la versión de seguridad 2.12.2), el soporte JNDI no estaba restringido en términos de qué nombres podían resolverse. Algunos protocolos no eran seguros o pueden permitir la ejecución remota de código. Log4j 2.15.0 restringió JNDI a solo búsquedas LDAP, y esas búsquedas están limitadas a conectarse a objetos primitivos Java en el host local de forma predeterminada.

Pero la corrección en la versión 2.15.0 dejó la vulnerabilidad parcialmente sin resolver, para implementaciones con “ciertos patrones de diseño no predeterminados” para Log4j, incluidos aquellos con búsquedas de contexto (como “$$ {ctx: loginId}”) o un contexto de subproceso Patrón de mapa (“% X”, “% mdc” o “% MDC”), todavía era posible crear datos de entrada maliciosos utilizando un patrón de búsqueda JNDI que resultaba en un ataque de denegación de servicio (DOS). En las últimas versiones, todas las búsquedas se han desactivado de forma predeterminada. Esto cierra por completo la función JNDI, pero protege Log4j contra la explotación remota.

Conclusión

Log4j es un marco de registro muy popular y utilizado por una cantidad significativa de productos de software populares, servicios en la nube y otras aplicaciones. Las vulnerabilidades en las versiones anteriores a 2.15.0 hacen posible que un actor malintencionado recupere datos de una aplicación afectada o su sistema operativo subyacente, o ejecute código Java que se ejecuta con los permisos otorgados al tiempo de ejecución de Java (Java.exe en Windows sistemas). Este código puede ejecutar comandos y scripts contra el sistema operativo local, que a su vez puede descargar código malicioso adicional y proporcionar una ruta para la elevación de privilegios y acceso remoto persistente.

Si bien la versión 2.15.0 de Log4j, eliminada en el momento en que la vulnerabilidad se hizo pública, soluciona estos problemas, todavía deja a los sistemas vulnerables en algunos casos a ataques de denegación de servicio y exploits (solucionados al menos parcialmente por 2.16.0). El 18 de diciembre, se lanzó una tercera versión nueva, 2.17.0, para prevenir ataques recursivos que podrían causar una denegación de servicio). Las organizaciones deben evaluar qué versiones de Log4j se encuentran en sus aplicaciones desarrolladas internamente y aplicar parches a las versiones más recientes (2.12.2 para Java 7 y 2.17.0 para Java 8), y aplicar parches de software de los proveedores a medida que estén disponibles.

Sophos proporciona cobertura para los comportamientos de red y las cargas útiles asociadas con esta vulnerabilidad, como se detalla a continuación:

AV:

IPS:

Sophos Firewall:

Sophos Endpoint

Sophos SG UTM

 

 

 

Exit mobile version