
CVE-2017-14948 para el firmware de D-Link 880
En este pequeño artículo veremos algunos fallos que encontré en productos D-Link. D-Link ofrece una amplia gama de productos, incluyendo muchos modelos diferentes de routers, con distintas versiones de firmware. En este documento abordaré las siguientes versiones de firmware: DIR-880L, DIR-868L, DIR-890L, DIR-885L y DIR-895L. Sin más preámbulos, comencemos.
Como no poseía ninguno de los routers D-Link, y ellos proporcionan acceso gratuito a su firmware, decidí encontrar fallos basándome únicamente en el análisis estático. Nótese que, en esta sección me referiré al firmware DIR-880L; los demás firmware tienen estructuras similares.
Después de descargar y desempaquetar el firmware del DIR-880L, descubrí que su firmware contiene un sistema de archivos squashFS completo, con aproximadamente 2160 archivos. Como no quería considerar cada uno de ellos de forma independiente, comencé a buscar aquel que gestionara las entradas del usuario.
Tras analizar los archivos de configuración y buscar cabeceras HTTP conocidas, finalmente limité mi enfoque a tres binarios y, al final, a uno solo: fileaccess.cgi.
Aquí está el desensamblado de la función vulnerable:
signed int __fastcall content_type(char *a1)
{
char *dest; // [sp+4h] [bp-10h]@1
const char *haystack; // [sp+Ch] [bp-8h]@1
char *haystacka; // [sp+Ch] [bp-8h]@3
dest = a1;
haystack = getenv("CONTENT_TYPE");
if ( !haystack )
return -22;
haystacka = strstr(haystack, "boundary=");
if ( !haystacka )
return -22;
strcpy(dest, haystacka + 9);
return 0;
}
En el código anterior, el contenido de la variable 'CONTENT_TYPE' (apuntada por la variable haystack) está controlado por el usuario (a través de la cabecera de la petición HTTP). Su contenido, después de la palabra clave 'boundary', se copia en un buffer dest sin comprobar la longitud de haystacka. Si uno observa la función que realiza la llamada (dirección 0x1CE6C), puede deducir que el tamaño de dest es de 256 bytes. Como un atacante puede controlar el contenido de CONTENT_TYPE, podría enviar la cadena 'boundary=' seguida de al menos 257 caracteres para desencadenar un desbordamiento de buffer.
Se encontraron otros dos fallos similares en la misma muestra de firmware, relacionados con la cookie HTTP. Uno de ellos se muestra a continuación:
v10 = getenv("HTTP_COOKIE");
if ( v10 )
{
strcpy((char *)&v5, &v10[v11]);
v17 = strlen((const char *)&v5);
}
Aquí, la variable v10 apunta a la cookie del usuario, que puede tener como máximo 4k bytes (según la RFC2109). Sin embargo, la variable v5 tiene un tamaño de 1024 bytes (como podemos deducir del marco de pila de la función). Esto puede desencadenar un desbordamiento de buffer.
Estos fallos fueron reportados y confirmados por D-Link.
Estas muestras de firmware presentan una estructura similar a la del DIR-880L y tienen los mismos fallos relacionados con los mismos campos HTTP.