分析介绍
设备固件的安全性分析是IoT安全测试中非常重要的部分。获得固件是分析中的众多挑战之一,你可以通过大量技术来做到这一点。获得固件后,对其进行解包以进行更广泛的分析。但是,获取设备固件的最简单方法是从供应商更新服务器(通常是FTP服务器)下载该设备,他们在其中存储了不同版本的固件,获取下一个版本固件的技术已编码在固件中。为了防止这种情况,供应商已开始以加密形式在服务器上存储固件,因此,即使你购买了固件,在进行任何进一步分析之前仍需要对其进行解密。
最近,我在ZDI博客上看到了一篇非常有趣的文章,作者分享了不同的技术来解密固件,我强烈建议你阅读该文章。在这篇文章中,我将引导你详细分析DLINK路由器DIR-822 US的固件解密,我们将使用ZDI博客中介绍的技术,并研究有关设备和逆向工程师如何处理解密的详细信息解密算法。
https://www.thezdi.com/blog/2020/2/6/mindshare-dealing-with-encrypted-router-firmware
固件对比
在本节中,我将总结一下ZDI帖子。
让我们考虑一种情况,你已经获得了已加密的固件版本,并且用于解密更新固件的算法位于设备固件中。当你上传固件时,它会解密并开始正常的更新过程。但是,该解密例程不是固件初始出厂版本的一部分,并且在以后的某个时间点,供应商考虑引入这种安全机制,因此他们将新的加密/解密API编码为新的固件版本。此版本可以称为过渡版本。由于过渡版本未加密,因此我们可以对解密算法进行逆向工程并手动解密固件,这正是我们在这篇文章中要做的。
二进制diff是一种非常有意思的技术,你可以采用同一软件的不同版本的两个二进制文件并使用diff工具来了解程序新版本中引入的新函数。我们将使用kdiff3在过渡版本和之前的版本之间进行文件系统区分,因为在过渡版本中将具有加密/解密例程,而先前的版本则没有。
目标详情
在深入研究之前,看一下设备详情。
发行版本
简要了解路由器固件的发行历史,下表显示了发布日期以及FTP服务器上的版本ID和文件名。
固件FW303WWb04_i4sa_middle于2018年9月17日发布,进行解压缩文件并在每个固件二进制文件上执行binwalk,然后观察每个文件的结果,我做了一个有趣的观察,即所有固件在FW303WWb04_i4sa_middle binwalk 以及之前的版本中至少都匹配了lzma压缩和squashfs文件系统。版本FW303WWb04_i4sa_middle之后的任何固件都没有签名匹配,在进一步分析在zip文件DIR822C1_FW303WWb04_i4sa_middle.zip中找到的发行说明pdf时,如下所示,这证实了我的疑惑。
此固件更新是一个过渡版本,其中引入了加密/解密函数,因为你可以看到同一日期有两个固件更新,并且在发行说明中还提到_固件v3.10必须从过渡版本升级v303WWb04 中间固件版本。
如果在某些情况下,发行说明中未提及固件保护,则可以使用熵计算方法来确定固件是否已加密。简而言之,熵是对随机性的一种度量,它的值在0到1之间,值越高表示随机性越好。接近1的值被认为是高熵,反之亦然。压缩或加密的数据具有较高的熵值。
二进制图像的熵分布将为我们提供二进制文件增量偏移量的熵值。此信息将帮助你猜测二进制文件的哪个部分被加密/压缩以及哪个是代码。看一下两个不同的二进制版本的熵分布,一个过渡加密的FW303WWb04_i4sa_middle和加密版本3.15B02,看看它们之间有何不同。
如果你注意到图中的差异,则图B的熵几乎恒定在0.9以上,这意味着很有可能在固件的不同部分对其进行了加密。在图C中,初始部分的熵很低,然后一直很高,然后又下降,然后再次上升,这种波动表明它是代码和加密/压缩数据的混合体。
对于未加密的固件,你经常会看到这种模式,该固件最初具有波动的熵,而在随后的部分中具有较高的熵数据。这可能意味着二进制文件的初始部分中有代码,该代码会在设备启动期间动态解压缩代码。
注意:加密和压缩在这里都被归咎于高熵,因为没有确切的方法可以根据熵值来判断其中哪一个是造成随机性的原因。
接下来尝试找出新版本中进行了哪些更改,并尝试逆向该算法。
分析文件系统
现在拿到了过渡版本,通过在版本3.02B05和FW303WWb04_i4sa_middle之间进行文件系统对比来找出新版本中引入了哪些更改。使用kdiff3,在文件名中查找包含诸如“固件”,“更新”,“升级”,“下载”或这些关键字的组合之类的关键字的更新。
动态分析
在进行文件差异搜索期间,你将可以找到许多与固件更新函数相关的有趣文件,但问题的实质是在第111行的/etc/templates/hnap/StartFirmwareDownload.php文件中,将发现以下代码片段。
// fw encimg setattr("/runtime/tmpdevdata/image_sign" ,"get","cat /etc/config/image_sign"); $image_sign = query("/runtime/tmpdevdata/image_sign"); fwrite("a", $ShellPath, "encimg -d -i ".$fw_path." -s ".$image_sign." > /dev/console \n"); del("/runtime/tmpdevdata");
从上面的代码中,我们可以推断出encimg二进制文件是通过command执行encimg -d -i
做一些动态分析以进一步解密该命令,运行文件命令表明它是ELF 32位MIPS MSB可执行文件。将qemu用户空间仿真用于MIPS体系结构来运行此二进制文件,转到固件的squashfs-root目录,然后运行以下命令。
$ qemu-mips -L ./usr/sbin/encimg Usage: encimg {OPTIONS} -h : show this message. -v : Verbose mode. -i {input image file} : input image file. -o {output image file} : output image file. -e : encode file. -d : decode file. -s : signature.
注意:在上面的命令中,我们为qemu-mips提供-L参数,该参数指定用于加载依赖项的根目录的路径。经常使用的另一种方法是Linux chroot。
从上面的帮助用法消息中,很明显,这是用于解密固件的二进制文件,-s参数称为image_sign签名,但是我认为它用于将解密密钥作为从文件/ etc / config /读取的参数。该文件包含字符串值_wrgac43s_dlink.2015 dir822c1,它是解密密钥。另一个参数-i是输入文件,它将是新接收到的加密固件文件,现在尝试使用qemu仿真器解密固件。
qemu-mips -L . ./usr/sbin/encimg -d -i -s wrgac43s_dlink.2015_dir822c1
Qemu用户空间仿真器还具有另一个有趣且非常重要的函数,它可以逆向strace,执行二进制文件进行的系统调用日志记录。你可以通过向qemu提供-starce参数来启用它,它将打印二进制文件进行的所有系统调用,我在上述二进制文件上进行了尝试,并提取了一些有趣的日志,如下所示。
# Aahh.... a crypto library been loaded by the binary, it # hints that it is using some sort of encryption algorithm possiblity AES # or some symentic encryption algorithm as we have seen there already # a password we provide to the binary. open("/lib/libcrypto.so.0.9.8", O_RDONLY) = 3 ... ... ... # opening the file (return fd 3) open("/home/payatu/test_1.bin", O_RDWR) = 3 stat("/home/payatu/test_1.bin", 0x7fffea90) = 0 write(1,0x7f689298,99)The file length of /project/dlink/AC1200/test_1.bin is 6865072 = 99 read(3,0x7fffeb50,4) = 4 # mmap fd 3 mmap(NULL,6865072,PROT_WRITE,MAP_SHARED,3,0) = 0x7ef51000 munmap(0x7ef51000,6865072) = 0 # again truncate operation on fd 3 ftruncate(3,6865044,0,0,0,0) = 0 # good bye fd 3 close(3) = 0
逆向加密算法
你可以在喜欢的反汇编程序/反编译器工具中加载encimg二进制文件,以进行更深入的分析。我在函数部分徘徊,偶然发现了一个有趣的函数main(0x401244),该方法解析参数,然后调用具有加密/解密所有核心函数的build(0x400d24)。此外,二进制还进行了加密相关导入,其中一些函数是AES_set_encrypt 密钥,AES_set_decrypt 密钥和_AES_cbc 加密这确认二进制文件正在使用AES加密算法,这意味着用于加密和解密文件的密钥相同,做一些基础研究,可以设法了解函数原型,这是这些函数的简短说明。
// Same prototype for AES_set_encrypt_key AES_set_decrypt_key ( // user input key const unsigned char *userKey, // size of key const int bits, // encryption key struct which will be used by // encryption function AES_KEY *key ) AES_cbc_encrypt ( // input buffer const unsigned char *in, // output buffer unsigned char *out, // buffer length size_t length, // key struct return by previous function const AES_KEY *key, // initializatin vector unsigned char *ivec, // is encryption or decryption const int enc )
看一下build函数的反编译代码。
二进制文件是使用mmap函数映射到内存的。然后通过基于参数调用AES_set_encrypt_key / AES_set_decrypt_key来设置AES_KEY数据结构,并使用该结构通过AES_cbc_encrypt加密/解密有效负载,然后使用munmap函数调用将数据写回到文件中。
解密了固件,再来看一下解密后的固件的熵。
它看起来与我们之前看到的未加密固件非常相似。
攻击面分析
1. 由于我们将二进制文件上传到操作系统服务(固件更新服务)处理该文件。我们可以在文件解析中找到使用过的解密算法的错误,并通过某种内存损坏问题来破坏服务进程,从而使我们可以访问系统。
2. 我们可以使用诸如固件mod-kit之类的固件修补工具来更改固件文件并重新打包,并使用相同的加密二进制文件对其进行加密并上传文件以进行更新。如果没有完整性检查的方法,则修补的固件将更新而不会出现任何问题。尽管进行了加密,但是恶意固件更新仍然是一个问题。
分析工具
使用十种不同的工具进行分析可能既耗时又容易出错,这反映了我们的日常工作流程,我们创建了一个工具来自动执行繁琐的固件分析工作,该产品是Firmware Auditor,社区版免费提供给任何人使用。我使用https://app.expliot.io/进行了上面的大多数分析。你可以在此链接上找到有关该产品的更多详细信息功能。
1. 熵图对比
2. 分析Linux文件系统并下载所有内容(在我们的情况下为enimg文件,PHP文件)
3. 反编译的代码和函数
4. https://expliot.io/pages/firmware-auditor
分析总结
我们用了不同的方法来确定固件是否已加密,如何使用固件diff方法来找到要使用的解密方法,以及如何使用它并复制该方法到另一个固件,我们还讨论了解密方法打开的一些攻击面。
参考资料
2. Qemu用户空间仿真
本文翻译自:https://payatu.com/blog/munawwar/solving-the-problem-of-encrypted-firmware如若转载,请注明原文地址: