Movimiento lateral sin archivos con objetos COM atrapados

Primer plano de las manos de un hombre que escribe en una computadora portátil y sostiene una tableta en una oficina oscura con iluminación azul

El Modelo de objetos componentes (COM) ha sido una piedra angular del desarrollo de Microsoft Windows desde principios de la década de 1990 y todavía es muy frecuente en los sistemas operativos y aplicaciones Windows modernos. La dependencia de los componentes COM y el amplio desarrollo de características a lo largo de los años ha creado una generosa superficie de ataque. En febrero de 2025, James Forshaw (@tiraniddo) de Google Project Zero publicó una entrada en el blog que detalla un enfoque novedoso para abusar de la tecnología de comunicación remota COM distribuida (DCOM) donde los objetos COM atrapados se pueden usar para ejecutar código gestionado .NET en el contexto de un servidor del lado del proceso DCOM. Forshaw destaca varios casos de uso para la escalada de privilegios y la omisión de Protected Process Light (PPL).

Según la investigación de Forshaw, Mohamed Fakroud (@T3nb3w) publicó una implementación de la técnica para eludir las protecciones PPL a principios de marzo de 2025. Con Jimmy Bayne (@bohops), realizamos una investigación similar en febrero de 2025, que nos llevó a desarrollar una técnica de prueba de concepto de movimiento lateral sin archivos mediante el abuso de objetos COM atrapados.

Antecedentes

COM es un estándar de interfaz binaria y un nivel de servicio de middleware que permite la exposición de componentes modulares distintos para interactuar entre sí y con aplicaciones, independientemente del lenguaje de programación subyacente. Por ejemplo, los objetos COM desarrollados en C++ pueden interactuar fácilmente con una aplicación .NET, lo que permite a los desarrolladores integrar diversos módulos de software de manera efectiva. DCOM es una tecnología que permite a los clientes COM comunicarse con servidores COM mediante comunicación interprocesos (IPC) o llamadas a procedimientos remotos (RPC). Muchos servicios de Windows implementan componentes DCOM a los que se puede acceder local o remotamente.

Las clases COM suelen estar registradas y contenidas en el Registro de Windows. Un programa cliente interactúa con un servidor COM creando una instancia de la clase COM, conocida como objeto COM. Este objeto proporciona un puntero a una interfaz estandarizada. El cliente utiliza este puntero para acceder a los métodos y propiedades del objeto, lo que facilita la comunicación y la funcionalidad entre el cliente y el servidor.

Los objetos COM suelen ser objetivos de investigación para evaluar la exposición a vulnerabilidades y descubrir características abusivas. Un objeto COM atrapado es una clase de error en la que un cliente COM instancia una clase COM en un servidor DCOM fuera de proceso, donde el cliente controla el objeto COM a través de un puntero de objeto calculado por referencia. Dependiendo de la condición, este vector de control puede presentar fallas lógicas relacionadas con la seguridad.

El blog de Forshaw describe un caso de uso de bypass PPL en el que la interfaz IDispatch, tal como se expone en la clase COM de WaaSRemediation, se manipula para abusar de objetos COM atrapados y ejecutar código .NET. WaaSRemediation se implementa en el servicio WaaSMedicSvc, que se ejecuta como un proceso svchost.exe protegido en el contexto de NT AUTHORITY\SYSTEM. El excelente recorrido de Forshaw fue la base de nuestra investigación aplicada y el desarrollo de una técnica de prueba de concepto de movimiento lateral sin archivos.

Hombre mirando una computadora

Fortalezca su inteligencia de seguridad 


Adelántese cada semana a las amenazas con novedades e información sobre seguridad, IA y más con el boletín Think. 


Resumen de la investigación

Nuestro proceso de investigación comenzó explorando la clase COM WaaSRemediation que admite la interfaz IDispatch. Esta interfaz permite a los clientes realizar enlaces tardíos. Normalmente, los clientes COM tienen las definiciones de interfaz y tipo para los objetos que utilizan en tiempo de compilación. En cambio, el enlace tardío permite al cliente descubrir y llamar métodos sobre el objeto en tiempo de ejecución. IDispatch incluye el método GetTypeInfo , que devuelve una interfaz ITypeInfo. ITypeInfo tiene métodos que se pueden utilizar para descubrir información sobre el tipo del objeto que lo implementa.

Si una clase COM utiliza una biblioteca de tipos, el cliente puede consultarla a través de ITypeLib (obtenida de ITypeInfo-> GetContainingTypeLib) para recuperar información sobre los tipos. Además, las bibliotecas de tipos también pueden hacer referencia a otras bibliotecas de tipos para obtener información adicional sobre los tipos.

Según la entrada en el blog de Forshaw, WaaSRemediation hace referencia a la biblioteca de tipos WaaSRemediationLib, que a su vez hace referencia a stdole (automatización OLE). WaaSRemediationLib utiliza dos clases COM de esa biblioteca, StdFont y StdPicture. Al realizar COM Hijacking en el objeto StdFont modificando su clave de registro TreatAs, la clase apuntará a otra clase COM de nuestra elección, como System.Object en la infraestructura .NET. Cabe destacar que Forshaw señala que StdPicture no es viable, ya que este objeto realiza una comprobación de instancias fuera del proceso, por lo que nos centramos en utilizar StdFont.

Los objetos .NET nos resultan interesantes gracias al método GetType de System.Object . A través de GetType, podemos realizar una reflexión .NET para acceder finalmente a Assembly.Load. Si bien se eligió System.Object, este tipo resulta ser la raíz de la jerarquía de tipos en .NET. Por lo tanto, se podía usar cualquier objeto .NET COM.

Con la etapa inicial establecida, había otros dos valores DWORD en la clave HKLM\Software\Microsoft\.NetFramework necesarios para hacer realidad nuestro caso de uso percibido:

  • AllowDCOMReflection: como señaló Forshaw, este valor habilitado nos permite realizar una reflexión arbitraria para llamar a cualquier método .NET. Por lo general, .NET Reflection sobre DCOM se evita debido a las mitigaciones abordadas en MS14-009.
  • OnlyUseLatestCLR: Con Procmon, hemos descubierto que este valor debe estar habilitado para cargar la última versión de .NET CLR (versión 4); de lo contrario, se carga la versión 2 de forma predeterminada.

Al confirmar que la última versión de CLR y .NET podía cargarse en nuestros esfuerzos iniciales de prueba, sabíamos que estábamos en el camino correcto.

Del proceso local a la computadora remota

Centrando nuestra atención en los aspectos programáticos remotos, primero utilizamos Remote Registry para manipular los valores de la clave de registro .NetFramework y secuestrar el objeto StdFont en la máquina de destino. A continuación, cambiamos CoCreateInstance por CoCreateInstanceEx para crear una instancia del objeto COM WaaSRemediation en el objetivo remoto y obtener un puntero a la interfaz IDispatch.

Con un puntero a IDispatch, llamamos al método miembro GetTypeInfo para obtener un puntero a la interfaz ITypeInfo, que está atrapada en el servidor. Los métodos miembro llamados a partir de entonces ocurren en el lado del servidor. Después de identificar la referencia de interés de la biblioteca de tipos contenida (stdole) y derivar la referencia de objeto de clase posterior de interés (StdFont), finalmente utilizamos el método CreateInstance "remotable" en la interfaz ITypeInfo para redirigir el flujo de enlace de objetos StdFont (a través de la manipulación previa TreatAs) para crear una instancia de System.Object.

Dado que AllowDCOMReflection está configurado correctamente, podemos realizar una reflexión de .NET sobre DCOM para acceder a Assembly.Load para cargar un ensamblado .NET en el servidor COM. Dado que estamos utilizando Assembly.Load sobre DCOM, esta técnica de movimiento lateral es completamente sin archivos, ya que la transferencia de bytes de ensamblaje se gestiona con la magia de comunicación remota de DCOM. Para obtener una explicación detallada de este flujo técnico desde la creación de instancias de objetos hasta la reflexión, consulte el siguiente diagrama:

diagrama de flujo que muestra la creación de instancias de la clase System.Object
Flujo de creación de instancias de la clase System.Object

Dificultades de desarrollo

Nuestro primer y principal problema fue llamar a Assembly.Load_3, a través de IDispatch->Invoke. Invoke pasa una matriz de objetos de argumentos a la función de destino, y Load_3 es la sobrecarga de Assembly.Load que toma una sola matriz de bytes. Por tanto, necesitábamos envolver el SAFEARRAY de bytes dentro de otro SAFEARRAY de VARIANTs : inicialmente, intentábamos pasar un solo SAFEARRAY de bytes.

código que muestra cómo crear un equivalente no gestionado de Object Byte
Creación de un equivalente no gestionado de Object Byte

Otro problema fue encontrar la sobrecarga adecuada de Assembly.Load. Las funciones auxiliares se tomaron del código CVE-2014-0257 de Forshaw, que incluía la función GetStaticMethod . Esta función utilizó la reflexión de .NET sobre DCOM para encontrar un método estático dado un puntero de tipo, el nombre del método y su recuento de parámetros. Assembly.Load tiene dos sobrecargas estáticas que toman un solo argumento; como tal, terminamos usando una solución hacky. Notamos que la tercera instancia de Load con un solo argumento fue nuestra elección correcta.

código utilizado para buscar la sobrecarga adecuada de Assembly.Load
Buscar la sobrecarga adecuada de Assembly.Load

Dificultades operativas

Uno de los mayores inconvenientes que observamos con esta técnica fue que la baliza generada tendría su vida útil limitada al cliente COM; en este caso, la vida útil de la aplicación de nuestro binario de armamento "ForsHops.exe" (con un nombre elegante, por supuesto). Por lo tanto, si ForsHops.exe limpiaba sus referencias COM o salía, también lo haría la baliza que se ejecutaba bajo el svchost.exe de la máquina remota. Probamos diferentes soluciones, como hacer que nuestro ensamblaje .NET colgara indefinidamente su subproceso principal, ejecutar shellcode en otro subproceso y hacer que ForsHops.exe dejara el subproceso de exploit colgado, pero nada fue elegante.

El subproceso principal del cargador.NET se bloquea mientras el shellcode se ejecuta en un subproceso separado
El subproceso principal del cargador.NET se bloquea mientras el shellcode se ejecuta en un subproceso separado

En su estado actual, ForsHops.exe se ejecuta hasta que sale la baliza, momento en el que elimina sus operaciones de registro. Hay oportunidades de mejora, pero lo dejaremos como ejercicio para el lector.

demostración de la ejecución de ForShops.exe
Ejecución de ForShops.exe
Baliza exitosa en Windows 2019 Server
Baliza exitosa en Windows 2019 Server
captura de pantalla de baliza que se ejecuta en un proceso svchost de PPL
Baliza se ejecuta en un proceso PPL svchost
ejemplo de ForShops.exe que elimina los cambios después de que la baliza sale
ForShops.exe elimina los cambios después de la salida de la baliza

Recomendaciones defensivas

La guía de detección propuesta por Samir Bousseaden (@SBousseaden) tras la publicación de su implementación por parte de Mohamed Fakroud también se aplica a esta técnica de movimiento lateral:

  • Detección de eventos de carga CLR dentro del proceso svchost.exe de WaaSMedicSvc
  • Detección de manipulación del Registro (o creación) de la siguiente clave: HKLM\SOFTWARE\Classes\CLSID\{0BE35203-8F91-11CE-9DE3-00AA004BB851}\TreatAs( claveTreatAs de StandardFont CLSID)

Además, recomendamos implementar los siguientes controles adicionales:

  • Detección de la manipulación DACL de HKLM\SOFTWARE\Classes\CLSID\{0BE35203-8F91-11CE-9DE3-00AA004BB851}
  • Buscar la presencia de los valores OnlyUseLatestCLR y AllowDCOMReflection habilitados en HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework.
  • Habilitar el cortafuegos basado en el host para restringir el acceso efímero a puertos DCOM siempre que sea posible

Además, aproveche la siguiente regla YARA de prueba de concepto para detectar el ejecutable estándar ForsHops.exe:

regla Detect_Standard_ForsHops_PE_By_Hash

{
    meta:   
        description = "Detects the standard ForShops PE file by strings"
        reference = "GitHub Project: https://github.com/xforcered/ForsHops/"
    strings:
        $s1 = "System.Reflection.Assembly, mscorlib" wide
        $s2 = "{72566E27-1ABB-4EB3-B4F0-EB431CB1CB32}" wide
        $s3 = "{34050212-8AEB-416D-AB76-1E45521DB615}" wide
        $s4 = "GetType" wide
        $s5 = "Load" wide

    condition:
        all of them
}

Conclusión

Nuestra implementación amplía ligeramente el abuso de COM explicado en el blog de Forshaw al aprovechar los objetos COM atrapados para el movimiento lateral en lugar de la ejecución local para eludir PPL. Por lo tanto, sigue siendo susceptible a las mismas detecciones que las implementaciones que realizan ejecución local.

Puede encontrar el código de movimiento lateral de prueba de concepto de ForsHops.exe aquí.

Agradecimientos

Un agradecimiento especial a Dwight Hohnstein (@djhohnstein) y Sanjiv Kawa (@sanjivkawa) por dar su feedback sobre esta investigación y por revisar el contenido de la entrada en el blog.

Recursos

Mixture of Experts | 12 de diciembre, episodio 85

Decodificación de la IA: Resumen semanal de noticias

Únase a nuestro panel de ingenieros, investigadores, responsables de producto y otros profesionales de talla mundial que se abren paso entre el revuelo de la IA para ofrecerle las últimas noticias e insights al respecto.

Soluciones relacionadas
Soluciones de seguridad empresarial

Transforme su programa de seguridad con las soluciones del mayor proveedor de seguridad empresarial.

Explore las soluciones de ciberseguridad
Servicios de Ciberseguridad

Transforme su negocio y gestione el riesgo con servicios de consultoría de ciberseguridad, nube y seguridad gestionada.

    Explore los servicios de ciberseguridad
    Ciberseguridad de la inteligencia artificial (IA)

    Aumente la velocidad, precisión y productividad de los equipos de seguridad con soluciones cibernéticas potenciadas por IA.

    Explorar la ciberseguridad de IA
    Dé el siguiente paso

    Ya sea que necesite una solución de seguridad de datos, gestión de endpoints o gestión de identidad y acceso (IAM), nuestros expertos están listos para trabajar con usted para lograr una postura de seguridad sólida. Transforme su negocio y gestione el riesgo con un líder global del sector en servicios de consultoría de ciberseguridad, en la nube y de seguridad gestionada.

    Explore las soluciones de ciberseguridad Descubrir los servicios de ciberseguridad