Uniview RCE 漏洞分析
Uniview RCE 漏洞分析,PoC来自exploit-db
1. 漏洞复现
PoC:
1 |
|
执行命令,将/etc/shadow
文件复制到/tmp/packetcapture.pcap
。
获得/etc/shadow
的内容。
2. 漏洞详细分析
对于该漏洞,我决定先利用POC
去寻找漏洞点,然后逆着分析参数传递过程,来分析漏洞原理。
2.1 根据POC寻找漏洞点
根据POC
来分析一下漏洞。
很明显,POC
中stSelNicName
这个参数传入了所执行的命令,使用IDA打开关键程序main-cgi
,搜索字符串stSelNicName
。
进而找出存在该字符串的函数,sub_2248C()
。
为了方便阅读,根据函数实现的功能,将函数名修改为startTcpDump
。
可以看到在该函数的后面,进行了命令的拼接,由此猜测,应该是前面没有做好对传入的参数进行过滤,进行拼接后就使用system()
执行了代码。
这里应该就是漏洞点了,接下来往上找一下调用,分析一下传参,来验证自己的猜想。
2.2 参数传递过程分析
首先往上查找调用startTcpDump()
的函数。
找到sub_477FC()
再往上,就到了CGI
请求开始处理的地方sub_4E2A4()
。
可以看到,程序在第8
行获得了传入的请求数据v0
,经过处理后传入关键函数sub_477FC()
中。
跟进函数getRequestValue()(也就是sub_164D0)
,
可以看到,当请求方法为GET
时,该函数会获得并返回经过URL
编码之后的数据,而且程序不支持POST
请求。
也就是说在dealWithCGIRequest()
函数中,第13
行v2 = sub_477FC(v1);
传入的v1
是一个字符串。
对于POC
来说,就是
1 |
|
然后进入函数sub_477FC()
,可以看到在第237
-269
,对传入的字符串进行了处理。
从处理流程来看,使用=
和&
对字符串进行分割,获取key
和value
,存储在v5
中。counter
中存储了传入的键值对的数目。
v5
的数据结构:
1 |
|
接下来函数对处理后的字符串进行遍历,处理请求。
首先对Value
值进行url
解码。
然后继续往下:
对于代码中的v11
来说,它就是经过urldecode
之后的v5
。
也就是*v11 == "key"
、*(v11+32) == "value"
。
然后根据传入的key
来决定处理方式,在POC
中我们传入了一个json
数据。
此时343
行if
条件成立,在347
行,将value
值传入函数sub_4E204()
,对json
字符串进行解析,返回一个存储了json
的数据结构。
然后351
行获得cmd
的值,然后根据该值,使用switch
来决定如何进行处理后续请求。
跟进347
行v23 = sub_4E204((v11 + 32));
,分析一下json
的数据结构。
在这里我只是大致分析了下,动态调试环境弄不好,只能静态分析,后面还涉及到递归,有点困难。
往下走两步,跟进到sub_4E164(a1, 0, 0);
,其中a1
就是传入的value
值。
后面的分析过程太过于繁琐,而且并没有分析出有关数据的过滤的函数,就说一下我分析的json
的数据结构吧。
在
json
中有六种数据,分别是数字(整数或者浮点数)、字符串、逻辑值 (true
或false
)、数组、对象、null
。
在该程序中,是通过调用getFortySpace()
(也就是sub_4CA70
)来分配空间的,
根据整个流程调用来判断,存储json
中键值对的数据结构如下
1 |
|
猜测使用了cjson
这个库。
在解析json
的流程中,只是调用了leftStrip()
(也就是sub_4C788
),来保证所有字符串都以可见字符开头。
在获取双引号之间的值时处理unicode
编码,没有其他的针对性的过滤手段。
然后回到函数sub_477FC()
1 |
|
到现在,传入的json
数据已经进入前面我们之前猜测的漏洞点了。
2.3 漏洞点详细分析
重新回到函数startTcpDump(int a1)
中。
25
行到51
行程序对系统状态进行判断。
根据上面的条件,我们必须传入bSelectAllPort
、bSelectAllIP
、stSelIp
、stSelPort
、stSelNicName
这五个值。
在后面可以看到,四个不同条件下的命令执行语句都拼接了stSelNicName
字符串。
每个都分析下。
第一条
1 |
|
第二条
1 |
|
第三条
1 |
|
第四条
1 |
|
可以知道,在传入的参数中,bSelectAllIp
和bSelectAllPort
只要都存在并且值是0
或者1
。就能够将stSelNicName
的值拼接到执行的命令中。
在这命令中,
1 |
|
其中%s
的值可控,于是我们可以使用分号来截断命令。
比如传入;id;
,则此时执行的命令为tcpdump -i ;id; -p -nn ….
,命令id
成功执行。
就这样实现命令注入,造成远程代码执行。
从总体来看,该漏洞产生的最主要的原因就是,程序没有对传入的参数进行过滤,然后直接将其拼接到了命令中,造成了远程命令执行。
3. 漏洞攻击利用思路
这是一个无回显的远程命令执行漏洞,不过既然能够执行命令了,就有很多利用方式了。
3.1 利用程序本身的功能
在该程序中提供了下载数据包的功能,文件路径为/tmp/packetcapture.pcap
,我们可以执行命令,将输出重定向到该文件中,然后利用程序自身功能来下载到结果。
如果在Web
目录中有权限,也可以直接将结果输出到Web
目录下,然后下载得到结果。
3.2 使用HTTP请求和DNS解析外带数据
如果目标主机可以连通外网,可以让目标主机向外网的一个自己可控的Web服务器发出携带数据的HTTP
请求,从而将获得命令执行的结果。
也可以使目标主机解析携带有数据的二级域名,然后查询DNS
解析记录。
我们可以使用ceye.io
这个平台来达到目的。
使用curl
向平台发起HTTP请求获取命令执行的结果。
成功获取执行命令的内容。
使用DNS
请求获取数据
成功获取执行命令的内容
需要注意的是,在外带数据的时候应该要对数据base64
编码一下,或者其他编码也可以,防止特殊字符对命令的执行过程产生影响。我这个树莓派上没有base64
,在这就不演示了。
3.3 一点发现
在漏洞分析过程中,发现该漏洞是有回显的,执行的命令会在请求头里出现。
只要执行的命令存在标准输出,即使用echo
,而且输出内容中存在:
,即可在响应头中获得命令执行的结果。
但是在分析漏洞点中没有发现获取命令结果的地方。
我认为应该是CGI
程序将标准输出重定向到Web
服务器上,内容中有:
,符合响应头的标准,将内容成功输出。
从而获取到命令执行的结果。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!