Introducción: la página de inicio de sesión que no es phishing
Estaba buscando el próximo regsvr32. No ese binario en específico, sino su categoría: un binario firmado por Microsoft que ya está en cada equipo Windows y que puede obtener código remoto y ejecutarlo, de modo que un atacante nunca tenga que soltar nada sin firmar. Extraje un catálogo de binarios firmados que no aparecen en LOLBAS y filtré cualquiera que pudiera alcanzar la red y ejecutar lo que recibiera.
La familia de hosts web AppX apareció en ese filtro, y un binario destacó. WWAHost.exe, el Windows Web App Host, renderiza cualquier contenido web al que un paquete AppX lo apunte. Solo eso ya lo hace interesante. Sin embargo, lo que me detuvo fue la bandera del manifiesto: declarar WindowsRuntimeAccess="all" y el JavaScript remoto que renderiza no solo se ejecuta, sino que hereda toda la superficie de la API del Windows Runtime, incluida la API que impulsa el inicio de sesión OAuth. Ese fue el momento en que encajó como un ataque. Si una página que yo controlaba podía alcanzar esa API de inicio de sesión, podía levantar un inicio de sesión real de Microsoft y quedarse con los tokens que devolviera. Quería saber si en realidad funcionaba.
Así que lo armé. Un paquete desechable cargado lateralmente, una página alojada en mi equipo Kali, y una llamada a WebAuthenticationBroker usando el ID de cliente propio de Microsoft Office. Lo ejecuté y observé abrirse un diálogo de inicio de sesión real de Microsoft en el escritorio. Real, porque lo era: servido desde login.microsoftonline.com, renderizado por un proceso firmado por Microsoft, sin barra de direcciones y sin navegador. Escribí la contraseña. Completé mi MFA. Un segundo después, el token de acceso y el token de actualización estaban en mi listener.
Esa fue la parte que me impactó. El usuario hace todo bien y nada cambia, porque no hay página de phishing que detectar, ningún dominio similar, ninguna advertencia de certificado. Nada en ella es falso. Es el flujo de inicio de sesión real de Microsoft, apuntado hacia mí.
Probé esto en Windows 11 24H2 (build 26100) con el Modo de Desarrollador habilitado. No necesita privilegios de administrador más allá de activar esa única configuración. Una vez activado ese interruptor, cada componente de la cadena es un binario de Microsoft confiable y firmado haciendo exactamente lo que fue diseñado para hacer, así que no hay nada que las defensas basadas en firmas tengan una razón obvia para marcar. Los tokens que roba sobreviven por completo al MFA, porque el usuario se autentica legítimamente y yo capturo lo que regresa.
Requisitos previos
El Modo de Desarrollador debe estar habilitado. Este es el requisito principal y la restricción principal de este ataque. Sin él, Add-AppxPackage -Register falla de inmediato con 0x80073CFF. Habilitarlo requiere derechos de administrador local sin importar el método (la documentación de Microsoft sobre el Modo de Desarrollador):
Vía Configuración: Configuración > Para desarrolladores > Modo de desarrollador > ACTIVADO (controlado por UAC, requiere administrador).
Vía registro (requiere administrador):
reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock" `
/v AllowDevelopmentWithoutDevLicense /t REG_DWORD /d 1 /f
Una vez que el Modo de Desarrollador está activado, el resto de la cadena se ejecuta como un usuario estándar: sin más administrador, sin aviso de UAC, y sin firma de código.
Figura 1: Habilitando el Modo de Desarrollador en el equipo de prueba. Windows mismo advierte que activarlo permite instalar y ejecutar apps fuera de la Store y que "podría exponer tu dispositivo y datos personales a riesgos de seguridad." Este interruptor es la puerta. Todo lo que sigue depende de que un usuario o una política lo haya activado.
Esto importa para delimitar la superficie de ataque. El Modo de Desarrollador es común en máquinas de desarrollo, ejecutores de CI/CD y VMs en la cloud, y puede habilitarse en toda una flota vía GPO. No está activado por defecto en las máquinas estándar de usuario final. Un matiz que vale la pena precisar: la verdadera puerta es el Modo de Desarrollador o una política empresarial de carga lateral (la ruta de AllowAllTrustedApps). El registro falla sin uno de los dos, el 0x80073CFF menciona ambos en su texto de error, y la política empresarial es la forma más probable en que una flota administrada termine en el estado vulnerable a escala. La mitigación vía GPO más adelante en esta publicación cierra ambas.
Cómo funciona: convirtiendo un binario firmado en un ladrón de tokens
Windows viene con WWAHost.exe (Windows Web App Host), un binario firmado por Microsoft que aloja contenido web dentro de paquetes AppX. Cuando un manifiesto AppX declara ContentUriRules con WindowsRuntimeAccess="all", cualquier JavaScript cargado por ese paquete obtiene acceso completo a la superficie de la API del Windows Runtime, incluido WebAuthenticationBroker, el manejador de flujo OAuth a nivel de sistema.
Una aclaración para el lector versado en WinRT: este es el WebAuthenticationBroker heredado, del cual Microsoft ha alejado a los desarrolladores desde entonces en favor del Web Account Manager (WebAuthenticationCoreManager). Sigue presente y alcanzable desde dentro del host AppX, que es el punto clave. Una superficie de API antigua pero aún conectada es exactamente el tipo de cosa que sobrevive mucho después de que la ruta recomendada haya avanzado.
Cualquier usuario estándar puede registrar un paquete AppX cargado lateralmente vía Add-AppxPackage -Register, siempre que el Modo de Desarrollador esté habilitado. No se requiere firma de editor confiable. El paquete apunta su ContentUriRules a una URL controlada por el atacante, y el JavaScript del atacante ahora se ejecuta dentro de un proceso confiable de Microsoft con acceso completo a WinRT.
A partir de ahí, la cadena de ataque es directa:
Requisito previo: el Modo de Desarrollador ya debe estar habilitado (o la política empresarial de carga lateral AllowAllTrustedApps).
Paso 1. Cargar lateralmente un paquete AppX mínimo. Ejecuta Add-AppxPackage -Register como usuario estándar. El ContentUriRules del manifiesto apunta al servidor del atacante con WindowsRuntimeAccess="all".
Paso 2. El JavaScript del atacante llama a WebAuthenticationBroker.authenticateAsync(). Usa el ID de cliente propio de Microsoft Office (d590ed36-52b3-4102-aeff-aad2292ab01c) y el URI de redirección urn:ietf:wg:oauth:2.0:oob.
Paso 3. El usuario ve un diálogo de inicio de sesión real de Microsoft. Servido desde login.microsoftonline.com. Renderizado por un proceso firmado por Microsoft. Sin barra de URL. Sin indicadores de compromiso. El usuario completa el MFA.
Paso 4. El código de autorización regresa al JavaScript del atacante vía el callback de WebAuthBroker. El URI de redirección oob envía el código directamente a la aplicación que lo llama, que es el atacante.
Paso 5. El código se intercambia por tokens y se exfiltra. Token de acceso más token de actualización con un amplio conjunto de ámbitos de Microsoft Graph. El token de actualización proporciona acceso persistente sin más MFA.
Los tokens llegan con el conjunto de ámbitos de Microsoft Office. El token de actualización persiste hasta que se revoca: por un administrador, por un evento de revocación de token, o por Continuous Access Evaluation. Sin uno de esos, el atacante puede generar silenciosamente nuevos tokens de acceso desde cualquier ubicación durante la vida del token.
Prueba de concepto: robando un token de principio a fin
La PoC es una configuración de dos partes. kali_listener.py se ejecuta en Kali y sirve el payload y captura el código de autorización. register_appx.ps1 se ejecuta en Windows para crear y registrar el paquete. Una vez que el código llega, exchange_token.py maneja el intercambio de tokens y la validación de la API de Graph.
1. El manifiesto AppX
El paquete cargado lateralmente es mínimo. La clave es WindowsRuntimeAccess="all" en la entrada de ContentUriRules que apunta al servidor del atacante:
El AppxManifest.xml completo se omite. Solo una línea hace algo en realidad, y es la regla de ContentUriRules que otorga esa superficie al JavaScript remoto: WindowsRuntimeAccess="all" apuntado a un origen que el atacante controla, alojado por WWAHost.exe.
Registro como usuario estándar, con el Modo de Desarrollador habilitado:
Add-AppxPackage -Register .\AppxManifest.xml
No hay aviso de UAC, ni SmartScreen, ni verificación de firma: el paquete carga JavaScript alojado por el atacante dentro de WWAHost.exe.
Figura 2: Registro del paquete en el equipo de prueba, con el Modo de Desarrollador activado. El logo y el manifiesto se escriben, y el paquete se registra con éxito.
2. Kali: iniciar el listener
Figura 3: El listener de Kali activo en modo de ataque, esperando callbacks.
3. El payload de JavaScript
El servidor del atacante aloja una página que llama a WebAuthenticationBroker.authenticateAsync() usando el ID de cliente propio de Microsoft Office y el URI de redirección oob.
La construcción de la URL de autorización y la llamada de exfiltración permanecen en el laboratorio. La Figura 4 muestra cómo se ve cuando se dispara.
Figuras 4 y 5: La secuencia de inicio de sesión exactamente como la ve el usuario, ingreso de credenciales y luego el aviso de MFA real. Renderizado por WWAHost.exe. Sin barra de URL. Sin interfaz de navegador. El dominio login.microsoftonline.com está dentro del cuerpo del diálogo, y el aviso de MFA es el real.
El usuario completa el MFA normalmente. El código de autorización regresa al JavaScript del atacante y se envía por POST al listener de Kali.
Figura 6: El listener segundos después de que el usuario termina el MFA. El banner "OAUTH AUTH CODE CAPTURED" se dispara y el callback llega (POST /collect). El código de autorización y el comando de intercambio están censurados.
4. Intercambio de tokens
Figura 7: Intercambio de tokens en Kali. El código de autorización capturado se intercambia por un token de acceso y un token de actualización, con los ámbitos de Graph otorgados (incluido AuditLog.Create), luego las lecturas del perfil /me y del directorio /users confirman el acceso. Más adelante, el token de actualización genera un nuevo token de acceso sin reautenticación, la persistencia que hace que los tokens sean valiosos después de que la sesión haya desaparecido. Todos los datos mostrados provienen de mi propio tenant de prueba.
5. Resultados confirmados
Esto se probó de principio a fin contra un tenant real de Entra ID (Azure AD) con MFA habilitado y configuración de seguridad predeterminada.
Ámbitos de token confirmados. El token capturado llevaba el conjunto completo de ámbitos delegados adjuntos al ID de cliente propio de Microsoft Office. La cadena exacta de ámbitos del token capturado:
email openid profile
AuditLog.Create
Calendar.ReadWrite Calendars.Read.Shared Calendars.ReadWrite
Channel.Create Channel.ReadBasic.All ChannelMember.ReadWrite.All
ChannelMessage.Read.All ChannelMessage.Send ChannelSettings.ReadWrite.All
Chat.Create Chat.ReadWrite ChatMember.ReadWrite
Contacts.ReadWrite Content.Process.User
DataLossPreventionPolicy.Evaluate
Directory.AccessAsUser.All Directory.Read.All
Files.Read Files.Read.All Files.ReadWrite.All FileStorageContainer.Selected
Group.Read.All Group.ReadWrite.All
InformationProtectionPolicy.Read
Mail.ReadWrite Mail.Send
Notes.Create
Organization.Read.All
People.Read People.Read.All
Printer.Read.All PrinterShare.ReadBasic.All PrintJob.Create PrintJob.ReadWriteBasic
ProtectionScopes.Compute.User
Reports.Read.All
SensitiveInfoType.Detect SensitiveInfoType.Read.All SensitivityLabel.Evaluate
Tasks.ReadWrite
Team.ReadBasic.All TeamMember.ReadWrite.All TeamsTab.ReadWriteForChat
User.Read.All User.ReadBasic.All User.ReadWrite Users.Read
.default
Hay dos cosas que son imprescindibles de entender aquí. Primero, estos son ámbitos delegados, así que el poder efectivo del token es la intersección entre el ámbito y lo que el usuario que inició sesión ya puede hacer. Directory.Read.All en un token delegado lee lo que ese usuario puede leer, y no significa acceso automático de administrador de tenant. El radio de impacto escala con el privilegio propio de la víctima, por lo que esto es peor cuando el usuario phisheado es un administrador. Segundo, nota la forma del conjunto: lectura/escritura y envío de correo, acceso completo a archivos en OneDrive y SharePoint, toda la superficie de Teams (canales, chats, mensajes, membresía), lectura/escritura de directorio y grupos, y calendario y contactos. Es, en efecto, toda la vida laboral de Microsoft 365 de la víctima en un solo token, y a diferencia de la sesión de la que fue robado, sigue funcionando desde cualquier lugar hasta que se revoque el token de actualización. AuditLog.Create es el que vale la pena destacar: un token que puede escribir entradas en el registro de auditoría no es algo que la mayoría de los defensores esperen que salga de un inicio de sesión de Office, y tiene un valor obvio para enturbiar una investigación.
Persistencia del token de actualización confirmada. Se obtuvieron nuevos tokens de acceso horas después sin reautenticación ni aviso de MFA, desde una máquina diferente en una red diferente. Esto se ve en las Figuras 8 y 9, que muestran el registro de inicio de sesión de Entra ID para la ejecución capturada.
Figura 8: Este panel superior es la mitad que luce limpia: Aplicación "Microsoft Office," App ID d3590ed6-52b3-4102-aeff-aad2292ab01c, Estado Correcto, Aplicación cliente "Aplicaciones móviles y clientes de escritorio," tipo de credencial Ninguna, sin banderas de riesgo y sin fallos de Acceso Condicional. Es indistinguible de un inicio de sesión rutinario de Office y exactamente la entrada que un SOC no tiene razón para abrir.
Figura 9: Este panel inferior desplaza el mismo registro hasta el campo que importa: Agente de usuario Mozilla/5.0 (Windows NT 10.0; Win64; x64; Trident/7.0; MSAuthHost/1.0; rv:11.0) like Gecko. Eso es MSAuthHost en el motor Trident, no MSAppHost/3.0, que es el propio registro de Microsoft confirmando que el tramo de inicio de sesión lleva un agente de usuario diferente al del tramo de exfiltración en el que se basa la regla.
No es solo WWAHost: una causa raíz, una clase de puertas de entrada
WWAHost.exe es el binario que probé de principio a fin, pero no es especial. Es uno de una clase de procesos host AppX firmados por Microsoft, y la superficie vulnerable no vive en ninguno de ellos. Vive en la capa compartida de WinRT que todos cargan. Así que la forma correcta de enmarcar esto no es un conteo de binarios vulnerables. Es una causa raíz con muchos puntos de entrada posibles, y un impacto que debe leerse estrictamente según lo que en realidad se demostró.
Una nota sobre lo que significan las palabras en esta sección, porque la distinción es todo el punto. "Probado" significa demostrado de principio a fin hasta el impacto, y exactamente una ruta cumple ese estándar (WWAHost, robo de token). "Disponible" significa que el espacio de nombres de WinRT se resuelve en el build probado, lo cual es una afirmación mucho más débil y no implica que se haya ejercido la capacidad. Lee lo que sigue con esas definiciones en mente.
La pertenencia a la clase es una función del build de Windows, no una constante fija. Los hosts van y vienen entre versiones, y no todos viven en el mismo lugar. En 24H2 (build 26100), por ejemplo, algunos se distribuyen desde System32 o SystemApps y al menos uno ahora se distribuye desde la tienda empaquetada bajo C:\Program Files\WindowsApps, lo que significa que un inventario que solo busque en directorios del sistema lo subestimará.
Miré el conjunto más amplio, y hay más hosts que WWAHost. Deliberadamente no estoy publicando una enumeración de ellos. La detección de esta publicación se basa en el motor de renderizado compartido, no en ningún nombre de host, así que captura toda la clase sin importar si los binarios individuales están listados o no, y un defensor que quiera medir su propia exposición puede hacerlo directamente: puede escanear los binarios host AppX firmados en su build en busca de presencia y firma, y consultar la superficie WinRT con ApiInformation.IsTypePresent. Esa es una verificación de solo lectura que cualquiera puede ejecutar en su propia máquina, y es la única razón por la que alguien necesita la lista. Publicar el conjunto objetivo aquí no aportaría nada para los defensores y mucho para el otro tipo de lector. Lo que hace que los hosts sean intercambiables es la capa de activación compartida que todos cargan, que es el siguiente punto.
Ninguno de estos binarios host implementa la funcionalidad peligrosa por sí mismo. Son procesos host. Las APIs reales son proporcionadas por componentes compartidos del Windows Runtime que cualquier host AppX puede activar. Así que esto nunca fue un conjunto de binarios cada uno vulnerable de forma independiente. Es una falla de diseño: un paquete cargado lateralmente con WindowsRuntimeAccess="all" en su ContentUriRules hereda la misma superficie de WinRT sin importar qué proceso host lo renderice.
Por eso parchar binarios individuales no solucionará el problema, y por eso una regla de EDR solo para WWAHost.exe es inútil. Bloquea un host y el atacante retarget al siguiente. Los hosts disponibles abarcan funcionalidad de búsqueda, shell, autenticación, entrada y respaldo. Bloquearlos todos rompería Windows. La solución tiene que vivir en la capa de activación: WindowsRuntimeAccess="all" otorga acceso irrestricto a WinRT a JavaScript remoto sin validación del llamador.
Las clases de WinRT alcanzables a través de esa superficie no se corresponden con un conjunto fijo de DLLs de System32. WinRT se activa a través de la capa de API-set/activación, y los nombres y ubicaciones de los módulos de respaldo varían según el build. En 24H2, dos de los cuatro módulos que las pruebas originales nombraron no estaban donde se esperaba:
API | Clase de WinRT | Estado en 24H2 (build 26100) |
|---|---|---|
WebAuthBroker |
| Se resuelve vía |
Launcher |
| Se resuelve vía |
CredentialPicker |
| Módulo de respaldo no encontrado en System32. Alcanzabilidad no verificada. |
DPAPI |
| Módulo de respaldo no encontrado en System32. Alcanzabilidad no verificada. |
El escaneo mide disponibilidad, si el espacio de nombres de WinRT responde desde un host dado, no explotación de principio a fin. Solo una ruta se demostró hasta llegar al impacto:
Capacidad | Qué produce | ¿Probado? |
|---|---|---|
WebAuthBroker | Tokens de acceso + actualización OAuth, amplio conjunto de ámbitos de Graph | Sí. Demostrado de principio a fin en WWAHost |
CredentialPicker | Credenciales en texto plano vía un diálogo nativo | Solo disponibilidad. Captura completa no reverificada en 24H2 |
DPAPI | Descifrar secretos del ámbito del usuario | Solo disponibilidad. No reverificado en 24H2 |
Launcher | Lanzamiento de manejadores de protocolo | El lanzamiento tiene éxito. Payloads a menudo mitigados por Defender |
Esa primera fila contiene la capacidad que vale la pena documentar: robo de token vía WebAuthBroker, probado de principio a fin. El resto es una superficie compartida que vale la pena señalar, pero honestamente etiquetada como disponible en lugar de explotada.
Más allá del robo de tokens: el resto de la superficie WinRT
WebAuthBroker es el titular, pero la superficie completa de WinRT disponible para el JavaScript del atacante es más amplia que OAuth.
Una nota sobre la evidencia. Las capacidades siguientes se ejercieron en el laboratorio original en Windows 11 22H2. A diferencia de la cadena OAuth, no se han reconfirmado de principio a fin en 24H2 (ver la tabla de impacto probado-versus-disponible arriba). Trátalas como demostrado-entonces, disponible-ahora en lugar de recién probado.
CredentialPicker. Muestra un diálogo de credenciales nativo de Windows, el real, renderizado por el sistema operativo, visualmente idéntico a cualquier aviso de autenticación legítimo de Windows. Devuelve el nombre de usuario y la contraseña en texto plano al JavaScript que lo llama. Dado que WWAHost.exe renderiza el flujo sin barra de direcciones, el usuario no tiene forma de distinguirlo de un aviso legítimo del sistema, porque es un aviso legítimo del sistema, solo que invocado por un llamador ilegítimo.
DataProtectionProvider (DPAPI). Operaciones de cifrado/descifrado usando el contexto de la clave maestra DPAPI del usuario. Datos cifrados con el ámbito LOCAL=user se descifraron en el laboratorio original, lo que indica que el JavaScript del atacante tiene el mismo contexto DPAPI que cualquier aplicación nativa que se ejecute bajo ese usuario.
Lanzamiento de manejador de protocolo. Launcher.launchUriAsync invocó powershell:, cmd:, ms-msdt:, search-ms:, ms-officecmd:, y otros. Algunos payloads son bloqueados por Defender, pero el mecanismo de lanzamiento en sí tiene éxito desde dentro del contexto de proceso confiable.
Modo silencioso. WebAuthBroker expone un parámetro silentMode que intenta la adquisición de tokens desde sesiones en caché sin interfaz. En una máquina unida a un dominio con una sesión Entra activa, se espera que esto devuelva tokens sin interacción del usuario. Pero no confirmé la adquisición silenciosa respaldada por PRT de principio a fin, así que la presento como comportamiento documentado/esperado y una vía abierta, no un resultado probado. Si lo reproduces, toda la cadena se ejecuta sin interacción del usuario mientras permanece dentro de la superficie del host firmado, lo que es lo que la distingue de las herramientas WAM silenciosas existentes. Hasta entonces, trátala como no verificada.
Por qué esto importa
Esta es una técnica de recolección de credenciales posterior al compromiso que corre a través de componentes confiables en máquinas donde el Modo de Desarrollador está habilitado. Toda la cadena usa APIs documentadas de Windows, binarios firmados por Microsoft y la propia infraestructura de autenticación de Microsoft, así que no hay nada para que la detección basada en firmas marque.
La entrega es flexible. El paquete AppX cargado lateralmente puede entregarse como una "herramienta de TI corporativa," una app de "Verificación de Cuenta Microsoft," o cualquier pretexto de ingeniería social. Una vez confirmado el Modo de Desarrollador en el objetivo, Add-AppxPackage -Register se ejecuta silenciosamente desde PowerShell sin aviso de UAC. El flujo OAuth presenta un inicio de sesión real de Microsoft, del tipo que los usuarios están entrenados para confiar y completar.
La detección es difícil. El proceso que hace la solicitud OAuth está firmado por Microsoft. El endpoint es login.microsoftonline.com. El ID de cliente es Microsoft Office. Los registros de inicio de sesión de Entra muestran una autenticación de Office normal, excepto por una cosa, y de eso trata la siguiente sección.
La persistencia está incorporada. El token de actualización funciona desde cualquier máquina, cualquier red, sin más interacción del usuario, y a diferencia de la sesión de la que fue robado, sigue funcionando después de que la máquina sea reinstalada o el usuario cierre sesión. Sobrevive cambios de contraseña hasta que se revoque: por un administrador, un evento de revocación, o Continuous Access Evaluation. Una interacción de 30 segundos produce acceso de larga duración al correo, archivos, directorio, calendario y Teams del usuario. Esta es una de varias rutas de tokens posteriores al compromiso; lo nuevo es la superficie del host web AppX firmado por la que corre, y que una sola regla de red captura toda la clase.
Esta es una de varias rutas de tokens posteriores al compromiso. Si la víctima ya tiene una sesión iniciada, las solicitudes silenciosas de tokens WAM (el askWAM de Dirk-jan Mollema, y las herramientas WAM/PRT más amplias) obtienen tokens sin diálogo, heredando el estado del dispositivo y derrotando la Protección de Token, a menudo de manera más silenciosa que un inicio de sesión interactivo. Lo nuevo aquí es el vector: un host web AppX firmado por Microsoft realizando la autenticación y la llamada saliente, por lo que tiene una firma de red limpia que captura toda la clase de estos hosts. La detección es la contribución.
Detección: la única regla que captura toda la clase
Aquí es donde se pone interesante. El ataque está diseñado para parecer que no es nada: un proceso firmado por Microsoft, el endpoint de autenticación de Microsoft, el propio ID de cliente de Microsoft. Cada capa de la cadena es confiable, que es exactamente por qué la telemetría de endpoint e identidad no muestra nada. Pero el tráfico mismo lo delata.
Cada host web AppX renderiza a través del mismo motor EdgeHTML heredado, y ese motor se anuncia a sí mismo: MSAppHost/3.0 emparejado con Edge/18 en el agente de usuario. Ningún navegador moderno produce esa cadena.
Edge basado en Chromium retiró EdgeHTML hace años, así que su única fuente legítima es un host AppX hablando con Microsoft. Cuando ese mismo agente de usuario se comunica con algo fuera de la infraestructura propiedad de Microsoft, no hay explicación benigna. Es un paquete cargado lateralmente con WindowsRuntimeAccess="all" llamando a casa hacia infraestructura controlada por el atacante. Una regla cubre toda la clase. Se basa en ese motor compartido, no en ningún binario host individual, independientemente de qué API de WinRT abuse el payload.
La regla se basa en ese agente de usuario y excluye destinos propiedad de Microsoft. La lista de permitidos importa. MSAppHost/3.0 también aparece en tráfico legítimo de primera parte hacia dominios propiedad de Microsoft que no terminan en .microsoft.com, como telemetría de la Store y otras llamadas de host AppX, así que un filtro ingenuo de "no microsoft.com" marcaría ese tráfico benigno.
Regla Sigma:
title: Sideloaded AppX Web Host Beaconing to Non-Microsoft Host
id: 8b1e2f34-5a6c-47d8-9e0a-1b2c3d4e5f60
status: experimental
description: >
Detects the MSAppHost/3.0 (EdgeHTML) user agent making outbound requests to
destinations outside Microsoft-owned domains. AppX web hosts (WWAHost.exe and
the wider class) only legitimately contact Microsoft endpoints; this user agent
to any other host indicates a sideloaded AppX package with
WindowsRuntimeAccess="all" reaching attacker-controlled infrastructure.
author: Andrew Schwartz
date: 2026/07/21
logsource:
category: proxy
detection:
selection:
c-useragent|contains: 'MSAppHost/3.0'
filter_microsoft:
cs-host|endswith:
- '.microsoft.com'
- '.microsoftonline.com'
- '.msauth.net'
- '.msftauth.net'
- '.windows.com'
- '.windows.net'
- '.windowsupdate.com'
- '.live.com'
- '.office.com'
- '.office365.com'
- '.sharepoint.com'
- '.msn.com'
- '.bing.com'
- '.msftconnecttest.com'
condition: selection and not filter_microsoft
falsepositives:
- First-party Microsoft Store / AppX telemetry to Microsoft-owned
domains not present in the filter list (extend the allow-list to tune)
level: high
Escribe eso en tu proxy, tu SIEM, o tu firewall. MSAppHost/3.0 hacia endpoints de Microsoft es normal: telemetría de la Store, y similares. MSAppHost/3.0 hacia cualquier otro lugar es el ataque.
Una nota sobre la lista de permitidos como un compromiso. Ampliar la lista de permitidos de Microsoft reduce los falsos positivos pero introduce una evasión teórica. Un atacante que pueda hacer que su endpoint de exfiltración caiga en un dominio propiedad de Microsoft, una redirección abierta, un subdominio de tenant abandonado, un sitio de SharePoint controlado por el atacante, pasa el filtro. Para la mayoría de los entornos, la reducción de falsos positivos vale la pena. Un entorno de alta seguridad puede ejecutar la lista estrecha (.microsoft.com, .microsoftonline.com, .windows.net únicamente) y aceptar el ruido extra a cambio de cerrar esa brecha.
Las capturas resuelven esto. El tráfico de exfiltración hacia mi servidor lleva MSAppHost/3.0 (el host de contenido EdgeHTML); el propio tráfico de inicio de sesión de Microsoft hacia login.microsoftonline.com es renderizado por un host diferente, MSAuthHost, en el motor Trident, y el registro de inicio de sesión de Entra registra su agente de usuario como "Mozilla/5.0 (Windows NT 10.0; Win64; x64; Trident/7.0; MSAuthHost/1.0; rv:11.0) like Gecko." Dos hosts diferentes, dos agentes de usuario diferentes. Así que MSAppHost/3.0 hacia cualquier destino no-loopback y no-Microsoft es anómalo de forma incondicional — el tramo del broker nunca llevará esa cadena. (Observado en 24H2; la lista de permitidos anterior aún ayuda con otro tráfico legítimo de MSAppHost como la telemetría de la Store.)
IOCs de respaldo de endpoint e identidad
Estos tienen menor confianza que la regla de red pero vale la pena conectarlos como corroboración:
Invocaciones de
Add-AppxPackage -Registercon rutas fuera deC:\Program Files\WindowsApps. Sysmon Event ID 1 / Windows 4688. De forma nativa, sin Sysmon:AppXDeploymentServer/Operational Event ID 400 registra el registro, y el registro de bloques de script de PowerShell (Event ID 4104) captura el manifiesto — ambos validados en el laboratorio.AppxManifest.xmlbajo rutas escribibles por el usuario (%LOCALAPPDATA%,%USERPROFILE%,%TEMP%) que contengaWindowsRuntimeAccess="all"con una URL externa, o una StartPage que apunte a una URL no-localhost.Conexiones salientes desde cualquier binario host AppX hacia IPs no-Microsoft. Sysmon Event ID 3. De forma nativa vía auditoría de Windows Filtering Platform (Security Event ID 5156), que registra la imagen del proceso y la IP de destino — validado en el laboratorio.
Cargas de DLL desde
C:\Users\*\AppData\Local\Packages\*\en lugar de System32. Sysmon Event ID 7.
Figura 10: Evento de seguridad 5156 — wwahost.exe realizando una conexión saliente hacia la IP del atacante; la imagen del proceso y la dirección de destino están ambas en el evento. No se requiere Sysmon.
Figura 11: AppXDeploymentServer/Operational Evento 400 — el paquete cargado lateralmente se registró con éxito — junto con la salida de Get-AppxPackage que muestra su InstallLocation bajo %LOCALAPPDATA%\Packages, la ruta escribible por el usuario.
Figura 12: AppXDeploymentServer/Operational Event ID 613 — el resumen de rendimiento del motor de despliegue para el paquete cargado lateralmente MicrosoftAccountVerification_1.0.0.0_neutral__ap5pwk43ghhtp. Este es solo un evento de temporización, registra la duración de cada etapa de la operación de registro y es puramente suplementario, incluido para contexto adicional. El registro probatorio es el Event ID 400 complementario ("Deployment Register operation … finished successfully").
Recomendaciones para defensores: la mitigación depende de ti
1. Despliega la regla de proxy MSAppHost/3.0 (arriba). Una regla, toda la clase de hosts AppX, la más alta confianza, la tasa más baja de falsos positivos una vez que se ajuste la lista de permitidos.
2. Audita y restringe el Modo de Desarrollador en toda la flota. Esta es la puerta de requisito previo. Las máquinas estándar de usuario final no deberían tenerlo habilitado. Deshabilita vía GPO: Configuración de Equipo > Plantillas Administrativas > Componentes de Windows > Despliegue de Paquetes de Aplicación > Permitir que todas las apps confiables se instalen > Deshabilitado. Inventario del estado actual:
$devMode = Get-ItemProperty `
-Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock" `
-Name "AllowDevelopmentWithoutDevLicense" -ErrorAction SilentlyContinue
if ($devMode.AllowDevelopmentWithoutDevLicense -eq 1) {
Write-Host "DEVELOPER MODE ON: $env:COMPUTERNAME"
}
4. Acceso Condicional, requiere dispositivos compatibles/administrados para la emisión de tokens. Esto no previene el ataque en un dispositivo administrado, pero limita la capacidad de un atacante de usar un token de actualización capturado desde una máquina no administrada en una red diferente. Combínalo con la Protección de Token donde esté disponible.
5. Acorta la vida útil de los tokens de actualización y habilita CAE. Limita la ventana de persistencia si la regla de red no lo captura a tiempo.
Gracias a Aaron Margosis y Nick Powers por su revisión exhaustiva de esta publicación, y a Lindsey O'Donnell-Welch por revisarla, formatearla y publicarla.
Para más información sobre la superficie ofensiva de AppX y MSIX, consulta la charla de Nick Powers en DEF CON 34, MSIX'd Up: Weaponizing the Modern Windows App Packaging Ecosystem.