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 协议 ,转载请注明出处!