译者:长长长性
预估稿费:200RMB
投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿
引言
Context的研究团队过去曾经研究过大量现成的家用路由器,发现其安全状况几乎普遍堪忧。然而,来自大型ISP(如BT,Sky和Virgin Media)的旗舰路由器却没有受到路由器各种漏洞的影响。是否这些路由器比其他路由器更加安全?我们决定利用一些公共研究时间,对部分设备一探究竟。
针对办公室的一次调查显示, Virgin Media用户占大多数,所以我们把目标锁定在Super Hub。研究期间(2016年10月),Super Hub(SH)的最新版本是SH2AC(VMDG490)。同时,鉴于SH2(VMDG485)的普及,我们也对SH2进行了测试。本博客详细介绍了漏洞研究的方法和发现,其中包括如何从局域网获得root权限。
漏洞研究方法
根据被评估产品类型的不同,Context的的产品安全评估通常遵循以下几个步骤:
确定可利用的攻击面,包括网络接口,输入设备和USB等外部端口。为了节省时间,我们采取通过管理界面进行命令行注入。
了解设备上运行的软件。这包括任何开源组件、固件(如果提供,尝试从供应商处获取),各种组件的版本号,并检查对应版本号现有的CVE漏洞。
全面分析硬件(如果需要提取固件的话),包括识别调试接口,了解存储设备(例如NAND闪存模块)的类型和规格。
漏洞研究和利用。利用产品开源部分或者固件部分尝试在设备上获得未经授权的代码执行。
我们很快发现,Super Hub已经对Web管理界面进行了安全测试——似乎很好的过滤了输入。这是标准家用路由器一个令人耳目一新的变化。
我们决定对运行的软件进行更详细的分析。由于Super Hub 2和2ac都由Netgear制造,故所有GPL组件的源码均可从该网站获得。
虽然源代码有助于了解Hub上运行的内容,但关于这些设备内部运作的具体信息我们仍然知之较少。因为固件更新过程完全自动化,并且明智地使用了安全通道。这意味着,为了进行分析,我们需要查看硬件才能检索出具有代表性的固件映像。
获取固件映像
使用3.3v USB转串口(实现计算机USB接口到通用串口之间的转换)适配器连接到大多数家用路由器的串行接口非常简单,在这里不再强调。只需要几个UART(通用异步收发传输器)接口:一个用于主要的SoC芯片(System-on-Chip)——基于ARM的Intel Puma V,另一个用于Atheros的无线芯片(AR9344)。
粗略来看,Atheros芯片相当稀疏,我们转向主要的SoC芯片。虽然可以看到U-Boot系统引导的输出,但“取消自动引导”功能已被禁用,这意味着我们无法与引导程序进行交互。
下面的截图显示了初始的u-Boot输出。
这种配置会阻止大多数人继续下去,很明智。但是我们喜欢打破砂锅问到底,所以我们思考如何不花费太多的时间和精力中断引导程序。图1中的输出表明U-Boot正在执行一个引导脚本,这正是我们需要分析的。
第一步是通过读取闪存获取引导程序的副本。棘手的是不能通过软件输入字符串,所以我们启动了热风枪,并拆除了Spansion(S25FL129P)NAND闪存芯片。
从闪存芯片中读取数据的方法有很多种,稍后会在另一篇博客中详细介绍。在本例中,由于作为首选的I2C /SPI(串行外设接口)读写器在另一个办公室,所以我们使用BeagleBone Black和Python来手动驱动芯片的SPI总线,如下图所示。
既然有了一个32MB的映像文件,我们可以看到U-Boot引导程序的所有内容。
Super Hub 2和2ac均使用U-Boot脚本来执行引导过程的第二阶段,初始化并运行Linux内核。通过对映像文件中的U-Boot脚本进行稍微改动,我们可以将内核输出重定向到UART连接,并强制引导程序退出,从而启用U-Boot控制台。一旦修改成功,闪存芯片会被重新焊接到板上。这对Super Hub 2可行。但对于Super Hub 2AC,引导程序在NAND和NOR两个芯片上运行,需要U-Boot控制台额外给第二阶段内存中的部分加载程序打补丁,包括在引导程序执行之前修复几个校验和。
最后,通过U-Boot控制台修改内核命令行参数,以通过串行电缆启用详细的内核引导消息。
识别漏洞
现在我们已经能够通过UART接口访问固件映像和内核调试器的输出,便可以进一步检查服务于Web管理界面的cgi-bin二进制文件。这些二进制文件用来实现用户通过Web界面提交的请求,例如添加防火墙规则或ping IP地址。而这些请求容易受到命令注入的攻击。在对这些Web管理界面进行了相当详细的审查之后,我们证实了之前的猜想:输入已被适当过滤。正当我们想要放弃这一审查方式时,我们看看了备份和还原机制。
备份/还原界面用于获取用户对Super Hub自定义配置设置的副本,例如防火墙或端口转发规则。以便用户稍后将此配置文件重新提交给路由器时恢复设置。在设备需要进行出厂设置时,省去了大量手动重新配置,非常有用。此功能有趣的一点在于它会直接上传攻击者控制的数据(一个恶意的配置文件)到Super Hub进行解析。
为了查看数据格式并构造恶意的配置文件,我们从Super Hub抽取了一个配置文件。导出后,我们发现文件被加密了,并且包含120KB的无结构二进制数据,熵接近于1。随着兴趣被激起,我们决定进一步调查。
负责加密和解密配置文件blob的二进制文件libunihan_utilities.so包含两个函数:des3_encrypt_backup和des3_decrypt_backup。该库根据OpenSSL进行编译,并在进行路由器的收/发时,使用DES_ede3_ofb64_encrypt函数执行blob的三重DES加解密。致命的是,用于此过程的密钥在二进制文件中是硬编码的,这意味着,通过使用密钥和算法的知识,我们能够编写一个小型C语言程序来解密从Super Hub抽取到的配置文件blob。
一旦我们拥有一个解密的配置文件blob,接下来尝试识别文件类型。使用xxd和head提取出该文件的前几个字节,显示备份文件似乎是一个开头附加了未知数据的TAR文件。利用强大的Binwalk工具进一步确认这是一个TAR文件,偏移量为0x4。
对文件VmRgBackupCfgCgi进行逆向后,我们发现该二进制文件负责处理上传到服务器的配置文件,前4个字节是紧随其后的TAR文件的CRC-32校验和。TAR文件似乎是非易失性RAM(或NVRAM)的部分备份。这是嵌入式设备存储配置信息的常用方法。该文件包含敏感信息的各种字段,例如Web管理界面的凭据。稍后我们会对该内容进行更加详细的讨论。
当我们掌握了TAR文件和CRC32校验和后,我们需要制作自己的备份文件,这些文件能被路由器接收和解析。
此时,我们知道如何构建一个有效的配置文件blob并把它交由路由器处理,但实际上我们能做些什么?回溯到VmRgBackupCfgCgi,它告诉我们该文件是如何被处理的,这是我们漏洞的出发点。一旦配置文件有效,运行以下命令将路由器上的/var/tmp/backup_var打包成Tar文件:
tar -xf /var/tmp/backup_var -C /
该命令非常强大。它会以root身份,将我们提交到Super Hub文件系统根目录下的TAR文件进行解压缩,就像是任意文件的写/覆盖操作。虽然该命令的主要作用不在此,但这个功能反而经常被使用。所有被覆盖的配置文件包含在/nvram文件夹下。那么可以覆盖什么呢?乍看之下,我们可以进行任意的文件覆盖,但实际上有一些限制。大部分的Super Hub文件系统被挂载为只读squashFs(一套基于Linux内核使用的压缩只读文件系统)。当Super Hub运行时,只有少数几个有趣的区域是可写的:
/nvram
/var
/tmp (/var/tmp的符号链接)
/etc文件夹下的一些文件 (实际上是/tmp的符号链接)
在文件系统的这些可写部分中,需要找到一个我们可以写/覆盖的文件,让我们进一步访问路由器。幸运的是,在/etc/init.d/we中,我们发现启动脚本rcS是一个不错的选项。
Super Hub路由器使用rcS文件启动重要的服务,如设置内核参数和系统设置。该脚本在每次路由器启动时调用。在脚本的各种功能之中,有一部分吸引了我们的注意:
这一部分检查文件/nvram/0/sys_setup.sh是否存在,如果存在,则执行该文件。但Super Hub的固件中不包含此文件,因此进入“else”子句,执行几个服务启动命令。这部分脚本非常有用。我们对 /nvram 具有写入权限,而且为保证每次启动后的可靠执行,重新启动后也是如此。现在我们可以将任意的文件写入脚本的其余部分(可能来自调试或个人系统定制),以完全控制Super Hub。
为了利用这个缺陷,我们创建一个/nvram/0/的本地目录,并在其中创建sys_setup.sh文件。然后对其进行压缩、CRC32检验、加密,以创建有效的配置文件备份。一旦提交到路由器,它将被解密、验证,然后解压到文件系统的根目录。作为备份/复原过程的一部分,Super Hub的重启会很好的帮助脚本的执行。为了测试我们的理论,我们创建了一个删除防火墙规则的脚本,并编写了一个C程序对其进行打包备份。如下所示上传成功。
等待系统完全启动后,我们重新扫描Super Hub,看看我们对防火墙规则的修改是否具有预期的效果(见下图)。值得一提的是,这是局域网的端口扫描——因为我们实验室没有有线广域网的连接,但telnet守护进程正在监听所有接口。
尝试连接发生了异常。刚建立与Super Hub的连接,在没有任何提示之前连接又被释放。我们转向定制的utelnetd二进制文件来查找原因。
utelnetd是一个小型二进制文件,它实现了telnet协议,并将一个外部TCP流连接到一个内部程序。该内部程序在Super Hub上默认为/bin/sh。Super Hub已经对该默认的开源版本进行了修改,以添加一些新功能。逆向该二进制文件查找接受连接的位置,我们可以看到其中一个修改:
反汇编中的第一个基本块显示Super Hub通过调用库函数accept()接受连接。第二个基本块是代码被修改的地方。基于函数调用(BLX指令)的返回值决定连接是继续还是终止。调用该函数核查某种内部状态,看看是否允许telnet访问。具体检查什么?有什么办法可以从我们的脚本中修改这个设置?
答案存在于从utelnetd导入的共享库中。这个共享库大部分是帮助函数,这些帮助函数获取和设置Super Hub的各种持久参数。进一步的逆向表明,它实现了一个内存中的数据库,在启动时从/nvram目录下的一系列配置文件中读取设置,并不受重启/关机过程的影响。如前所述,/ nvram目录由一系列编号的目录和文件组成,是合法的备份。事实证明,每个文件都是TLV编码。
下图中,我们可以看到一些熟悉的字符串,如我们的管理用户名和密码。
上面的图片显示了其中一个配置文件的部分内容,具体支持ManagementDb(其他文件支持其他方面,例如PortForwardingDb,MacFilteringDb等)。每个文件以28字节的头文件(红色)开始,之后是一系列TLV(Type-length-value类型长度值)编码。在这种情况下,“type”指定记录号(绿色)。 其次是“length”值(绿色),type和length都是2字节。最后是指定字节长度的”value”字节(橙色)。每条记录都记录了Super Hub某一方面详细的配置信息。对/nvram文件夹下各种二进制文件的逆向之后,我们知道第10条记录用来标记telnet访问是否可用。它是一个单字节值,0为禁用telnet,1为启用telnet。
在系统启动时,首先读取配置文件,然后在内存中管理Super Hub的运行时间。如果我们可以在启动nvram服务之前翻转启用telnet的字节(0转为1),那么我们可以为设备启用telnet。可以在恶意脚本中插入以下内容实现这一点:
printf ‘x01’ | /bin/dd of=/nvram/9/5 bs=1 seek=534 count=1 conv=notrunc
它会强制开启telnet访问,删除防火墙后,我们甚至可以在任何接口上连接到telnet服务。最后使用从配置文件中收集到的凭据,我们得到了root shell:
泄露
这些问题一经发现,Context便将其报告给Virgin Media,并提供了Poc。Virgin Media在验证了我们的发现后,与我们合作开发了一套缓解措施,并将其作为现有固件周期补丁的一部分发布出来。感谢Virgin Media与Context在解决这个问题时的专业性和响应能力。
以下是主要事件的时间轴:
2016年10月20日:通过http://virginmedia.com/netreport第一次披露
2016年10月20日:VM的互联网安全小组请求Context提供的更详细的说明
2016年10月24日:Context和Virgin Media召开电话会议,详细讨论。Context给出Poc。
2010年11月-2017年2月:Virgin Media与Netgear和Context合作开发和测试两种设备的补丁
2017年5月:作为定期固件更新的一部分Virgin Media推出补丁