0x00 前言(一堆废话建议跳过)

​ 最近考研复习的有些烦躁,正巧10月份爆出来的海康威视CVE公布了POC,暑假挖了大半个月没挖穿就想看看他是怎么挖穿的,分析完后气得我大半夜睡不着觉,因为这个漏洞点跟我当时分析出来的漏洞点一模一样,但由于本人逆向能力的差劲,逆了大半个月也没能分析出来调用链条,不过看到作者是在6.20给海康威视提交的漏洞点后,心态平衡了很多,(我是在7月20拿到的固件,27号找到的漏洞点),不过当时如果分析出来说不定也能打Geekpwn了,要是今年能上岸,我一定好好学逆向。当时脑残的以为漏洞点是从web端传过去的,怎么构造怎么不对劲(web转pwn后遗症了属于是),下面是当时脑袋抽风了的分析(大佬轻喷)

image-20210726203036540

image-20210726203048472

0x10 固件提取

固件版本build 5.5.104

官方给出的固件是加密过的固件,我们的固件是从flash里面提取出来的,但提取出来的文件系统貌似有些(一定)不太完整

image-20210726200740667

对比其他海康威视提取出来的flash

image-20210726201854888

很明显是少了文件系统,猜测不通型号的摄像头挂载文件系统的方式不一样?不过这并不影响接下来的分析

0x20 串口调试(未成功)

mmexport1627037178906

我拿到的海康威视的这款摄像头的串口有点小(也许它都是这样),当时一度怀疑它不是串口,甚至测电压发现它有两个3.3V,且由于飞线技术不太熟练,一度放弃了它是串口的可能性,后来是定制了一种的夹子,用那种最小的夹上测试可以连接上串口(淘宝yyds)

291636863997_.pic

不过串口并没有得到有用的信息,海康威视的串口(在海康威视里叫psh)的debug模式需要密码,是用他们的软件生成的密码,经过逆向发现它使用的RSA,暂时无法绕过,此方法拿shell失败

image-20211114123248454

还有一种拿shell的方法是在串口中修改启动参数类似于这样:https://paper.seebug.org/993/#34-login-bypass

但这种方法似乎在现在的海康威视串口上并不生效(可能被修复了,因此,通过这种办法拿shell的方法也失败了

最后一种方法是通过重新打包固件的办法拿shell,也是最通用的一种方法,这种方法确实可以拿到shell,但当时可能是由于一些操作的问题导致固件没刷回去,没能拿到shell分析(这也是我分析了大半个月硬是没找到点的一大原因,还是要动态调试啊

0x30 主程序以及漏洞点分析

海康威视的摄像头主程序为davinci

此漏洞成因是由于过滤检查不严格导致的

漏洞点位于sub_1192B4函数

image-20211114031129861

image-20211114031014118

可以看到假设a1 (filename)可控,那么则有

  1. 过滤filename中的非法字符(; `)这两种字符,注:新版本就是在这里修复的,改成了filename只允许包含数字和字母
  2. 检查 /home/webLib/doc/xml/filename 是否存在(对于我们传入的filename来说一定是不存在的,因此这一条必过)
  3. snprintf(&s,0x1f,"/dav/%s.tar.gz",filename) (这里就造成了我们的payload的长度限制:(0x1f-strlen(/dav/.tar.gz)=19 个字节,但对于熟悉web的师傅们已经够用了可以使用:$(cmd)或者&cmd&来绕过,这里值得一提的是有的设备跟这台不一样,有的设备snprintf可以达到37个字节payload就可以达到25个字节)
  4. 最后执行system("tar zxf /dav/%s.tar.gz -C /home/webLib/doc/xml",filename)来完成RCE

分析完漏洞点,接下来我们来寻找分析触发点

我们可以看到漏洞函数是有两个调用的

image-20211114034124196

触发点位于sub_5F1DC4 这个函数

image-20211114034027669

(另一个就是我开头分析的那个,至今还在疑惑为什么分析那个函数且为什么没分析明白,没搞清楚那个函数是干什么的,错失好洞,选错了路)

而对这个函数以及分析完之后(也看了网上的分析)

发现这个函数实现了一个标签解析的功能,(看下面debug给的日志也能看出来sub_557828这个函数其实可以给他改个名叫read_tag_language

但分析到这里我们还是不知道要如何控制这个tag_language的输入,因此我们需要找到这个函数的上层引用,此时IDA就和我一样抽风了,找不到上层引用,可能是IDA有些函数没分析完导致找不到上层引用,或者使用了相对地址传参数,(因为还要复习,这个坑暂时先放在这里

但这里其实还有一个问题,也就是我一开始找到的那个函数调用,我感觉也是可以利用的,但同样不知道他是取的包里的哪一个字段

而且要构造那一个利用的话条件更苛刻一点,原因如下:

image-20211114162532639

函数这里使用以及下面doc/xml的输入匹配都使用了
sscanf(v39,"/%[^/]",&haystack) 来做匹配
这就导致我们的payload里面不能出现("/") 字符,从而相比较于POC那个点的构造来说难度比较高

不过这两种方法在最新版本都无法在使用了,因为官方的修复是对UnzipLang函数添加的过滤,但同样也给我们一个好处就是可以利用这个版本的漏洞拿shell去调试其他接口(比重新刷回固件好使的多

0x40 漏洞利用

分析完漏洞

这里我们来简单过一遍漏洞流程

构造payload请求包为这个样式

PUT /SDK/weblanguage HTTP/1.1
headers

<?xml version="1.0" encoding="UTF-8"?>
  <language>&{query_args}&</language>

或者像爆出来的poc这样

<?xml version="1.0" encoding="UTF-8"?>
	<language>$({query_args})</language>

我测试使用&cmd& 形式可以执行(x86下,真实环境未测试),相较于$()可以更省出来一个字节(如果真实环境支持&的话,应该是支持的,我看程序中的一些本身命令里有&字符)

而这个请求包会触发函数read_tag_lanugage 解析出&cmd&传给漏洞函数,最终执行命令system("tar zxf /dav/&cmd&.tar.gz -C /home/webLib/doc/xml") 完成RCE

同时github上也有了POC

但这个POC并不能通用,因为其命令长度原因(虽然它优化到了18+3=21但还是太长,如果改用&cmd&可以优化到20个字符)

对于本设备而言就没办法使用,本设备能使用的payload长度最长为(0x1f-12-2 = 17),所以如果要在本设备下拿shell的话,还要进行优化

还有就是busybox的精简程度,要根据busybox来构造命令进行rce还需要在优化一下,至于优化的方法就有很多了,这里不展开讨论,师傅们可以自行尝试

0x50 总结与反思

  • 随缘挖洞不可取,很容易找不到触发点

  • 提取出程序所有的路径接口来fuzz一遍看它是否有接口存在权限认证错误是否可行

  • 如何快速理清程序逻辑以及相对完整的恢复符号表

    这里我的想法是这样的,可以找对应设备的官方手册(如果有的话,像这个设备就有官方的SDK开发包,但我没发现有什么用

    还有就是在玩路由器的时候发现的:有些设备它MIPS版本没去符号,但他还有个ARM版本去符号去的干干净净的

  • 如何写出对这种类型做匹配的工具或fuzz

    这里我的思路是做后项数据流匹配,标记命令注入函数例如system,popen,execve等函数,从后往前找触发点,这肯定不是最优解,但我目前水平还想不到更好的办法来匹配这样的隐式污点源

留下的坑考完再补

0x100 Reference

海康威视 CVE-2021-36260 分析&利用

POC

https://paper.seebug.org/993/#34-login-bypass