¿Necesita Cloud Computing? Empiece ahora

Llamada y registro: ataque de retransmisión en el cliente de RPC de Winreg

Stiv Kupchik

escrito por

Stiv Kupchik

October 19, 2024

Stiv Kupchik

escrito por

Stiv Kupchik

Stiv Kupchik es experto sénior en seguridad y reside en Tel Aviv, Israel.

Stiv Kupchik, investigador de Akamai, descubrió una nueva vulnerabilidad de escalada de privilegios (EoP) en el cliente Remote Registry de Microsoft.
Stiv Kupchik, investigador de Akamai, descubrió una nueva vulnerabilidad de escalada de privilegios (EoP) en el cliente Remote Registry de Microsoft.

Resumen ejecutivo

  • Stiv Kupchik, investigador de Akamai, descubrió una nueva vulnerabilidad de escalada de privilegios (EoP) en el cliente Remote Registry de Microsoft, CVE-2024-43532, con una puntuación de CVSS de 8,8.

  • La vulnerabilidad abusa de un mecanismo de reversión en la implementación de cliente de WinReg que utiliza protocolos de transporte obsoletos de forma insegura si el transporte SMB no está disponible.

  • Al aprovechar esta vulnerabilidad, un atacante puede retransmitir los detalles de autenticación NTLM del cliente a los Servicios de certificados de Active Directory (AD CS) y solicitar un certificado de usuario para utilizarlo para una autenticación posterior en el dominio. Proporcionamos una prueba de concepto en nuestro repositorio de GitHub.

  • La vulnerabilidad se reveló de forma responsable al Centro de recursos de seguridad de Microsoft en febrero de 2024 y se le aplicó un parche como parte del Patch Tuesday de octubre de 2024.

  • Afecta a todas las versiones de Windows que no tengan el parche aplicado.

  • Nuestros resultados también se presentaron en la conferencia de seguridad informática No Hat.

Introducción

MS-RPC es la implementación de Microsoft del protocolo y el estándar de llamada a procedimiento remoto (RPC). RPC es una forma de mecanismo de comunicación entre procesos que permite a los procesos exponer funcionalidades a las que pueden llamar otros procesos. Es un componente fundamental del sistema operativo Windows y varios servicios dependen de él, desde el administrador de servicios hasta los apagados en Wininit.

Nuestro equipo ha investigado mucho sobre MS-RPC: una investigación tanto ofensiva, en la que descubrimos un gran vector de ataque en forma de ataques de almacenamiento en caché, como defensiva, en la que analizamos los mecanismos de seguridad para ello.

Esta vez, queríamos ver el RPC desde una perspectiva diferente. Cualquier protocolo que permita la comunicación y las operaciones entre diferentes equipos tiene que estar implicado con la autenticación de usuario y, de hecho, el protocolo RPC admite el paso de credenciales y la autenticación como parte de su proceso de enlace. Sin embargo, cuando hay autenticación, existe la potencialidad de la retransmisión de autenticación, por lo que nos propusimos encontrar oportunidades de retransmisión.

RPC, autenticación y lo que hay entre medias

Las sesiones RPC se gestionan por enlaces. Una aplicación cliente se conecta a una aplicación de servidor, se enlaza a la interfaz RPC necesaria y solicita ejecutar una función específica (Figura 1).

Una aplicación cliente se conecta a una aplicación de servidor, se enlaza a la interfaz RPC necesaria y solicita ejecutar una función específica (Figura 1). Fig. 1: El proceso básico de llamada RPC

La solicitud y la respuesta de enlace pueden transferir varios campos de datos, según sea necesario para la conexión. Normalmente, si no hay ninguna autenticación implicada, el enlace RPC se utiliza simplemente para decidir sobre la sintaxis de transferencia que se utilizará para encapsular parámetros de función en llamadas posteriores.

¿Qué falta en esta interacción? La autenticación, ¡por supuesto! ¿Cómo puede conocer el servidor la identidad del cliente y si dicho cliente puede realizar la acción solicitada? La respuesta es: no lo hace, a menos que el cliente haya agregado específicamente el contexto de seguridad (autenticación) al enlace. De forma predeterminada, todas las conexiones RPC están sin autenticar y no todos los servidores RPC requieren autenticación.

Para autenticar (o, en términos RPC, "agregar contexto de seguridad"), el cliente tiene que agregar datos adicionales a la solicitud de enlace, negociar el protocolo de autenticación (por ejemplo, NTLM o Kerberos) e insertar metadatos adicionales requeridos por el protocolo de autenticación (como nombre de usuario, dominio, etc.; Figura 2).

Para autenticar (o, en términos RPC, "agregar contexto de seguridad"), el cliente tiene que agregar datos adicionales a la solicitud de enlace, negociar el protocolo de autenticación (por ejemplo, NTLM o Kerberos) e insertar metadatos adicionales requeridos por el protocolo de autenticación (como nombre de usuario, dominio, etc.; Figura 2). Fig. 2: Metadatos de autenticación agregados a la solicitud de enlace RPC

Encontrar objetivos de investigación

La primera tarea a realizar es entender cómo debería verse la autenticación desde una perspectiva de API. Esto se realiza mediante una llamada a una de las funciones RpcBindingSetAuthInfo* del cliente después de crear un identificador de enlace. Si consulta la documentación de estas funciones, verá un campo llamado AuthenticationLevel, que indica el nivel de seguridad que proporciona la autenticación.

La seguridad con autenticación va más allá de solo verificar que el usuario existe y tiene permiso, también se puede usar para evitar manipulaciones. Los niveles de autenticación varían desde simplemente verificar la conexión correcta (RPC_C_AUTHN_LEVEL_CONNECT) hasta cifrar y firmar completamente todo el tráfico para asegurarse de que no se ha manipulado nada (RPC_C_AUTHN_LEVEL_PKT_PRIVACY). Por supuesto, los atacantes estarían interesados en el primer nivel, que no tiene defensas sobre el tráfico, lo que significa que es manipulable.

Sin embargo, la historia no es tan sencilla. Los ataques de retransmisión RPC no son un concepto nuevo, por lo que muchos de los clientes y servidores RPC de Windows ya tenían parches para utilizar el nivel más alto de autenticación a fin de garantizar que los ataques de retransmisión no se puedan realizar correctamente. Tendremos que explorar el sistema operativo con la esperanza de encontrar algunos fragmentos antiguos de código que todavía son inseguros por alguna razón (Figura 3).

Tendremos que explorar el sistema operativo con la esperanza de encontrar algunos fragmentos antiguos de código que todavía son inseguros por alguna razón (Figura 3). Fig. 3: Ejecución de un script IDAPython en la carpeta system32 de un servidor Windows para encontrar instancias de autenticación RPC insegura; el script se puede encontrar en nuestro repositorio GitHub

WinReg: un candidato prometedor

Como se sospecha, la lista de posibles objetivos que encontramos incluía menos del 5 % del total de servidores y clientes RPC; la mayoría simplemente ya no utilizan la autenticación insegura. Pero encontramos un candidato prometedor en advapi32.dll.

advapi32.dll es un componente principal de la API de Windows e implementa gran parte de la lógica "avanzada" de Windows (como su nombre indica). Exporta más de 800 funciones de varios campos: registro de eventos, cifrado, WMI y mucho más.

Para nuestros propósitos, hemos encontrado que, en algunas ocasiones, la función interna BaseBindToMachine llama a RpcBindingSetAuthInfoA con un nivel de autenticación RPC_C_AUTHN_LEVEL_CONNECT, que es lo que queremos. BaseBindToMachine se llama mediante la función exportada (aunque no documentada) RegConnectRegistryExW (Figura 4), si recibe una ruta UNC para un nombre de equipo.

La función exportada (aunque no documentada) RegConnectRegistryExW llama a BaseBindToMachine (Figura 4), si recibe una ruta UNC para un nombre de equipo. Fig. 4: La documentación de Rust para RegConnectRegistryExW, ya que no está documentada en MSDN

Observando BaseBindToMachine, podemos ver que en realidad contiene llamadas a ambos RpcBindingSetAuthInfoW y RpcBindingSetAuthInfoA. La primera se utiliza de forma segura, con el nivel de autenticación RPC_C_AUTHN_LEVEL_PKT_PRIVACY, mientras que la segunda utiliza el nivel de autenticación RPC_C_AUTHN_LEVEL_CONNECT, que se puede transmitir ya que no verifica la autenticidad o integridad de la conexión (Figura 5).

La primera se utiliza de forma segura, con el nivel de autenticación RPC_C_AUTHN_LEVEL_PKT_PRIVACY, mientras que la segunda utiliza el nivel de autenticación RPC_C_AUTHN_LEVEL_CONNECT, que se puede transmitir ya que no verifica la autenticidad o integridad de la conexión (Figura 5). Fig. 5: Las dos llamadas para establecer la información de autenticación

Solo tenemos que averiguar por qué hay dos llamadas en conflicto. Si observamos la lógica de la función, podemos ver que tiene una variable de puntero de función y una matriz de funciones (Figura 6). Estas funciones establecen la información de enlace RPC para utilizar un transporte RPC específico; de forma predeterminada, intenta utilizar SMB y canales con nombre pero, si falla, intenta enlazar a través de SPX, TCP/IP y otros.

Por alguna razón, una vez que revierte a cualquier otro protocolo aparte de SMB, utiliza RpcBindingSetAuthInfoA para establecer el nivel de autenticación en Connect, que no es seguro.

Solo tenemos que averiguar por qué hay dos llamadas en conflicto. Si observamos la lógica de la función, podemos ver que tiene una variable de puntero de función y una matriz de funciones (Figura 6). Fig. 6: Punteros de función y matriz de funciones dentro de BaseBindToMachine

La reversión a TCP/IP es bastante prometedora, ya que significa que podemos utilizar el método de autenticación inseguro para retransmitir el tráfico mediante un ataque de máquina intermediaria sin que el cliente se dé cuenta. Aunque también es posible con los otros protocolos de transporte, son bastante obsoletos, por lo que podría ser poco realista encontrarlos en una red moderna (y su uso podría activar algunas alarmas). TCP/IP es mucho más común como transporte RPC, por lo que debería estar bien incluso en una configuración de simulación de ciberataques.

Es importante saber que ambos, BaseBindToMachine y RegConnectRegistryExW , aceptan un indicador como argumento que impide el comportamiento de reversión, pero la función básica RegConnectRegistryW llama a RegConnectRegistryExW sin la presencia de ese indicador.

El proceso de transmisión

Transmitir es bastante simple ya que la transmisión NTLM es una técnica común. La mayor parte de la lógica que necesitamos ya está implementada en ntlmrelayx de Impacket, que es lo que más usaremos.

Creación del servidor de transmisión RPC

Lo que le falta a ntlmrelayx es un servidor RPC TCP/IP, ya que solo implementó un servidor SMB. Como tal, necesitaremos construir nuestro propio servidor de transmisión, que rechaza el canal con nombre WinReg para activar una reversión a la función de enlace TCP/IP.

Hay tres puntos críticos que debemos implementar:

  1. El asignador de terminales RPC

  2. La solicitud de enlace RPC con NTLM

  3. El desafío de NTLM

El asignador de terminales RPC es responsable de traducir los UUID de interfaz RPC en sus respectivos terminales, que en el caso del transporte TCP/IP, sería un número de puerto. A diferencia de SMB, donde los terminales son canales con nombre que son únicos y que se pueden conocer por adelantado, los terminales TCP utilizan puertos efímeros, por lo que se necesita otra capa de traducción.

La parte crítica son los problemas relacionados con NTLM. El funcionamiento del enlace RPC con NTLM consiste en enviar un mensaje de negociación NTLM durante la solicitud de enlace y, a continuación, se envía un desafío NTLM con la respuesta de enlace. Por último, el cliente tiene que enviar otro mensaje, llamado AUTH3, con la respuesta al desafío (Figura 7).

El cliente tiene que enviar otro mensaje, llamado AUTH3, con la respuesta al desafío (Figura 7). Fig. 7: Autenticación NTLM sobre enlace RPC

Para transmitir, solo tenemos que analizar los mensajes correspondientes en nuestro servidor RPC. Una vez que vemos un mensaje NTLM de negociación en un mensaje de enlace, abrimos nuestra propia conexión con nuestro servidor de autenticación de destino y también solicitamos la autenticación a través de NTLM. A continuación, solo tenemos que capturar el desafío que el servidor nos envía, retransmitirlo a la víctima y transmitir la respuesta de vuelta al servidor para obtener nuestra propia sesión autenticada.

Todo lo que tenemos que tener en cuenta es qué servidor queremos utilizar para transmitir la autenticación.

Transmisión de RPC a RPC

La primera idea sería transmitir la información a otro servidor RPC en otro equipo, como el administrador de servicios o el programador de tareas, y lograr una ejecución remota de código de esa manera. El problema con esto, sin embargo, es que ya nadie usa la autenticación insegura a través de RPC, por lo que no podemos transmitir a ningún servidor RPC de alto perfil. (Esta falta de autenticación insegura a través de RPC es la misma razón por la que teníamos objetivos de investigación limitados).

Tanto los servidores del administrador de servicios como del programador de tareas requieren RPC_C_AUTHN_LEVEL_PKT_PRIVACY, que cifra la totalidad del tráfico con el hash NTLMv2 del cliente, que no conocemos ni siquiera con la transmisión. En cambio, debemos verlo desde otro punto de vista.

De RPC a AD CS

Por suerte, los chicos de SpecterOps han trabajado mucho en AD CS; específicamente en la transmisión de NTLM a AD CS. Esto también se implementa en Impacket de forma predeterminada, por lo que todo lo que tenemos que hacer es pasar nuestra sesión autenticada al módulo HTTPAttack de Impacket y dejar que la magia ocurra por sí sola.

El servidor web HTTP de AD CS no requiere ninguna seguridad y es vulnerable a ataques de retransmisión. Al abusar de eso, una vez que nos autenticamos, podemos solicitar un certificado de usuario, que podemos utilizar por sí mismo para la autenticación, sin tener que pasar por el problema de retransmitir la autenticación de nuevo (Figura 8).

Al abusar de eso, una vez que nos autenticamos, podemos solicitar un certificado de usuario, que podemos utilizar por sí mismo para la autenticación, sin tener que pasar por el problema de retransmitir la autenticación de nuevo (Figura 8). Fig. 8: Solicitud y recepción de un certificado de AD CS tras un ataque de retransmisión NTLM

Utilizamos este certificado para autenticar el servicio LDAP en el controlador de dominio y crear un nuevo administrador de dominio persistente en el dominio comprometido (Figura 9).

Utilizamos este certificado para autenticar el servicio LDAP en el controlador de dominio y crear un nuevo administrador de dominio persistente en el dominio comprometido (Figura 9). Fig. 9: Creación de un nuevo administrador de dominio mediante un shell LDAP

Posible impacto

Una función en advapi no es interesante por sí misma, solo es impactante si algo más la está utilizando. Una búsqueda rápida de las importaciones de RegConnectRegistryExW o RegConnectRegistryExA no muestra nada en un controlador de dominio actualizado, pero una búsqueda de RegConnectRegistryW descubre muchos candidatos potenciales, como certutil y certsrv (AD CS), EFS, DFS y más.

Detección

El servicio de registro remoto no está habilitado de forma predeterminada en todos los equipos Windows. Es posible detectar su estado mediante la siguiente osquery:

  SELECT display_name, status, start_type, pid FROM services WHERE name='RemoteRegistry'

Sin embargo, esto no protege de CVE-2024-43532, ya que es un problema del cliente. Los resultados de la consulta deberían generar casos de uso reales para el registro remoto de la organización que podría necesitar tener en cuenta a la hora de reforzar los sistemas.

Para detectar clientes que utilizan cualquiera de las WinAPI vulnerables, puede utilizar la siguiente regla de YARA:

  import "pe"

rule winreg_client_import {
    meta:
        description =  "Detect binaries that rely on RegConnectRegistry"
        author = "Stiv Kupchik with Akamai Technologies"

    condition:
        pe.is_pe and (
            pe.imports(pe.IMPORT_ANY, "advapi32.dll", "RegConnectRegistryA")
            or pe.imports(pe.IMPORT_ANY, "advapi32.dll", "RegConnectRegistryW")
            or pe.imports(pe.IMPORT_ANY, "advapi32.dll", "RegConnectRegistryExA")
            or pe.imports(pe.IMPORT_ANY, "advapi32.dll", "RegConnectRegistryExW")
        )
    
}

Los usuarios de Akamai Guardicore Segmentation también pueden crear reglas de políticas para el tráfico que entra en el servicio RemoteRegistry (Figura 10).

Los usuarios de Akamai Guardicore Segmentation también pueden crear reglas de políticas para el tráfico que entra en el servicio RemoteRegistry (Figura 10). Fig. 10: Regla de política de segmentación para alertar sobre el tráfico al servicio RemoteRegistry

También es posible utilizar el seguimiento de eventos para Windows (ETW) para supervisar el tráfico RPC en ambos lados de la comunicación, tanto en el del cliente como en el del servidor. Hemos detallado este tema en nuestra presentación en Black Hat 2023 y su entrada de blog correspondiente. Los usuarios pueden utilizar nuestra herramienta de código abierto RPC Visibility para realizar un seguimiento de las llamadas RPC y filtrar el UUID de la interfaz RPC de WinReg {338cd001-2244-31f1-aaaa-900038001003}.

Conclusión

Aunque los protocolos RPC y MS-RPC se crearon pensando en la seguridad, podemos ver claramente la evolución de los principios de seguridad a lo largo del tiempo mediante el análisis de varias implementaciones de interfaz RPC. Si bien la mayoría de los servidores y clientes RPC son seguros hoy en día, es posible, de vez en cuando, descubrir reliquias de implementación insegura en diversos grados.

En este caso, hemos conseguido lograr la retransmisión NTLM, que es una clase de ataques que pertenecen más bien al pasado. Esto solo demuestra que las defensas de la red deben ser lo más exhaustivas posible, ya que nunca se sabe qué interfaz antigua está aún expuesta o en ejecución.

Cronograma de la información compartida

01/02/2024: vulnerabilidad revelada a MSRC

25/04/2024: informe cerrado como problema de documentación

17/06/2024: reapertura del informe con una PoC y una explicación mejores

08/07/2024: vulnerabilidad confirmada

08/10/2024: parche aplicado a la vulnerabilidad

19/10/2024: entrada de blog publicada



Stiv Kupchik

escrito por

Stiv Kupchik

October 19, 2024

Stiv Kupchik

escrito por

Stiv Kupchik

Stiv Kupchik es experto sénior en seguridad y reside en Tel Aviv, Israel.