Windows Notification Facility: la superficie de ataque más indocumentada

Debajo del corte hay una traducción de la presentación "La instalación de notificaciones de Windows: la superficie de ataque de kernel más indocumentada hasta ahora" presentada por Alex Ionescu y Gabrielle Viala en la conferencia BlackHat 2018 .




¿Qué es Windows Notification Facility (WNF)?


Windows Notification Facility es un mecanismo de notificación (disponible tanto en el núcleo como en el modo de usuario), que se basa en un modelo de editor-suscriptor ( pubsub , Publisher / Subscriber). El mecanismo se agregó en Windows 8: en parte para resolver algunas limitaciones de diseño de larga data en el sistema operativo, pero también sirvió como base para la implementación de notificaciones push similares a iOS / Android.


Su característica clave es que es un modelo ciego (en su mayoría sin registro) que permite la suscripción y publicación sin orden. Esto implica que un consumidor puede suscribirse a una notificación incluso antes de que la fuente haya publicado la notificación. Y que el que genera los eventos no está obligado a "registrar" el aviso por adelantado.


Además, el mecanismo admite:


  • notificaciones permanentes y temporales
  • identificadores únicos que aumentan monótonamente
  • búfer de carga útil (hasta 4 kilobytes) para cada evento
  • modelo de notificación de grupo de subprocesos con serialización basada en grupos
  • Un modelo de seguridad basado en el alcance que implementa descriptores de seguridad a través del mecanismo estándar DACL / SACL


¿Por qué apareció WNF?


Considere un ejemplo canónico: hay un controlador que quiere saber que se ha conectado un volumen con acceso de lectura y escritura. Para notificarle esto, Autochk (un análogo de fsck en Windows) informa un evento llamado VolumesSafeForWriteAccess. Pero para informar un evento, primero debe crear el objeto del evento en sí.


También necesitamos saber que Autochk ya está trabajando en el volumen, pero aún no ha señalado el evento que estamos esperando. Mala solución: sentarse en un bucle con sleep (), verificar la presencia de un evento y, cuando se crea el evento, espere.


Pero después de salir de la aplicación de Windows, todos sus descriptores están cerrados. Y cuando el objeto no tiene descriptores, se destruye. Entonces, ¿quién llevará a cabo este evento?


Sin WNF, la solución es que el núcleo del sistema operativo genere un evento antes de que se cargue cualquier controlador, y que Autochk lo abra como lo haría un consumidor, pero en lugar de esperar, debería señalar este evento.



Nombres de estado WNF


En el mundo WNF, un nombre de estado es un número de 64 bits. Pero hay un truco: de hecho, es una estructura codificada. El nombre del estado tiene una versión , una vida útil , un alcance , un indicador de persistencia de datos y un número de serie único .


typedef struct _WNF_STATE_NAME_INTERNAL { ULONG64 Version:4; ULONG64 NameLifetime:2; ULONG64 DataScope:4; ULONG64 PermanentData:1; ULONG64 Unique:53; } WNF_STATE_NAME_INTERNAL, *PWNF_STATE_NAME_INTERNAL; 

Pero estos datos estarán disponibles solo si pro-XOR es un número de 64 bits con una constante mágica:


 #define WNF_STATE_KEY 0x41C64E6DA3BC0074 


Vida del nombre del estado


El nombre del estado de WNF puede ser (WNF_STATE_NAME_LIFETIME):


  • bien conocido
  • permanente
  • persistente
  • temporal

Los primeros tres están asociados con las claves correspondientes en el registro, donde se almacenará la información de estado:


  • los nombres conocidos viven en HKLM \ SYSTEM \ CurrentControlSet \ Control \ Notificaciones
  • los nombres persistentes viven en HKLM \ SOFTWARE \ Microsoft \ Windows NT \ CurrentVersion \ Notificaciones
  • los nombres persistentes viven en HKLM \ SOFTWARE \ Microsoft \ Windows NT \ CurrentVersion \ VolatileNotifications

Los nombres conocidos tienen su propia peculiaridad: no se pueden registrar. Dicho nombre ya debería presentarse en el registro en el momento del inicio del sistema. Los nombres persistentes y persistentes requieren el privilegio SeCreatePermanentPrivilege incluido (como otros objetos globales) para crearlos. Los nombres persistentes viven fuera del proceso de registro, mientras que los nombres persistentes sobreviven al reinicio del sistema.



Alcance de los datos


El ámbito de datos define el primer límite de seguridad alrededor del nombre de estado WNF; determina quién lo ve y tiene acceso a él. El alcance del nombre del estado puede ser:


  • el sistema
  • el carro
  • sesión de usuario
  • el usuario
  • el proceso

Además de proporcionar límites de seguridad, los ámbitos WNF se pueden usar para proporcionar diferentes instancias de datos para el mismo nombre. El núcleo (como con otros mecanismos de seguridad) omite las comprobaciones de acceso de estado. El privilegio TCB permite el acceso de alcance cruzado a los nombres de estado WNF.


El "sistema" de alcance y la "máquina" de alcance son ámbitos globales. No tienen sus propios identificadores (usan contenedores globales diferentes). El alcance de la sesión del usuario utiliza el identificador de sesión (ID de sesión) como ID. El alcance de un usuario específico utiliza el SID de este usuario como identificador. La dirección del objeto EPROCESS es el identificador del alcance del proceso.



Números de secuencia


Para garantizar la unicidad, cada nombre de estado tiene un número de secuencia único de 51 bits. Los nombres conocidos incluyen una etiqueta de familia de 4 caracteres en su número de serie, y los 21 bits restantes se utilizan como un identificador único. Los nombres permanentes almacenan su número incremental con el valor de registro "SequenceNumber". Los nombres persistentes y temporales usan un contador de incremento común, que se encuentra en una variable global. Estos datos se almacenan y procesan por separado para cada contenedor (por silo) y están disponibles en PspHostSiloGlobals-> WnfSiloState.


Dentro de Microsoft, cada nombre WNF tiene un identificador "amigable" que se usa en el código, a veces se almacena en el espacio de nombres global con el mismo nombre. Por ejemplo, el símbolo nt! WNF_BOOT_DIRTY_SHUTDOWN, que tiene el valor 0x1589012fa3bc0875. Después de XOR con la constante mágica WNF_STATE_KEY obtenemos el valor 0x544f4f4200000801, que puede interpretarse a nivel de bits como:


 BOOT1, Well-Known Lifetime, System Scope, Version 1 


Sistema de llamadas para trabajar con WNF


Las llamadas al sistema Kernel le permiten registrar y eliminar nombres de estado de WNF, publicar y recibir datos de nombres de estado de WNF y también recibir varias notificaciones de WNF.



Registrar nombre de estado WNF


Con la excepción de nombres conocidos (como se mencionó anteriormente), el nombre de estado WNF se puede registrar mientras se ejecuta el sistema operativo:


 NTSTATUS ZwCreateWnfStateName ( _Out_ PWNF_STATE_NAME StateName, _In_ WNF_STATE_NAME_LIFETIME NameLifetime, _In_ WNF_DATA_SCOPE DataScope, _In_ BOOLEAN PersistData, _In_opt_ PCWNF_TYPE_ID TypeId, //      _In_ ULONG MaximumStateSize, //   4-  _In_ PSECURITY_DESCRIPTOR SecurityDescriptor // **  ); 

Hay un sistema simétrico llamado ZwDeleteWnfStateName con el que puede eliminar el nombre del estado registrado (de nuevo, excepto los conocidos).



Publicar datos de estado de WNF


Para establecer o cambiar los datos del nombre de estado WNF, puede usar la llamada al sistema ZwUpdateWnfStateData:


 NTSTATUS ZwUpdateWnfStateData ( _In_ PCWNF_STATE_NAME StateName, _In_reads_bytes_opt_(Length) const VOID* Buffer, _In_opt_ ULONG Length, //   ,   MaximumSize,    _In_opt_ PCWNF_TYPE_ID TypeId, //      _In_opt_ const PVOID ExplicitScope, //  , SID ,  (ID)  _In_ WNF_CHANGE_STAMP MatchingChangeStamp, //     _In_ LOGICAL CheckStamp //         ); 

Hay un sistema simétrico que llama a ZwDeleteWnfStateData para eliminar (limpiar) los datos del nombre de estado WNF.



Obtener datos de estado de WNF


Para solicitar los datos del nombre de estado WNF, se puede utilizar la siguiente llamada al sistema (la mayoría de los parámetros son similares a la función Actualizar):


 NTSTATUS ZwQueryWnfStateData ( _In_ PCWNF_STATE_NAME StateName, _In_opt_ PCWNF_TYPE_ID TypeId, _In_opt_ const VOID* ExplicitScope, _Out_ PWNF_CHANGE_STAMP ChangeStamp, _Out_writes_bytes_to_opt_(*BufferSize, *BufferSize) PVOID Buffer, _Inout_ PULONG BufferSize //   0,      ); 

La verdadera fortaleza radica en el hecho de que las funciones API Actualizar y Consultar no requieren de hecho un nombre de estado WNF registrado . Y si el nombre no es temporal (y el código de llamada tiene suficientes privilegios), ¡se puede registrar una instancia del nombre en tiempo real!



Notificaciones de WNF


Hasta ahora, hemos asumido que el consumidor sabe cuándo llamar a la función de adquisición de datos. Pero también está bloqueando la lectura , que funciona utilizando un sistema de notificación (que está más cerca del verdadero modelo de editor-suscriptor).


Primero, el proceso debe registrar el evento llamando a la función ZwSetWnfProcessNotificationEvent. Luego debe llamar a la función ZwSubscribeWnfStateChange, especificando una máscara de evento para obtener el identificador de suscripción en la salida. Los eventos pueden ser de dos tipos:


  • Notificaciones de datos:
    • 0x01 - apariencia de datos
    • 0x10 - destrucción de nombre
  • Meta Metanotificaciones
    • 0x02: aparición de un suscriptor que recibe notificaciones de datos (suscriptor de datos)
    • 0x04: aparición de un suscriptor que recibe meta notificaciones (Meta suscriptor)
    • 0x08: aparición de un suscriptor que recibe notificaciones de datos y metanotificaciones (suscriptor genérico)

Entonces debe esperar el evento que se grabó. Y cada vez que el evento se convierte en una señal, debe llamar a la función ZwGetCompleteWnfStateSubscription, que devuelve WNF_DELIVERY_DESCRIPTOR.


Pero estas funciones API de bajo nivel tienen un problema (gracias a Gabi por investigarlo): cada proceso solo puede tener un evento registrado.



API de modo de usuario de alto nivel (ntdll)


Cuando se trata de notificaciones, las cosas se complican, por lo que la capa rtl de ntdll.dll proporciona una interfaz más simple:


 NTSTATUS RtlSubscribeWnfStateChangeNotification ( _Outptr_ PWNF_USER_SUBSCRIPTION* Subscription, _In_ WNF_STATE_NAME StateName, _In_ WNF_CHANGE_STAMP ChangeStamp, _In_ PWNF_USER_CALLBACK Callback, _In_opt_ PVOID CallbackContext, _In_opt_ PCWNF_TYPE_ID TypeId, _In_opt_ ULONG SerializationGroup, _In_opt_ ULONG Unknown ); 

De hecho, no es necesario llamar directamente a los servicios del sistema: solo use una única cola de eventos controlada por ntdll.dll.


Detrás de escena, el contenido de WNF_DELIVERY_DESCRIPTOR se convierte en parámetros de devolución de llamada:


 typedef NTSTATUS (*PWNF_USER_CALLBACK) ( _In_ WNF_STATE_NAME StateName, _In_ WNF_CHANGE_STAMP ChangeStamp, _In_opt_ PWNF_TYPE_ID TypeId, _In_opt_ PVOID CallbackContext, _In_ PVOID Buffer, _In_ ULONG BufferSize); 

Para cada nueva suscripción, se realiza una entrada, que se coloca en la lista a la que apunta la variable global RtlpWnfProcessSubscriptions. La lista se basa en uno de los campos WNF_NAME_SUBSCRIPTION, que es de tipo LIST_ENTRY. Cada WNF_NAME_SUBSCRIPTION, a su vez, tiene otro campo LIST_ENTRY para organizar una lista de WNF_USER_SUBSCRIPTION con una devolución de llamada y contexto.



API de nivel de kernel de alto nivel (Ex)


WNF también proporciona funciones casi idénticas para el código del modo kernel (que se puede usar desde el controlador): tanto a través de llamadas al sistema exportadas como a través de funciones API de alto nivel en el tiempo de ejecución (capa Ex).


La función ExSubscribeWnfStateChange acepta el nombre de estado, las máscaras de tipo y la dirección de la función de devolución de llamada + contexto como entrada, y devuelve un descriptor de suscripción. Las funciones de devolución de llamada reciben el nombre de destino, la máscara de eventos, la etiqueta de cambio, pero no el búfer o su tamaño.


La función ExQueryWnfStateData, basada en el descriptor de suscripción pasado, lee los datos del estado actual. De hecho, cada devolución de llamada termina llamando a la función ExQueryWnfStateData para obtener los datos asociados con la notificación.


Tanto para las suscripciones en modo kernel como para las suscripciones en modo usuario, WNF (para rastrear suscripciones) crea una instancia de la estructura WNF_SUBSCRIPTION. Pero para el modo de usuario, algunos campos no se completarán, por ejemplo, Devolución de llamada y Contexto, porque para el modo de usuario, ntdll.dll almacena y procesa las direcciones de los controladores.



Estructuras de datos WNF



De un traductor : vea la siguiente sección.



WNF Analysis Utilities


De un traductor : aquí vale la pena recordar nuevamente que la presentación fue realizada no solo por Alex, sino también por Gabrielle Viala . En particular, su autoría pertenece al módulo WnfCom que se describe a continuación. Además, Gabrielle describió las estructuras internas de WNF con suficiente detalle (vea la ilustración en la sección anterior). Desafortunadamente, la mayoría de sus diapositivas están ausentes en el pdf de la presentación (indicado como el original) o se indican exclusivamente por títulos. Pero:



Y del traductor : si alguien quiere complementar la traducción actual con el contenido de las diapositivas de Gabrielle o ampliar la traducción de la taquigrafía de cualquier parte del video del discurso, bienvenido. Para la conveniencia de agregar / cambiar fragmentos grandes, puedo publicar la fuente de traducción en github (u otro servidor de control de versiones).



Wnfcom


WnfCom es un módulo de Python ( código fuente de github ) que muestra la interoperabilidad a través de WNF. Características clave:


  • le permite leer / escribir datos de instancias de instancias existentes
  • le permite crear nombres de estado temporales (como servidor )
  • le permite obtener una instancia de un objeto del lado del cliente que procesará notificaciones sobre el cambio de una instancia específica de un nombre

Ejemplo de uso:


 >>> from wnfcomimport Wnfcom >>> wnfserver = Wnfcom() >>> wnfserver.CreateServer() [SERVER] StateNamecreated: 41c64e6da5559945 >>> wnfserver.Write(b"potatosoup") Encoded Name: 41c64e6da5559945, Clear Name: 6e99931 Version: 1, Permanent: No, Scope: Machine, Lifetime: Temporary, Unique: 56627 State update: 11 bytes written 

 >>> from wnfcomimport Wnfcom >>> wnfclient = Wnfcom() >>> wnfclient.SetStateName("41c64e6da5559945") >>> wnfclient.Listen() [CLIENT] Event registered: 440 [CLIENT] Timestamp: 0x1 Size: 0xb Data:00000000: 70 6F 74 61 74 6F 20 73 6F 75 70 potato soup 


Wnfdump


WnfDump es una utilidad de línea de comandos escrita en C. El archivo ejecutable se puede encontrar en https://github.com/ionescu007/wnfun seleccionando el subdirectorio de la profundidad de bits requerida. La utilidad se puede utilizar para buscar información sobre nombres de estado WNF:


  • -d ( D ump) Volcar todos los nombres de estado WNF utilizando una enumeración basada en el registro. Se puede complementar con opciones:
    • -v ( V erbose) Una salida detallada que incluye un volcado hexadecimal de datos de estado WNF;
    • -s (Seguridad) Descriptores de seguridad: cadenas de permisos SDDL para el nombre de estado WNF.
  • -b ( B rute-force) Enumeración directa de nombres de estado WNF temporales (más sobre esto a continuación)
  • -i (Información) Muestra información sobre un solo nombre de estado WNF especificado
  • -r ( R ead) Lee datos del nombre de estado WNF especificado
  • -w ( W rite) Escribe datos en el nombre de estado WNF especificado
  • -n ( N otificación) Registre un suscriptor de notificaciones para el nombre de estado WNF especificado (en adelante será un caso de uso más específico con Edge)


Superficie de ataque WNF


Esta sección (más precisamente, sus subsecciones) discutirá posibles ataques y datos WNF sensibles e interesantes.



Divulgación de datos privilegiados


Al leer los miles de nombres de estado WNF que existen en el sistema, se pueden observar varios, cuyos datos parecen muy interesantes. Entre ellos, algunos cuyos datos son sospechosamente similares a los punteros u otros datos privilegiados.


Después de jugar en varias máquinas, en algunos casos fue posible encontrar un montón, una pila y otra información privilegiada que se divulgó a través de los límites de privilegios. Los informes de errores / vulnerabilidades se enviaron a MSRC en julio, pero se corrigieron en noviembre (después de la presentación). Por ejemplo: ¡4 kilobytes de pila se filtraron a través del evento WNF_AUDC *!


Los principales problemas son los mismos que vimos en estudios anteriores de j00ro, taviso y otros. Ciertos nombres de estado WNF contienen estructuras de datos codificados con varios problemas de relleno y / o alineación. En algunos casos, las pérdidas de memoria no inicializadas.
Del traductor : traducción de la parte introductoria del documento Detección de la divulgación de la memoria del núcleo con emulación x86 y seguimiento de manchas de Mateusz Jurczyk, también conocido como j00ro .



Descubrimiento de nombres de estado y permisos


El primer enfoque fue descubrir todos los posibles nombres de estado que podrían manipularse maliciosamente. Para nombres conocidos, permanentes y persistentes, la enumeración es factible enumerando las claves de registro. Luego, los valores encontrados se pueden comparar con identificadores amigables (hay varios lugares donde puede encontrarlos :))


Luego, también podemos ver el descriptor de seguridad en el registro (esto es lo primero en el búfer de datos). El descriptor de seguridad no es canónico: no tiene un propietario y un grupo, por lo que técnicamente no es válido. Pero no hay problema en sustituir un propietario y un grupo falsos para corregir el descriptor de seguridad.



Detección de nombres de estado temporales y sus permisos.


Pero con nombres temporales, los trucos descritos anteriormente no funcionarán: no están en el registro. Y solo el núcleo almacena estructuras de datos para ellos (! Wnf) en la memoria. Pero los nombres temporales en realidad no son tan difíciles de forzar:


  • La versión siempre importa 1
  • La vida siempre importa WnfTemporaryStateName
  • La marca permanente siempre se borra (el nombre de estado temporal no puede tener datos permanentes)
  • El alcance (alcance) puede tomar uno de los 4 valores

Sí, ¡pero el número de secuencia restante es de 51 bits! De hecho ... pero no olvides que los números de serie están creciendo de forma monótona. Y para los nombres temporales, la secuencia se restablece a 0 en cada arranque. Convencionalmente, puede tomar una ventana de un millón de números de serie: en un bucle, verifique la existencia de cada nombre (comenzando desde 0) llamando a ZwQueryWnfStateNameInformation con la clase de información solicitada WnfInfoStateNameExist (dado que el error de acceso también indica la existencia de un nombre). Si no existen otros millones de nombres, puede detener la búsqueda.


Los descriptores de seguridad de nombres temporales (como otros datos de nombres temporales) se almacenan en el núcleo. Por lo tanto, la única forma de solicitarlos es la extensión! Wnf al depurar el modo kernel. Pero podemos:


  • Haga una conclusión sobre los permisos de lectura cuando intente leer datos.
  • Para concluir que se permite la grabación al intentar escribir datos. Pero vale la pena considerar que una escritura exitosa de incluso 0 bytes destruye los datos que el consumidor real aún no ha logrado obtener. Y nuevamente, hay un truco: podemos aplicar el sello de cambio apropiado. Estamos tratando de escribir con la etiqueta 0xFFFFFFFF: la etiqueta se verifica después de la verificación de acceso, por lo tanto, el valor del error produce una pérdida de permiso de escritura.

Esto no nos da un descriptor de seguridad completo, pero al ejecutar el código con diferentes privilegios podemos tener una idea de las restricciones para diferentes cuentas del sistema (IL / Usuario / Administrador / SISTEMA bajo).



Listado de suscriptores


En la estructura WNF_PROCESS_CONTEXT, uno de los campos es el encabezado de la lista (LIST_ENTRY) de todas las suscripciones de este proceso. Cada suscripción es una instancia separada de WNF_SUBSCRIPTION.


Los suscriptores en modo kernel son principalmente propiedad del proceso del Sistema. Podemos usar el comando! List debugger para volcar controladores y sus parámetros registrados en el proceso del sistema WNF_SUBSCRIPTION. Vale la pena señalar que, en algunos casos, se utiliza un agregador de eventos (CEA.SYS), que oculta las direcciones de devolución de llamada reales en su estructura de contexto.


Podemos repetir este enfoque para los procesos en modo de usuario, pero la dirección de devolución de llamada será NULL, ya que estos son suscriptores en modo de usuario. Por lo tanto, debemos unirnos al espacio de usuario del proceso, obtener la tabla RtlpWnfProcessSubscriptions y luego volcar la lista de instancias WNF_USER_SUBSCRIPTION, cada una de las cuales ya contiene la dirección de devolución de llamada. Desafortunadamente, este personaje es estático, lo que significa que no está en caracteres abiertos, pero se puede encontrar al desarmarlo. Y nuevamente vale la pena prestar atención (por analogía con el modo de núcleo CEA.SYS) que muchos de los controladores de modo de usuario usan el agregador de eventos (EventAggregation.dll), que almacena la devolución de llamada en su contexto.



Nombres de estado WNF interesantes y sensibles


Esta sección proporcionará algunos ejemplos interesantes de cómo algunos nombres de estado WNF revelan información del sistema.



Determinar el estado del sistema y el comportamiento del usuario utilizando WNF


Algunos identificadores WNF se pueden usar para obtener información sobre el estado de la máquina que le interesa:


  • WNF_WIFI_CONNECTION_STATUS - Estado inalámbrico
  • WNF_BLTH_BLUETOOTH_STATUS - de manera similar, pero para Bluetooth (también WNF_TETH_TETHERING_STATE)
  • WNF_UBPM_POWER_SOURCE: muestra la fuente de alimentación (batería o adaptador de corriente)
  • WNF_SEB_BATTERY_LEVEL: contiene el nivel de batería
  • WNF_CELL_ *: en Windows Phone contiene información sobre: ​​red, número, intensidad de la señal, EDGE o 3G, ...

WNF :


  • WNF_AUDC_CAPTURE/RENDER — ( PID), /
  • WNF_TKBN_TOUCH_EVENT — ,
  • WNF_SEB_USER_PRESENT/WNF_SEB_USER_PRESENCE_CHANGED — Windows


API


, API , API , , /. WNF . , , WNF .


: WNF_SHEL_(DESKTOP)_APPLICATION_(STARTED/TERMINATED) modern- ( , ) DCOM, Win32. — ShellExecute: Explorer, cmd.exe, ...


, WNF API , :


  • WNF_SHEL_LOCKSCREEN_ACTIVE —
  • WNF_EDGE_LAST_NAVIGATED_HOST — URL, ( ) Edge

: Edge



WNF


WNF, . : WNF_FSRL_OPLOCK_BREAK — , (/), PID' !


WNF , . : WNF_SHEL_DDC_(WNS/SMS)_COMMAND – 4 , .


, WNF, . : WNF_CERT_FLUSH_CACHE_TRIGGER ( ), WNF_BOOT_MEMORY_PARTITIONS_RESTORE, WNF_RTDS_RPC_INTERFACE_TRIGGER_CHANGED, ...



WNF


:


  • WriteProcessMemory —
  • ( ) —
  • (Atom) —
  • — , WM_COPYDATA DDE,
  • GUI — ( ) ,

WNF :


  • WNF, (, )
  • Rtl/ZwQueryWnfStateData WNF

, :


  • APC s
  • (Remote Threads)
  • (Changing Thread Context)
  • " window long " — , ,

WNF_USER_SUBSCRIPTION ( WNF_NAME_SUBSCRIPTION, RtlpWnfProcessSubscriptions). ( CFG ), ( 5 6 ).


, : , , , -.




WNF SEB_, ( S ystem E vents B roker). SystemEventsBrokerServer.dll SystemEventsBrokerClient.dll API . , SEB SEB, .


CEA.SYS EventAggregation.dll. " " (Event Aggregation Library), , : , , WNF , . WNF, . .




: .






, Windows Notification Facility Alex' Gabrielle. ( ) redp .



WNF ( ) wincheck . , Gabrielle Viala , redp, : http://redplait.blogspot.com/search/label/wnf .




PoC ( github ) explorer ( — notepad). modexp : Callback WNF_USER_SUBSCRIPTION. :


  • explorer.exe
  • WNF_USER_SUBSCRIPTION
  • RWX- , WriteProcessMemory (, VirtualAllocEx + WriteProcessMemory)
  • WNF_USER_SUBSCRIPTION ( WriteProcessMemory)
  • ntdll!NtUpdateWnfStateData(...) ,
  • Restaurar el controlador original a WNF_USER_SUBSCRIPTION y recursos asignados gratis

Source: https://habr.com/ru/post/459626/


All Articles