
Vulnerabilidad de ejecución remota de código por desbordamiento de búfer de pila en IGD UPnP de LINKSYS AC1900 EA7500v3
Esta vulnerabilidad permite a atacantes adyacentes a la red ejecutar código arbitrario en instalaciones afectadas de routers LINKSYS EA7500. No se requiere autenticación para explotar esta vulnerabilidad.
La falla específica existe en el manejo de los datos de las solicitudes HTTP hacia el servicio IGD UPnP. Al analizar el contenido de una variable proporcionada por el usuario en una determinada solicitud de acción SOAP UPnP, el proceso no valida correctamente la longitud de los datos proporcionados por el usuario antes de copiarlos a un búfer de pila de longitud fija. Un atacante puede aprovechar esta vulnerabilidad para ejecutar código en el contexto de root.
Producto/Firmware: Firmware de Linksys EA7500 TODAS LAS VERSIONES, incluida la Ver.3.0.1.207964 - Otros modelos de router y versiones de firmware que utilicen este binario también están afectados
El binario del servicio UPnP IGD se encuentra en /usr/sbin/IGD y se ejecuta por defecto en el puerto 49152. Este servicio proporciona el archivo de descripción XML UPnP IGDdevicedesc.xml, que detalla varias funciones que pueden invocarse mediante solicitudes HTTP con un cuerpo XML. Una de estas funciones es SetDefaultConnectionService. Esta función requiere una variable de tipo cadena. Cuando se invoca y ejecuta la función SetDefaultConnectionService, el programa no valida la longitud de la variable proporcionada por el usuario antes de realizar una llamada a strncpy que involucra este búfer. Tanto la dirección de origen como las variables de tamaño de copia de la llamada a strncpy están controladas por el usuario, siendo el tamaño de copia la longitud de la variable proporcionada por el usuario. Los datos se copian entonces a un búfer fijo de 184 bytes, lo que conduce a una vulnerabilidad de desbordamiento de búfer en la pila.
La función SetDefaultConnectionService está etiquetada como _set_connection_type. La función comienza inicializando un búfer de 184 bytes y luego obtiene un puntero al búfer que contiene la variable de cadena proporcionada por el usuario incluida en la solicitud, si no es NULL. Esto se hace llamando a PAL_xml_node_GetFirstbyName y luego a PAL_xml_node_get_value. Ver el código siguiente:
int _set_connection_type(int **param_1)
{
int iVar1;
char *var_value;
size_t var_value_length;
undefined uVar2;
undefined1 *puVar3;
char **ppcVar4;
undefined4 *puVar5;
char *pcVar6;
int *piVar7;
char acStack_d4 [184]; -----> /* Initializing 184-byte buffer */
memset(acStack_d4,0,0xb4);
iVar1 = PAL_xml_node_GetFirstbyName((*param_1)[0xf0],"NewConnectionType",0); -----> /* iVar1 now points to the user-supplied value */
if ((iVar1 != 0) && (var_value = (char *)PAL_xml_node_get_value(), var_value != (char *)0x0)) { -----> /* Ensures the user-supplied value is not empty and obtains a pointer to it */
...
Más adelante en la misma función, se realiza una llamada a strlen para obtener el tamaño de la cadena proporcionada por el usuario más un desplazamiento estático de 0x174. La condición vulnerable se desencadena en la llamada posterior a strncpy, donde el argumento de destino es la dirección del búfer recientemente inicializado de 184 bytes, el origen es el puntero a la cadena proporcionada por el usuario, y el tamaño de la operación de copia es el tamaño de la cadena proporcionada por el usuario devuelto por la llamada a strlen más un desplazamiento estático de 0x174. Esto conduce a una vulnerabilidad de desbordamiento de búfer, ya que tanto la dirección de origen como las variables de tamaño están controladas por el usuario y no se realizan comprobaciones de validación de tamaño. Ver el código siguiente:
int _set_connection_type(int **param_1)
{
...
var_value_length = strlen((char *)(iVar1 + 0x174)); ----> /* iVar1 is a pointer to the user supplied string */
strncpy(acStack_d4,(char *)(iVar1 + 0x174),var_value_length + 1); ----> /* Vulnerable strncpy call */
...
El desplazamiento para sobrescribir la dirección de retorno de una función en la pila es de 276 bytes. Los siguientes 4 bytes se pueden utilizar para redirigir la ejecución a una dirección arbitraria y así secuestrar el flujo de control del programa.
Utilice una función de copia de cadenas más segura: en lugar de usar strncpy, que no garantiza la terminación nula del búfer de destino, se puede utilizar una función de copia de cadenas más segura como strncpy_s o memcpy_s. Estas funciones aseguran que el búfer de destino esté siempre terminado en nulo y no permiten copiar más datos de los que el búfer puede contener.
Validación de entrada: valide la entrada del usuario para asegurarse de que no exceda el tamaño del búfer de destino. Si la entrada es más larga que el tamaño del búfer, rechácela o trúnquela para que quepa dentro del búfer.
Utilice un búfer asignado dinámicamente: asigne memoria para el búfer de destino dinámicamente en lugar de usar un búfer de pila de tamaño fijo. Este enfoque permite ajustar el tamaño del búfer según el tamaño de los datos de entrada. (No recomendado para un sistema con recursos limitados)
Ejecución del PoC: python poc.py 192.168.1.1 49152
Enlace de descarga del software: https://support.linksys.com/kb/article/559-en/ (Versión de firmware Ver. 3.0.1.207964)
gdbserver-7.7.1-armel-eabi5-v1-sysv disponible aquí: https://github.com/stayliv3/gdb-static-cross/tree/master/prebuilt).pkill IGD para terminar el binario y después reláncelo usando ./gdbserver :1337 /usr/sbin/IGD. El siguiente archivo .gdbinit se puede utilizar para iniciar una sesión de depuración estable:> set follow-fork-mode child
> set detach-on-fork off
> target remote 192.168.1.1:1337
> c