在上一篇文章中,我们了解了物联网的基本概念,并以物联网终端作为切入点,介绍了物联网设备的硬件与固件知识。接下来,笔者将介绍物联网终端设备的固件获取方法、文件系统提取及分析技巧。
想要分析固件内容,必须先获取固件映像文件。获取固件的方法如下:
部分厂商会在自己的官网售后支持区提供固件下载,以便消费者能够手动上传固件更新设备。
当无法通过官网或售后获取固件时,可以通过编程器读取设备Flash或硬盘的方式来获取固件。提取固件前,需准备如下所示提取工具:
我们以D-Link DAP1360调制解调器为例,讲解编程器获取固件的典型步骤:
1. 拆卸物联网终端设备的外包装
在拆卸物联网设备时,首先需要寻找外包装安置的螺丝位置。需要注意的是有部分螺丝位置可能会被垫脚、说明标签隐藏起来,需要仔细寻找,避免暴力拆解。
拆解完全后,DAP1360的PCBA板示图如下。
2. 查找存储芯片
由于这款物联网终端设备的电路架构较为简单,可以清晰的看到右上角的八脚芯片即为设备的存储芯片。在《了解物联网终端》篇章也讲到,物联网终端设备的固件通常就保存在外置的存储芯片中。
注意:当电路上芯片较多,无法确认存储芯片时,可以使用元器件查询网站搜索芯片型号。
3. 安装编程器驱动+编程器烧录工具
使用编程器前需要安装相应的驱动,我们这里使用的编程器芯片为CH341A,则安装CH341A专用的驱动。
编程器烧录工具则无需安装,可以直接使用。
4. 确认芯片型号
在拆卸芯片前,需要先确认存储芯片的型号。由于部分存储芯片规格较小,肉眼无法看清芯片上的型号,需要借助显微镜进行查看。如下图所示,DAP1360的存储芯片型号为25L3206E。
在确认存储芯片型号后,将编程器插入电脑的USB接口上,打开烧录工具。此时,如果编程器驱动安装无误,烧录工具右下角的设备连接状态会显示已连接,反之则表示之前的步骤出现问题,需要回去一一排查。
点击左上角的芯片查找按键,将存储芯片的型号输入进去,并选择对应型号。需要注意的是,这款存储芯片的协议类型为“25 SPI FLASH”。
5. 芯片夹识别
使用芯片夹可以避免拆除物联网终端设备的存储芯片,通常用在设备价格较为昂贵或拆卸存储芯片较为麻烦的情况下。在使用芯片夹获取固件时,存储芯片的电源由PC端提供,无需接通设备电源。
将芯片夹的八个引脚对准存储芯片的八引脚,夹在存储芯片上。由于设备电源由PC端提供,当芯片夹与存储芯片连接正确时,相应的电源灯等指示灯通常会长亮。如果电源灯等指示灯闪烁或亮灭不定,则说明芯片夹没夹好。
当设备的指示灯常亮且稳定时,点击烧录工具左上角的检测按钮,能够正确识别出存储芯片的信息。
初次使用芯片夹时,需要多次尝试才能识别成功,且在读取固件过程中,如果芯片夹没有夹牢固,会出现固件读取中断的情况,缺乏稳定性,这也是芯片夹的缺陷所在。
注意事项:使用芯片夹时设备不能接通电源,否则有烧毁设备或编程器的可能。
6. 拆卸存储芯片
我们将二合一焊台启动,等待热风机器加热,直至预设温度250℃。
我们将热风机器对准存储芯片两侧的引脚焊锡处,并使用镊子夹住存储芯片,直至两侧焊锡熔化,能够轻易用镊子取下存储芯片。
注意事项:热风机器温度较高,防止烫伤;电路板上细小元器件较多,加热存储芯片的焊锡时,注意不要将细小元器件吹掉。
随后我们把存储芯片放入弹座中,并将弹座与编程器连接起来。CH341A编程器支持25SPI与24IIC两种协议,我们的存储芯片为25SPI协议,所以将弹座嵌入到编程器的25SPI区。
7. 提取固件
打开烧录工具,点击左上角的检测按键,可以看到烧录工具能够读出存储芯片的相关信息。如果烧录工具没能正确读出下方四个参数的值,16进制数显示为$FF或$00时,可能是芯片查找处选取的芯片型号不相符或编程器的弹座接错方向了。
(识别成功图)
(识别失败图)
在存储芯片识别成功后,我们点击上方的读取按钮,左下角的进度条会逐渐增加,并显示正在读取中。固件读取完毕后,点击上方的保存按键,选定目录,并将保存的文件命名为xxx.bin,就能获得设备的固件。
当无法通过官网或编程器的方式获取物联网设备固件时,我们通常使用终端设备shell获取固件。常见的获取设备shell的方法有:
在上述获取shell的方法中,uart调试接口的方法相对操作流程更为复杂与全面,我们将以uart调试接口获取shell的方法作为本节主要讲解内容。
《了解物联网终端》讲解了uart的理论知识,现在我们通过实际案例来学习uart调试接口的使用方法。在开始使用uart调试接口前,需要准备一些调试工具:
1.安装串口调试工具
我们这里安装的串口调试工具共有两款。第一款是SSCOM,可以自动识别TTL转USB模组,并提供常见波特率选项,便于测试波特率。第二款是PUTTY,这款工具支持命令行式交互,调试过程更加便捷。
需要注意的是,两款工具只能同时使用一款,否则会显示COM占用警告。
2. 连接uart串口
根据《了解物联网终端》这一章的内容,我们知道uart串口通常由4个引脚(Rx、Tx、Vcc、GND)组成,接下来我们通过万用表找到uart串口上的相应引脚。
我们使用NETGEAR R7000作为演示案例。可以清楚的看到在PCBA板上,有4个已经焊接好的排针,是官方用于调试的uart串口,我们依次将4个排针从左到右排序为1-4。
将终端设备接通电源,并拿出万用表,调至蜂鸣档(红表笔与黑表笔接触会有蜂鸣声)。将黑表笔抵到金属散热片上(接地断路),将红表笔在1-4排针间依次接触,发现2排针发出蜂鸣声,可以判定2排针为GND引脚。
随后使用杜邦线将其余3个排针依次与2排针进行短接,若出现终端设备重启现象,则说明与2排针短接的排针为Vcc引脚。测试过程中发现1排针为Vcc引脚。
将万用表调至直流电压档,将黑表笔接到GND引脚,分别测3、4排针的电压,发现均为3.3V左右。由于终端设备开机时会进行数据传输,Tx引脚电压会频繁变化,此时可以通过重启设备观察两排针电压变化。通过测试判断3排针为Tx引脚,4排针为Rx引脚。
根据《了解物联网终端》一篇介绍的uart引脚与TTL转USB模块接法,PC端接通设备uart串口。通过不停调试波特率,最终确定该终端设备uart串口波特率为115200。
在使用SSCOM确认uart串口的COM口与波特率后,我们按下PUTTY的"Open"按键,在接收完设备的初始化信息后,输入命令"id",确认当前权限为root权限;输入"uname -a"命令,可以看到设备的相关信息。
3.提取固件
终端设备的存储芯片通常挂载在文件系统上,我们通过执行命令“cat /proc/mtd”看到boot、内核、文件系统等挂载的起始地址与字节大小,其中文件系统“rootfs”挂载的位置为mtd3。
图中的proc/mtd文件保存着系统的磁盘分区信息,mtd0分区"boot"保存的是系统启动引导程序;mtd1分区"nvram"保存着系统设置的各种配置数据,诸如管理员账户密码等;mtd2分区"linux"保存着Linux内核程序;mtd3分区rootfs保存着文件系统的数据。其他分区则根据开发者设计使用。
使用dd命令获取设备文件系统镜像:“dd if=/dev/mtd3 of=/tmp/R7000.bin”
在获取文件系统镜像后,如何使用命令将固件外传是一个问题。笔者整理了如下几种常用的固件外传方法:
如果shell支持ftpput命令,首先需要在本机搭建一个ftp服务器,使用命令"ftpput 10.0.0.2 R7000.bin /tmp/R7000.bin"将固件上传到本机的ftp服务器中。测试案例中本机ip为10.0.0.2,物联网终端ip为10.0.0.1。
如果shell支持tftp命令,首先在本机上下载tftp工具,开启tftp服务器。在终端设备的文件系统的/tmp目录下,使用命令"tftp -pl R7000.bin 10.0.0.2"将固件上传到本机的tftp服务器中。测试案例中本机ip为10.0.0.2,物联网终端ip为10.0.0.1。
如果shell支持nc命令,首先在本机终端shell上执行命令"nc -lp 1234 >R7000.bin",随后在物联网设备shell终端上执行命令"nc 10.0.0.6 1234 <R7000.bin"。测试案例中,本机ip为10.0.0.6,物联网终端ip为10.0.0.1。
如果shell支持mount、df命令,首先使用"df -h"命令查看根目录挂载名称为"ubi:rootfs_ubifs"。
常见的/www目录一般为只读权限,需要使用命令"mount -o remount,rw ubi:rootfs_ubifs"重置文件系统的读写权限。随后将/tmp目录下的AX88U.bin文件覆盖了/www目录下能够直接访问的前端页面。由于文件系统内存容量不够,所以提示空间不足。
测试终端所覆盖的页面为/blocking.asp。通过访问设备前端页面,最终将固件下载到本机。
在《了解物联网终端》下篇中,我们介绍了固件的组成部分,其中最重要的部分之一就是文件系统。所以在这一节中我们介绍文件系统提取的常用方法。
物联网终端设备常用的内核主要是Linux与Vxworks,接下来主要介绍这两种系统的文件系统提取方法。
Linux文件系统手动提取
在介绍提取方法前,我们先介绍linux系统中常用于二进制程序分析的系统命令:
系统命令 | 作用 | 选项 |
file | 用于文件类型识别 | -L:查看链接文件 |
grep | 用于查找文件里符合条件的字符串 | -i:忽视大小写 -s:不显示错误信息 -a:不忽略二进制数据 |
hexdump | 将二进制文件转换为ASCII、八进制、十进制、十六进制格式进行查看 | -C:输出规范的十六进制和ASCII码 -n length:格式化输出文件的前length个字节 -s:从偏移量开始输出 |
strings | 在对象文件或二进制文件中查找可打印的字符串 | -n:显示的最少字符数 -a:扫描整个文件 |
dd | 从标准输入或文件中读取数据,根据指定的格式来转换数据,再输出到文件、设备或标准输出 | if=文件名:指定输入文件 of=文件名:指定输出文件 bs=bytes:设置输入/输出块大小为bytes字节 skip=blocks:从输入文件开头跳过blocks个块后再开始复制 |
我们将NETGEAR R7000的V1.0.11.126版本固件作为本节的演示案例。首先使用strings命令查看固件所包含的字符串。
在《了解物联网固件》的下篇里,我们介绍了常见的物联网终端设备的文件系统有SquashFS、JFFS2、YAFFS2等。这些文件系统通常会在映像保存有头部特征字符串:
标准固件大端序模式为sqsh,标准固件小端序模式为hsqs,LZMA压缩下的大端序模式为sqlz,3.3版本的Squashfs文件系统在LZMA压缩下的大端序模式为qshs,部分非标准固件小端序模式为shsq,DD-WRT固件小端序模式为hsqt,DD-WRT固件大端序模式为tqsh[1]。
JFFS2文件系统通常使用"0x1985"作为头部特征标识符。
Cramfs文件系统头部特征字符为"0x28cd3d45"
使用hexdump命令检索上述文件系统的头部特征标识符,首先测试终端设备最常用的SquashFS文件系统。使用命令"hexdump -C R7000-V1.0.11.126_10.2.112.chk |grep "hsqs""。
根据检索结果可以确定测试固件为SquashFS小端序文件系统,文件系统的起始地址为0x21E636。
使用dd命令将SquashFS文件系统映像从测试固件中提取出来,完整命令为"dd if=R7000-V1.0.11.126_10.2.112.chk bs=1 skip=2221622 of=squashfs"。if指定输入文件,of指定输出文件,bs=1指输入输出数据块的单位大小为1字节 ,skip=2221622是指跳过2221622大小(十六进制为0x21E636)的字节,也可以理解为指定提取的起始地址。
接下来,使用file命令查看一下提取到的文件系统的文件类型。从下图可以看到,一些文件系统的基础信息都能识别出来。
由于SquashFS文件系统是一种只读压缩文件系统,需要使用unsquashfs等开源工具从中提取数据。
解压后的文件系统映像中的文件结构与PC端Linux文件系统基本一致。
Linux文件系统自动提取
binwalk工具集成了多种bootloader、Linux内核、文件系统等固件映像中包含文件的magic签名,能够自动识别这些文件映像并将其信息、数据进行解压提取。除了提取文件的功能,binwalk还支持如系统架构识别"-A"、计算文件熵"-E"等诸多功能。具体可以参考https://github.com/ReFirmLabs/binwalk。
我们使用binwalk对测试固件进行解析。如下图所示,binwalk将测试固件的大小端序、内核架构、文件系统类型等信息都解析出来。
使用命令"binwalk -Me R7000-V1.0.11.126_10.2.112.chk",以递归扫描的方式检索固件映像并自动提取可识别的文件。最终binwalk提取出的文件系统与手动提取的文件系统内容一致。
除了binwalk工具,如针对ubifs文件系统映像,我们还可以使用ubi_reader工具提取其文件系统。
对于yaffs文件系统映像,可以使用unyaffs工具提取其文件系统。
Vxworks文件系统提取
VxWorks是美国WindRiverSystem公司(风河公司)推出的一个RTOS(实时操作系统)。VxWorks系统凭借其优秀的实时性占据着不小的市场份额,包括NASA的火星探测器、波音787客机、网络路由器等,市场范围跨越各种安全领域。本次测试案例使用的是TP-LINKWDR7660路由器的固件。与Linux内核的固件不同,Vxworks固件无法通过binwalk进行解析,需要我们通过手动分析才能获取其文件系统。
先使用binwalk对固件进行分析,发现在0x10400-0x15B440的地址处有一块很大的LZMA压缩文件,通常文件系统文件块最大。使用dd将这块文件读取出来。使用"lzma -d"命令对文件进行解压,显示解压失败,将固件放入ghex中进行分析。
通过ghex分析,在0x15B440地址之前均为FF的十六进制,所以0x15B440并不是LZMA文件的结尾,向上查询数据,最终发现LZMA压缩文件的结尾在0x15A477。重新用dd将压缩文件提取出来,通过解压获得Vxworks的文件系统。
除了上述的文件系统提取情况外,还有部分固件会进行各种各样的加密,有固件整体加密与部分加密等,目的是保护固件的各个模块不被轻易破解提取。由于本章篇幅有限,在下一篇中,我们会向笔者介绍固件解密常用的方法与案例。
经过从固件获取到最终文件系统提取一系列操作,我们终于获取物联网终端设备的文件系统。接下来我们分析一下物联网终端设备的文件系统。
Linux文件系统目录
在测试固件的文件系统根目录"/"下,包含许多不同的目录,如下图所示。
目录 | 作用 |
/bin | bin(binary)目录保存着系统里基础的二进制可执行文件,诸如常见的"cd"、"ls"等都保存在bin目录中 |
/dev | 由于Linux系统继承了Unix系统的特性,Linux系统将一切资源都看作为文件,即使是外部硬件设备的访问端口都以文件的形式保存在文件系统中,也就是/dev(device)目录中,用户可以通过对这些文件的读写实现对硬件设备的访问。 |
/lib | /lib(library)目录保存着系统所需要的库文件。 |
/mnt | /mnt(mount)目录用于存储用户手动挂载的存储设备或分区目录。当有设备被系统识别时,访问设备的端口会以文件的形式保存在/dev目录下,如果设备存储的文件系统类型能够Linux识别出来,则设备存储的文件系统能够通过/dev目录直接访问。但是当Linux系统识别不出设备存储的文件系统类型时,则需要用户指定文件系统格式挂载(mount)在/mnt目录下,用户才能访问设备存储的文件信息与内容。 |
/proc | /proc(process)目录是proc文件系统的挂载目录。proc文件系统与常见的文件系统不同,proc是一种虚拟文件系统。/proc存储的文件是当前Linux内核运行状态下一系列特殊文件,这些文件保存着系统相关硬件的信息以及正在运行的进程信息,通过更改其中某些文件的内容甚至能够改变内核运行的状态。/proc所存储的文件不占ROM的存储空间,这些文件存储在运行内存RAM当中,所以也被称为虚拟文件。 |
/share | /share目录是共享文件夹,用户可以将想共享的文件存储在/share目录下,通过局域网或广域网进行分享。 |
/tmp | /tmp(temporary)目录存储着临时文件。在许多只读文件系统中,/tmp目录是少数挂载到根目录且用户能够与之进行实际交互的目录。 |
/var | /var(variable)目录用于存储系统运行时要改变数据的目录,如/var/log(记录系统日志数据)、/var/lock(记录系统资源上锁情况)、/var/run(记录已登录的用户数据)等目录。 |
/data | /data目录存储着系统使用的一些数据文件。 |
/etc | /etc(etcetera)目录保存着系统软硬件的配置信息文件。如系统初始化时所执行的bash文件/etc/rc、/etc/rc.d、/etc/rc*.d;系统用户的用户名、密码文件/etc/passwd、/etc/shadow;物联网终端设备的固件版本信息/etc/version等。 |
/media | /media目录同样保存着挂载目录,但不同于/mnt目录的用户手动挂载,/media目录保存的是由系统自动建立的载点。 |
/opt | /opt(option)目录用来存放附加软件安装包,是用户级的程序目录。 |
/sbin | /sbin(superuser binary)目录存储的是root用户使用的二进制可执行文件。 |
/sys | 与proc文件系统类似,sys也是一种虚拟文件系统。sys文件系统向用户提供了访问内核空间的入口,通过访问sys文件系统的挂载点/sys下的虚拟文件,用户能够获取系统的各种内核信息。 |
/usr | /usr(Unix Software Resource)目录存储着Unix操作系统软件资源。当系统安装软件时,都会将/usr、目录作为默认安装目录。/usr/bin目录通常保存着大部分用户使用的命令;/usr/include目录存储着c/c++程序的头文件;/usr/lib目录存储着/usr/bin、/usr/sbin中二进制可执行文件的动态库文件;/usr/local存储着系统管理员自行安装的软件;/usr/sbin存储着非系统正常运行时所需的系统指令,常见的网络服务器软件telnetd、dropbear等;/usr/share与/share一致,存储共享文件。 |
/www | /www目录通常存放着终端设备的web页面文件、web程序、web数据等。在分析终端设备web端口的信息泄露、未授权等漏洞可以重点关注/www目录。 |
Linux文件系统分析思路
在Linux文件系统中,可能存在安全问题的情况如下:
安全风险 | 分析思路 |
配置安全风险 | 在文件系统中,常见的配置文件格式为*.conf、*.cfg、*.ini等 |
敏感信息泄露 | 常见的敏感信息包括用户的账号与密码、用户的个人信息等,常见的文件格式有passwd、shadow、*.psk等 |
密钥安全 | 常见的密钥或证书文件格式有*.crt、*.pem、*.cer、*.p7b、*.p12、*.key等 |
源代码安全 | 常见的源代码格式有*.c、*.h、*.py、*.lua |
数据库安全 | 常见的数据库文件有*.db、*.sqlite、*.sqlite3等 |
开源组件安全风险 | 开源组件中漏洞数量较多的文件有busybox、openssl、hostapd |
闭源组件安全风险 | 闭源组件可以重点关注web组件apache、lighttpd、mini_httpd、httpd、goahead、boa,以及upnp组件等 |
除了人工手动对上述安全风险较高的文件进行分析,还可以使用一些常用的文件系统分析工具如Firmwalker等。
Firmwalker是一款由bash程序编写的分析工具,其涵盖了许多敏感信息、危险组件的字符串特征,能够快速扫描文件系统与定位文件系统中安全风险较高的文件。
下图是Firmwalker整体bash程序的思维导图。Firmwalker会将敏感信息、危险文件的特征字符串存储在数据库中,如常见passfile文件、配置文件、密钥文件、数据库文件、源代码文件、危险组件的文件名称等特征,并在进行文件系统扫描时将扫描结果与特征字符串对应匹配。
使用Firmwalker扫描一下测试固件的文件系统,可以看到扫描出一些重要的敏感文件。
Vxworks文件系统分析
在2.1节中,我们成功从WDR7660固件中提取出文件系统,接下来继续分析Vxworks的文件系统。
Vxworks文件系统是一个整体的elf文件,需要分析其加载地址才能将二进制程序中的函数正确解析。分析Vxworks文件系统的加载地址需要用到反汇编工具,目前主流的反汇编工具有IDA与ghidra等。
使用命令"binwalk -A xxx"分析文件系统的架构为ARM,通过2.1节中binwalk分析结果可以知道文件系统为小端序。
由于VxWorks系统的加载基址与栈初始化地址相同,根据VxWorks官方给出的说明,其采用usrInit进行栈初始化,而usrInit是VxWorks系统引导后运行的第一个函数,找sp寄存器首次出现的位置,就是VxWorks系统的加载基址。
将VxWorks系统文件放入IDA中,设置处理器类型为ARM小端序,加载地址随机设为0x1000,文件加载完毕后在第一行DCB汇编处按下"P"键手动让IDA分析汇编。
在第一个SP寄存器上汇编出现的第一个地址0x40205000即为文件系统加载地址。
在确定Vxworks文件系统的加载基址后,还需要恢复文件系统的函数名称以便后续逆向分析时能够快速寻找漏洞。bzero是VxWorks中一个函数,系统启动过程中会使用bzero函数对bss区的数据进行清零。
首先使用grep命令搜索文件系统elf文件中的bzero字符,发现elf文件中并没有这个字符串,说明符号表与文件系统是分离的。使用"binwalk -e"命令解压WDR7660固件,对解压后的文件使用"grep -r bzero"命令搜索符号表,匹配到二进制文件15CBBA。
使用ghex工具对15CBBA文件进行分析,确定符号表的起始地址为0x1A728。
根据观察,在0x8地址处,出现了以8字节为单位的规范数据。经过分析,第一个字节54为flag,第二到第四个字节为在符号表中的偏移量,后四个字节为符号对应文件系统中函数的地址。如第一个函数为AES_CMAC在文件系统中的地址为0x40373684,通过字符串等信息可以确认这种分析是正确的。
完成符号表恢复后,后续的分析工作就基于基于逆向分析展开,我们将会在后续的章节中为读者介绍逆向分析的各种方法与技巧。
本期《玩转物联网固件》的上篇固件获取方法、文件系统提取及分析技巧的学习到这里就结束了,下一期我们将会为读者继续介绍固件仿真、固件打包相关内容,敬请期待!
参考文献:
[1] (美)亚伦·古兹曼,(美)阿迪蒂亚·古普塔著.物联网渗透测试.北京:机械工业出版社,2019.05.
[2] http://blog.nsfocus.net/tp-link-wdr/
[3] https://linux.cn/article-9798-1.html
[4] https://elinux.org/File_Systems