利用污点分析批量挖掘路由器固件安全漏洞 - 嘶吼 RoarTalk – 网络安全行业综合服务平台,4hou.com

利用污点分析批量挖掘路由器固件安全漏洞

fanyeee 技术 2021-08-11 11:40:00
393441
收藏

导语:在本文中,我们为读者详细介绍如何利用污点分析批量挖掘路由器固件安全漏洞。

在过去的几个月里,我们开发了一个污点分析工具,专门用于寻找路由器中的安全漏洞。我们还参考编号为CVE-2019-8312到CVE-2019-8319之间安全漏洞开发了一个检测工具;这些漏洞都是固件版本为1.12A1的D-Link DIR-878路由器中的命令注入漏洞。我们的目标是自动检测此类漏洞。在理想情况下,使用该工具应该比手动查找漏洞更快。

在本文中,我们将分享我们所使用的方法,以及通过该工具在PROLiNK PRC2402M、D-Link DIR-1960和D-Link DIR-X1560路由器上找到的安全漏洞。

关于工具

现有工具

现在,现成的污点分析工具已经有很多了。其中,我最感兴趣的是Tritonbincat,因为两者已经相当成熟。然而,我们却无法使用这两种工具,因为它们不支持目标设备所使用的MIPS架构。

使用angr进行符号执行测试

因此,我们把工作重点放在利用angr打造自己的工具上;angr是一个基于Python的二进制分析框架。我们之所以选择angr,是因为它支持大多数架构,包括我们所针对的MIPS和ARM架构。早些时候,@puzzor曾经对angr进行了一些自定义修改,用于静态污点分析:在angr的帮助下,通过符号执行模拟程序,然后根据生成的VEX IR程序跟踪信息进行静态分析。通过这种方法,我们成功地在测试固件中发现了命令注入漏洞。

然而,我们很快就遇到了一个问题:为了生成程序跟踪信息,我们需要angr通过模拟每条指令来模拟每个函数,并使用符号执行来决定是否跟随一条分支指令。

具体来说,angr会维护一个状态堆栈。一个状态包含诸如寄存器值和内存内容方面的信息。因此,当模拟一个函数时,它只会从一个状态开始。当遇到一个分支指令时,如果angr不确定是否跟随该分支,angr将重复该状态,其中一个将跟随该分支,而另一个则不跟随。

大多时候,函数中都会存在循环。如果循环条件是基于一些用户的输入,那么,状态的堆栈就会“爆炸”。由于angr将始终不确定是继续还是从循环中跳出,所以,它会不断复制状态。此外,还需要注意的一件事是,这些状态并不是同时模拟的。相反,每次只有一个状态被模拟。在这种情况下,需要很长的时间才会有一个状态达到易受攻击的代码;或者,如果该函数根本没有易受攻击的代码,那么,模拟过程可能永远不会终止。

作为一个符号执行框架,angr提供了多种可定制设置(称为模拟技术)来决定先模拟哪个状态。并且,在尝试了许多不同的技术后,我们仍然无法改善执行时间。

例如,在为待分析二进制代码中的每个函数设置了2分钟的超时的情况下,有时候即使经过了2小时,仍然无法完成对二进制文件的分析(因为如果一个函数没有漏洞,它将一直模拟执行下去,直到超时位置)。更糟糕的是,angr中存在一个未知的内存泄漏问题,所以,2小时后,电脑的内存早就耗尽了……

别忘了,我们之前的目标是希望这个工具比手工方式更快一些。所以,通过这种方式是不可能的,所以,我们继续寻找改进方法或替代方案。

应用angr的Reaching Definition分析技术

最终,我们偶然发现了这个漏洞后,燃起了我们对于angr的Reaching Definitions分析技术的热情,于是仔细阅读了下面的资料:

A reaching definition engine for binary analysis built-in in angr

◼Handle function calls during static analysis in angr

◼CSE545 Guest Lecture: Binary Analysis

Use-def关系

总之,这种分析方法将生成函数中原子之间的use-def关系。在这里,所谓原子类似于变量,并且,原子也具有各种类型,如寄存器、栈变量、堆变量。实际上,只要把原子看作变量,事情就很简单了,下面,我们举例说明:

1.png

在上面的函数中,存在一个明显的命令注入漏洞:含有漏洞的代码为system(command),其中注入的命令来自querystring的参数name。在这个函数中,querystring和其他原子之间的use-def关系如下所示:

 

1.png

首先,我们看到querystring被定义为函数vuln的参数,并被get_querystring_value函数作为参数querystring使用。除此之外,函数get_querystring_value还定义了一个参数name。最后,get_querystring_value函数定义了一个返回值,并用到了上面定义的两个参数。

然后,通过下图我们可以看到,在调用sprintf函数时,还用到了name变量(函数get_querystring_value的返回值)和一个字符串echo %s >> /tmp/log。这一次,情况略有不同。因为我们知道sprintf函数的第一个参数是目标,所以,我们必须对command进行适当的定义,从而让它全面使用提供给spritnf函数的2个参数,而不是仅使用返回值。生成的use-def关系如下所示:

 

1.png

使用相同的概念,通过这种分析方法可以为函数中的所有原子生成相应的use-def关系。正如我们在上面看到的,这种关系可以被建模为一个图:“使用”用边表示,“定义”用节点表示。 因此,我们可以将其转换为图分析问题。

在污点分析术语中,source点是程序中产生污点数据的地方,而sink点是污点数据可能到达也可能不到达的地方。污点分析是确定来自source点的数据是否到达sink点。在上面的例子中,get_querystring_value函数是source点,因为它从用户输入中提取一些值,而system函数是sink点。就本例来说,来自source点的数据确实到达了sink点。

在我们的use-def图中,我们可以确定source点和sink点的定义(即节点),然后用一些启发式方法遍历该图,以确定source点的数据是否被sink点所使用。如果是,那么我们就把source点标记为易受攻击的,并继续对其进行筛查。

工具总结

总而言之,我们的工具首先利用angr的Reaching Definitions分析方法,生成一个由路由器固件中的函数的组成的use-def关系图。然后,对该图进行相应的分析,以检测可能的安全漏洞,比如,如果(来自source点)用户输入到达一个危险的函数(即sink点),如system函数,我们就认为发现了一个潜在的安全漏洞。

实际上,我们的工具与CodeQL或Joern等引擎的功能非常类似,只是我们的工具缺乏强大的查询界面而已。

测试结果

前面我们曾提到,使用符号执行的方法时,有时分析一个程序需要花费2个多小时。但是,使用上面介绍的方法,分析同样的程序只需2分钟左右就能搞定了。所以,这看起来的确是一个不错的工具。 在对该工具进行改进以消除假阳性并覆盖更多的假阴性后,我们在DLink和PROLiNK路由器上进行了测试。

PROLiNK PRC2402M

使用该工具,我们立即发现了近20个命令注入漏洞,其中10个不需要身份验证,可以直接通过WAN接口进行访问。我们马上向PROLiNK报告了这些漏洞,他们也很快做出了回应。在这些漏洞被修复后,我们申请了相应的CVE编号,它们分别为CVE-2021-35400到CVE-2021-35409。 下面是一些易受攻击的代码片段,其中source点和sink点分别是:

◼Source点:web_get

◼Sink点:system, do_system, popen

2.png

硬编码的密码,还是后门?

在这个过程中,我还发现了一些其他的安全漏洞。似乎有一个硬编码的密码或后门密码,可以用来登录到路由器的管理面板:管理页面将用户提供的密码的md5哈希值发送到login.cgi进行验证,相应的伪代码如下所示:

3.png

然而,在它后面还有一段可疑的代码:

4.png

通过将user作为密码,我们竟然成功登录到管理页面。通过这种方式登录后,显示的仪表板会略有不同,它似乎比通过实际密码登陆的用户提供的功能要少。然而,我们仍然可以访问http://prc2402m.setup/setting.shtml,这就足以控制路由器的设置了。

我们向供应商报告了这一情况,他们很快就更新了固件。为了确定该后门已经消失,我再次打开了同一个函数。这次,我并没有再看到strcat(salted_password, "user"),却看到了以下内容:

5.png

实际上,通过nvram查找Password_backup的值也不是什么难事。

6.png

我们很快又向供应商报告了这个问题。幸运的是,经过再次修复后,已经找不到Debugdoor或后门密码了。

基于堆栈的缓冲区溢出

由于缺乏边界检查,我们还发现了许多基于堆栈的缓冲区溢出漏洞。通过利用这些漏洞,攻击者可以覆盖堆栈上的返回地址,从而获得对程序执行的控制。在上面的一些命令注入的例子中可以看到,用户的输入是通过sprintf函数而不是snprintf函数复制到一个字符串中的。

拒绝服务漏洞

在测试缓冲区溢出漏洞的PoC时,我还发现了一个漏洞,它导致路由器停止响应请求,直到用电源按钮手动重启为止。在下面的伪代码中,cli_num被作为参数传给/sbin/sta_qos.sh脚本。

7.png

通过检查脚本内容,我发现以下for循环,其中$sta_num用于保存cli_num的值。

8.png

如果cli_num是一个很大的值,例如999999999,那么这个脚本几乎会永远困在循环中,实际上,这就是陷入了一个无限的循环。通过向路由器发送这样的请求,会有很多这种脚本被执行并卡在循环中。 一段时间后,路由器会停止响应任何请求,这时,只能通过手动重启,它们才能再次正常工作。

时间线

●6月9日:向供应商报告了10个命令注入漏洞。

●6月11日:供应商修复了相应的漏洞。

●6月11日:建议供应商使用一些额外的过滤器来防止此类漏洞。

●6月28日:供应商根据我们的建议进行了修复。

●7月9日:向供应商报告了另外3个漏洞(后门、缓冲区溢出、DoS)。

●7月23日:供应商进行了修复。

DLink DIR-1960

除了PROLiNK路由器外,我们还在DIR-1960固件上运行了该工具。这一次,该工具返回了近200个检测结果。然而,在对结果进行筛查后,发现只有4个是通过HNAP API的命令注入漏洞(我们已经在前面报告过了),并且所有这些都需要认证。(由此看来,在消除假阳性方面,还有很大的改进空间!)

对于HNAP,这里简单介绍一下:它是Home Network Administration Protocol的首字母缩写,它实际上就是一个基于SOAP的协议,用于与路由器管理面板进行通信。

DLink DIR-X1560

接着,我决定也在DIR-X1560固件上试一下这个工具。上面的两个路由器都是基于MIPS架构的,但DIR-X1560是在ARM处理器上运行的。通过稍加调整,该工具就可以正确地分析基于ARM的固件。由此证明,这个工具具有很好的架构兼容性,这让我很开心。

然而,由于抽象层很多,识别固件上的漏洞并不那么简单。有鉴于此,该工具在固件逆向工程中提供了巨大的帮助。我不确定固件所基于的框架的确切名称,但我设法在GitHub上找到了一些源代码,这非常有帮助,因为其中含有许多注释。我在源代码中找到的最接近的术语是CMS(CPE管理系统)、CPE(客户驻地设备)和TR-069。但是,请注意,此repo不包含任何特定于dlink的代码,因此需要执行一些逆向分析。

在我看来,它类似于MVC(模型-视图-控制器)架构,尽管它也可能不是这样的。

9.png

关于术语和缩略语的进一步解释,请参考这里。

DAL(数据聚合层)API,顾名思义,是用来与数据进行交互的,主要是传递路由器的配置。但是数据的实际存储是由MDM(内存数据模式)和ODL(对象调度层)API完成的。DAL使用cmsObj_get和cmsObj_set函数(或其变体)作为与MDM/ODL的接口,以获取或设置某些对象的值。例如,获取IP_PING_DIAG MDM对象并将其存储在ipPingObj中,然后在修改后将其保存回来的代码如下所示:

10.png

下面解释用到的参数: 

◼MDMOID_DEV2_IP_PING_DIAG:一个枚举变量,指定访问IP_PING_DIAG对象。

◼iidStack:一些我们不需要关心的内部数据。

◼ipPingObj:IP_PING_DIAG对象的内容。

除此之外,还有RCL(运行时配置层)和RUT(运行时使用工具)API。每个MDM对象(例如MDMOID_DEV2_IP_PING_DIAG)都有一个相应的RCL处理程序(rcl_dev2IpPingDiagObject)。每次调用cmsObj_set时,ODL都会调用该对象的RCL处理程序,它又会进一步调用RUT的实用工具函数。

通过逆向分析,我们发现其工作流程如下所示:    

1、用户提出一个POST请求,与HNAP API进行交互(例如SetTimeSettings)。

2、HNAP API处理程序调用DAL API(例如:cmsDal_setNtpCfgDLink_dev2)。

3、DAL API调用MDM/ODL API(cmsObj_set)来设置MDM对象(例如Dev2TimeDlinkObject)。         例如 cmsObj_set(MDMOID_DEV2_TIME_DLINK, &iidstack, 0, &timeDlinkObj)    

4、ODL API调用RCL处理程序(例如rcl_dev2TimeDlinkObject)。

5、RCL处理程序调用RUT API(例如rut_TZ_Nvram_update)。

如果我们查看上面提到的HNAP和RUT函数,我们会看到:

11.png

经过漫长的旅程,NTPServer参数最终出现在一个传递给system的命令中。

正如我们在上面看到的,用户输入字符串(来自 HNAP)途径许多函数后,最终到达system调用(在RUT中),从而导致命令注入漏洞。如果我手动查看固件,除非我很幸运,否则我几乎要花很长时间才能找到它。然而,在这个工具的帮助下,虽然无法直接实现HNAP到RUT的连接,但至少我能把相关的DAL函数列出来看看,从而节省了我很多时间。

DAL和RCL/RUT之间的关系

在这里,我们进一步考场一下DAL API与RCL/RUT API的关系。其中,cmsDal_setNtpCfgDLink_dev2(如前所述由HNAP API调用的DAL API)的伪代码如下所示:

12.png

上面的代码片段展示了DAL函数设置/更新MDM对象的典型过程。请注意,cmsObj_get是以值为0x416的MDMOID(MDM对象ID)进行调用的。由于没有源代码,我只看到值(0x416),而没有看到枚举名称(MDMOID_DEV2_TIME_DLINK),这些都是从固件中的函数名称和一些字符串推断出来的。

如前所述,当cmsObj_set被调用时,ODL API将调用相应的RCL处理程序,在这种情况下是rcl_dev2TimeDlinkObject。我没有研究cmsObj_set的实现细节,因为它相当复杂——需要执行许多检查和函数调用。如果你有兴趣,可以考察这一行,它将调用RCL处理函数。

获得MDMOID和RCL处理程序之间的映射关系并不困难,因为它存储在固件的OID表中,具体如下所示:

13.png

在这个表中,我们很容易看出0x416是TimeDlink MDM对象的MDMOID,而rcl_dev2TimeDlinkObject是RCL处理程序。在这里,我们也看到了一个叫做STL处理程序的东西,但是它并没有做太多事情。

现在,RCL处理程序rcl_dev2TimeDlinkObject看起来像下面这样:

14.png

我们看到,newMdmObj被传递给易受攻击的函数rut_TZ_Nvram_update(前面讲过)。而这个newMdmObj正是刚才DAL函数传递给cmsObj_set的那个timeDlinkObj。所以,DAL和RCL的关系如下图所示:

15.png

DAL会为cmsObj_set提供一个MDMOID和一个对象,然后    

◼MDMOID决定调用哪个RCL处理程序

◼该对象被交给RCL处理程序进行处理

我们看到,从一个DAL函数中,找出哪个RCL函数被调用并非难事,因为我们不仅有MDMOID,而且还可以参考上面的OID表。但在寻找命令注入漏洞时,步骤就反过来了。

首先,通过这个工具,我找到了可能有漏洞的RCL/RUT函数,source点是函数的参数,sink点是system函数(或其变体)。这里没有什么新东西。但是现在,我需要找到访问相关MDM对象的DAL函数。换句话说,就像上面一样,虽然我知道MDMOID,但这次,我不是找RCL处理程序,而是回答下面的问题:哪些DAL函数用这个MDMOID调用cmsObj_set?

16.png

起初,我使用的是一种笨方法:逐一查看cmsObj_set的交叉引用,直到找到一个被调用的MDMOID正确为止。因为这里的交叉引用太多,足足有200多个,几分钟后,我就放弃了。所以,我决定用这个工具来帮助我过滤出使用某个MDMOID的函数。特别是,我只关心作为字符串/缓冲区的MDM对象字段。如果一个字段保存一个整数值,那么它对于命令注入或缓冲区溢出其实是没有用的。

回顾一下,一个MDM对象的字符串字段是这样设置的:

17.png

所以,我不需要对这个工具做太多的修改,只需把source点设置为cmsObj_get,把sink点设置为cmsMem_free即可。结果,我成功了。对于每个MDMOID,我过滤出了修改相关MDM对象的几个DAL函数。然后,我检查这些DAL函数的交叉引用,看它们是如何被HNAP API调用的,以找出用户输入是如何被传入MDM对象的。 借助于这个工具,工作效率获得了巨大提升,最后,我成功地在这个固件中找到了4个命令注入漏洞。

演示视频

现在是演示时间,演示视频地址见这里

小结

目前,该工具仍处于开发的初级阶段:只能挖掘命令注入漏洞。此外,在分析像DIR-X1560这样复杂的固件时,仍然需要做一些手工工作,因为它不能自动判断出哪些HNAP函数是易受攻击的。我会继续对这个工具进行改进,希望有一天它能协助发现其他类型的漏洞,如固件中的缓冲区溢出、UAF等漏洞。

本文翻译自:https://starlabs.sg/blog/2021/08/identifying-bugs-in-router-firmware-at-scale-with-taint-analysis/如若转载,请注明原文地址
  • 分享至
取消

感谢您的支持,我会继续努力的!

扫码支持

打开微信扫一扫后点击右上角即可分享哟

发表评论

 
本站4hou.com,所使用的字体和图片文字等素材部分来源于原作者或互联网共享平台。如使用任何字体和图片文字有侵犯其版权所有方的,嘶吼将配合联系原作者核实,并做出删除处理。
©2022 北京嘶吼文化传媒有限公司 京ICP备16063439号-1 本站由 提供云计算服务