Imagen: PexelsCon el lanzamiento de las actualizaciones de enero para Windows, la noticia de la vulnerabilidad críticamente peligrosa
CVE-2019-0547 en clientes DHCP
conmovió al público. La alta calificación de CVSS y el hecho de que Microsoft no publicó inmediatamente una evaluación de desempeño, lo que dificultó a los usuarios decidir sobre una actualización urgente del sistema, despertó el interés. Algunas publicaciones incluso sugirieron que la falta de un índice puede interpretarse como evidencia de que un exploit funcional aparecerá en el futuro cercano.
Soluciones como
MaxPatrol 8 pueden identificar computadoras en la red que son vulnerables a ataques específicos. Otras soluciones, como PT NAD, detectan tales ataques por sí mismos. Para que esto sea posible, es necesario describir tanto las reglas para detectar vulnerabilidades en los productos como las reglas para detectar ataques en estos productos. A su vez, para que esto sea posible, es necesario que cada vulnerabilidad individual descubra el vector, el método y las condiciones de su operación, es decir, literalmente todos los detalles y matices asociados con la operación. Se requiere una comprensión mucho más completa y profunda de lo que generalmente se puede compilar a partir de descripciones en sitios de proveedores o en CVE, tales como:
La vulnerabilidad se manifiesta porque el sistema operativo procesa incorrectamente los objetos en la memoria.
Por lo tanto, para agregar a los productos de la compañía las reglas para detectar ataques a una vulnerabilidad recién creada en DHCP, así como las reglas para identificar los dispositivos afectados por ella, debe comprender los detalles. En el caso de las vulnerabilidades binarias, patch-diff se usa a menudo para obtener información sobre los errores subyacentes, es decir, una comparación de los cambios realizados en el código binario de una aplicación, biblioteca o núcleo del sistema operativo con un parche específico, una actualización que corrige este error. Pero la primera etapa es siempre el reconocimiento.
Nota :
Para ir directamente a la descripción de la vulnerabilidad, omitiendo los conceptos DHCP subyacentes, puede omitir las primeras páginas e ir directamente a la sección "Función DecodeDomainSearchListData".Reconocimiento
Pasamos al motor de búsqueda y vemos todos los detalles de vulnerabilidad conocidos actualmente. Esta vez hay un mínimo de detalles, y todos ellos son procesiones gratuitas de la información recopilada de la
publicación original en el sitio web de MSRC. Esta situación es bastante típica para los errores descubiertos por Microsoft durante una auditoría interna.
En la publicación, descubrimos que nos enfrentamos a una vulnerabilidad de corrupción de memoria, que está contenida en los sistemas cliente y servidor de Windows 10 versión 1803 y aparece en el momento en que un atacante envía respuestas especialmente diseñadas a un cliente DHCP. Después de un par de días a partir de ese momento en la página, también aparecerán los índices de rendimiento:

Como puede ver, MSRC calificó "2 - Explotación menos probable". Esto significa que un error con una alta probabilidad no es operacional en absoluto, o la operación está llena de dificultades, cuya superación requerirá costos laborales demasiado altos. Es cierto que Microsoft no tiende a subestimar tales estimaciones. Esto está en parte influenciado por el riesgo de pérdida de reputación, y en parte por cierta independencia del centro de respuesta dentro de la empresa. Por lo tanto, suponga: dado que la amenaza de explotación se indica en el informe como poco probable, ciertamente lo es. En realidad, esto podría haber completado el análisis, pero no sería superfluo verificar dos veces y al menos descubrir cuál era la vulnerabilidad. En última instancia, a pesar de toda la personalidad innegable, los errores tienden a repetirse y manifestarse en otros lugares.
Desde la misma página, descargamos el parche (actualización de seguridad) provisto en forma de archivo .msu, lo desempaquetamos y buscamos los archivos relacionados con el procesamiento de las respuestas de DHCP en el lado del cliente. Recientemente, se ha vuelto mucho más difícil hacer esto, ya que las actualizaciones comenzaron a entregarse no en forma de paquetes separados que corrigen errores específicos, sino como un único paquete acumulativo que incluye todas las correcciones mensuales. Esto aumentó en gran medida el exceso de ruido, es decir, los cambios no relacionados con nuestra tarea.
Entre todo el conjunto de archivos, la búsqueda encuentra varias bibliotecas adecuadas para el filtro, que comparamos con sus versiones en un sistema no parcheado. La biblioteca dhcpcore.dll parece la más prometedora. En este caso,
BinDiff produce cambios mínimos:

En realidad, aparte de los cambios cosméticos realizados en una sola función: DecodeDomainSearchListData. Si conoce bien el protocolo DHCP y sus opciones que no se utilizan con demasiada frecuencia, puede suponer que esta función procesa la lista. De lo contrario, pase a la segunda etapa: el estudio del protocolo.
DHCP y sus opciones
DHCP (
RFC 2131 |
wiki ) es un protocolo extensible cuyas capacidades de reposición son proporcionadas por el campo de opciones. Cada opción se describe mediante una etiqueta única (número, identificador), el tamaño ocupado por los datos contenidos en la opción y los datos en sí. Esta práctica es típica de los protocolos de red, y una de las opciones "implantadas" en el protocolo es la Opción de búsqueda de dominio descrita en
RFC 3397 . Permite al servidor DHCP establecer las terminaciones de nombre de dominio estándar en los clientes, que se utilizarán como sufijos DNS para la conexión configurada de esta manera.
Supongamos, por ejemplo, las siguientes terminaciones de nombre establecidas en nuestro cliente:
.microsoft.com .wikipedia.org

Luego, en cualquier intento de determinar la dirección por el nombre de dominio, las consultas de DNS sustituirán los sufijos de esta lista hasta que se encuentre una asignación exitosa. Por ejemplo, si el usuario ingresó ru en la barra de direcciones del navegador, las consultas DNS se generarán primero para ru.microsoft.com, luego para ru.wikipedia.org:

De hecho, los navegadores modernos son demasiado inteligentes y, por lo tanto, responden a los redireccionamientos al motor de búsqueda a nombres que no son similares al FQDN. Por lo tanto, a continuación adjuntamos la conclusión de utilidades menos estropeadas:

Puede parecerle al lector que esta es la vulnerabilidad, porque la capacidad de sustituir sufijos DNS usando un servidor DHCP, con el que cualquier dispositivo en la red puede identificarse, representa una amenaza para los clientes que solicitan parámetros de red a través de DHCP . Pero no: como se desprende del RFC, esto se considera un comportamiento bastante legítimo y documentado. En realidad, el servidor DHCP es inherentemente uno de esos componentes confiables que pueden tener un fuerte impacto en los dispositivos que acceden a ellos.
Opción de búsqueda de dominio
La opción de búsqueda de dominio está numerada 0x77 (119). Como todas las opciones, está codificada con una etiqueta de un solo byte con el número de opción. Como la mayoría de las otras opciones, inmediatamente después de la etiqueta hay un tamaño de un solo byte de los datos que siguen al tamaño. Las instancias de opción pueden estar presentes en el mensaje DHCP más de una vez. En este caso, los datos de todas estas secciones se concatenan en la secuencia en que aparecen en el mensaje.

En el ejemplo presentado, tomado de
RFC 3397 , los datos se dividen en tres secciones, cada una de 9 bytes. Como puede ver en la imagen, los nombres de subdominio en el nombre de dominio completo están codificados con una longitud de un solo byte del nombre, seguido inmediatamente por el nombre mismo. La codificación del nombre de dominio completo termina con un byte nulo (es decir, un nombre de subdominio de tamaño nulo).
Además, la opción utiliza el método más simple de compresión de datos, o mejor dicho, solo vuelve a analizar los puntos. En lugar del tamaño del nombre de dominio, el campo puede contener el valor 0xc0. Luego, el siguiente byte establece el desplazamiento relativo al comienzo de los datos de la opción, que debe usarse para buscar el final del nombre de dominio.
Por lo tanto, en este ejemplo, se codifica una lista de dos sufijos de dominio:
.eng.apple.com .marketing.apple.com
Función DecodeDomainSearchListData
Entonces, el número de opción DHCP 0x77 (119) permite al servidor configurar sufijos DNS en los clientes. Pero no en máquinas con sistemas operativos Windows. Los sistemas de Microsoft han ignorado tradicionalmente esta opción, por lo que históricamente el final de los nombres DNS, si es necesario, se pasó a través de políticas de grupo. Esto continuó hasta hace poco, cuando la próxima versión de Windows 10, versión 1803, agregó procesamiento para la Opción de búsqueda de dominio. A juzgar por el nombre de la función en dhcpcore.dll, en el que se realizaron los cambios, es en el controlador agregado donde reside el error en cuestión.
Ponerse a trabajar. Peinamos un poco el código y descubrimos lo siguiente. El procedimiento DecodeDomainSearchListData, de acuerdo con el nombre, decodifica los datos de la Opción de búsqueda de dominio del mensaje recibido del servidor. En la entrada, recibe una matriz de datos empaquetada de la manera descrita en el párrafo anterior, y en la salida, genera una cadena terminada en nulo que contiene una lista de terminaciones de nombres de dominio, separadas por comas. Por ejemplo, esta función convierte los datos del ejemplo anterior en una cadena:
eng.apple.com,marketing.apple.com
Se llama a DecodeDomainSearchListData desde el procedimiento UpdateDomainSearchOption, que establece la lista devuelta en el valor "DhcpDomainSearchList" de la clave del registro:
HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\{INTERFACE_GUID}\
almacenar los parámetros principales de una interfaz de red específica.

La función DecodeDomainSearchListData se cumple en dos pases. En el primer paso, realiza todas las acciones excepto escribir en el búfer de salida. Por lo tanto, la primera pasada se dedica a calcular el tamaño de la memoria requerida para acomodar los datos devueltos. En la segunda pasada, la memoria ya está asignada para estos datos y la memoria asignada está llena. La función es bastante pequeña, aproximadamente 250 instrucciones, y su trabajo principal es procesar cada una de las tres opciones posibles para el carácter representado en la secuencia de entrada: 1) 0x00, 2) 0xc0 o 3) todos los demás valores. La solución hipotética para el error relacionado con DHCP básicamente se reduce a agregar una verificación del tamaño del búfer resultante al comienzo del segundo paso. Si este tamaño es cero, la memoria no está asignada para el búfer y la función finaliza inmediatamente la ejecución y devuelve un error:

Resulta que la vulnerabilidad se manifiesta en casos donde el tamaño del búfer de destino es cero. Al mismo tiempo, al comienzo de la ejecución, la función verifica los datos de entrada, cuyo tamaño no puede ser inferior a dos bytes. Por lo tanto, para la operación se requiere seleccionar una opción no vacía de sufijos de dominio de tal manera que el tamaño del búfer de salida sea cero.
Operación
Lo primero que viene a la mente es que puede usar los puntos de análisis descritos anteriormente para que los datos de entrada no vacíos generen una línea de salida vacía:

Un servidor configurado para enviar una opción con dicho contenido en la respuesta realmente causará violación de acceso en clientes no actualizados. Esto sucede por la siguiente razón. En cada paso, cuando la función analiza parte del nombre de dominio completo, lo copia en el búfer de destino y coloca un punto después. En el ejemplo tomado del RFC, los datos se copiarán al búfer en el siguiente orden:
1). eng. 2). eng.apple. 3). eng.apple.com.
Luego, cuando el dominio contiene un tamaño de dominio cero, la función reemplaza el carácter anterior del búfer de destino con una coma:
4). eng.apple.com,
y continúa analizando:
5). eng.apple.com,marketing. 6). eng.apple.com,marketing.apple. 7). eng.apple.com,marketing.apple.com. 8). eng.apple.com,marketing.apple.com,
Al final de la entrada, solo queda reemplazar la última coma con un carácter cero y obtienes una línea lista para escribir en el registro:
9). eng.apple.com,marketing.apple.com
¿Qué sucede cuando un atacante envía un búfer formado de la manera descrita? Si observa el ejemplo, puede ver que la lista que contiene consta de un elemento: una cadena vacía. En la primera pasada, la función calcula el tamaño de los datos de salida. Como los datos no contienen un solo nombre de dominio distinto de cero, el tamaño es cero.
En la segunda pasada, se asigna un bloque de memoria dinámica para colocar datos en él y copiar los datos en sí. Pero la función de análisis encuentra inmediatamente un carácter nulo, lo que significa el final del nombre de dominio y, por lo tanto, como se dijo, reemplaza el carácter anterior de un punto a una coma. Y aquí nos enfrentamos con un problema. El iterador del búfer de destino está en la posición cero. No hay personaje previo. El carácter anterior pertenece al encabezado del bloque de memoria dinámica. Y este mismo personaje será reemplazado con 0x2c, es decir, con una coma.
Sin embargo, esto solo ocurre en sistemas de 32 bits. El uso de unsigned int para almacenar la posición actual del iterador del búfer de destino introduce ajustes en el procesamiento en sistemas x64. Prestemos más atención al código responsable de escribir una coma en el búfer:

La unidad se resta de la posición actual utilizando el registro eax de 32 bits, mientras que al direccionar el búfer, el código accede al registro completo de 64 bits. En la arquitectura AMD64, cualquier operación con registros de 32 bits anula la parte superior del registro. Esto significa que en el registro rax, que anteriormente contenía cero, después de la resta, no se almacenará el valor –1, sino 0xffffffff. Por lo tanto, en sistemas de 64 bits, el valor 0x2c se escribirá en la dirección buf [0xffffffff], es decir, mucho más allá de los límites de la memoria asignada para el búfer.
Los datos obtenidos están en buen acuerdo con la evaluación de rendimiento de Microsoft, porque para aprovechar esta vulnerabilidad, un atacante necesita aprender a realizar de forma remota la pulverización de montón en un cliente DHCP y al mismo tiempo tener un control suficiente sobre la asignación de memoria dinámica para registrar valores predefinidos, es decir, una coma y cero byte, producido en la dirección preparada y conducido a consecuencias negativas controladas. De lo contrario, escribir datos en una dirección no verificada provocará una caída en el proceso svchost.exe, junto con todos los servicios actualmente alojados en él, y un nuevo reinicio de estos servicios por parte del sistema operativo. Un hecho que los atacantes en ciertas condiciones también pueden usar para su propio beneficio.
Eso parece ser todo lo que se puede decir sobre el error bajo investigación. Solo queda la sensación de que esto está lejos del final. Como si no consideráramos todas las opciones. Debe haber algo más que esté oculto en estas líneas.
CVE-2019-0726
Probablemente como es. Si observa detenidamente el tipo de datos que causan el error y lo compara con la forma exacta en que ocurre este error, notará que la lista de nombres de dominio se puede cambiar de tal manera que el búfer resultante sea de un tamaño distinto de cero, pero un intento de escribir fuera de él es Lo mismo se hará. Para hacer esto, el primer elemento de la lista debe ser una cadena vacía, y todos los demás pueden contener terminaciones de dominio normales. Por ejemplo:

La opción presentada incluye dos elementos. El primer sufijo de dominio está vacío, inmediatamente termina con un byte cero. El segundo sufijo es .ru. El tamaño de línea calculado en la salida será igual a tres bytes, lo que permitirá superar la comprobación impuesta por la actualización de enero sobre el vacío del búfer de destino. Al mismo tiempo, cero al comienzo de los datos obligará a la función a escribir una coma en la cadena resultante, pero dado que la posición actual del iterador en la cadena es igual a cero, como en el caso considerado anteriormente, la grabación volverá a ocurrir fuera del búfer asignado.
Ahora es necesario confirmar los resultados teóricos obtenidos en la práctica. Simulamos una situación en la que el servidor DHCP envía un mensaje con la opción presentada en respuesta a una solicitud del cliente, e inmediatamente detectamos una excepción al intentar escribir una coma en la posición 0xffffffff asignada bajo la línea de búfer resultante:

Aquí, el registro r8 contiene un puntero a las opciones entrantes, rdi es la dirección del búfer de destino seleccionado y rax es la posición en este búfer donde se va a escribir el carácter. Obtuvimos dichos resultados en un sistema completamente actualizado (a partir de enero de 2019).
Escribimos sobre el problema descubierto en Microsoft y ... pierden la carta. Sí, esto a veces sucede incluso con proveedores acreditados. Ningún sistema es perfecto, y en este caso hay que buscar otras formas de comunicación. Por lo tanto, una semana después, sin siquiera recibir una respuesta automática durante este tiempo, contactamos al gerente directamente a través de Twitter y, de acuerdo con los resultados de varios días de analizar la aplicación, descubrimos que los detalles enviados no tienen nada que ver con CVE-2019-0547 y representan una vulnerabilidad independiente para la cual nuevo identificador CVE. Un mes después, en marzo, sale la corrección correspondiente y el error recibe el número
CVE-2019-0726 .
Así es como a veces puedes tratar de descubrir los detalles de la vulnerabilidad de 1 día para descubrir accidentalmente 0 días simplemente confiando en tu intuición.
Publicado por Mikhail Tsvetkov, Especialista en Análisis de Aplicaciones de Tecnologías Positivas.