Windows Defender Application Control (WDAC) es una solución de seguridad que restringe la ejecución al software de confianza. Dado que está clasificado como un límite de seguridad, Microsoft ofrece pagos de recompensas por errores para las omisiones calificadas, lo que lo convierte en un campo de investigación activo y competitivo.
Resultados típicos de un envío de recompensas por errores de omisión de WDAC:
Al mirar la lista de bloqueos recomendados de WDAC de Microsoft, vemos que leyendas como Jimmy Bayne (@bohops) y Casey Smith (@subTee) descubrieron omisión de WDAC que siguen sin corregirse, pero que recibieron menciones honoríficas. Más allá de esta lista, el proyecto LOLBAS contiene omisiones adicionales no corregidas que no se han reconocido en la lista de bloqueo de Microsoft. Un ejemplo es la aplicación Microsoft Teams, que sigue siendo una omisión viable de WDAC a pesar de estar documentada en LOLBAS.
Al encontrar WDAC durante las operaciones del equipo rojo, lo omitimos con éxito y ejecutamos nuestra carga útil de comando y control (C2) de la etapa 2 utilizando las siguientes técnicas:
1. Utilice un LOLBIN conocido como MSBuild.exe
2. Carga lateral de DLL en una aplicación de confianza con una DLL que no es de confianza
3. Explote la regla de exclusión personalizada de la política WDAC del cliente
4. Encontrar una nueva cadena de ejecución en una aplicación confiable que permita el despliegue de C2
Como explicó Ruben Boonen (@FuzzySec) en su charla del Wild West Hackin' Fest Statikk Shiv: Aprovechando las aplicaciones Electron para la post-explotación, las aplicaciones de electrones funcionan como navegadores web que generan aplicaciones de escritorio usando tecnología en línea estándar como HTML, JavaScript y CSS. El motor de JavaScript en Electron es Node.js, que proporciona potentes API capaces de interactuar con el sistema operativo host. Estas API permiten acciones como leer y escribir archivos, ejecutar programas y otras operaciones típicas de las aplicaciones nativas.
En tiempo de ejecución, una aplicación Electron lee archivos JavaScript, interpreta su código y los ejecuta dentro del proceso Electron. La siguiente animación muestra cómo la aplicación Microsoft Teams Electron lee un archivo JavaScript en tiempo de ejecución, que luego utiliza el módulo child_process para ejecutar whoami.exe.
En este ejemplo, el proceso Teams Electron lee el archivo JavaScript, que a continuación genera whoami.exe utilizando el módulo child_process. Este módulo activa el proceso Electron para ejecutar su API exportada uv_spawn, responsable de interactuar con el sistema operativo para crear un nuevo proceso.
La arquitectura tradicional de una aplicación de Windows consiste en:
El EXE llama a las funciones exportadas desde las DLL para ampliar sus capacidades. Sin embargo, las aplicaciones Electron invierten esta arquitectura. En lugar de que el EXE llame a las API desde las DLL, el propio Electron EXE expone las exportaciones de API, que son llamadas por:
Esta estructura permite que Node.js y los módulos de nodo interactúen con el sistema operativo de formas que el JavaScript tradicional en un navegador no puede.
En la imagen de abajo examinamos la aplicación Teams Electron usando PE Bear, una herramienta asombrosa creada por @hasherezade, que revela que el ejecutable de Teams Electron contiene 2.977 API exportadas. Esta gran superficie de API proporciona una amplia funcionalidad que los archivos JavaScript de Node.js y los módulos de nodo pueden aprovechar para interactuar con el sistema operativo.
Dado que las aplicaciones Electron ejecutan JavaScript en tiempo de ejecución, la modificación de estos archivos JavaScript permite a los atacantes inyectar código Node.js arbitrario en el proceso de Electron. Al aprovechar las API de Node.js y Chromium, el código JavaScript puede interactuar con el sistema operativo.
No descubrí la capacidad de modificar archivos JavaScript de aplicaciones Electron confiables para ejecutar código JavaScript Node.js arbitrario. Las primeras referencias que puedo encontrar datan de 2022.
A principios de 2022, Andrew Kisliakov publicó el blog "Microsoft Teams and other Electron Apps as LOLbins". Andrew y @mrd0x contribuyeron con sus hallazgos al proyecto LOLBAS.
Más adelante, en 2022, Valentina Palmiotti (@chompie1337), Ellis Springe (@knavesec) y Ruben exploraron este enfoque, lo que llevó al desarrollo de una herramienta de persistencia interna que desde entonces se ha utilizado en operaciones del equipo rojo.
También en 2022, Michael Taggart lanzó el proyecto quASAR, una herramienta diseñada para modificar aplicaciones Electron para permitir la ejecución de comandos. En su blog “Quasar: Compromising Electron Apps”, compartió que en septiembre de 2022, un miembro del proyecto Electron se puso en contacto con él y le dijo que la verificación de integridad era una característica experimental y que, con suerte, sería totalmente compatible en el futuro.
Tras experimentar personalmente con aplicaciones más recientes de Electron como Signal, confirmé que ahora existen comprobaciones de integridad para algunas aplicaciones de Electron que impiden que sus archivos JavaScript sean modificados. Aun así, muchas aplicaciones Electron distribuidas activamente siguen siendo vulnerables.
Esta técnica también se ha observado en ataques del mundo real. En 2022, un actor de amenazas hizo una puerta trasera a la aplicación de chat MiMi modificando sus archivos JavaScript incluidos en el servidor de distribución. Trend Micro identificó esto como un ataque a la cadena de suministro, donde la aplicación Electron comprometida se distribuyó a los usuarios finales, lo que permitió la ejecución de código JavaScript malicioso que descargó y ejecutó una carga útil C2 de segunda etapa.
En abril de 2024, Yo, Bobby Cooke (@0xBoku) estaba buscando una nueva cadena de ejecución para usar en la preparación de una próxima operación del equipo rojo para un cliente del sector financiero. Este sector tiene estándares de seguridad más altos y regulaciones más estrictas, y a menudo implementa controles de seguridad adicionales como WDAC. Durante mi investigación, me encontré con otra aplicación Electron vulnerable. Sin embargo, dado que no estaba firmado por Microsoft, era poco probable que eludiera la política WDAC del cliente.
Luego pasé a la aplicación heredada de Microsoft Teams, que está firmada por Microsoft y puede eludir incluso las políticas WDAC más estrictas. En este punto, Dylan Tran (@d_tranman) se unió a mí en esta búsqueda, y comenzamos a buscar una forma de pasar de la ejecución arbitraria de JavaScript en Node.js a la ejecución de nuestro shellcode C2 de etapa 2.
Si bien Node.js puede interactuar con el sistema operativo a través de sus API, carece de la funcionalidad completa de C, donde los desarrolladores pueden llamar directamente a WINAPI y NTAPI. Para cerrar esta brecha, los desarrolladores crearon módulos de nodo, que amplían las capacidades de la infraestructura Node.js. Estos módulos, compilados a partir de código C++, pueden llamar a WINAPI, interactuar con las API de Node.js y ejecutar JavaScript dentro de las aplicaciones Electron. Los módulos de nodo compilados tienen un nodo y se cargan en los procesos de Windows mediante un evento de carga DLL.
Durante nuestra investigación, examinamos varias aplicaciones Electron y analizamos sus módulos de nodo firmados. Descubrimos que se podía interactuar con estos módulos directamente desde JavaScript, lo que nos permitía aprovechar sus capacidades integradas.
Si bien crear nuestros propios módulos de nodo personalizados para ejecutar shellcode es un enfoque viable y es una capacidad de Loki C2, presenta un problema del huevo y la gallina. La carga de un módulo de nodo desde JavaScript desencadena un evento de carga de DLL, que puede bloquearse mediante políticas de WDAC que aplican reglas estrictas contra DLL sin firmar. Afortunadamente, existe una gran cantidad de módulos de nodo firmados en aplicaciones Electron legítimas.
Este enfoque para ejecutar nuestra carga útil parecía prometedor, por lo que compartimos nuestros hallazgos con Valentina y ella se unió a nosotros en esta búsqueda. Con su ayuda, profundizamos en la reversión de módulos de nodo firmados, buscando vulnerabilidades o capacidades que nos permitan ejecutar código de shell arbitrario.
Un ejemplo de un módulo de nodo con capacidades útiles es windows_process_tree.node, un módulo firmado por Microsoft que se incluye con Visual Studio Code. Cuando se examina en PE Bear, revela dos funciones exportadas, como se ve a continuación.
A diferencia de las DLL tradicionales, los módulos de nodo no enumeran todas sus funciones disponibles en la tabla de exportación. El proceso Electron llama a la función exportada napi_register_module_v1 y es responsable de cargar el módulo y exponer su funcionalidad exportada al proceso Electron. Esto actúa como un puente, permitiendo que JavaScript dentro del proceso Electron llame e interactúe con las funciones del módulo.
Una forma sencilla de enumerar todas las funciones invocables en un módulo de nodo es aprovechar el código Node.js que se muestra a continuación.
Al ejecutar este script Node.js en PowerShell, vemos que hay dos funciones invocables en windows_process_tree.node. Son getProcessList y getProcessCpuUsage.
Con persistencia, es posible determinar cómo llamar a estas funciones desde JavaScript. Una limitación de Node.js es que carece de una API integrada para enumerar todos los procesos en ejecución en el sistema. Esta limitación es la razón por la que Microsoft introdujo la función getProcessList en este módulo, ampliando las capacidades de la aplicación VS Code Electron.
Es posible recuperar esta información directamente en JavaScript utilizando el módulo child_process para ejecutar PowerShell en un proceso secundario, que devuelve detalles sobre los procesos en ejecución. En la imagen a continuación, Loki C2 genera un proceso secundario de PowerShell para recuperar la lista de procesos.
Este enfoque presenta importantes riesgos de seguridad operativa. La ejecución de procesos secundarios de PowerShell es altamente detectable y aumenta la probabilidad de que una operación se marque o queme. Para evitar esto, Loki C2 aprovecha módulos de nodo firmados como windows_process_tree.nodo para ampliar las capacidades de Node.js.
Loki C2 incluye el comando ps, que recupera información del proceso cargando el módulo windows_process_tree.nodo firmado por Microsoft y llamando a la función getProcessList, como se ve en la imagen siguiente.
A continuación se muestra el código JavaScript de Loki C2 que llama a la función getProcessList en el módulo windows_process_tree.node. getProcessList devuelve datos de procesos en formato JSON, que Loki C2 formatea en una tabla estructurada para mejorar la legibilidad.
Determinar cómo llamar correctamente a funciones dentro de los módulos de nodo puede ser complicado, ya que sus estructuras internas no están documentadas. Sin embargo, mediante el uso de herramientas como Ghidra, desarrollada por la NSA, y la colaboración con ingenieros inversos calificados como Valentina, hemos analizado con éxito estos módulos e identificado cómo interactuar con sus funciones.
Valentina finalmente descubrió una forma de ejecutar nuestro shellcode C2 de la Etapa 2 sin cargar un archivo DLL sin firmar, pero dejaré que ella revele los detalles. Juntos, Dylan, Valentina y yo trabajamos en refinar la técnica para garantizar la estabilidad de la próxima campaña de phishing.
Lamentablemente, nuestra campaña inicial de phishing por correo electrónico fue denunciada y bloqueada por el Blue Team. Tras este revés, Brett Hawkins (@h4wkst3r) y yo empezamos a preparar una segunda campaña. Como encargado designado de la carga útil, no quería reutilizar la misma carga útil; hacerlo habría facilitado que el Blue Team nos rastreara y detuviera nuestra segunda campaña. Sin embargo, no tuvimos tiempo suficiente para aplicar la técnica de Valentina a una nueva carga útil, así que comencé a desarrollar una nueva carga útil utilizando un enfoque alternativo.
Por lo general, la capacidad de ejecutar JavaScript arbitrario en aplicaciones Electron confiables se utiliza para ejecutar comandos que despliegan un agente C2. Sin embargo, sin la técnica de Valentina, este enfoque fallaría contra WDAC, ya que eventualmente requeriría ejecutar un programa sin firmar, que probablemente estaría bloqueado.
Con solo unos días para prepararme para la segunda campaña, pensé: ¿y si construyo una infraestructura C2 completa en JavaScript?
Si el agente C2 en sí estuviera escrito completamente en JavaScript, podría establecer un canal C2 incluso contra las políticas más estrictas de WDAC. Desde allí, se podía realizar reconocimiento para encontrar la forma de desplegar una carga útil C2 de la etapa 2. No habría eventos de carga de DLL sin firmar, solo JavaScript ejecutándose dentro del proceso de Teams de confianza.
Todo lo que necesitábamos era suficiente funcionalidad para:
Aprovechando todo el código Node.js que había escrito durante mi investigación, elaboré una prueba de concepto C2 de la noche a la mañana. Al día siguiente, se lo mostré a Dylan y, juntos, lo ampliamos rápidamente hasta convertirlo en un C2 totalmente funcional basado en JavaScript. Nuestro C2 fue capaz de:
El JavaScript C2, ahora conocido como Loki C2, fue un éxito en la segunda campaña. Desde entonces, hemos seguido perfeccionando y ampliando Loki C2, añadiendo más características, aumentando la estabilidad y mejorando las capacidades.
Con todo el conocimiento de Electron que obtuve de esta investigación, construí una interfaz gráfica de usuario para Loki C2 utilizando la infraestructura Electron.
En el siguiente video, demuestro eludir una estricta política WDAC con Loki C2. Las dos secciones a continuación explican lo que sucede en el video.
Para esta demostración, WDAC se despliega a través de la política de control de aplicación en una instancia EC2 de Windows Server 2025 actualizada en AWS. El asistente proporciona tres plantillas de políticas básicas:
El modo predeterminado de Windows es el más estricto y permite la ejecución de:
En la demostración, se selecciona la política Modo de Windows predeterminado. El modo de auditoría predeterminado está deshabilitado para que WDAC aplique la política de inmediato. Además, se marcan las opciones Fusionar con listas de bloqueo recomendadas, que incluyen las reglas de la lista de bloqueo WDAC recomendada de Microsoft. El asistente de control de aplicación genera un archivo XML y CIP para la política WDAC, que luego se despliega en el servidor mediante CITool.exe.
Una vez que WDAC está activo, intento ejecutar Loki C2 Agent.exe, pero WDAC lo bloquea, ya que el ejecutable no está firmado por Microsoft.
Para eludir esta restricción, copio el contenido del directorio /recursos/aplicación/ de Loki Agent. En el escritorio hay una carpeta llamada "teams" que contiene una aplicación legítima heredada de Microsoft Teams. Al ver las propiedades de Teams.exe, se confirma que está firmado por Microsoft.
Luego navego hasta el directorio /recursos/ de la aplicación Teams y elimino todos los archivos existentes. Una vez borrado, pego el directorio Loki C2 Agent /recursos/aplicación/ previamente copiado en ~/Escritorio/teams/recursos/aplicación/.
Con esta modificación, ejecuto Teams.exe haciendo clic en él. Dado que el ejecutable de Teams está firmado por Microsoft, WDAC no lo bloquea. En System Informer, podemos ver que el proceso de Teams se crea correctamente sin la intervención de WDAC. Sin embargo, debido a que reemplacé el directorio Teams /recursos/aplicación/ con el código de Loki C2 Agent, la aplicación Teams basada en Electron ahora ejecuta el JavaScript de Loki C2 Agent dentro del proceso de confianza de Teams.
El proceso de Teams devuelve la llamada al cliente Loki C2 y ejecuto varios comandos para demostrar el control remoto del servidor comprometido.
Después de obtener acceso inicial con Loki C2, identificamos varias formas de ejecutar un agente C2 de etapa 2 más capaz, como Dragon, el C2 interno desarrollado por Shawn Jones (@anthemtotheego) y yo. Si bien todos los diferentes métodos de escalamiento que hemos descubierto desde la creación inicial de Loki C2 no se divulgarán en esta publicación, planeamos cubrirlos en futuras versiones.
Cuando se implementa correctamente, esta técnica continúa eludiendo las soluciones de detección y respuesta de endpoint de primer nivel. Sin embargo, sin un C2 de etapa 2 sigiloso, los operadores deben confiar en la ejecución de comandos a través de spawn, que ejecuta comandos en procesos secundarios. Esto activará rápidamente las detecciones posteriores a la explotación contra los principales EDR.
Loki C2 se alinea con la técnica MITRE ATT&CK T1218.011 - Ejecución de proxy binario del sistema: aplicaciones Electron.
Después de buscar en Internet, no encontré esta técnica de vaciar las aplicaciones Electron y reemplazar su código con un C2 divulgado públicamente o utilizado en la naturaleza. Sin embargo, después de compartir Loki C2 con equipos rojos de confianza, uno confirmó que han desarrollado capacidades similares internamente.
Incluso con un TTP de MITRE ATT&CK, múltiples publicaciones de investigación y una entrada LOLBAS, esta técnica de vaciado de aplicaciones Electron en sí misma permanece sin detectar. Supongo que las soluciones de ejecución de la detección y respuesta de endpoints (EDR) no se centran en detectar esto, sino en indicadores posteriores a la explotación, como generar procesos hijos para ejecutar comandos. Dado que hemos desarrollado métodos para desplegar el C2 etapa 2 evitando estas detecciones comunes posteriores a la explotación, hemos utilizado con éxito esta técnica en múltiples interacciones evitando la detección.
Con todo esto en mente, la próxima vez que escuche a un proveedor afirmar "100 % de cobertura MITRE", vale la pena preguntarse qué significa realmente...