NETGEAR PSV-2019-0076: 从漏洞公告到PoC
前言
最近看到一篇安全资讯,提到Netgear
修复了其产品中的多个高危漏洞,包括PSV-2019-0076
、PSV-2018-0352
和PSV-2019-0051
等。其中,利用部分漏洞可实现远程代码执行,且无需认证。以PSV-2019-0076
为例,查看Netgear
的安全公告,如下,并没有透露过多的细节。
通常来说,IoT
设备上的漏洞相对比较简单,于是打算花点时间看下,尝试通过补丁比对定位具体的漏洞,进一步地得到对应的PoC
。
本文写于3月。
漏洞定位
由公告可知,该漏洞在1.0.2.68
版本中修复,下载邻近的两个版本1.0.2.62
和1.0.2.68
的固件到本地进行分析。通过对两个文件系统进行简单比对,发现这2个版本之间的差异非常多。通常来说,不同版本之间的差异越小,越有助于定位漏洞。
1 | diff -r _R7800-V1.0.2.62.img.extracted/squashfs-root/ _R7800-V1.0.2.68.img.extracted/squashfs-root/ | grep Binary | wc -l |
从更新时间来看,这两个版本之间间隔差不多有11个月。
在对文件系统进行简单分析后,将比对的目录缩小在/www
和/usr/sbin
两个目录中。浏览了下diff
的结果,其中有几个文件比较有意思,包括proccgi
和uhttpd
等。
先对proccgi
进行分析,借助Bindiff
插件进行比对,如下。在函数sub_00008824()
中,仅改变了处理流程的顺序,未发现安全问题。
同样,对uhttpd
进行分析,Bindiff
比对的结果如下。大部分发生变化的是系统函数,除了uh_cgi_auth_check()
函数之外。
两个版本中uh_cgi_auth_check()
函数内的主要差异如下。在新版本中增加了dni_system()
函数,而在老版本中则使用snprintf() + system()
的模式,熟悉的人一看可能就知道这是典型的命令注入漏洞。在查看dni_system()
后,其内部使用execve()
来执行命令,更加证实了这一点。
现在大体上定位到了漏洞的具体位置(当然也有可能不是…),还需要进一步分析看能否触发以及如何触发。
静态分析
uh_cgi_auth_check()
函数的部分伪代码如下,其主要逻辑为:找到请求头中的Authorization
部分,获取"Basic "
后面的内容,在base64
解码后获取其中的password
,再传入snprintf()
中进行格式化,最后调用system()
执行。典型的命令注入模式,且发生在进行认证的过程中,与安全资讯中提到的的”无需认证”相对应,再一次说明漏洞很可能就是这里(当然还没有完全确定…)。
1 | signed int __fastcall uh_cgi_auth_check(int a1, int a2, int a3) |
如果手边有真实设备的话,其实就可以直接在设备上进行测试了,然而我手边并没有真实设备:( … 所以继续对调用路径进行分析。uh_cgi_auth_check()
函数的调用路径很简单,仅有2处调用,且均在main()
函数中,如下。对main()
函数前面的逻辑进行了简单的分析,主要是解析uhttpd
命令行参数、服务初始化、解析部分HTTP请求参数之类的,没啥特别的。
现在确信这里是可以触发的,奈何手边没有真实设备,于是又开始折腾固件仿真,想进一步通过动态测试验证。
动态分析
对IoT
设备进行固件仿真,常见的方式如下。
- 基于
qemu user mode
,模拟单个服务:D-Link
的很多设备可以采用这种方式 - 基于
qemu system mode
, 模拟整个系统:一些第三方工具对qemu
进行了封装,比如Firmadyne
、ARM-X
- “纯软件模拟”:如
Qiling
为了方便,首先使用Firmadyne
框架进行测试,发现无法获取网络配置信息。而ARM-X
和Qiling
框架暂时未仔细研究,所以还是采用我经常使用的方式:基于qemu user mode
模拟单个服务,如下。幸运地是,服务成功跑起来了,暂时没有报错,无需手动修复环境。
1 | '-f' option is used for debugging easily |
由于对R7800
这款设备不太熟悉,不知道url
的前缀,先直接访问/
路径,并带上对应的payload
,测试后发现并未成功,难道是没有触发对应的路径?然后在启动时加上qemu
的-g
选项,采用gdb-multiarch
进行附加调试,分析发现在uh_cgi_auth_check()
函数头部有一个判断没通过,如下。
1 | signed int __fastcall uh_cgi_auth_check(int a1, int a2, int a3) |
在将url
改为/cgi-bin
后,浏览器成功地弹出了认证的对话框,之后在gdb
中可以看到成功地到达了漏洞点。然而,命令执行完毕之后,本地还是没有生成hello.txt
文件… (PS:尝试了多种payload无果,可能和基于qemu user mode
仿真有关)
上述问题与
binfmt_misc
机制有关,一种简单的解决办法为:将qemu-arm-static
文件拷贝到解压后的文件系统的/usr/bin
目录下。具体可参考【置顶】技巧misc 中”qemu
仿真出现execve()
错误”小节。
小结
本文从漏洞公告出发,通过固件版本差异分析,再到补丁比对,最终成功定位到漏洞,并结合静态分析和动态仿真的方式对漏洞进行了验证。整体上来说,思路算是完整的,也适用于分析其他的N day
,区别在于整个过程中每一步的复杂程度不一样。
相关链接
- Security Advisory for Unauthenticated Remote Code Execution on R7800, PSV-2019-0076
本文首发于信安之路,文章链接:https://mp.weixin.qq.com/s/QUrErOgaUcQVhQz5fGhc_w