Capacidades defensivas dentro de Windows para RPC
Tabla de contenido
El contenido de este blog se presentó originalmente en BlackHat USA 2023.
MS-RPC: Desglosar el protocolo para detectar ataques
Seguimos con nuestra inmersión en MS-RPC, con otra entrada de blog. Pero esta vez, en lugar de centrarnos en el lado ofensivo y buscar vulnerabilidades, analizaremos algunas de las capacidades defensivas integradas de Windows. Veremos cómo utilizarlas para echar un vistazo a lo que está pasando tras RPC, con suerte detectando actividad delictiva a lo largo del camino.
MS-RPC es parte integral del sistema operativo Windows, lo que significa que muchas rutas de movimiento lateral pasan por él. Ataques como PSExec, Tarea remota programada, DCSynce PetitPotam se lleva a cabo a través de protocolos MS-RPC y puede resultar difícil distinguir entre tráfico de red benigno y malicioso, con solo metadatos de red tradicionales (puerto de origen y destino y dirección IP; a veces también información de proceso).
Reforzaremos nuestra visibilidad con Event Tracing for Windows (ETW), un mecanismo integrado de seguimiento y supervisión en el sistema operativo Windows. ETW nos proporciona una valiosa fuente de información, específicamente para RPC, especialmente cuando se compara con los metadatos de red tradicionales.
El concepto de seguimiento de eventos RPC mediante el uso de su proveedor ETW no es nuevo, y hay muchos recursos y herramientas buenos ya disponibles para ello (porporcionamos enlaces a algunos de ellos en nuestra sección Referencias ; háganos saber si tiene alguno más). La mayoría de las investigaciones existentes se centran en eventos del lado del cliente, que los atacantes pueden manipular o modificar el programa para eludir el registro por completo. En su lugar, nos centraremos en detectar ataques mediante eventos del lado del servidor, que están fuera del alcance de los atacantes, y veremos las consideraciones únicas que necesitamos para analizarlos.
En esta publicación, veremos cómo consumir y analizar eventos del proveedor de RPC ETW, y cómo analizar eventos en busca de actividad potencialmente maliciosa. Con el proveedor de ETW, también podemos ver la operación exacta que se solicita, lo que nos proporciona una granularidad mucho más precisa con la que podemos detectar ataques. Veremos exactamente cómo funciona en un momento.
Recúerdeme: ¿Qué es RPC?
RPC significa llamada a procedimiento remoto y es una forma de comunicación entre procesos (IPC). Específicamente, este protocolo está diseñado para permitir la invocación remota de funciones entre diferentes procesos. En nuestro caso, nos centraremos en la implementación de Microsoft, MS-RPC.
MS-RPC está diseñado como un modelo cliente-servidor. El servidor define la interfaz que expondrá utilizando el lenguaje de definición de interfaz (IDL). Dentro de la IDL tenemos un identificador único universal (UUID) para la interfaz, así como las definiciones de función para las funciones que expone (Figura 1).
[
uuid(12345678-4000-2006-0000-20000000001a)
]
interface Test
{
void Foo([in] int number, [in] char *message);
void Bar([out] int * result);
}
Fig. 1: Ejemplo de definición de interfaz IDL
La comunicación se transmite a través de determinados protocolos de transporte y cada transporte tiene su propio tipo de punto final (Figura 2). La mejor manera de explicar esto es con un ejemplo: La comunicación RPC se puede llevar a cabo a través de TCP, en cuyo caso el transporte es TCP y el punto final es el socket TCP, identificado por un número de puerto.
Transportes |
Terminales |
---|---|
TCP Canal con nombre UDP ALPC HTTP Conector Hyper-V |
<número de puerto> <nombre de canal> <número de puerto> <puerto ALPC> <nombre de host> <Identificador único universal (UUID)> |
Fig. 2: Los protocolos de transporte comunes y sus respectivos tipos de punto final
Es importante tener en cuenta que aunque las funciones tienen un nombre legible en el archivo IDL, se identifican de forma diferente en la red. En lugar de un nombre de cadena, se identifican mediante un entero, denominado opnum (abreviatura del número de operación). Normalmente se asigna según el orden de aparición de las funciones en la definición de interfaz IDL (de modo que, en el ejemplo de la figura 1, Foo se identificará mediante opnum 0, mientras que Bar será opnum 1). Esto es importante más adelante, cuando necesitaremos conocer el número de operaciones de las funciones relevantes para identificarlas en los datos que veremos.
Para obtener una descripción más amplia y detallada de MS-RPC, puede consultar nuestra publicación anterior, o una de nuestras presentaciones de conferencia en Hexacon o DEF CON en el blog de Akamai.
Definir ETW
Seguimiento de eventos para Windows (ETW) es un mecanismo integrado de seguimiento y registro, implementado dentro del kernel de Windows. Funciona en un modelo proveedor-consumidor; los proveedores envían eventos al kernel, que los redirecciona a cualquier programa consumidor. Tanto los proveedores como los consumidores tienen que registrarse en el kernel con antelación (Figura 3).
Además, puesto que el enrutamiento de eventos lo gestiona el kernel, si los proveedores envían eventos pero no hay consumidores para ellos, los eventos simplemente se descartan y se envían al vacío.
Microsoft-Windows-RPC
El proveedor de RPC ETW se implementa dentro del tiempo de ejecución de RPC, rpcrt4.dll. Tiene 13 eventos diferentes, pero nos interesan principalmente cuatro de ellos: los eventos 5 y 7 para el inicio y parada de llamadas de cliente (respectivamente), y los eventos 6 y 8 para el inicio y parada de llamadas de servidor. Nos centraremos en los eventos de inicio de llamada (Figura 4), ya que proporcionan la mayor parte de la información. (Los eventos de parada de llamada simplemente indican el estado de devolución de RPC). Los eventos de cliente y servidor comparten el mismo formato.
<template tid="RpcServerCallStartArgs_V1">
<data name="InterfaceUuid" inType="win:GUID"/>
<data name="ProcNum" inType="win:UInt32"/>
<data name="Protocol" inType="win:UInt32"/>
<data name="NetworkAddress" inType="win:UnicodeString"/>
<data name="Endpoint" inType="win:UnicodeString"/>
<data name="Options" inType="win:UnicodeString"/>
<data name="AuthenticationLevel" inType="win:UInt32"/>
<data name="AuthenticationService" inType="win:UInt32"/>
<data name="ImpersonationLevel" inType="win:UInt32"/>
</template>
Fig. 4: Esquema de eventos de inicio de llamada ETW RPC
En teoría, los datos del evento deberían proporcionarnos todos los metadatos que necesitamos para obtener información sobre el tráfico RPC; ahora sabemos lo que se solicita desde la interfaz UUID y opnum, y también sabemos la dirección de origen o destino (dependiendo de si estamos mirando eventos de cliente o servidor), a través del campo NetworkAddress. No puede ser tan simple, ¿verdad?
No lo es. Resulta que el tiempo de ejecución de RPC no rellena el campo NetworkAddress al procesar eventos de llamada al servidor, por lo que tendremos que encontrar otra forma de encontrar esos datos si queremos tener los metadatos de conexión. Los eventos de cliente tienen este campo completado.
Esto plantea la siguiente pregunta: ¿Podemos ignorar los eventos del servidor y confiar únicamente en el cliente? La respuesta es que no. Puesto que estamos intentando encontrar un comportamiento malicioso, que se originará en el equipo controlado del atacante, no podemos estar seguros de que no van a alterar el proveedor de ETW del lado del cliente (y desactivarlo o bloquear sus eventos), ni podemos estar seguros de que incluso pasarán por el tiempo de ejecución de RPC.
La popular biblioteca Impacketde python, que se utiliza a menudo en pruebas de concepto de ataque (POC) y herramientas (y contiene implementaciones de ataques a la red, como PSExec), implementa el tráfico RPC en su interior, de modo que cualquier atacante que lo utilice eludirá el tiempo de ejecución de RPC y no se registrará en el proveedor de ETW. Dado que los eventos de servidor están fuera del control de los atacantes, es más prudente confiar en ellos, por lo que ahora nos centraremos en cómo obtener los datos de red de otro lugar y relacionarlos con el evento de RPC.
Coincidencia de eventos de RPC con flujos de red
Nos tomamos un descanso de nuestro enfoque en el proveedor de ETW RPC para mirar a otros proveedores de ETW, concretamente los proveedores de TCP y SMB . Estos dos protocolos son los protocolos de transporte comunes para el tráfico de RPC. Como dijimos que el tipo de extremo RPC depende del protocolo de transporte, podemos hacer coincidir el extremo (número de puerto, nombre de canal, etc.) tal como lo recibimos del proveedor de RPC con el valor respectivo del proveedor de transporte de ETW.
Para TCP, es bastante sencillo. Veamos el ID del evento 1017, llamado TcpAcceptListenerComplete, que se activa una vez que se ha completado el establecimiento de enlace de tres direcciones TCP.
Tiene dos campos (básicamente): LocalAddress y RemoteAddress (sin embargo, en nuestro caso, puesto que estamos viendo eventos de servidor, local se refiere al servidor mientras que remoto se refiere al cliente). Los valores de los campos de dirección están en formato binario y contienen la familia de direcciones, la dirección IP y el número de puerto (Figura 6).
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
---|---|---|---|---|---|---|---|
Familia de direcciones |
Número de puerto |
Valor de dirección (IP si AF_INET) |
Fig. 6: Formato de campo binario de dirección
Todo lo que tenemos que hacer es extraer la dirección IP (del cliente) del campo RemoteAddress y realizar un seguimiento con el puerto (de destino) en el campo LocalAddress . Ahora, en el momento en que obtenemos un evento RPC en nuestro servidor, a través del mismo número de puerto TCP, podemos saber de dónde vino en función de la coincidencia de puerto a ip que hemos extraído del proveedor de TCP (Figura 7).
Con SMB, la situación es un poco más complicada, ya que diferentes bits de información aparecen en diferentes eventos ETW. El terminal es un canal con nombre, que es lo mismo que un archivo, pero se puede acceder a varios archivos a través de la misma sesión SMB. Por lo tanto, en este caso, para hacer coincidir el terminal con su origen de red, tenemos que realizar un seguimiento de dos eventos: uno para la conexión real y otro para la solicitud de archivo (Figura 8).
Para el evento de conexión, tenemos el ID de evento 500, Smb2ConnectionAcceptStart, que se activa cuando se establece la conexión SMB. Obtenemos la IP de origen y un UUID de conexión de ella. A continuación, buscamos el ID de evento 8, Smb2RequestCreate_V2, que contiene el nombre de archivo solicitado y el mismo campo UUID de conexión. Ahora, solo necesitamos hacer una referencia cruzada de ambos eventos a través del UUID de conexión para hacer coincidir el nombre del canal con la IP que la solicitó (y más adelante, tendremos que hacer coincidir el nombre del canal con el terminal de llamada RPC).
Para ahorrarle la molestia de implementar todo esto por sí mismo, hemos implementado este algoritmo y puede encontrar la herramienta RPC Visibility en nuestro Repositorio de GitHub. La herramienta está escrita en Python y guarda el tráfico de red RPC registrado en una base de datos Neo4j para facilitar la visualización.
Detección de ataques
Ahora que tenemos toda la información que necesitamos, podemos por fin centrar nuestra atención en la detección de flujos RPC maliciosos. El proceso general es sencillo: Encontramos un ataque que se transfiere a través de RPC, ejecutamos una prueba de concepto de él, y vemos qué interfaz RPC utiliza, así como la operación solicitada. A continuación, simplemente podemos crear una firma que coincida con esa operación. Hemos incluido consultas de firmas que funcionan con la implementación de la base de datos Neo4j en nuestra versión, pero seguimos leyendo para conocer la lógica y las condiciones generales.
PSExec
PsExec es un nombre general para una técnica de ataque y una herramienta Sysinternals (la que le dio su nombre a la técnica). Básicamente, la herramienta copia un archivo binario de servicio en el recurso compartido ADMIN$ del destino remoto (carpeta de instalación de Windows) y, a continuación, se comunica con el administrador de servicios a través de su interfaz RPC (MS-SCMR) para crear un servicio para el binario y ejecutarlo (Figura 9).
Existen muchas razones legítimas para ponerse en contacto con máquinas remotas a través de SCMR; por ejemplo, los dispositivos de vigilancia que consultan el estado del servicio remoto. Hay muchas menos razones para crear nuevos servicios de forma remota. Por lo tanto, no queremos activar alertas en cualquier conexión a través de SCMR (que podemos detectar incluso sin RPC ETW, simplemente haciendo coincidir una conexión de red entrante con el proceso del administrador de servicios) services.exe), pero solo en conexiones que crean servicios remotos.
En consecuencia, nuestra firma debe ser (en términos generales, no específica para nuestra implementación de RPC Visibility):
interface_uuid == “367ABB81-9844-35F1-AD32-98F038001003” AND (opnum == 0xC OR opnum == 0x18)
donde 0xC es el opnum para RCreateServiceW y 0x18 es para RCreateServiceA.
Programador de tareas remotas
De forma similar a PsExec, el Programador de tareas se puede utilizar para iniciar un archivo binario remoto y lograr así el movimiento lateral. Ni siquiera tiene que lanzar un nuevo binario, ya que también puede lanzar una consola cmd o PowerShell y descargar un binario alojado en línea.
También de forma similar a PsExec, no queremos detectar ningún acceso al servicio Programador de tareas, sino que estamos principalmente interesados en las llamadas RPC a SchRpcRegisterTask.
interface_uuid == “86D35949-83C9-4044-B424-DB363231FD0C” AND opnum == 0x1
DCSync
DCSync es otro ataque basado en RPC, pero dirigido a controladores de dominio. En este caso, el atacante se conecta al controlador de dominio real, fingiendo ser un controlador de dominio nuevo. A continuación, piden replicar la base de datos de credenciales del controlador de dominio, obteniendo acceso a los hashes de contraseñas de KRBTGT.
La solicitud de replicación se produce a través de la interfaz MS-DRSR RPC y utiliza la función específica DRSGetNCChanges (opnum 3).
interface_uuid == “e3514235-4b06-11d1-ab04-00c04fc2dcd2” AND opnum == 0x3
PetitPotam
PetitPotam Es un ataque de coerción de autenticación en el servicio Sistema de archivos cifrados (EFS). Básicamente, los atacantes pueden conectarse a la interfaz EFS RPC (MS-EFSR) y le indica que abra un archivo remoto especificado por una ruta UNC. A continuación, activaría una conexión SMB saliente con autenticación que el atacante puede transmitir.
Cuando se lanzó el PoC de ataque, se utilizó EfsRpcOpenFileRaw (opnum 0), que se ha aplicado desde entonces. Topotam, el investigador que encontró la vulnerabilidad, también descubrió que EfsRpcEncryptFileSrv (opnum 4) tenía el mismo defecto.
interface_uuid == “c681d488-d850-11d0-8c52-00c04fd90f7e” AND (opnum == 0x0 OR opnum == 0x4)
Inconvenientes
Aunque hay mucha información que obtener del proveedor RPC ETW, no es una solución integral para todas nuestras necesidades de seguridad. Si bien saber qué operación se solicita en cada flujo de red es información valiosa, la información más importante, qué datos se pasaron en cada solicitud, no se registra. Esto significa que la detección de movimiento lateral a través del proveedor de ETW sigue siendo solo un enfoque basado en heurística, aunque con mucho más contexto que las redes tradicionales de cuatro tuplas.
También es un método de detección puro y no se puede utilizar para detener o responder a ataques. Microsoft nos proporciona otro mecanismo de defensa integrado para RPC: el filtro RPC en el firewall de Windows. Puede obtener más información sobre ese mecanismo de filtrado y aprender a utilizarlo en nuestra Guía definitiva para el filtro de llamada a procedimiento remoto (RPC) POST.
Resumen
El proveedor RPC ETW no es una nueva incorporación a Windows, pero se ha descuidado en su mayor parte en lo que respecta a la defensa de la red. Existen algunas herramientas que interactúan y consumen eventos con TI, pero están principalmente dirigidas a investigadores de seguridad y se centran menos en el lado de la red de las cosas.
En esta publicación, hemos hablado sobre cómo podemos utilizar el proveedor RPC ETW, junto con los proveedores TCP y SMB, para obtener visibilidad de las operaciones RPC solicitadas que provienen de la red. Esto nos proporciona un enfoque heurístico que podemos utilizar para detectar posibles solicitudes maliciosas que se pueden utilizar para el movimiento lateral.
Referencias
Herramientas de consumidor RPC ETW de otros investigadores de seguridad
RpcMon por CyberArk
RpcInvestigator por Trail of Bits
Uso de telemetría RPC por Jonathan Johnson de SpecterOps
Nuestro repositorio de GitHub para todo lo relacionado con RPC
Aspectos internos ofensivos de Windows IPC 2: RPC por Carsten Sandker
- Cómo proteger un servidor RPC de Windows y cómo no por James Forshaw