OpenWrt是一款应用于嵌入式设备如路由器等的Linux操作系统。类似于kali等linux系统中的apt-get等,该系统中下载应用使用的是opgk工具,其通过非加密的HTTP连接来下载应用。但是其下载的应用使用了SHA256sum哈希值来进行检验,所以将下载到的数据包进行哈希值的比对即可知道是否下载的数据包被修改,所以理论上来说是没有安全隐患的。
学习参考:
OPENWRT中的远程命令执行漏洞(CVE-2020-7982)-安全客 - 安全资讯平台
Uncovering OpenWRT Remote Code Execution (CVE-2020-7982) | Mayhem
我们对于这个漏洞将进行几个步骤,具体的目录如下:
目录
分析学习漏洞以及利用条件
搭建OpenWrt环境并启动
模拟漏洞利用和攻击
漏洞的相关修复
分析学习漏洞以及利用条件
分析漏需要相应的源代码,参考源代码的地址为:
https://git.openwrt.org/?p=project/opkg-lede.git;a=blob;f=libopkg/pkg_parse.c;h=0baa4db396569be816386b50568c57e12d1cd98c;hb=80d161eb5b95ceb51db989196405eaa00950e03b#l312
也可以直接clone到本地学习代码:
git clone https://git.openwrt.org/project/opkg-lede.git
首先对于源代码中这个位置
针对哈希值采用了SHA256sum的情况,会调用函数pkg_set_sha256来进行处理。传递给该函数的字符串是字符串SHA256sum后面的字符串。该函数为:
https://git.openwrt.org/?p=project/opkg-lede.git;a=blob;f=libopkg/pkg.c;h=e5bfe6f61b67583c00e528fb381162ace308dc13;hb=80d161eb5b95ceb51db989196405eaa00950e03b#l244
其会继续使用函数checksum_hex2bin来进行校验处理。如果最终检验的结果是0或者文件的长度不为32,就会出现相应的错误,返回值为NULL,从而不会保存相应的哈希值。继续进入函数checksum_hex2bin:
https://git.openwrt.org/?p=project/opkg-lede.git;a=blob;f=libopkg/file_util.c;h=61ff736cd2c82a224cb10f48d14532b8224bd792;hb=80d161eb5b95ceb51db989196405eaa00950e03b#l234
其中函数isxdigit是检查其是否为十六进制数字字符,而isspace是检查是否是空格。在这个函数中,最开始指针s和指针src是指向同一个位置的,而如果src所指向的内容出现空格,其会循环直到把空格去掉。也就是说,如果存在空格字符,也就是字符串SHA256sum后面的字符串的开头是一个空格,src和s所指向的地址就不同了。但是在256行开始的循环中,判断用到的字符是isxdigit(s[0]),依然用的是指针s所指向的内容。所以如果存在空格,此时循环会直接终止,指针len的长度为0,然后函数执行完毕。
也就是说,通过上面这样的操作,我们就可以使checksum_hex2bin函数最终处理的len值长度为0,所以pkg_set_sha256函数也会返回NULL,最终其哈希值就没有被成功设置。
接下来包列表解析就算完成了,下一步会开始HTTP下载包,然后会进入相应的验证步骤。
首先要求下载的软件包必须等于列表中指定好的大小,如下:
https://git.openwrt.org/?p=project/opkg-lede.git;a=blob;f=libopkg/opkg_install.c;h=27c9484cfb8189e42cbc073eaa14a67c71c3507a;hb=80d161eb5b95ceb51db989196405eaa00950e03b#l1379
检查相应的文件大小。且还要求如果指定了软件的哈希值,则其也需要匹配:
但是由于刚才checksum_hex2bin没有对其进行hash编码,所以这里1416行的if语句被直接跳过,不进行哈希验证。这就是相应的漏洞存在的位置。
漏洞利用
为了利用这个漏洞,我们需要实现两件事。首先让被攻击的电脑下载时重定向到我们有恶意软件包的服务器,而不是直接与downloads.openwrt.org服务器进行通信,这个需要我们能够做到更改本地的DNS或者基于ARP欺骗等策略。其次,两重检查中,哈希检查已经被绕过了,就还剩一个数据包大小的检查需要应对。那么参考文章中提供了一种很有效的方法:
1.创建一个受损的软件包,但是其大小要小于原软件包
2.计算两者之间的大小差异
3.最受损包的末尾用0字节进行填充,使其相同大小