加密固件分析实战
介绍
设备固件的安全性分析是IoT安全审计中非常重要的部分 。 获取固件是分析中的众多挑战之一 , 你可以通过多种技术来做到这一点 。 拥有固件后 , 就可以对其进行更仔细的分析 。 获取设备固件的最简单方法是从供应商更新服务器(通常是FTP服务器)下载 , 服务器中存储了不同版本的固件 , 而获取下一个版本的技术已编码在固件中 。 为了防止这种情况 , 供应商已开始以加密形式在服务器上存储固件 , 因此 , 即使你获取了固件 , 在进行进一步分析之前仍需要对其进行解密 。
最近 , 我在ZDI博客上看到了一篇非常有趣的文章 , 作者分享了不同的技术来解密固件 , 我强烈建议你阅读该文章 。 在这篇文章中 , 我将引导你详细分析DLINK路由器DIR-822US变体的固件解密 , 我们将使用ZDI博客中介绍的技术 , 研究设备如何处理解密的细节以及逆向解密算法 。
固件比对技术在本节中 , 我会总结ZDI文章中的内容 , 如果你已阅读 , 则可以跳过本节 。
让我们考虑一种情况 , 你具有已加密的固件版本 , 并且用于解密更新固件的算法位于设备固件中 。 当你上传固件时 , 它会解密并开始正常的更新过程 。 但是 , 可以说该解密例程不是固件初始出厂版本的一部分 , 并且在以后的某个时间点 , 供应商考虑引入这种安全机制 , 因此他们将新的加密/解密API编码到新的固件版本中 , 此版本可以称为过渡版本 。 由于过渡版本未加密 , 因此我们可以对解密算法进行逆向并手动解密固件 。 这正是我们在这篇文章中要做的 。
二进制比对是一种技术 , 你可以采用同一软件的不同版本的两个二进制文件并使用比对工具来了解程序新版本中引入的新功能 。 我们将使用kdiff3在过渡版本和先前的版本之间进行文件系统比对 , 因为在过渡版本中具有加密/解密例程 , 而先前的版本则没有 。
产品详情在深入研究之前 , 让我们看下设备的一些细节 。
产品IDDIR-822-USCPU架构MIPSR3000描述具有高增益天线的无线AC1200双频路由器支持链接链接链接发布历史简要了解路由器固件的发布历史 。 下表显示了发布日期以及FTP服务器上的版本ID和文件名 。
ReleaseDateVersionCodeFilename08/02/20203.15B02DIR-822_REVC_FIRMWARE_v3.11B01_ICJG_WW_BETA.zip03/12/20193.15B02DIR-822_REVC_FIRMWARE_v3.15B02.zip11/07/20193.13B01DIR-822_REVC_FIRMWARE_v3.13B01.zip10/05/20193.12B04DIR-822_REVC_FIRMWARE_v3.12B04.zip22/04/20193.11B01DIR-822_REVC_FIRMWARE_v3.11B01.zip17/09/2018FW303WWb04_i4sa_middleDIR822C1_FW303WWb04_i4sa_middle.zip17/09/20183.10B06DIR-822_REVC_FIRMWARE_v3.10B06.zip14/09/20173.01B02DIR-822-US_REVC_FIRMWARE_v3.01B02.zip08/06/20183.02B05DIR-822_REVC_FIRMWARE_v3.02B05.zip于2018年9月17日发布的固件FW303WWb04_i4sa_middle似乎有些奇怪 。 进行文件解压缩并对每个固件二进制文件执行binwalk , 然后观察每个文件的结果 , 可以发现 , 对于以及之前版本的所有固件 , binwalk至少都匹配一个lzma压缩和squashfs文件系统 。 版本之后的任何固件都没有签名匹配 。 在DIR822C1_FW303WWb04_i4sa_middle.zip文件中找到了如下所示的发行说明pdf , 其内容证实了我的猜测 。

文章图片
此固件更新是一个过渡版本 , 其中引入了加密/解密功能 , 因为你可以看到同一日期有两个固件更新 , 并且在发布说明中还提到固件v3.10必须从固件v303WWb04_middle过渡版本升级 。 看来我们有很好的线索 。
可视化方法如果在某些情况下 , 发行说明中未提及固件保护 , 则可以使用熵计算方法来确定固件是否已加密 。 简而言之 , 熵是对随机性的一种度量 , 它的值在0到1之间 , 值越高表示随机性越好 。 接近1的值被认为是高熵 , 反之亦然 。 压缩或加密的数据具有较高的熵值 。
二进制图像的熵分布将为我们提供二进制文件增量偏移的熵值 。 此信息将有助于猜测二进制文件的哪部分被加密/压缩以及哪部分是代码 。 让我们看一下两个不同的二进制版本的熵分布:过渡加密的FW303WWb04_i4sa_middle和加密版本3.15B02 。 让我们看看它们之间有何不同 。

文章图片

文章图片
如果你注意到图中的差异 , 则上图的熵几乎恒定在0.9以上 , 这意味着很有可能固件的不同部分对其进行了加密 。 在下图中 , 初始部分的熵很低 , 然后一直很高 , 然后又下降 , 然后再次上升 , 这种波动表明它混合了代码和加密/压缩数据 。
对于未加密的固件 , 你经常会看到这种模式 , 该固件最初具有波动的熵 , 而在随后的部分中具有较高的熵数据 。 这可能意味着二进制文件的初始部分中有一些代码 , 其会在设备启动期间动态解压缩代码(从后面的部分开始) 。
注意:加密和压缩在这里都被认为是造成高熵的原因 , 因为没有确切的方法可以根据熵值来判断其中哪一个是造成随机性的原因 。
【加密固件分析实战】接下来 , 我们应该尝试找出新版本中进行了哪些更改 , 并尝试逆向该算法 。
文件系统分析现在我们知道了过渡版本 , 让我们通过在版本3.02B05和FW303WWb04_i4sa_middle之间进行文件系统比对来找出新版本中引入了哪些变化 。 我们将为此使用kdiff3 。 我们应该在文件名中查找包含诸如“固件”、“更新”、“升级”、“下载”或这些关键字的组合之类的更新 。
加密二进制的动态分析在进行文件比对搜索期间 , 你能找到许多与固件更新功能相关的有意思的文件 , 但问题的关键是在/etc/templates/hnap/StartFirmwareDownload.php文件中的第111行 , 你会看到以下代码片段 。
//fwencimgsetattr("/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/consolen");del("/runtime/tmpdevdata");encimg-d-i-s执行了encimg二进制文件 。 接下来 , 搜索encimg二进制文件在文件系统中的位置 , 它位于路径/usr/sbin/encimg中 , 其他未知变量是fw_path , 我猜测它是固件路径 , 另一个变量是image_sign , 我们可以追溯该变量的值是从/etc/config/image_sign中读取的 , 还有一个-d参数尚不清楚 。
文章图片
让我们进行动态分析以进一步理解该命令 。 运行简单的file命令表明它是一个ELF32位MIPSMSB可执行文件 。 现在 , 我们可以使用MIPS体系结构的qemu用户空间模拟器来运行此二进制文件 。 转到固件的squashfs-root目录 , 运行以下命令:$qemu-mips-L<roothpathoffilesystem>./usr/sbin/encimgUsage:encimg{OPTIONS}-h:showthismessage.-v:Verbosemode.-i{inputimagefile}:inputimagefile.-o{outputimagefile}:outputimagefile.-e:encodefile.-d:decodefile.-s:signature.注意:在上面的命令中 , 我们为qemu-mips提供-L参数 , 该参数指定用于加载依赖项的根目录的路径 。 经常使用的另一种方法是Linuxchroot 。
从上面的帮助消息中可以看出这是用于解密固件的二进制文件 , -s参数称为签名 , 但是我认为它用于将从文件/etc/config/image_sign读取的解密密钥作为参数 。 该文件包含字符串_wrgac43s_dlink.2015dir822c1 , 我觉得它是解密密钥 。 另一个参数-i是输入文件 , 它将是新接收到的加密固件文件 。 现在 , 让我们尝试使用qemu模拟器解密固件 。
qemu-mips-L../usr/sbin/encimg-d-i-swrgac43s_dlink.2015_dir822c1Qemu用户空间模拟器还具有另一个有意思且非常重要的功能 , 它可以记录二进制文件执行的系统调用 。 可以通过向qemu提供-strace参数来启用它 , 它将打印二进制文件执行的所有系统调用 , 我在上述二进制文件上进行了尝试 , 并提取了一些有趣的日志 , 如下所示 。
#Aahh....acryptolibrarybeenloadedbythebinary,it#hintsthatitisusingsomesortofencryptionalgorithmpossiblityAES#orsomesymenticencryptionalgorithmaswehaveseentherealready#apasswordweprovidetothebinary.open("/lib/libcrypto.so.0.9.8",O_RDONLY)=3.........#openingthefile(returnfd3)open("/home/payatu/test_1.bin",O_RDWR)=3stat(,0x7fffea90)=0write(1,0x7f689298,99)Thefilelengthof/project/dlink/AC1200/test_1.binis6865072=99read(3,0x7fffe***,4)=4#mmapfd3mmap(NULL,6865072,PROT_WRITE,MAP_SHARED,3,0)=0x7ef51000munmap(0x7ef51000,6865072)=0#againtruncateoperationonfd3ftruncate(3,6865044,0,0,0,0)=0#goodbyefd3close(3)=0逆向加密方法你可以在喜欢的反汇编/反编译工具中加载encimg二进制文件以进行更深入的分析 。 我发现了main函数(0x401244) , 该方法解析参数 , 然后调用具有加密/解密所有核心功能的build函数(0x400d24) 。 此外 , 二进制还导入了加密相关函数 , 其中一些函数是_AES_set_encrypt_key、_AES_set_decrypt_key和_AES_cbc_encrypt , 这说明二进制文件使用AES加密算法 , 意味着用于加密和解密文件的密钥相同 。 做一些基础研究 , 你可以了解函数原型 , 这是这些函数的简短说明 。
//SameprototypeforAES_set_encrypt_keyAES_set_decrypt_key(//userinputkeyconstunsignedchar*userKey,//sizeofkeyconstintbits,//encryptionkeystructwhichwillbeusedby//encryptionfunctionAES_KEY*key)AES_cbc_encrypt(//inputbufferconstunsignedchar*in,//outputbufferunsignedchar*out,//bufferlengthsize_tlength,//keystructreturnbypreviousfunctionconstAES_KEY*key,//initializatinvectorunsignedchar*ivec,//isencryptionordecryptionconstintenc)让我们看一下build函数的反编译代码 。

文章图片
从上面的代码 , 我们可以看到二进制文件是使用mmap函数映射到内存的 。 然后基于参数调用AES_set_encrypt_key或者AES_set_decrypt_key来设置AES_KEY数据结构 , 并使用该结构通过AES_cbc_encrypt加密/解密有效载荷 , 最后使用munmap函数调用将数据写回到文件中 。 没什么特别的!
结果一旦我们解密了固件 , 再来看一下解密后的固件的熵 。

文章图片
它看起来与我们之前看到的未加密固件非常相似 。
列举攻击面1、由于我们将二进制文件上传到操作系统服务(固件更新服务)以处理该文件 , 我们可以找到用于解密算法的文件解析错误 , 并通过某种内存损坏问题来破坏服务进程 , 从而使我们可以访问系统 。
2、我们可以使用诸如firmwaremod-kit之类的固件补丁工具来更改固件文件并重新打包 , 并使用相同的加密二进制文件对其进行加密并上传文件以进行更新 。 如果没有完整性检查 , 则补丁固件将更新而不会出现任何问题 。 尽管使用了加密 , 但是恶意固件更新仍然是一个问题 , 固件签名机制用于防御这种攻击 。
注意:由于项目时间和范围的限制 , 我尚未测试上述攻击 , 但如果我是攻击者 , 我会尝试这些方法 。
FirmwareAuditor使用不同的工具进行分析可能既耗时又容易出错 , 这反映了我们的日常工作流程 , 我们开发了一款工具来自动执行繁琐的固件分析工作 , 该产品称为FirmwareAuditor , 任何人都可以免费使用社区版 。 如你所见 , 我使用FirmwareAuditor进行了上面的大多数分析 。 你可以在此链接上找到有关该产品的更多详细功能 , 并通过相同的方式将反馈发送给我们 。 FirmwareAuditor可用于:
1、熵图
2、探索Linux文件系统并下载所有内容(在本文案例中为enimg二进制文件、PHP文件)
3、build函数的反编译代码
4、更多内容
结论我们掌握了不同的方法来确定固件是否已加密 , 如何使用固件比对方法来查找固件中使用的解密方法 , 以及如何使用它并复制该方法到另一个固件 。 我们还讨论了一些可能的攻击面 。 使用这种保护方案时 , 需要意识到这一点 。
参考1.MINDSHARE:DealingWithEncryptedRouterFirmware
2.QemuUserspaceEmulation
3.https://payatu.com/blog/munawwar/solving-the-problem-of-encrypted-firmware
精彩推荐

文章图片
推荐阅读
- 为何CBA本土第一人易建联如此受球迷欢迎?看完分析,豁然开朗
- 德雷斯|剑与远征德雷斯技能详细分析
- 办理美国留学签证需要offer业界内最独到分析
- 啤酒节|延时收班、加密夜间车距 惠民公交助力2020武汉啤酒节
- 蒋哲浩:8.17黄金白银能否再次创新的高位金银分析
- 【用车攻略】准备入手别克君越,养车成本分析你看了吗?
- 静听雨轩|DNF100版本现状分析:毕业玩家仍是少数,神话依然是玩家最大追求
- 理性分析|中国隐形轰炸机究竟何时能登场?最快2020年首飞,2025年量产
- 理性分析|迈入世界级海军门槛,首批8艘055驱逐舰4艘定岗,剩下4艘怎么安排
- 爵士vs掘金赛前分析!后卫群难敌锋线群!爵士首轮游恐再现!
