En 2022 y 2023, Sophos X-Ops publicó una investigación sobre un conjunto de herramientas para sabotear las funciones del software de protección de endpoints que se estaba desarrollando y utilizando junto con varias bandas importantes de ransomware. La compañía Mandiant había denominado anteriormente a esta herramienta Poortry y a su aplicación cargadora Stonestop.
Los creadores de la herramienta Poortry habrían conseguido que se firmaran controladores personalizados a nivel de kernel mediante el proceso de firma de atestación de Microsoft. Después de que publicáramos nuestra investigación (y de que Microsoft cerrara la vía que permitía firmar estos controladores), los creadores de la herramienta no se detuvieron. Han seguido añadiendo características y funciones al controlador Poortry, en un intento continuo de eludir la detección y encontrar nuevas formas de desactivar el software EDR y de protección de los endpoints.
Para explicar las nuevas funciones de Poortry, repasemos cómo interactúan los controladores con el sistema operativo y cómo los desarrolladores de este EDR killer evolucionaron su herramienta con el paso del tiempo.
Cómo los controladores de Windows pueden hacer peligrar la protección
La mayoría de los EDR killers dependen de que se cargue un controlador de dispositivo en el núcleo del sistema operativo, lo que les da acceso a tipos de funcionalidad de bajo nivel para poder desconectar y terminar procesos de varios tipos de software de protección.
En Windows, que admite multitud de periféricos y componentes conectados, los controladores en modo kernel disponen de amplia libertad para este tipo de funciones de bajo nivel. En circunstancias normales, estos controladores no interactúan con el software o hardware de otras empresas o fabricantes, pero no se les exige que lo hagan. Así, si un controlador legítimo firmado no valida correctamente los procesos que interactúan con él, los EDR killers pueden explotar algunas de sus funciones para eliminar las medidas de protección.
Microsoft ha desarrollado diversas formas para que sus sistemas operativos puedan controlar si los controladores se cargan o no, como el mecanismo de Control de la Firma de Controladores: los controladores deben estar firmados digitalmente por un editor de software en el que confíe Microsoft antes de poder cargarse.
Los desarrolladores de EDR killers aprovechan las lagunas de este modelo de confianza: pueden utilizar un controlador vulnerable a abusos que en su día publicó una empresa de software legítima; también pueden firmar su propio controlador con un certificado legítimo de firma de código (y hay muchas formas de obtener certificados robados o filtrados).
En general, hay tres formas mediante las que los desarrolladores de EDR killer abusan de las firmas de código:
Abuso de certificados filtrados
Esta es la forma más directa de abordar el problema: encuentra un certificado de firma de código filtrado, robado o comprometido de algún otro modo de una empresa legítima y utilízalo para firmar tu controlador (o para engañar a las Autoridades de Certificación Raíz para que emitan un certificado).
Para todas las versiones de Windows posteriores a Windows 10 versión 1607, Microsoft ha exigido a todos los desarrolladores externos de controladores en modo kernel que envíen sus controladores al portal de desarrolladores de Microsoft, para que sean firmados de forma cruzada por Microsoft. Sin embargo, los controladores con firma cruzada no firmados por Microsoft aún pueden cargarse si cumplen una de las siguientes condiciones:
- El PC se ha actualizado desde una versión anterior de Windows a Windows 10, versión 1607
- Secure Boot está desactivado en la BIOS del sistema
- El controlador se firmó con un certificado de entidad final emitido antes del 29 de julio de 2015 que se encadena a una CA de firma cruzada compatible
Aunque la actualización redujo el peligro de los controladores con firma cruzada que habían sido firmados por certificados robados, el tercer punto crea una laguna que permite el segundo método a los atacantes.
Falsificación del sello de tiempo de la firma
Para mantener la compatibilidad con los controladores antiguos, Windows carga los controladores firmados con «certificados de entidad final emitidos antes del 29 de julio de 2015 que se encadenen a una CA de firma cruzada compatible».
Al firmar un controlador de núcleo, Microsoft proporciona al editor del software una herramienta llamada signtool.exe. Además de firmar el archivo proporcionado, signtool también comprueba que el certificado proporcionado sigue siendo válido. Una forma de asegurarse de ello es utilizar la función
Mediante una serie de interceptores en estas llamadas API de bajo nivel dentro del sistema operativo, los atacantes pueden alterar el proceso de firma y saltarse estas comprobaciones para firmar su propio controlador del núcleo. Una de las funciones que se está aplicando en esta técnica es GetLocalTime para devolver una marca de tiempo falsificada para pasar las comprobaciones en signtool.exe.
Eludir la firma de atestación de Microsoft
El último método consiste en eludir el proceso de firma de atestación de Microsoft y conseguir que Microsoft firme directamente el controlador del núcleo. Esto es probablemente lo más difícil de conseguir, pero también proporciona una firma un certificado WHQL fuerte emitida por la propia Microsoft, casi un santo grial de las firmas digitales.
Para abusar de este método, los atacantes necesitan:
- Un certificado EV válido
- Acceso al portal de desarrolladores de Microsoft
Si cumplen estos requisitos, pueden preparar un archivo CAB, que incluye el propio controlador, firmarlo con el certificado EV y enviarlo al panel de control.
Una vez enviado, el controlador se somete a varias comprobaciones para garantizar que no es malicioso. Si el controlador supera estas pruebas, llevará la firma «Microsoft Windows Hardware Compatibility Publisher».
Poortry y Stonestop: una amenaza importante desde 2022
Poortry (también llamado a veces BurntCigar) es un controlador de kernel malicioso utilizado junto con un cargador llamado Stonestop por Mandiant, que informó por primera vez de la existencia de la herramienta. El controlador elude el control de la Firma del Controlador utilizando cualquiera de las tres técnicas descritas anteriormente. Ambos están fuertemente ofuscados por empaquetadores comerciales o de código abierto, como VMProtect, Themida o ASMGuard.
Desde finales de 2022 hasta mediados de 2023, las variantes de Poortry llevaban el certificado WHQL de Microsoft. Sin embargo, gracias al trabajo conjunto entre Sophos X-Ops y Microsoft, se descubrieron la mayoría de estas muestras firmadas con certificado y Microsoft desactivó las cuentas de las que se abusó para conseguir esos controladores firmados.
Los creadores de Poortry no se dejaron disuadir; en su lugar, cambiaron a la falsificación de marcas de tiempo de firma o a la obtención de un certificado válido filtrado.
A lo largo del año pasado, pudimos vincular el uso de Poortry a ataques que implicaban al menos a cinco grandes familias de ransomware:
- CUBA
- BlackCat
- Medusa
- LockBit
- RansomHub
Desde 2023, hemos observado que los actores de amenazas utilizan repetidamente Poortry durante los ataques. Una característica que observamos en nuestra investigación anterior es que los creadores de Poortry cambian su empaquetador con frecuencia, creando un volumen de variantes ligeramente modificadas basadas en el original. En nuestra investigación, encontramos múltiples variantes diferentes firmadas por WHQL, empaquetadas con diferentes empaquetadores comerciales o no comerciales.
Desde que se les cerró esa vía, los creadores de Poortry despliegan ahora los controladores firmados por una amplia variedad de certificados ajenos a Microsoft.
La figura siguiente ilustra una cronología de los nombres de firmantes observados utilizados por el controlador de carga útil de Poortry durante un periodo de 15 meses.
Merece la pena mencionar que a veces realizamos nuestras observaciones durante compromisos de respuesta a incidentes y otras veces las recogemos como telemetría. De lo que podemos estar seguros es de que el número total y la variedad de certificados es mayor de lo que nuestra observación puede determinar por sí sola.
Jugar a la ruleta de los certificados
Sophos ha observado en diferentes ocasiones que un actor de amenazas despliega variantes de Poortry en diferentes máquinas durante un ataque. Estas variantes contienen la misma carga útil, pero firmada con un certificado distinto del controlador que se vio utilizar por primera vez durante el ataque. En agosto de 2023, durante una investigación de Sophos X-Ops, descubrimos que los atacantes obtenían acceso inicial mediante una herramienta de acceso remoto llamada SplashTop. En cuanto los atacantes estuvieron en la red, desplegaron Poortry y Stonestop. Pero el nombre del firmante, «bopsoft», ya era conocido como un certificado robado y fue bloqueado mediante una regla de comportamiento.
A los 30 segundos del último intento con el código firmado por «Bopsoft», los atacantes cargaron un controlador Poortry distinto, este firmado por «Evangel Technology (HK) Limited». El host fue aislado rápidamente y el ataque frustrado.
Transición de EDR killers a limpiador EDR
En julio de 2024, mientras estábamos inmersos en un incidente en el que los adversarios intentaron desplegar el ransomware RansomHub, Sophos CryptoGuard frustró el intento de cifrado de datos mientras los analistas cerraban los puntos de acceso de los atacantes. Un análisis posterior al incidente reveló que se habían lanzado dos ejecutables adicionales en varias máquinas antes del ataque final del ransomware:
<d>Users\<u>\desktop\c7iy3d.exe
<d>Usuarios<u>appdata\local\temp\usnnr.sys
Mediante una combinación de análisis estáticos y dinámicos, determinamos que los archivos eran Poortry y Stonestop. Entre las diferencias que observamos entre la versión anterior y esta, Poortry ahora también puede eliminar por completo componentes EDR críticos, en lugar de limitarse a terminar sus procesos.
Trend Micro informó en 2023 de que Poortry había desarrollado la capacidad de eliminar archivos del disco, pero esta fue la primera vez que observamos que se utilizaba esta función en un ataque.
Un vistazo más de cerca a las últimas variantes
Tanto el ejecutable Stonestop como el controlador Poortry están fuertemente empaquetados y ofuscados. Este cargador fue ofuscado por un empaquetador de código cerrado llamado ASMGuard, disponible en Github.
El controlador está firmado con un certificado que lleva el nombre del firmante «FEI XIAO». Sophos X-Ops confía plenamente en que la marca de tiempo de la firma fue falsificada para firmar el controlador. En particular, intenta enmascararse utilizando la misma información en su hoja de propiedades que un controlador (idmtdi.sys) para un software disponible comercialmente, Internet Download Manager de Tonec Inc. Pero no es el controlador de este paquete de software: los atacantes se limitaron a clonar la información del mismo.
A efectos explicativos, dividimos el flujo de ejecución en tres fases distintas.
Fase de inicialización
En los incidentes que hemos rastreado, los actores de la amenaza lanzan Poortry y Stonestop juntos, en el mismo directorio. Al ejecutarse, Stonestop busca el controlador correspondiente en el directorio actual.
.
Tanto el nombre del archivo como el nombre del dispositivo del controlador están codificados en el cargador. Al iniciarse, el cargador obtiene el «handle» del controlador del núcleo malicioso e inicia un «handshake» enviando una cadena codificada al controlador mediante la llamada a la API DeviceIoControl.
En general, la comunicación entre los componentes se produce a través de esta API DeviceIoControl. Cada función proporcionada por el componente en modo kernel se activa mediante el envío de un código IOCTL diferente. Las variantes anteriores se comunicaban mediante el controlador IRP_MJ_DEVICE_CONTROL. La variante actual utiliza ahora el controlador IRP_MJ_MAXIMUM_FUNCTION para recibir paquetes de solicitud de E/S.
Merece la pena mencionar que las correspondencias del código IOCTL a la función han cambiado desde nuestro último análisis. Por ejemplo, la orden de matar un proceso concreto por ID de proceso se activaba enviando un paquete de solicitud de E/S con el código 0x222094. La última muestra asigna el código IOCTL 0x222144 a la misma funcionalidad.
Desde el informe 2023 de Trend Micro, los desarrolladores de Poortry aumentaron el número de códigos IOCTL admisibles de 10 a 22. Nuestro análisis de todas las funciones disponibles sigue en curso.
Al igual que las versiones anteriores, el handshake se inicia enviando una cadena codificada al controlador. Una vez aceptado el valor del handshake, se activa una bandera en el binario que habilita las funcionalidades del controlador malicioso.
Fase de desactivación
La segunda fase se centra en inutilizar los productos EDR mediante una serie de técnicas diferentes, como la eliminación o modificación de las rutinas de notificación del kernel.
Los controladores de seguridad hacen uso de diferentes funciones proporcionadas por Windows para registrar llamadas de retorno cuando se producen eventos específicos en el sistema Windows. Un ejemplo sería la función PsSetCreateProcessNotifyRoutine, que añade una rutina de devolución de llamada suministrada por el controlador cuando se crea un nuevo proceso.
Eliminar estas rutinas de devolución de llamada suele ser un paso crítico para inutilizar los productos EDR. En 2022, también escribimos sobre un caso similar en el que el ransomware BlackByte abusó de un controlador legítimo vulnerable para eliminar rutinas de notificación críticas del núcleo.
En la segunda fase, observamos que se envían un total de siete códigos IOCTL distintos al componente del modo kernel. Solo se ejecuta la funcionalidad asignada a 0x222400. Las demás funciones se interrumpieron antes de tiempo debido a que se activaron banderas específicas en el binario. Sospechamos que las funcionalidades no activadas son experimentales, solo se activan en determinados tipos de sistemas o simplemente están desactivadas.
Los códigos IOCTL y sus comportamientos asignados son los siguientes:
0x2220C0 (Desactivado)
Cuando se recibe, Poortry entra en una rutina de inicialización adicional, obteniendo las direcciones de varias estructuras y funciones críticas.
0x222100 (Desactivado)
Cuando se recibe, Poortry intenta desactivar o activar las retrollamadas del kernel mediante la modificación de la bandera PspNotifyEnableMask. Se trata de un truco habitual utilizado por los rootkits para activar o desactivar las retrollamadas de rutina del kernel, como se explica en este artículo.
0x222104 (Desactivado)
Cuando recibe este código IOCTL, Poortry modifica las retrollamadas del kernel de los tipos de objeto PsProcess, PsThread y ExDesktopObj. Se trata de estructuras de datos en modo kernel que representan objetos específicos del kernel de Windows. Autoexplicativo, el tipo de objeto PsProcess representa un objeto proceso. Estos tipos de objeto también contienen una variable que apunta a las llamadas de retorno registradas para el objeto correspondiente.
Dado que esta función estaba desactivada, no estamos seguros de cómo los adversarios podrían intentar modificar estas listas de retrollamadas. Uno de los posibles escenarios podría ser desactivarlas por completo estableciendo las retrollamadas en una función personalizada sin ninguna funcionalidad, que simplemente devolviera instantáneamente,
0x222108 (Desactivado)
Cuando se recibe, Poortry modifica la variable CmpCallbackCount para activar o desactivar las retrollamadas del núcleo del registro. La variable se utiliza para contar el número de devoluciones de llamada registradas. Sospechamos que si este valor se parchea a cero, las devoluciones de llamada quedarán inutilizadas.
0x22210C (Desactivado)
Cuando se recibe, Poortry intenta eliminar el controlador fltMgr.sys del dispositivo \FileSystem\FastFat y \FileSystem\Ntfs mediante la función DeviceIoDetachDevice. Los controladores válidos suelen utilizar esta función para limpiar durante el apagado. Sin embargo, los rootkits pueden utilizar la función para impedir que los controladores objetivo reciban más peticiones de E/S.
fltMgr.sys es el gestor de filtros de Windows. Este controlador se utiliza para ampliar o modificar la funcionalidad de las funciones existentes en el sistema Windows. Los productos EDR también suelen utilizar este controlador.
Sospechamos que al desvincularlo mediante el uso de IoDetachDevice los filtros instalados quedan inutilizados en el sistema objetivo.
0x2221C0 (Desactivado)
Cuando se recibe, Poortry entra en rutinas para obtener la dirección de los principales gestores de funciones de ClassPnp.sys y ntfs.sys, como NtfsFsdClose o NtfsFsdRead de ntfs.sys. Por tanto, sospechamos que esta rutina puede utilizarse como rutina de inicialización adicional para obtener direcciones de funciones críticas que utilizan otras funciones.
0x222400 (Activado)
Cuando se recibe, Poortry desactiva las retrollamadas del kernel instaladas mediante una serie de técnicas diferentes. El componente de modo usuario incluye el nombre del controlador objetivo cuando se envía el paquete de solicitud de E/S.
Se parchean las retrollamadas al núcleo instaladas mediante PsSetLoadImageNotifyRoutine, PsSetCreateThreadNotifyRoutine y PsSetCreateProcessNotifyRoutine. En el prólogo de la función de retrollamadas, Poortry modifica la primera instrucción para que devuelva cero instantáneamente cuando se introduzca.
Hasta ahora, hemos identificado las siguientes técnicas para inutilizar las retrollamadas del kernel y los controladores de seguridad:
- Se iteran las estructuras internas utilizadas por las funciones correspondientes PsSetLoadImageNotifyRoutine, PsSetCreateThreadNotifyRoutine y PsSetCreateProcessNotifyRoutine. Si la retrollamada pertenece a un controlador de seguridad etiquetado, la función de llamada de retorno registrada sale inmediatamente sin ejecutar ninguna de las operaciones previstas.
- El núcleo de Windows implementa importantes estructuras de datos como PsProcess, PsThread y ExDesktopObject que representan elementos fundamentales del sistema operativo Windows. Estas estructuras contienen una variable llamada CallbackList que gestiona todas las rutinas de devolución de llamada asociadas al objeto específico. Poortry itera esta lista y si la retrollamada pertenece a un controlador de seguridad etiquetado la función de retrollamada registrada sale inmediatamente sin ejecutar ninguna de sus operaciones previstas.
- Se itera una lista enlazada interna utilizada por CmRegisterCallback y CmUnregisterCallback. Esta lista enlazada contiene puntos de función a las retrollamadas de registro y de objeto registradas. Si la devolución de llamada pertenece a un controlador de seguridad etiquetado, se parchea el prólogo de la función.
- Poortry utiliza la función exportada FltEnumerateFilters de fltMgr.sys para iterar por los filtros aplicados. Si el filtro pertenece a un controlador de seguridad etiquetado, se parchea el prólogo de la función.
- Aunque no hemos podido activar directamente la función, hemos encontrado pruebas de que Poortry puede abusar de la función IoDetachDevice para separar un objeto dispositivo de la pila de dispositivos de un sistema. Al contrario que la funcionalidad proporcionada por el código IOCTL 0x22210C, es menos evasiva y separa los dispositivos solo si el nombre del dispositivo coincide con el nombre de entrada enviado a través de DeviceIoControl.
Fase de limpieza
Tras la desactivación, el EDR killer tiene como objetivo terminar los procesos relacionados con la seguridad e inutilizar el agente EDR borrando del disco los archivos críticos.
En primer lugar, el componente en modo usuario envía varias peticiones de E/S con código IOCTL 0x222144 al componente en modo kernel, incluyendo el id del proceso a matar.
El cargador contiene una lista de rutas codificadas que apuntan a la ubicación donde están instalados los productos EDR. Recorre todas las subcarpetas y archivos de la carpeta y elimina los archivos críticos para el agente EDR, como archivos EXE o archivos DLL, enviando una petición IOCTL con el código 0x222180 al controlador. La petición enviada incluye la ruta del archivo a borrar.
En particular, el componente en modo usuario puede funcionar en dos modos:
- Eliminación de archivos por tipo
- Borrado de archivos por nombre
Sospechamos que el autor añadió estos modos de funcionamiento para garantizar la flexibilidad a la hora de apuntar a diferentes objetivos. También creemos que la lista de rutas codificadas que apuntan a las carpetas de instalación de los productos EDR cambia en función del objetivo.
Conclusión
Poortry y su cargador asociado Stonestop han experimentado una importante mejora de funciones en los 20 meses transcurridos desde que Sophos y Microsoft publicaron un informe conjunto sobre el abuso del mecanismo de firma WHQL por parte del EDR killer. Lo que antes era una herramienta relativamente sencilla para desenganchar componentes de protección de endpoints «problemáticos» se ha convertido, en sí misma, en una navaja suiza de capacidades maliciosas que abusa de un suministro prácticamente ilimitado de certificados de firma de código robados o utilizados incorrectamente para eludir las protecciones del Control de Firma de Controladores.
Los desarrolladores de Poortry hicieron que una característica diferenciadora de su herramienta fuera que podía hacer algo más que desenganchar un EDR o un controlador antimanipulación de protección de endpoints. Poortry ha evolucionado hasta convertirse en algo parecido a un rootkit que también tiene con controles finitos sobre una serie de diferentes llamadas API utilizadas para controlar la funcionalidad de bajo nivel del sistema operativo. Ahora también tiene la capacidad de borrar del disco a sus enemigos (el software de seguridad) como forma de despejar el camino para el despliegue de un ransomware.
Sophos X-Ops ha publicado Indicadores de Compromiso (IOC) en nuestro GitHub.