Hunting for Blues: el BSOD Plan 9 Protocol BSOD


Subsistema de Windows para Linux Plan 9 Descripción general de la investigación de protocolo

Este es el blog final de la trilogía de la serie de investigación de McAfee sobre la implementación del Subsistema de Windows para Linux (WSL): vea The Twin Journey (parte 1) y Knock, Knock – Who’s There (parte 2). La investigación anterior discutió los ataques de evasión de archivos cuando el servidor Microsoft P9 puede ser secuestrado con un servidor malicioso P9 (Plan 9 File System Protocol). Desde Windows 10 versión 1903, es posible acceder a los archivos de Linux desde Windows utilizando el protocolo P9. El sistema operativo Windows 10 viene con el servidor P9 como parte de la instalación de WSL para que pueda comunicarse con un sistema de archivos Linux. En esta investigación exploramos la implementación del protocolo P9 dentro del núcleo de Windows y si podríamos ejecutar código desde un servidor P9 malicioso. Creamos un servidor P9 malicioso secuestrando el servidor P9 de Microsoft y reemplazándolo por un código que podemos controlar.

En un escenario de ataque típico, descubrimos que si WSL está habilitado en Windows 10, un atacante local no privilegiado puede secuestrar el canal de comunicación WSL P9 para provocar una Denegación de servicio (DoS) local o Pantalla azul de la muerte (BSOD) en el kernel de Windows No es posible lograr la escalada de privilegios (EoP) dentro del kernel de Windows debido a esta vulnerabilidad; el BSOD parece ser el diseñado por Microsoft dentro de su flujo de fallas legítimo, si el núcleo de Windows recibe paquetes de comunicación del servidor P9 con formato incorrecto. Un usuario sin privilegios no debería poder BSOD el kernel de Windows, desde una perspectiva local o remota. Si WSL no está habilitado (deshabilitado de forma predeterminada en Windows 10), el ataque aún puede ejecutarse, pero requiere que el atacante sea un usuario privilegiado para habilitar WSL como requisito previo.

Recientemente ha habido algunas vulnerabilidades de protocolo críticas y transmisibles dentro de los protocolos RDP y SMB en forma de Bluekeep y SMBGhost. Las vulnerabilidades explotables de forma remota tienen un riesgo muy alto si son aptas para el trabajo, ya que pueden extenderse a través de los sistemas sin ninguna interacción del usuario. Las vulnerabilidades locales son de menor riesgo ya que un atacante primero debe tener presencia en el sistema; en este caso deben tener un servidor P9 malicioso ejecutándose. La implementación del protocolo P9 se ejecuta localmente dentro del kernel de Windows, por lo que el objetivo, como ocurre con la mayoría de la búsqueda de vulnerabilidades locales, es encontrar una vulnerabilidad que permita una escalada de privilegios (EoP).

En este blog profundizamos en la implementación del protocolo y el proceso de búsqueda de vulnerabilidades. No existe ningún riesgo para los usuarios de WSL de esta investigación, que ha sido compartida y validada por Microsoft. Esperamos que esta investigación ayude a mejorar la comprensión de la pila de comunicaciones WSL P9 y que la investigación adicional sea más fructífera más adelante.

Ha habido algunas vulnerabilidades en WSL como aquí y aquí pero no parece haber ninguna investigación documentada de la implementación del protocolo P9 que no sea esta.

Descripción general del protocolo P9

los Plan 9 Protocolo de sistema de archivos El servidor permite que un cliente navegue por su sistema de archivos para crear, eliminar, leer y escribir archivos. El cliente envía solicitudes (mensajes T) al servidor y el servidor responde con mensajes R. El protocolo P9 tiene un encabezado que consta de campos de tamaño, tipo y etiqueta, seguidos de un campo de tipo de mensaje según la solicitud del cliente. El tipo de mensaje R enviado por el servidor debe coincidir con el tipo de mensaje T iniciado desde el cliente. El cliente decide el tamaño máximo de conexión para la transferencia de datos durante la configuración de la conexión; en nuestro análisis a continuación, es 0x10000 bytes.

Encabezado de protocolo P9 seguido de unión de tipo de mensaje (solo hemos incluido el subconjunto de tipos de mensaje P9 que son de interés para la investigación de vulnerabilidad):

struct P9Packet

tamaño u32;

tipo u8;

etiqueta u16;

Unión

struct p9_rversion rversion;

struct p9_rread rread;

struct p9_rreaddir rreaddir;

struct p9_rwalk rwalk;

u

P9Packet

El mensaje T P9 y los números correspondientes del mensaje R para los tipos que nos interesan (el mensaje R siempre es un mensaje T + 1):

enumeración p9_msg_t

P9_TREADDIR = 40,

P9_RREADDIR = 41,

P9_TVERSION = 100,

P9_RVERSION = 101,

P9_TWALK = 110,

P9_RWALK = 111,

P9_TREAD = 116,

P9_RREAD = 117,

En la capa de tipo de mensaje, que sigue al encabezado del protocolo P9, puede ver los campos, que son de tamaño variable, resaltados a continuación:

struct p9_rwalk

u16 nwqid;

struct p9_qid wqids (P9_MAXWELEM);

struct p9_rread

u32 contar;

u8 *datos;

struct p9_rreaddir

u32 contar;

u8 *datos;

struct p9_rversion

u32 msize;

struct p9_str versión;

struct p9_str

u16 Len;

char *str;

Según la estructura de paquetes del protocolo P9, debemos buscar vulnerabilidades de tipo de mensaje y corrupción de memoria, como lectura / escritura fuera de los límites.

Entonces, ¿cómo se verá una estructura de paquetes en la memoria? La figura 1 muestra el encabezado del protocolo y el diseño de memoria del tipo de mensaje de WinDbg. El tamaño del mensaje (msize) se negocia a 0x10000 y la cadena de versión es "9P2000.W".

Figura 1. Paquete P9 para el tipo de mensaje rversion

Windows WSL P9 Communication Stack y estructuras de datos

Figura 2. Implementación del protocolo del sistema de archivos de Windows Plan 9 dentro de WSL

El controlador de mini redirector de red p9rdr.sys registra el dispositivo “\ Device \ P9Rdr” con el Subsistema de búfer de unidad redirigido (RDBSS) utilizando el RxRegisterMinirdr API como parte de la rutina p9rdr DriverEntry. Durante este registro, las siguientes API P9 o rutinas de controladores están expuestas al RDBSS:

P9 No implementado

P9Inicio

P9Stop

P9DevFcbXXXControlFile

P9CreateSrvCall

P9CreateVNetRoot

P9ExtractNetRootName

P9FinalizeSrvCall

P9FinalizeVNetRoot

P9Crear

P9CheckForCollapsibleOpen

P9CleanupFobx

P9CloseSrvOpen

P9ForceClosed

P9ExtendFile

P9Flush

P9QueryDirectoryInfo

P9QueryVolumeInfo

P9QueryFileInfo

P9SetFileInfo

P9IsValidDirectory

P9Leer

P9Escribir

No se puede acceder directamente al controlador p9rdr desde el modo de usuario utilizando la API DeviceIoControl y todas las llamadas deben pasar por el RDBSS.

Como se ve en la Figura 2, cuando un usuario navega al recurso compartido WSL en "\ wsl $" desde Explorer, el controlador RDBSS llama al controlador P9 a través de las API registradas previamente.

DIODO es una implementación del servidor de archivos, que modificamos para que sea un servidor P9 "malicioso", donde reclamamos el nombre del socket "fsserver" antes del sistema operativo Windows en una forma de ataque en cuclillas. Una vez que reemplazamos el servidor Microsoft P9 con el servidor DIOD, modificamos la función "np_req_respond" (explicada en la sección de restricciones fuzzing) para que podamos controlar los paquetes P9 para enviar respuestas maliciosas al núcleo de Windows. Nuestro servidor malicioso P9 y el secuestro de sockets se explicaron en detalle aquí.

Entonces, ahora sabemos cómo viajan los datos desde Explorer al controlador P9, pero ¿cómo se comunica el controlador P9 con el servidor P9 malicioso? Se comunican a través de sockets AF_UNIX.

Hay dos estructuras de datos importantes que se utilizan para controlar el flujo de datos dentro del controlador P9 llamado P9Client y P9Exchange.

Las estructuras de datos P9Client y P9Exchange, cuando se realizan ingeniería inversa en los campos relevantes para esta investigación, se parecen a lo siguiente (los campos que no son relevantes para este análisis se han etiquetado como UINT64 para la alineación):

estructura typedef P9Client
PVOID * WskTransport_vftable
PVOID * GlobalDevice
UNINT64 RunRef
WskSocket * WskData
UINT64
UINT64
UINT_PTR
PVOID * MidExchangeMgr_vftable
PRDBSS_DEVICE_OBJECT * RDBSS
UINT64
PVOID ** WskTransport_vftable
PVOID ** MidExchangeMgr_vftable
P9Packet * P9PacketStart
UINT64 MaxConnectionSize
UINT64 Rmessage_size
P9Packet * P9PacketEnd
UINT_PTR
UINT64
UINT64
UINT_PTR
UINT64
UINT64
PVOID * Session_ReconnectCallback
PVOID ** WskTransport_vftable
UINT64
UINT_PTR
UINT_PTR
UINT64
UINT_PTR
UINT64
UINT64
UINT64
P9Client

Diseño de memoria de estructura de datos P9Client en WinDbg:

estructura typedef P9Exchange
UINT64
UINT64
P9Client * P9Client
UINT64 Tmessage_type
UINT64
UINT_PTR
PVOID * Lambda_PTR1
PVOID * Lambda_PTR2
PRX_CONTEXT * RxContextUINT64 Tmessage_size
UINT64
UINT64
UINT64
UINT64
UINT64
UINT64
P9Exchange

El diseño de la estructura de datos P9Exchange en WinDbg:

Para comunicarse con el servidor P9, el controlador P9 crea un Paquete de solicitud de E / S (IRP) para recibir datos del Winsock Kernel (WSK) Un punto importante a tener en cuenta es que el Lista de descriptores de memoria (MDL) utilizado para mantener los datos pasados ​​entre el servidor P9 y el cliente P9 del kernel de Windows es 0x10000 bytes (el tamaño máximo de conexión mencionado anteriormente).

WskTransport largo virtual :: Recibir ()

UNINT64 MaxConnectionSize = 0x10000;

P9_IRP_OBJECT = RxCeAllocateIrpWithMDL (2, 0, 0i64);

P9_MDL = IoAllocateMdl (P9Client-> P9PacketStart, MaxConnectionSize, 0, 0, 0i64);
anular MmBuildMdlForNonPagedPool (P9_MDL);
P9_IRP_OBJECT-> IoStackLocation-> Parámetros-> MDL = & P9_MDL;

P9_IRP_OBJECT-> IoStackLocation-> Parámetros-> P9Client = & P9Client;

P9_IRP_OBJECT-> IoStackLocation-> Parámetros-> DataPath = & P9Client :: ReceiveCallback;
P9_IRP_OBJECT-> IoStackLocation-> CompletionRoutine = p9fs :: WskTransport :: SendReceiveComplete
WskProAPIReceive (* WskSocket, * P9_MDL, 0, * P9_IRP_OBJECT);

El MDL se asigna a la dirección del campo P9PacketStart dentro de la estructura de datos P9Client.

Al finalizar IRP, se llama a la rutina de finalización WskTransport :: SendReceiveComplete para recuperar la estructura P9Client del IRP para procesar la respuesta del paquete P9 desde el servidor:

int static WskTransport :: SendreceiveComplete (IRP * P9_IRP_OBJECT)

P9Client = & P9_IRP_OBJECT-> IoStackLocation-> Parámetros-> P9Client;

P9Client :: ReceiveCallback (P9Client * P9Client);

La estructura de datos P9Client se utiliza dentro de un IRP para recibir los datos del mensaje R, pero ¿cuál es el propósito de la estructura de datos P9Exchange?

  1. Cuando el controlador P9 envía un mensaje T al servidor, debe crear un intercambio para que pueda rastrear el estado entre el tipo de mensaje enviado (mensaje T) y el que devuelve el servidor (mensaje R).
  2. Contiene funciones lambda para ejecutar en el tipo de mensaje específico. El campo Tmessage_type dentro de la estructura de datos de P9Exchange asegura que el servidor solo puede enviar mensajes R al mismo tipo de mensaje T que recibió del controlador P9.
  3. PRX_CONTEXT * La estructura RxContext se utiliza para transferir datos entre Explorer y el controlador p9rdr a través del controlador RDBSS.

El flujo de un mensaje WALK T se puede ver a continuación:

Dentro de la función P9Client :: CreateExchange, MidExchangeManager :: RegisterExchange es responsable de registrar la estructura de datos P9Exchange con el RDBSS utilizando una ID multiplex (MID) para distinguir entre el servidor concurrente y las solicitudes del cliente.

MidExchangeManager :: RegisterExchange (* P9Client, * P9Exchange)

NTSTATUS RxAssociateContextWithMid (PRX_MID_ATLAS P9Client-> RDBSS, PVOID P9Exchange, PUSHORT NewMid);

Los campos importantes dentro de las estructuras de datos P9Client y P9Exchange que discutiremos más a fondo durante el análisis:

  1. PClient-> MaxConnectionSize: se establece al comienzo de la conexión y no puede ser controlado por un atacante
  2. P9Client-> P9PacketStart: apunta al paquete P9 recibido y puede ser controlado completamente por un atacante
  3. P9Client-> Rmessage_size –puede ser controlado completamente por un atacante
  4. P9Exchange-> Tmessage_type: se establece durante la creación del mensaje T y no puede ser controlado por un atacante
  5. P9Exchange-> RxContext: se utiliza para pasar datos del controlador P9 a través del RDBSS al Explorer

Ahora que sabemos cómo funciona el protocolo dentro del núcleo de Windows, la siguiente etapa es la búsqueda de vulnerabilidades.

Búsqueda de vulnerabilidades en el servidor de Windows Kernel P9

Lógica de procesamiento de paquetes P9

Desde una perspectiva de vulnerabilidad, queremos auditar la lógica del kernel de Windows dentro de p9rdr.sys, responsable de analizar el tráfico del servidor P9 malicioso. La Figura 3 muestra la fuente del paquete P9 y el receptor, o dónde se completa el procesamiento del paquete dentro del controlador p9rdr.

figura 3. Capas de procesamiento de kernel de Windows para el análisis de respuesta de servidor malicioso del protocolo P9

Ahora que hemos identificado el código para analizar los tipos de mensajes de protocolo P9 de interés, necesitamos auditar el código para detectar confusiones de tipo de mensaje y vulnerabilidades de corrupción de memoria, tales como lectura / escritura fuera de límites y desbordamientos.

Restricciones difusas

Hubo una serie de restricciones que dificultaron la implementación de la lógica de fuzzing automatizada:

  1. El tipo de mensaje R enviado desde el servidor P9 malicioso debe coincidir con el tipo de mensaje T enviado por el núcleo de Windows
  2. Tiempos de espera en capas superiores de la pila WSL

Sin embargo, los desafíos anteriores podrían superarse, pero dado que el protocolo es relativamente simple, decidimos centrarnos en revertir la validación de la lógica de procesamiento. Para verificar la validación de la lógica de procesamiento, creamos algunas capacidades de fuzzing manual dentro del servidor malicioso P9 para probar los límites de campo de paquetes de longitud variable identificados en la descripción general del protocolo.

A continuación se muestra un tipo de mensaje RREAD R que envía un paquete P9 malicioso en respuesta a un mensaje T RREAD donde controlamos los campos de longitud variable de conteo y datos.

srv.c

vacío

np_req_respond (Npreq * req, Npfcall * rc)

NP_ASSERT (rc! = NULL);

xpthread_mutex_lock (& ​​req-> lock);

u32 cuenta = 0xFFFFFFFF;

Npfcall * fake_rc;

u8 * datos = malloc (0xFFF0);

memset (datos, "A", 0xFFF0);

if (! (fake_rc = np_alloc_rread1 (cuenta)))

devuelve NULL;

if (fake_rc-> u.rread.data)

memmove (fake_rc-> u.rread.data, datos, recuento);

if (rc-> type == 0x75)

fprintf (stderr, "Respuesta de paquete RREAD");

req-> rcall = fake_rc;

más

req-> rcall = rc;

if (req-> state == REQ_NORMAL)

np_set_tag (req-> rcall, req-> tag);

np_conn_respond (req);

xpthread_mutex_unlock (& ​​req-> lock);

Comprobaciones de validación

Los datos pasados ​​al controlador P9 están contenidos dentro de una asignación de memoria de conexión de 0x10000 bytes (P9Client-> P9PacketStart) y la mayor parte del procesamiento se realiza dentro de esta asignación de memoria, con dos excepciones donde se llama memmove dentro de P9Client :: FillData y P9Client :: Funciones Lambda_2275 (discutidas a continuación).

Un ataque de confusión de tipo mensaje no es posible ya que la estructura de datos de P9Exchange rastrea el mensaje R hasta su tipo de mensaje T correspondiente.

Además, el controlador P9 utiliza un lector de span para procesar campos de tipo de mensaje de longitud estática. La estructura P9Exchange almacena el tipo de mensaje que se utiliza para determinar el número de campos dentro de un mensaje durante el procesamiento.

Si bien podemos controlar el tamaño del paquete P9, no podemos controlar el P9Client-> MaxConnectionSize, lo que significa que se eliminarán los mensajes mayores o iguales a 0x10000.

Todas las verificaciones de campo de tamaño variable dentro de la capa de tipo de mensaje del protocolo se verifican contra el campo de tamaño de Paquete P9 asegurando que un campo malicioso no dará como resultado un acceso de lectura o escritura fuera de los límites fuera de la asignación de memoria de conexión 0x10000.

Las funciones lógicas de procesamiento identificadas previamente fueron diseñadas de forma inversa para comprender la validación en los campos del protocolo, con un enfoque específico en los campos de longitud variable dentro de los tipos de mensaje rversion, rwalk y rread.

Al importar las estructuras de datos P9Client y P9Exchange en IDA Pro, el proceso de ingeniería inversa es relativamente sencillo para comprender la lógica de validación de paquetes. Las funciones a continuación se han invertido al nivel requerido para comprender la validación y no son representativas de toda la base del código de función.

P9Client :: ReceiveCallback valida que Rmessage_size no exceda el tamaño máximo de conexión de 0x10000

nulo P9Client :: ReceiveCallback (P9Client * P9Client) {
struct p9packet; uint64 MaxConnectionSize; uint64 Rmessage_size; MaxConnectionSize = P9Client-> MaxConnectionSize;
Rmessage_size = P9Client-> Rmessage_size; if (MaxConnectionSize) !P9Packet) terminate(P9Packet);if (Rmessage_size >= 0 && P9Client-> MaxConnectionSize> = Rmessage_size)

P9Client :: HandleReply (* P9Client)
más

terminar (P9Packet);

P9Client :: HandleReply – hay múltiples DoS locales aquí que resultan en una pantalla azul de la muerte (BSOD) dependiendo del tamaño de P9Client-> Rmessage_size y P9Client-> P9PacketEnd-> size, p. cuando P9Client-> P9PacketEnd-> el tamaño es cero, se llama a terminate (), que es BSOD.

nulo P9Client :: HandleReply (P9Client * P9Client) {

uint64 P9PacketHeaderSize = 7;

uint64 Rmessage_size = P9Client-> Rmessage_size;

if (Rmessage_size> = 7)
mientras que (1)

P9PacketEnd = P9Client-> P9PacketEnd;

si (! P9PacketEnd) se rompe;

uint64 P9PacketSize = P9Client-> P9PacketEnd-> size;
if (P9PacketSize> P9Client-> MaxConnectionSize); HandleIoError ();

if (Rmessage_size <P9PacketSize); P9Client :: FillData ();

if (Rmessage_size <4) terminate (); // comprobar que existe un campo de tamaño de encabezado P9 en el paquete

if (Rmessage_size> 5) fastfail (); // comprobar que existe un campo de tipo de encabezado P9 en el paquete

int message_type = P9PacketEnd-> type;

if (Rmessage_size <7) fastfail (); // comprobar que existe un campo de etiqueta de encabezado P9 en el paquete

uint64 tag = P9PacketEnd-> etiqueta;

uint64 P9message_size = P9PacketSize – P9PacketHeaderSize; // obteniendo el tamaño del mensaje

if (Rmessage_size – 7 <0) terminate (); // existe una capa de mensaje de verificación después del encabezado P9

if (tamaño de mensaje – 7 <tamaño de mensaje P9); Terminar(); // BSOD aquí como cuando se establece P9PacketSize = 0 y luego restando 7 vueltas para que P9message_size sea mayor que Rmessage_size.

nulo P9Client :: ProcessReply (P9Client * P9Client, Rmessage_type, tag, y P9message_size);

más

P9Client :: FillData ();

P9Client :: FillData: no podemos alcanzar esta función con un Rmessage_size grande para forzar una escritura fuera de los límites.

int P9Client :: FillData (P9Client * P9Client) {
uint64 Rmessage_size = P9Client-> Rmessage_size; uint_ptr P9PacketEnd = P9Client-> P9PacketEnd;
uint_ptr P9PacketStart = P9Client-> P9PacketStart; if (P9PacketEnd! = P9PacketStart)
memmove (P9PacketStart, P9PacketEnd, Rmessage_size);

ProcessReply verifica el tipo de mensaje R con el del mensaje T dentro de la estructura de datos P9Exchange.

nulo P9Client :: ProcessReply (P9Client * P9Client, Rmessage_type, tag, y P9message_size) {
P9Exchange * P9Exchange = MidExchangeManager :: FindAndRemove (* P9Client, & P9Exchange); if (P9Packet-> tag> 0)
int message_type_size = GetMessageSize (P9Exchange-> Tmessage_type);
if (P9message_size> = message_type_size) int rmessage_type = P9Exchange-> MessageType; int rmessage_type = rmessage_type +1;
if (rmessage_type> 72)
Switch (MessageType)
caso 100:
P9Client :: ProcessVersionReply (P9Client * P9Client, P9Exchange, y P9message_size);
caso 110:
P9Client :: ProcessWalkreply (Rmessage_type, P9Exchange, & P9message_size);
más
P9Client :: ProcessReadReply (rmessage_type, P9Exchange, y P9message_size);

Durante la función P9Client :: ProcessReply llama a MidExchangeManager :: FindAndRemove para obtener la estructura de datos P9Exchange asociado con los mensajes R correspondientes al mensaje T.

MidExchangeManager :: FindAndRemove (* P9Client, & P9Exchange)

NTSTATUS RxMapAndDissociateMidFromContext (PRX_MID_ATLAS P9Client-> RDBSS_RxContext, USHORT Mid y P9Exchange);

ProcessVersionReply verifica la versión enviada por el Cliente “P92000.L” que tiene 8 caracteres y verifica la misma longitud al regresar para que el rversionlen no afecte la función tryString.

nulo P9Client :: ProcessVersionReply (* P9Client, * P9Exchange y P9message_size)

char * rversion;
int rversionlen = 0;

rversion = P9Client-> P9PacketStart.u.rversion-> version-> str;

rversionlen = P9Client-> P9PacketStart.u.rversion-> version-> len;

tryString (tamaño de mensaje y versión)

strcmp (Tversion, Rversion);

ProcessWalkReply verifica que el número total de estructuras de rwalk no exceda el P9message_size

nulo P9Client :: ProcessWalkReply (rmessage_type, * P9Exchange, y P9message_size)

uint16 nwqid = p9packet.rwalk.nwqid;

uint64 rwalkpacket_size = & P9message_size – 2; // 2 bytes de encabezado rwalk para el campo nwqid

unit_ptr rwalkpacketstart = & P9Client-> P9PacketStart.u.rwalk-> wqids;
uint64 error_code = 0x0C0000186;
uint64 rwalk_message_size = nwqid * 13; // 0xd es el tamaño de una estructura de rwalk

if (rwalk_message_size <= P9message_size)

P9Exchange-> Lambda_8972 (int, nwqid, & rwalk_message_size, P9Exchange-> RxContext, & rwalkpacketstart); // Lambda_8972 es Lambda_PTR1 para el tipo de mensaje rwalk

más

P9Exchange-> P9Client :: SyncContextErrorCallback (error_code, P9Exchange-> RxContext) // SyncContextErrorCallback es Lambda_PTR2 para el tipo de mensaje rwalk

ProcessReadReply comprueba que el tamaño del campo de recuento no exceda de 0x8000 y lo escribe en un MDL dentro de P9Exchange-> RxContext para pasar de nuevo la pila RDBSS para ver el contenido del archivo dentro del Explorador.

nulo P9Client :: ProcessReadReply (rmessage_type, * P9Exchange y P9message_size)
unint64 count = P9Client-> P9PacketStart.u.rread-> count;
P9Exchange-> Lambda_2275 (cuenta, P9Exchange-> RxContext, y P9message_size);
Lambda_2275 (cuenta, P9Exchange-> RxContext, y P9message_size)

uint64 maxsize = P9Exchange-> RxContext + offset; // max_size = 0x8000

unint64 MDL = P9Exchange-> RxContext + offset;

if (cuenta> tamaño máximo) terminar ();

memmove (& MDL, P9Client-> P9PacketStart.u.rread-> data, count);

Conclusión

A través de esta investigación, descubrimos una Denegación de servicio (DoS) local dentro de la implementación del kernel de Windows del protocolo P9. Como se explicó, la vulnerabilidad no se puede explotar para obtener la ejecución del código dentro del kernel de Windows, por lo que no hay riesgo para los usuarios de esta vulnerabilidad específica. Como requisito previo a los ataques maliciosos del servidor P9, un atacante debe secuestrar el socket del servidor P9 "fsserver". Por lo tanto, podemos mitigar este ataque detectando y evitando el secuestro del socket "fsserver". McAfee MVISION Endpoint y EDR pueden detectar y prevenir la cobertura contra el secuestro de "fsserver" del servidor P9, del cual puede leer más aquí.

Esperamos que esta investigación proporcione información sobre lo siguiente:

  1. El proceso de búsqueda de vulnerabilidades para nuevas características como el protocolo WSL P9 en el sistema operativo Windows 10
  2. Brindar soporte para futuras investigaciones más arriba en la pila de comunicaciones WSL que aumenta en complejidad debido a la implementación de un sistema virtual de archivos Linux en Windows
  3. El valor de McAfee Advanced Threat Research (ATR) trabajando en estrecha colaboración con nuestros equipos de productos e innovación para brindar protección a nuestros clientes

Finalmente, un agradecimiento especial a Leandro Costantino y Cedric Cochin por su investigación inicial del servidor Windows 10 WSL P9.





Enlace a la noticia original