Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
blogpost_cve-2018-19987-analysis — Este repositorio tiene una publicación de blog sobre mi análisis de CVE-2018-19987, una inyección de comandos del sistema operativo autenticada que afecta a múltiples routers D-Link. | Kitploit
Herramientas/GitHubGitHub/nahueldsanchez/blogpost_cve-2018-19987-analysis
Seguridad IoTAnálisis de VulnerabilidadesExplotaciónExplotación de Aplicaciones WebPapers e InvestigaciónAprendizaje y EducaciónAnálisis de Firmware
GitHubnahueldsanchez/blogpost_cve-2018-19987-analysis

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

blogpost_cve-2018-19987-analysis

Este repositorio tiene una publicación de blog sobre mi análisis de CVE-2018-19987, una inyección de comandos del sistema operativo autenticada que afecta a múltiples routers D-Link.

Ver Repositorio
213hace 5 añosAún no revisado

Análisis de CVE-2018-19987 (inyección de comandos del sistema operativo en D-Link) Twitter URL

Twitter Follow

¡Hola a todos!

En esta breve entrada de blog desglosaré un análisis rápido que realicé para comprender mejor los detalles detrás de CVE-2018-19987. Al principio fui tras este CVE porque pensé que no había información pública ni exploit. Poco después de hacer un primer análisis, encontré dos PoCs públicos en GitHub que puedes encontrar aquí y aquí.

Como ya había hecho la mayor parte del trabajo y no había encontrado un análisis completo, decidí escribir la entrada de todos modos.

¡Espero que lo disfrutes!

Actualización: Bueno... después de buscar en Google mientras estaba atascado con esta entrada de blog, encontré el siguiente artículo que describe una vulnerabilidad muy similar (CVE-2018-19986) en el D-Link DIR-818. Serie de análisis de vulnerabilidades de routers (5): análisis y reproducción de la vulnerabilidad de inyección de comandos CVE-2018-19986 DIR-818LW&828 (traducido por Google) por Ogur1.

Análisis de CVE-2018-19987

Comencé mi análisis recopilando toda la información que pude sobre el dispositivo:

  • Nombre de producto: D-Link DIR-822-US
  • Página del producto: https://us.dlink.com/en/products/dir-822-d-link-wifi-router-ac1200-dual-band
  • Página(s) de soporte: https://support.dlink.com/ProductInfo.aspx?m=DIR-822-US
  • Modelo: DIR-822 Revisión C (Otros dispositivos estaban afectados)
  • Versión de firmware afectada: FW v3.01B02
  • Nombre de archivo del firmware afectado: DIR822C1_FW301WWb02.bin (md5sum: 1bff7ec8b4da0643f65b4d44c630e92b)
  • Versión de firmware corregida: FW v3.13
  • Nombre de archivo del firmware corregido: DIR822C1_FW313WWb01.bin (md5sum: aa16c7016f67be384e0784e439ce26d2)
  • Página de archivo de firmware: ftp://ftp2.dlink.com/PRODUCTS/DIR-822-US/REVC/

Análisis de la causa raíz

Nota: Realicé todo el análisis con el firmware v3.01B02.

La información pública de esta vulnerabilidad, disponible en la página de Mitre, proporcionó suficiente información para empezar:

root@kitploit:~
D-Link DIR-822 Rev.B 202KRb06, DIR-822 Rev.C 3.10B06, DIR-860L Rev.B 2.03.B03, DIR-868L Rev.B 2.05B02, DIR-880L Rev.A 1.20B01_01_i3se_BETA, and DIR-890L Rev.A 1.21B02_BETA devices mishandle IsAccessPoint in /HNAP1/SetAccessPointMode. In the SetAccessPointMode.php source code, the IsAccessPoint parameter is saved in the ShellPath script file without any regex checking. After the script file is executed, the command injection occurs. A vulnerable /HNAP1/SetAccessPointMode XML message could have shell metacharacters in the IsAccessPoint element such as the `telnetd` string.

Para comenzar el análisis necesitaba algo que examinar, así que procedí a extraer el FS del router.

root@kitploit:~
binwalk -eM DIR822C1_FW301WWb02.bin

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             DLOB firmware header, boot partition: "dev=/dev/mtdblock/1"
10380         0x288C          LZMA compressed data, properties: 0x5D, dictionary size: 8388608 bytes, uncompressed size: 4213444 bytes
1376372       0x150074        PackImg section delimiter tag, little endian size: 10505216 bytes; big endian size: 5021696 bytes
1376404       0x150094        Squashfs filesystem, little endian, version 4.0, compression:lzma, size: 5019773 bytes, 2282 inodes, blocksize: 131072 bytes, created: 2016-03-18 09:35:31

Como podemos ver, Binwalk detecta un sistema de archivos Linux. Si observamos más detenidamente la información que tenemos, podemos ver que el aviso menciona la ruta /HNAP1. Por lo tanto, podemos empezar a ver cómo el router maneja estas URLs.

Manejo de solicitudes HNAP1

Como se explica en la excelente entrada de blog de /dev/tty0, estas URLs terminan siendo manejadas por un binario llamado cgibin, ubicado en htdocs/cgibin. Pero quería comprender mejor cómo estaba configurado esto y, al final, me llevó a tener que entender cómo estaba configurado el servidor HTTP para procesar las solicitudes. Procedí a buscar el archivo httpd.conf, asumiendo que se usaba para configurar el servidor HTTP, y encontré un archivo llamado HTTP.php en la carpeta /etc/services/, que contenía, entre otras cosas, las siguientes líneas interesantes:

root@kitploit:~
$httpd_conf = "/var/run/httpd.conf";
fwrite("a",$START, "xmldbc -P /etc/services/HTTP/httpcfg.php > ".$httpd_conf."\n");
fwrite("a",$START, "event PREFWUPDATE add /etc/scripts/prefwupdate.sh\n");
fwrite("a",$START, "httpd -f ".$httpd_conf."\n");
fwrite("a",$START, "event HTTP.UP\n");
fwrite("a",$START, "exit 0\n");

Supuse que en algún momento este archivo se ejecuta y escribe el archivo /var/run/httpd.conf. Para aprender cómo estaba configurado el servidor web, procedí a analizar el archivo /etc/services/HTTP/httpcfg.php (solo incluí las partes relevantes):

root@kitploit:~
	if ($hnap > 0)
	{
		echo
		"		Control".							"\n".
		"		{".									"\n".
		"			Alias /HNAP1".					"\n".
		"			Location /htdocs/HNAP1".		"\n".
		"			External".						"\n".
		"			{".								"\n".
		"				/usr/sbin/hnap { hnap }".	"\n".
		"			}".								"\n".
		"			IndexNames { index.hnap }".		"\n".
		"		}".									"\n";
	}

¡Ahora tenemos todas las piezas! Podemos asumir que el servidor web está configurado para manejar las solicitudes HTTP a /HNAP1 mediante /usr/sbin/hnap, y según la entrada de blog de /dev/tty0 sabemos que será un enlace al binario htdocs/cgibin.

El siguiente paso fue echar un vistazo al binario cgibin para entender cómo manejaba las solicitudes HNAP. En la siguiente imagen podemos ver parte de la función main descompilada, donde la ruta URL que se le pasa se compara con diferentes rutas (como session.cgi, authentication.cgi, captcha.cgi, por nombrar algunas) hasta que se encuentra hnap y se llama a nuestra función hnap_main.

nota: Mientras analizaba la función main, tuve algunos problemas para identificar la cadena hnap, ya que Ghidra no la detectó como cadena durante el análisis inicial.

El siguiente paso era entender qué hacía esta función. Proporcionaré solo fragmentos de código de las partes relevantes que ayudarán a comprender mejor lo que hace la función; también completaré otras partes relevantes con algo de pseudocódigo —renombré algunas variables para aclarar su propósito.

root@kitploit:~
...
HTTP_SOAPACTION = getenv("HTTP_SOAPACTION");
REQUEST_METHOD = getenv("REQUEST_METHOD");
HNAP_AUTH = getenv("HTTP_HNAP_AUTH");
__haystack = getenv("HTTP_COOKIE");
pcVar1 = getenv("HTTP_REFERER");

...
if (HTTP_SOAPACTION != "") {
	if  (HTTP_SOAPACTION == GetDeviceSettings) {
		...
	} else {
		// These actions will occur during auth. Process
		if ("GetCAPTCHAsetting" in HTTP_SOAPACTION) {
			sess_generate_captcha();
		} else {
			if ("Login" in HTTP_SOAPACTION) {
				perform_login();
			}
			// We'll land here once auth.
			if (HNAP_AUTH != "") {
				if ("uid=" in HTTP_COOKIE){
					is_valid_auth = perform_auth_process()
					if (is_valid_auth) {
						if("logout" in HTTP_SOAPACTION){
							perform_logout();
						// If we are auth. and NOT trying to logout
						// the code will try to perform the action
						// we requested
						} else {
							// If we arrive here we win
							// interesting code below
							goto LAB_004141d4;
						}

					}
				}
			}
			// If we are not authenticated we can't do anything
			Return "You need proper authorization to use this resource"
		}
	}
} else {
	...
}

LAB_004141d4:
    hnap_action = get_hnap_operation(HTTP_SOAPACTION);
    if (HTTP_SOAPACTION != "") {
    	hnap_action_len = strlen(hnap_action);
	}
	snprintf(path_to_hnap_php_file,0x100,"%s/%s.php","/etc/templates/hnap/",hnap_action);
	if (!check_file_access(path_to_hnap_php_file)){
		return "HNAP ACTION DOES NOT EXIST (FAIL)"
	}
	if (REQUEST_METHOD == "POST") {

		// Here arguments for the PHP are extracted
		parse_request_and_extract_xml()
    
		if (hnap_action == "GetFirmwareStatus") {
        	system("sh /etc/events/checkfw.sh > /dev/console");
		}

		// Here the final arguments for the xmldbc_ephp are crafted
        snprintf(ARGS_FOR_XMLDBC_PHP,0x100,"%s%s.php\nShellPath=%s%s.sh\nPrivateKey=%s\n",
                 "/etc/templates/hnap/", hnap_action, &ShellPath, hnap_action, &PRIVATE_KEY);

		// PHP is executed (in our case SetAccessPointMode.php) and the shell
		// script is written to ShellPath 
        xmldbc_ephp(0,0,ARGS_FOR_XMLDBC_PHP,stdout);
        snprintf(hnap_action, 0x100, "%s", hnap_action);
       
	   	// Shell command is built to run the previously written shell file
		// (File written by the PHP script)
        shell_command = "sh %s%s.sh > /dev/console &";
        }
        snprintf(cmd_to_execute, 0x100, shell_command, &PATH, hnap_action);

		// File is executed containing the command injection
        system(cmd_to_execute);
    }
...

Una vez completado el análisis de esta función, decidí echar un vistazo al archivo PHP SetAccessPointMode.php — que al final era el que contenía el fallo — y traté de unir todas las piezas:

root@kitploit:~
...
$IsAccessPoint	= query("/runtime/hnap/SetAccessPointMode/IsAccessPoint");
...
fwrite("w",$ShellPath, "#!/bin/sh\n");
fwrite("a",$ShellPath, "echo [$0] $1 ... > /dev/console\n");
fwrite("a",$ShellPath, "echo IsAccessPoint = ".$IsAccessPoint." > /dev/console\n");
fwrite("a",$ShellPath, "echo Result = ".$Result."\n");
...

Como podemos ver, tenemos nuestra variable $ShellPath, que es rellenada por la función hnap_main, y la variable $IsAccessPoint, que está controlada por el usuario y se pasa en la solicitud XML enviada. Con esto podemos corroborar cómo se ejecuta una inyección de comandos del sistema operativo en la variable escrita por el archivo PHP. Aquí puedes encontrar un PoC completo desarrollado por pr0v3rbs para explotar este problema.

Hablaremos un poco más sobre las versiones afectadas y corregidas más adelante. Como puedes ver en la tabla siguiente, parece que hubo algún tipo de regresión con el parche, que reintrodujo esta vulnerabilidad en versiones que ya deberían haber sido parcheadas.

Versiones de firmware analizadas

(*) No comprobé estas versiones de firmware, ya que sus contrapartes sin cifrar eran vulnerables.

Como podemos ver en la tabla anterior, la vulnerabilidad se corrigió en algunas versiones de firmware eliminando el archivo PHP afectado SetAccessPointMode.php. Una vez que el archivo no existe, las comprobaciones realizadas en la función fallarán y no se ejecutará nada. Confirmé esto analizando la hnap_function en las versiones de firmware FW v3.131 y 3.15B02 WW; el código de hnap_main no cambió en relación con este problema, pero el archivo PHP ya no estaba presente.

Lo más interesante es que, de algún modo, este error se reintrodujo en las versiones de firmware FW v3.11 hasta FW v3.12B04, después de haber sido parcheado en la versión 3.11B01_icjg_WW.

Conclusiones y próximos pasos

Como primera conclusión, diría que nunca confíes en estos dispositivos como dispositivos realmente seguros —lo que ocurrió con las actualizaciones es un claro ejemplo de por qué no deberías hacerlo. Además, tras el análisis realizado, puedo concluir que el primer PoC listado en esta entrada de blog no funcionará para esta versión específica, ya que vimos que hay algunas condiciones que deben cumplirse para ejecutar el archivo PHP vulnerable.

Y la conclusión más importante: ten mucho cuidado al decidir cuán crítica es una vulnerabilidad basándote en su puntuación CVSS. Decidí analizar este CVE porque tenía una puntuación de 9.8 (CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H) y está claro que, al menos para esta versión, el atacante necesitará credenciales para poder explotarla.

Como próximos pasos, trabajaré en poder emular este binario para explotar esta vulnerabilidad sin tener acceso al router en sí, ¡pero eso será material para otra entrada!

Gracias por leer.

Referencias

  • Escrito de Ogur1 para CVE-2018-19986
  • Entrada de blog /dev/tty0 sobre D-Link HNAP
  • Aviso de HNAP de Pedro Ribeiro
  • CVE-2018-19987 PoC #0 por Mario Ceballos
  • CVE-2018-19987 PoC #1 por Mingeun Kim
  • Enlace de detalles de CVE-2018-19987
  • Descifrando firmware de D-Link
  • Binwalk
  • pro0v3rbs Poc
Descargar herramienta
FirmwareVersionMD5 hashRelease dateVulnerable
DIR822C1_FW315WWb02.bin3.15B02 WW7121771c3e1706ba76fbf244023efad306/11/2019NO
DIR822C1_FW313WWb01.binFW v3.13aa16c7016f67be384e0784e439ce26d210/07/2019NO
DIR822C1_FW303WWb04_i4sa_middle.binFW v3.12B04c3b9a3f115c02e739690616aba2f2d9926/04/2019SÍ
DIR822C1_FW312WWb04.binFW v3.12B04eb11afbd136a5b29cea18141f727bfa826/04/2019SÍ (*)
DIR822C1_FW311WWb01.binFW v3.116d7c90eaaae835667faea65c862b3c8201/01/2019SÍ
DIR822C1_FW311bWWb01_icjg.bin3.11B01_icjg_WW75e361e1465604aeda5d5dbcaecca97721/12/2018NO
DIR822C1_FW303WWb04_i4sa_middle.binFW v3.10B06c3b9a3f115c02e739690616aba2f2d9917/08/2018SÍ
DIR822C1_FW310WWb06.binFW v3.10B06e33db75d0801fddb1c90308982e69fe517/08/2018SÍ (*)
DIR-822_C1_FW302WWb05.binFW v3.020dbf840c0ff5d3a5b593d33690e15d8214/09/2017SÍ
DIR822C1_FW301WWb02.binFW v3.01B021bff7ec8b4da0643f65b4d44c630e92b27/04/2016SÍ