Cómo arruiné mis vacaciones haciendo ingeniería inversa de WSC
(blog.es3n1n.eu)- defendnot, creado durante un viaje a Seúl, era una herramienta que intentaba desactivar Windows Defender llamando directamente a la API del servicio Windows Security Center (WSC), lo que terminó convirtiéndose en varios días de ingeniería inversa
- La herramienta anterior, no-defender, registraba en WSC la presencia de otro antivirus usando código de un antivirus existente; consiguió unas 1.5k estrellas en GitHub antes de ser eliminada por una solicitud de DMCA del fabricante del antivirus
- Al principio se reprodujeron las llamadas a la API COM de WSC en aproximadamente una hora, pero WSC validaba el proceso que hacía la llamada, así que el acceso era denegado desde procesos normales
- El análisis mostró que WSC comprobaba el SID de WinDefend, privilegios de administrador, firma y el flag
ForceIntegritydentro deDllCharacteristicsdel PE; en la implementación final se usóTaskmgr.exe - En un entorno enredado con una MacBook arm64, una PC remota en Estados Unidos, 210 ms de latencia con Parsec y una VM de Shadow.tech, la implementación se terminó corrigiendo un error de ruta de
ctx.biny un problema con las condiciones de energía de autorun
Contexto de por qué hice defendnot
- defendnot es una herramienta que usa directamente la API del servicio Windows Security Center para desactivar Windows Defender
- La parte clave de la implementación no fue tanto la llamada a WSC en sí, sino ir sorteando una por una las condiciones de validación que lo bloqueaban y un entorno de trabajo muy incómodo
- Una documentación técnica más detallada sobre WSC será publicada más adelante por otra persona
no-defender y el DMCA hace un año
- no-defender, publicado hace alrededor de un año, usaba la API de Windows para antivirus con el fin de apagar Windows Defender
- Esa API estaba pensada para avisarle al sistema que “hay otro antivirus, así que no hace falta ejecutar los escaneos de Defender”
- El componente del sistema que administra esa parte es Windows Security Center (WSC)
- no-defender funcionaba forzando el registro en WSC de un antivirus existente usando código de terceros de ese antivirus
- A las pocas semanas de publicarse consiguió aproximadamente 1.5k stars, y cuando el fabricante del antivirus usado presentó una solicitud de retiro por DMCA, se vació el repositorio y ahí terminó todo
El análisis de WSC que volvió a arrancar durante un viaje a Seúl
- Mientras se hospedaba en un Airbnb en Seúl, recibió un mensaje de MrBruh, que había estado revisando no-defender y estaba investigando si era posible una implementación “limpia” sin binarios de antivirus
- Normalmente lleva una laptop x86 aparte para CTFs o trabajos de reversing en x86, pero en este viaje solo había llevado una MacBook M4Pro
- Aun con la desventaja de no tener equipo para reversing x86, empezó a analizar WSC aprovechando el tiempo antes de que sus amigos se despertaran
Día 1: reproducción de la API COM de WSC y primer acceso denegado
- MrBruh proporcionó los binarios más recientes de WSC, y se tomó como referencia la implementación de registro en WSC del antivirus que se había usado antes
- WSC tiene una API COM usada por los antivirus, y se reprodujeron en alrededor de una hora las llamadas que hacía ese antivirus existente
- Se hicieron pruebas arrancando Windows arm64 en Parallels, pero el resultado fue access denied
- Por experiencia previa ya se sabía que WSC validaba el proceso que invocaba la API, y al principio se sospechó que podía tratarse de una validación de firma
- Al inyectar código en el proceso que el antivirus existente usaba para sus operaciones con WSC, las llamadas COM para registrar un nuevo antivirus y actualizar su estado funcionaron correctamente
Intento de eliminar la dependencia de binarios de antivirus
- Para evitar que el nuevo proyecto volviera a enfrentar reclamos del fabricante del antivirus anterior, se intentó usar binarios provistos por el sistema en lugar de binarios del antivirus
- El primer proceso elegido fue
cmd.exe, pero las llamadas a la API de WSC fueron rechazadas - Al revisar
wscsvc.dll, apareció código que comprobaba si el proceso llamador era PPL - Un proceso creado simplemente con
CreateProcessAno era un proceso protegido PPL, y esa madrugada ya no se pudo avanzar más
Día 2: montar un entorno incómodo de depuración remota
- En la MacBook arm64 era difícil trabajar bien con Windows x86, y se quería evitar tanto trabajar en arm64 como quedarse sin x64dbg
- Su amigo pindos permitió acceso a su PC y se conectó por Parsec
- Como la conexión era desde Corea a una PC ubicada en Estados Unidos, la latencia promedio era de unos 210 ms
- En ese momento el flujo de trabajo era extremadamente engorroso
- Compilar el módulo con MSVC en Windows arm64 dentro de Parallels
- Compartir los artefactos compilados con el host mediante una carpeta compartida
- Copiar los artefactos a la VM sobre la PC de pindos usando AnyDesk
- Depurar el servicio WSC con 210 ms de latencia por Parsec
- El entorno era lo bastante incómodo como para reducir mucho la velocidad de desarrollo y análisis
Depuración del servicio WSC y el SID de WinDefend
- El servicio WSC es una DLL ejecutada por
svchost, y el principal obstáculo para adjuntar el depurador era la protección PPL - En la VM se activó el modo de prueba y se usó un driver que, con unas pocas líneas de código en modo kernel, quitaba el PPL del proceso objetivo
- El punto donde fallaba
cmd.exeal intentar registrar un antivirus en WSC eraWscServiceUtils::CreateExternalBaseFromCaller - Esa función se hacía pasar por el cliente RPC y luego comprobaba si el token del proceso llamador contenía el SID de
WinDefend - Como en ese momento no se conocía bien el funcionamiento de los tokens de Windows, se concluyó que bastaba con hacerse pasar por
WinDefendpara superar la verificación - Por falta de sueño, también se interpretó erróneamente que el binario del antivirus existente pasaba esa comprobación de
IsMember
Intento de suplantar a WinDefend y fracaso
- Después de pasar varias horas aprendiendo sobre tokens de Windows, se implementó la idea de ejecutar el código con un token que incluyera el SID de WinDefend para pasar la verificación de WSC
- Se probó ejecutar el código con
cmdadjuntándole el SID deWinDefend, pero aunque la llamada COM devolvíaSTATUS_SUCCESS, en la práctica no se registraba ningún antivirus nuevo - Al final este enfoque no sirvió de mucho y hubo que volver a validarlo al día siguiente
Día 3: reconstrucción del algoritmo real de validación
- Al revisar de nuevo, se confirmó que el binario del antivirus existente no pasaba la comprobación del SID de WinDefend
- Pasar esa verificación llevaba a manipular el objeto WSC de Windows Defender, pero no servía porque no permitía desactivar Defender directamente solo con llamadas a WSC
- Se eliminó el código de suplantación de WinDefend y se analizó la otra rama de la condición
- En esa rama se comprobaba lo siguiente sobre el binario llamador
- Si el proceso estaba elevated
- Si la firma del binario era válida
- Si había un flag específico en
DllCharacteristicsdel PE
- El flag de
DllCharacteristicsque se comprobaba enCSecurityVerificationManager::CreateExternalBaseFromPESettingsera ForceIntegrity - Se creó en el repositorio de defendnot código que reproducía la validación binaria de WSC, dentro de la carpeta
wsc-binary-check, y se probó con binarios de System32
Uso de Taskmgr.exe y el bug de ctx.bin
- Como el amigo necesitaba volver a usar su PC, se pasó a conectarse directamente a la VM por Parsec, pero con codificación por software el entorno se volvió todavía más lento
- Se usó
Taskmgr.exeen lugar decmd.exe, pero seguían apareciendo errores de RPC - Por la latencia y los problemas de entrada ya era difícil depurar en esa misma VM, así que, por recomendación, se pagaron $30 por una suscripción a shadow.tech
- La VM de Shadow.tech tenía una versión más antigua de Windows, por lo que el código de
wscsvcno tenía tantas funciones inline como en la versión más reciente, y el resultado de la decompilación también era más fácil de leer - La causa real del error era que el nombre del AV enviado a WSC era incorrecto
defendnot-loaderusaba unctx.bincon parámetros serializados para pasar datos adefendnot.dll- Aunque ya se había implementado IPC aparte para seguimiento de estado, seguía quedando el método de
ctx.binpara pasar configuración, como residuo del viejo código de no-defender - La función que buscaba la ruta de
ctx.bintomaba como base la carpeta del móduloTaskmgr.exe, no la denodefend.dll - Como resultado, se enviaba un byte nulo como nombre del AV y WSC rechazaba ese buffer
- Después de corregir el problema de ruta, la prueba funcionó
Limpieza del código y problema con autorun
- Ese mismo día se siguió hasta las 8 a. m. limpiando el código e implementando funciones adicionales para terminar todo
- Entre esas funciones adicionales estaba la posibilidad de agregarse a autorun
- A las 8 a. m., lo único que todavía no funcionaba bien era autorun, y tras probar varios métodos sin éxito, se fue a dormir
- Al revisar de nuevo al día siguiente, se descubrió que el problema eran dos casillas relacionadas con energía en la creación de la tarea del programador
- Como la laptop no estaba conectada a corriente alterna, la tarea no se ejecutaba; al desactivar esos flags, autorun empezó a funcionar
- Después de unas horas más de limpieza de código, el trabajo quedó terminado
Cierre
- El trabajo en sí fue divertido, pero los problemas de entorno repetidos durante varios días y el flujo de depuración remota fueron una experiencia que no querría repetir
- En particular, la combinación de una MacBook arm64, una VM x86 remota, alta latencia, codificación lenta y un bug de ruta de archivo descubierto tarde elevó mucho la dificultad de la implementación
- Más adelante se publicará por separado documentación más técnica sobre WSC
1 comentarios
Opiniones de Hacker News
La forma más invasiva pero efectiva que encontré para desactivar Defender fue arrancar con un USB live de Linux, renombrar
C:\ProgramData\Microsoft\Windows Defendery luego crear un archivo vacío en su lugarComo referencia, WSC significa Windows Security Center
Me confundió bastante la expresión
the antivirus I was using. No entendía por qué esa empresa de antivirus tendría motivos para enviarle al autor una solicitud de baja por DMCAProbablemente quiso decir que el autor hizo ingeniería inversa de otro antivirus y metió parte de eso en un proyecto open source. Pero también vi títulos como
Impersonating WinDefend, así que al final me pregunto si el autor violó de alguna forma la ley de copyrightJusto antes del párrafo citado se explica que “el proyecto usó código de terceros de un antivirus que ya existía, y forzó a que ese antivirus se registrara en WSC como antivirus”
Este código se siente maldito:
https://github.com/es3n1n/defendnot/blob/master/defendnot-lo...
Si quieren ver qué está pasando realmente, es acá:
https://github.com/es3n1n/defendnot/blob/master/cxx-shared/s...
Por ejemplo, el lenguaje D trae incorporado el concepto de una sentencia que se ejecuta al final del scope
En resumen, no lo escribió una IA. Este código difiere la llamada a una función hasta el momento en que el objeto sale de scope. La implementación crea, mediante macros de C, una sintaxis más corta que omite parte de la definición necesaria de una lambda/función anónima de C, y genera un nombre de variable único para administrar la llamada diferida
Sin embargo, la sintaxis resultante evita la convención habitual de escribir en mayúsculas lo que representa una macro de C y, a primera vista, parece una llamada a función sobre un puntero a objeto. Si no estás familiarizado con este patrón o esperas que las macros se indiquen de otra forma, puede resultar confuso
Para algunas personas es lo bastante común y útil como para considerarlo casi un modismo en ciertos contextos. La explicación técnica en https://news.ycombinator.com/item?id=43959403#43960905 desglosa bien cómo funciona la macro
Durante unas vacaciones hice ingeniería inversa de los escritorios virtuales de Windows, y eso mejoró muchísimo mis vacaciones. Mi mejor recuerdo del año pasado fue darme cuenta de que la ingeniería inversa es realmente divertida
También aprendí muchas cosas interesantes; por debajo de RPC en Windows hay una capa de mensajería no documentada: https://csandker.io/2022/05/24/Offensive-Windows-IPC-3-ALPC....
Cada vez confirmo que, si la foto de perfil es un personaje de anime, el post va a ser bueno. Lo guardo para cuando en el futuro tenga que volver a un entorno Windows bastante malo
Para quien tenga curiosidad: WSC significa Windows Security Center. Yo también tuve que buscarlo
¿Por qué alguien querría desactivar WSC?
Si eres un proveedor de EDR, esto es una llamada de API ofuscada que puede usarse para suprimir o desactivar Windows Firewall. Por ejemplo, supongo que CrowdStrike puede tanto usar Windows Firewall como usar su propia implementación
netcat.exeno se puedeHace poco leí https://nostarch.com/windows-security-internals, y este artículo hizo que me cerrara mucho más
Ya tenía una idea general de cómo funcionan estas cosas por detrás en Windows, pero llegó en el momento justo. El último capítulo de ese libro también profundiza bastante en tokens y SID, tal como lo trató el autor de este artículo