IoT漏洞研究(一)固件基础

FreeBuf FreeBuf

跟着5G时代的到来,物联网饰演的脚色也越来越主要,同时也陪伴更多的平安风险。IOT平安涉及内容普遍,本系列文章将从手艺层面谈一谈笔者对IOT破绽研究的懂得。笔者将从固件、web、硬件、IOT和谈、移动应用五个维度离别商量,因为水平能力有限,欠妥或漏掉之处迎接人人斧正增补。

[原文来自:www.tt44.com]

IoT固件根蒂

之所以将固件作为第一个商量的主题,因为对照根蒂,IOT破绽研究一样无法绕过。以下将介绍固件解密(若加密)、解包打包、模拟和从固件整体上作平安评估四部门。 [好文分享:www.tt44.com]

1.1 固件解密

有些IOT设备会对固件加密甚至签名来提高研究门槛和升级时的平安性,因为加解密对照花消资源,这类设备一样设置会对照高,好比一些路由器和防火墙。

1.1.1 固件加密判断

判断固件是否加密对照简洁,有经验的小伙伴有二进制编纂器打开就能看出一二,一样会存在以下特征。

除了固件指示头没有可见字符,(除去header)数据按比特睁开01频率根基一致
binwalk(-e)无法解析固件构造,且(-A)没有识别出任何cpu架构指令

若是知足上述特点,就会猜测固件已被加密,固件解密一样会从这几个角度,但也不局限于下面的方式。

1.1.2 硬件获取密钥

此种方式只限于固件始终以加密状况存在,当系统启动时才经由解密解包加载至flash,且设备缺乏(UART/JTAG等)动态调试手段。因为flash中有完整的解密过程,能够经由编程器读取flash,逆向解密算法和密钥,达到解密固件的目的。好比从某设备的读取的flash内存分布如下:

0x000000-0x020000 boot section
0x020000-0x070000 encrypt section
0x070000-0x200000 encrypt section
0x200000-0x400000 config section

显然我们需要的加密过程在boot section中,我们需要从中找到加密算法和密钥,一样加密都采用AES等公开分组算法,要害是找到分组模式,IV(非ECB)和密钥。将boot加载到IDA pro中,并没有主动识别:
能够经由对比ARM代码最起头部门的休止向量表构造手动识别,常见的进口代码如下所示。

.globl _start
_start:
b reset
ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq
...
_irq:
.word irq

之后能够就能够逆向获得加密算法为AES,密钥经由设备序列号的sha256哈希获得。
经由IDA pro识别此类构造将在后文介绍RTOS时商量,行使这种固件加密体式的设备平安级别教高,一样设备只在升级时进行解密验证。

1.1.3 调试直接读取

这个方式最轻易懂得,即在设备启动后行使UART、JTAG、Console或收集等手段把固件(打包)回传,如许就绕过认识密环节。值得注重的是需要设备供应这些接口,具体方式因设备分歧而异,这些接口的使用将会在硬件篇里作介绍。

1.1.4 对比界限版本

此种方式适用于厂商一起头没采用加密方案,即旧版固件未加密,在某次升级中添加认识密法式,随后升级使用加密固件。如许我们就能够从一系列固件中找到加密和未加密之间的界限版本,解包最后一个未加密版本逆向升级法式即可还原加密过程。
经由下载上图所示某路由器固件,解包后经由搜刮包含诸如“firmware”、“upgrade”、“update”、“download”等要害字的组合定位升级法式位置。当然存在调试手段也能够在升级时ps查察历程更新定位升级法式和参数:

/usr/sbin/encimg -d -i <fw_path> -s <image_sign>

经由IDA pro逆向encimg法式很快获得加解密过程代码,采用了AES CBC模式:

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
)

1.1.5 逆向升级法式

此种方式适用于已经经由接口或界限版本获得升级法式,能够行使分组算法的盒检测对象来判别加密算法和定位位置,当然binwalk也能够解析某些简洁情形,好比某工控HMI固件:

iot@attifyos ~/Documents> binwalk hmis.tar.gz
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
34 0x22 OpenSSL encyption, salted, salt:0x5879382A7

直接加载升级法式,定位openssl挪用很轻易就获得解密号令:

1.1.6 破绽获取密钥

若是找不到界限版本,又找不到调试接口或不熟悉硬件调试,能够考虑采用汗青版本破绽先获取设备掌握权,在拿到升级法式逆向加密算法。这种方式对照取巧,需要设备存在RCE破绽的汗青固件,经由降级把持植入破绽获取权限,下载所需升级法式,然后逆向获得加密算法。

1.2 固件解包

初入IOT平安研究的小伙伴会感觉固件解包很简洁,直接binwalk -Me就能够了,然则幻想很丰满,实际很骨感,固件测试多了就会发现binwalk好多情形下都解不开。
IOT固件一样分为两类,一类存在文件系统,大多基于linux/BSD,另一类固件是一个整体,即我们所说的RTOS(Real-time operating system)。

1.2.1 存在文件系统

binwalk人人应该都很熟悉,使用binwalk能直接获得rootfs文件系统的情形这里不再赘述,笔者认为binwalk的壮大之处在于能够解析识别多重花样的header,为解包供应参考。以下介绍几种需要绕点弯的情形,当然固件千差万别,全看设计者设计,不克一一列举。

1.2.1.1 UBI(Unsorted Block Image)

UBI花样的固件算对照常见的,binwalk并不克直接解包,然则网上有现成的对象ubi_reader,这里有个需要注重的处所:

UBI_reader解包,UBI文件必需是1024bytes的整数倍,需要增删内容对其

好比经由剖析某路由器,发现其rootfs是UBI花样:

# binwalk ROM/wifi_firmware_c91ea_1.0.50.bin
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
684 0x2AC UBI erase count header, version: 1, EC: 0x0, VID header offset: 0x800, data offset: 0x1000

首先安装ubi_reader:

$ sudo apt-get install liblzo2-dev
$ sudo pip install python-lzo
$ git clone https://github.com/jrspruitt/ubi_reader
$ cd ubi_reader
$ sudo python setup.py install

或许直接

$ sudo pip install ubi_reader

然后将凭据地址将UBI构造提掏出来,行使ubireader_extract_files [options] path/to/file即可解包。

1.2.1.2 PFS

有些固件binwalk能够识别出header,然则无法解开,好比下面这个固件

iot@attifyos ~/Documents> binwalk -Me v2912_389.all

Scan Time: 2020-11-04 18:39:13
Target File: /home/iot/Documents/v2912_389.all
MD5 Checksum: 180c60197aae7e272191695e906c941e
Signatures: 396

DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
1546799 0x179A2F gzip compressed data, last modified: 2042-04-26 20:13:56 (bogus date)
1717744 0x1A35F0 LZ4 compressed data
4171513 0x3FA6F9 SHA256 hash constants, little endian
4179098 0x3FC59A Copyright string: "Copyright (c) 1998-2000 by XXXXX Corp."
4214532 0x404F04 Base64 standard index table
4224780 0x40770C HTML document header
4232369 0x4094B1 SHA256 hash constants, little endian
4307839 0x41BB7F SHA256 hash constants, little endian
4314017 0x41D3A1 XML document, version: "1.0"
4702230 0x47C016 Base64 standard index table
4707197 0x47D37D Certificate in DER format (x509 v3), header length: 4, sequence length: 873
4727609 0x482339 Base64 standard index table
4791281 0x491BF1 PFS filesystem, version 1.0, 12886 files
4807401 0x495AE9 Base64 standard index table
...
iot@attifyos ~/Documents> ls _v2912_389.all.extracted/pfs-root/000/
WEBLOGIN.HTM _WEBLOGIN.HTM.extracted/
iot@attifyos ~/Documents> ls _v2912_389.all.extracted/pfs-root/000/_WEBLOGIN.HTM.extracted/
3CB 3CB.zlib E235 E235.zlib

运行binwalk后查察究竟,发现没有发现任何可识其余器材,此时能够手动剖析或许去搜刮一些相关对象。
在网上找到相关对象,直接凭据提醒使用号令就可解开固件。

iot@attifyos ~/D/draytools> python draytools.py -F v2910_61252.all 
v2910_61252.all.out written, 12816484 [0x00C39064] bytes
FS extracted to [/home/iot/Documents/draytools/fs_out], 429 files extracted
iot@attifyos ~/D/draytools> ls fs_out/
v2000/ v2910.lst
iot@attifyos ~/D/draytools> ls fs_out/v2000/
act_sta.htm CSS/ header.htm INDEX2.HTM ivr_711u/ jg/ l_m.htm menu.htm STATUS.HTM SYSINFO_C.TXT UPNP/ webauth.htm
CGI-BIN/ DOC/ IMAGES/ ivr_711a/ ivr_729/ JS/ LOGIN.HTM rpage.htm STYLE.CSS SYSINFO.TXT VLAN/

这里简洁看一下固件解包要害代码,要害在于找到雷同’\xA5\xA5\xA5\x5A\xA5\x5A’的header,之后凭据具体花样解包解压即可,所以固件解包说究竟照样数据花样剖析。

def decompress_firmware(data):
flen = len(data)
sigstart = data.find('\xA5\xA5\xA5\x5A\xA5\x5A')
if sigstart <= 0:
sigstart = data.find('\x5A\x5A\xA5\x5A\xA5\x5A')
if sigstart > 0:
if draytools.verbose:
print 'Signature found at [0x%08X]' % sigstart
lzosizestart = sigstart + 6
lzostart = lzosizestart + 4
lzosize = unpack('>L', data[lzosizestart:lzostart])[0]
return data[0x100:sigstart+2] \
+ pydelzo.decompress('\xF0' + pack(">L",0x1000000) \
+ data[lzostart:lzostart+lzosize])
...

1.2.1.3 Openwrt Lua

lua构造解析放在解包这里或者不太得当,但鉴于Openwrt的使用基数很大,在这里简洁提一下。Lua是一门轻易嵌入并可扩展的轻量级剧本说话,Openwrt斥地中会使用该剧本说话。值得注重的是,有些设备的lua并不是纯文本,存在搅浑,需要使用luadec反编译。
openwrt中的lua剧本和传统的luajit编译后的有点纷歧样,需要打几个补丁才能正常使用luadec进行反编译,号令如下:

$ cd ..
$ mkdir luadec
$ cd luadec/
$ git clone https://github.com/viruscamp/luadec
$ cd luadec/
$ git submodule update --init lua-5.1
$ cd lua-5.1
$ make linux
$ make clean
$ mkdir patch
$ cd patch/
$ get https://dev.openwrt.org/export/HEAD/trunk/package/utils/lua/patches/010-lua-5.1.3-lnum-full-260308.patch
$ wget https://dev.openwrt.org/export/HEAD/trunk/package/utils/lua/patches/030-archindependent-bytecode.patch
$ wget https://dev.openwrt.org/export/HEAD/trunk/package/utils/lua/patches/011-lnum-use-double.patch
$ wget https://dev.openwrt.org/export/HEAD/trunk/package/utils/lua/patches/015-lnum-ppc-compat.patch
$ wget https://dev.openwrt.org/export/HEAD/trunk/package/utils/lua/patches/020-shared_liblua.patch
$ wget https://dev.openwrt.org/export/HEAD/trunk/package/utils/lua/patches/040-use-symbolic-functions.patch
$ wget https://dev.openwrt.org/export/HEAD/trunk/package/utils/lua/patches/050-honor-cflags.patch
$ wget https://dev.openwrt.org/export/HEAD/trunk/package/utils/lua/patches/100-no_readline.patch
$ wget https://dev.openwrt.org/export/HEAD/trunk/package/utils/lua/patches/200-lua-path.patch
$ wget https://dev.openwrt.org/export/HEAD/trunk/package/utils/lua/patches/300-opcode_performance.patch
$ mv patch/ patches
$ for i in ../patches/*.patch; do patch -p1 <$i ; done
$ for i in ./patches/*.patch; do patch -p1 <$i ; done
$ make linux

点窜 lua-5.1/src/MakeFile:

# USE_READLINE=1
+PKG_VERSION = 5.1.5
-CFLAGS= -O2 -Wall $(MYCFLAGS)
+CFLAGS= -fPIC -O2 -Wall $(MYCFLAGS)
- $(CC) -o $@ -L. -llua $(MYLDFLAGS) $(LUA_O) $(LIBS)
+ $(CC) -o $@ $(LUA_O) $(MYLDFLAGS) -L. -llua $(LIBS)
- $(CC) -o $@ -L. -llua $(MYLDFLAGS) $(LUAC_O) $(LIBS)
+ $(CC) -o $@ $(LUAC_O) $(MYLDFLAGS) -L. -llua $(LIBS)

接着执行:

$ make linux
$ ldconfig
$ cd ../luadec
$ make LUAVER=5.1
$ sudo cp luadec /usr/local/bin/

行使luadec显露代码构造:

$ luadec -pn squashfs-root/usr/lib/lua/luci/sgi/uhttpd.lua
0
0_0
0_0_0
0_0_1
0_0_2

行使luadec反编译指定的函数 (函数 0 包含 子函数):

$ luadec -f 0 squashfs-root/usr/lib/lua/luci/sgi/uhttpd.lua

需要注重的是,luadec编译与架构相关,用官方luadec无法解析arm情况下的lua文件,但网上也有响应的对象,这里不再赘述。

1.2.2 RTOS

好多IOT设备都采用RTOS(实时把持系统)架构,固件自己就是一个可执行文件,不存在文件系统,启动后直接加在运行。对RTOS的剖析最主要就是两点:

(一) 固件法式进口
(二) 固件法式符号

1.2.2.1 vxworks

首先从应用较广且有套路可循的vxworks说起,VxWorks是Wind River System公司推出的一个实时把持系统,普遍应用在通信、军事、航空、航天嵌入式设备范畴。因为有尺度,所以好识别,以下面这个固件为例:

iot@attifyos ~/Documents> binwalk image_vx5.bin

DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
335280 0x51DB0 PEM certificate
...
3721556 0x38C954 GIF image data, version "89a", 10 x 210
8518936 0x81FD18 VxWorks operating system version "5.5.1" , compiled: "Mar 5 2015, 15:56:18"
9736988 0x94931C SHA256 hash constants, little endian
...
13374599 0xCC1487 Copyright string: "Copyright 1999-2001 Wind River Systems."
13387388 0xCC567C VxWorks symbol table, big endian, first entry: [type: function, code address: 0xF4A09A00, symbol address: 0xF813C800]
13391405 0xCC562D VxWorks symbol table, little endian, first entry: [type: function, code address: 0xB8BD, symbol address: 0xD000C800]

binwalk已经识别出固件为Vxworks 5.5.1,而且给出了符号表位置。首先需要识别固件的进口点,若是固件被封装成ELF花样,直接行使readelf就能够获得基地址,这里显然不适用。

iot@attifyos ~/Documents> readelf -a image_vx5_arm_little_eniadn.bin 
readelf: Error: Not an ELF file - it has the wrong magic bytes at the start
iot@attifyos ~/Documents> binwalk -A image_vx5.bin |more

DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
244 0xF4 ARM instructions, function prologue
408 0x198 ARM instructions, function prologue
440 0x1B8 ARM instructions, function prologue
472 0x1D8 ARM instructions, function prologue
608 0x260 ARM instructions, function prologue

经由binwalk -A获得固件架构是ARM,直接用IDA pro载入:

剖析固件开首跳转判断加载地址为0x1000。对于Vxworks一样判断基址法子有:

剖析固件头部的初始化代码,找到vxworks启动的第一个函数usrInit跳
凭据BSS区初始化特征找到BSS界限,凭据偏移较量固件加载地址

然后凭据binwalk指示的位置,修复符号表名。
函数表存放了函数名和函数地址,经由两者定位也能够反过来验证基地址的准确性,好比上图所示的0x00c813f8是函数名:
0x009aa0f4是函数地址:
因为基地址和架构有关,在这里就不具体睁开,对于vxworks的剖析我们能够借助一款能主动化修复进口和符号的插件—vxhunter。
以Ghidra为例,载入固件后直接选择vxhunter_firmware_init.py插件和vxworks版本,就能够主动修复进口和符号:
1.2.2.2 U-boot

boot类的固件也是我们常会碰见的一类无文件系统固件,好比好多IOT设备会采用U-boot作指导,因为U-boot开源,我们能够参照源代码剖析,对于有些架构的U-boot也能够采用固定套路,好比mips能够凭据$gp寄放器等。

1.2.2.3 Chip firmware

有些IOT固件没有资料,逆向难题,好比下面某款ARM芯片的固件,将其载入IDA pro发现没有识别出任何函数:
如许我们就需要对固件有一个整体的剖析了,我们看到固件0x100的位置十分有趣:
4字节分列后都以0x2开首,这里既不是代码,也不是数据,那就很或者是地址了,这里应该是一张表,所以基地址很或者是0x200000。我们rebase之后再查察字符串:
看到很多雷同函数名的字符串,找到具体位置后,在固件中二进制搜刮0x16852A,即wlc_probresp_attach地址(小端)。
能够看到真的搜刮到了,并且也是一个表的构造:
凭据基址找到在IDA pro中的位置:
能够看到完成了部门的交叉引用,后续剖析对照复杂,这里就不再睁开,实际上0x100位置是函数地址表,在该固件中如许表有好多。所以雷同地址表,字符串都是我们剖析固件基址和函数的主要线索。

1.3 固件打包

拆器材轻易装器材难,这个事理也适用于固件打包。若是设备留有调试接口,一样不消打包把持,究竟平安研究是以逆向脑筋为主。
有时缺乏调试手段,我们就要在解开的固件中手动添加。一样将交叉编译好的telnetd,dropbear(sshd),gdb放入固件文件,再替代启动剧本打包。
linux的启动剧本套路浩瀚,尤其在IOT设备中,这里笔者一样采用对照讨巧的方式,好比确定/sbin/xxxd办事会开机运行,能够将其替代:

# mv rootfs/sbin/xxxd sbin/xxxdd
# touch rootfs/sbin/xxxd
# chmod +x rootfs/sbin/xxxd

之后在sbin/xxxd添加

#!/bin/sh

/usr/sbin/telnetd -F -l /bin/sh -p 1234 &
/sbin/xxxdd &

如许开机启动xxxd时就会先运行telnetd。

1.3.1 交叉编译

若是能从正向斥地角度来打包当然最轻易,也就是交叉编译的事。笔者研究过的一些设备中,首要是路由器固件会部门遵循GPL,就是开源一部门代码软件(一样正本就是基于开源对象),并供应剩下软件的二进制文件和整个固件的打包对象(方式)。
好比之前研究的某款路由设备就供应了开源下载:
下载该zip包,凭据本身的需求编译rootfs,最后行使zip包中自带的对象打包:

./packet -k %s -f rootfs -b compatible_r6400.txt 
-ok kernel -oall image -or rootfs -i ambitCfg.h

1.3.2 firmware-mod-kit

firmware-mod-kit(fmk)或者是最常用的基于binwalk的解打包对象,然则因为良久没用更新,使用场景有限。
fmk的安装使用都对照简洁,如下所示:

# For ubuntu
$ sudo apt-get install git build-essential zlib1g-dev liblzma-dev python-magic bsdmainutils autoconf
# For redhat/centos
$ yum groupinstall "Development Tools"
$ yum install git zlib1g-dev xz-devel python-magic zlib-devel util-linux
# 使用
$ ./extract-firmware.sh firmware.bin //解包
$ cp new-telnetd fmk/rootfs/usr/sbin/telnetd //按需点窜
$ ./build-firmware.sh //打包

1.3.3 手动剖析

打包的难度在于固件要与原固件一致,并经由各类校验,不然轻则刷机失败,重则设备变砖。笔者之前有一篇关于netgear upnp破绽的文章,涉及netgear固件打包过程,有乐趣的小伙伴能够看一看。
固件一样会分成很多section,为了轻易解析,每个section会有指示头,头中或者会存放标记、巨细和crc校验等信息,这些信息都为解打包供应依据。
好比能够先获取固件巨细(十六进制),凭据固件巨细端拆分字节,一样是4字节,然后在固件头上寻找雷同字节(固件头上的指示长度会减去头长度),接着从指示巨细的字节往后剖析就能够澄清花样,和剖析收集和谈的过程很像。
当然大部门头都是有尺度的,能够凭据尺度花样一一对应。值得注重的是,有些厂商会给固件签名,这个就会增加打包的难度。此时我们能够寻找一些遵循GPL的官方打包对象,或许行使openssl生成公私钥对,笼盖设备中的验证公钥,这里当然要有破绽,否则就掉进鸡生蛋蛋生鸡的轮回。当然还有一个对照好且廉价的法子—-固件模拟。

1.4 固件模拟

固件模拟凭据分歧需要或者有以下3个场景:

(一) 只需模拟某个应用,好比web、upnpd、dnsmasq等,目的是对该应用作调试。此时能够直接用模拟对象运行该法式,只需考虑动态库是否能加载。
(二) 需要模拟固件shell,与整个系统有所交互。这里能够经由chroot改变根路径,并行使模拟对象执行/bin/sh。同时能够挂在/proc,如许在ps查察历程时看上去加倍真实。
(三) 需要模拟整个固件启动,而且网卡等也能正常使用。这里要行使可模拟img系统的对象直接加载整个系统,也能够行使“套娃”大法,先模拟该架构的debian.img,再用chroot起设备的roofs。

下面介绍几个常用的模拟对象。

1.4.1 Qemu

Qemu是最老牌的多架构模拟对象,上述3个使用场景qemu都能够知足。qemu能够下载安装也能够直接行使源安装,这里要注重的是若是模拟应用不光需要qemu,还需安装qemu-user。

# For ubuntu
$ sudo apt-get install qemu
$ sudo apt-get install qemu-user qemu-uesr-static
  • qemu模拟应用

以模拟ARM固件为例,解开固件获得rootfs,下面是行使qemu模拟执行busybox:

iot@attifyos ~/Document> cp (which qemu-arm-static) ./rootfs/
iot@attifyos ~/Document> sudo chroot ./rootfs /qemu-arm-static /bin/busybox

BusyBox v0.47 (2018.08.30-14:14+0000) multi-call binary -- GPL2

Usage: busybox [function] [arguments]...
or: [function] [arguments]...

BusyBox is a multi-call binary that combines many common Unix
utilities into a single executable. Most people will create a
link to busybox for each function they wish to use, and BusyBox
will act like whatever it was invoked as.

Currently defined functions:
busybox, cat, chgrp, chmod, chown, cp, date, dd, df, echo, free,
grep, gunzip, gzip, halt, hex, hostname, id, init, kill, killall,
ln, ls, mkdir, mknod, more, mount, mv, ping, ps, pwd, reboot,
rm, rmdir, sh, sleep, sync, syslogd, tail, tar, touch, tty, umount,
uname, zcat
  • qemu模拟shell

行使qemu模拟sh与上述情形相似,能够先mount proc,使得ps查察历程时显得加倍真实:

iot@attifyos ~/Document> cd ./rootfs
iot@attifyos ~/Document> rm -rf proc
iot@attifyos ~/Document> sudo mount -t proc /proc ./proc
iot@attifyos ~/Document> cd ..
iot@attifyos ~/Document> sudo chroot ./rootfs /qemu-arm-static /bin/sh

BusyBox v0.47 (2018.08.30-14:14+0000) Built-in shell
Enter 'help' for a list of built-in commands.

/ # ls
bin gm sbin usr
dev lib store var
etc qemu-arm-static sys
/ # ps
PID PPID Uid Mem CPU St Command
1 0 0 29936 0.0 S init splash
2 0 0 0 0.0 S [kthreadd]
7 2 0 0 0.6 S [ksoftirqd/0]
332 1 0 26776 0.0 S systemd-journald
358 1 0 6568 0.0 S systemd-udevd
378 1 0 28144 0.0 S vmware-vmblock-fuse /run/vmblock-fuse -o rw,su
495 1 100 18500 0.0 S systemd-timesyncd
607 1 0 8244 0.0 S haveged --Foreground --verbose=1 -w 1024
608 1 0 42756 0.0 S VGAuthService
615 1 0 38824 0.0 S vmtoolsd
619 1 0 3740 0.0 S cron -f
621 1 103 6216 0.0 S avahi-daemon: running [attifyos.local]
...
  • qemu模拟系统

qemu的功能很壮大,能够像在vmware、virtualbox中一般安装系统:

$ qemu-img create -f qcow2 arm.qcow2 10G
$ qemu-system-arm -m 1024M -sd arm.qcow2 -M vexpress-a9 -cpu cortex-a9 -kernel ../Downloads/vmlinuz-3.2.0-4-vexpress -initrd ../Downloads/initrd.gz -append "root=/dev/ram" -no-reboot

行使qemu模拟完整固件最常规的法子就是将rootfs建造成img或qcow2文件,再用响应架构的qemu模拟执行,这里我们介绍一下前面提到的“套娃”大法。
首先下载Debian官方ARM构架的系统镜像。
挂在qcow2镜像,将rootfs拷贝至qcow2镜像:

$ sudo apt-get install libguestfs-tools
# 行使guestmount挂在qcow2镜像
$ guestmount -a debian_wheezy_armel_standard.qcow2 -m /dev/sda1 /mnt
# 拷贝rootfs
$ cp -rf ./rootfs /mnt/root/rootfs
$ guestunmount /mnt

然后启动qcow2文件:

qemu-system-arm -M versatilepb -kernel vmlinuz-3.2.0-4-versatile -initrd initrd.img-3.2.0-4-versatile -hda debian_wheezy_armel_standard.qcow2 -append "root=/dev/sda1"

行使chroot“套娃”系统:

$ chroot -u ./rootfs /bin/sh

BusyBox v0.47 (2018.08.30-14:14+0000) Built-in shell
Enter 'help' for a list of built-in commands.

/ #

使用debian现成的qcow2镜像能够省去网卡和其他一些设置过程,提高模拟效率。
值得注重的是,qemu在对法式黑盒测试时也经常使用,好比AFL的qemu_mode,在后背的篇章里我们会商量,当然AFL同样能够使用unicorn_mode,使用的就是下面介绍的模拟器unicorn。

1.4.2 Unicorn

Unicorn一个基于Qemu的cpu指令模拟框架,也就是能够模拟任何的cpu指令。我们一样能够行使Unicorn指令级模拟特征:

对(IOT)法式作恍惚测试
用于gdb插件,或代码模拟执行的插桩,点窜代码逻辑
模拟执行一些复杂搅浑代码,提高人工逆向效率

关于Unicorn模拟执行点窜代码逻辑的教程对照多,这里不再赘述,下面介绍一款基于Unicorn的IDA pro插件,该插件能够在IDA pro中模拟执行,并给出执行究竟,UnicornFuzz相关内容会在后背的篇章中介绍。

#include <stdlib.h>

int calc(int a,int b){
int sum;
sum = a+b;
return sum;

}

int main(){
calc(2,3);
}

上面非常简洁的较量器C代码是该插件的官方示例,其mipsel IDA pro反汇编代码如下:

.text:00400640                 .globl calc
.text:00400640 calc: # CODE XREF: main+18↓p
.text:00400640
.text:00400640 var_10 = -0x10
.text:00400640 var_4 = -4
.text:00400640 arg_0 = 0
.text:00400640 arg_4 = 4
.text:00400640
.text:00400640 addiu $sp, -0x18
.text:00400644 sw $fp, 0x18+var_4($sp)
.text:00400648 move $fp, $sp
.text:0040064C sw $a0, 0x18+arg_0($fp)
.text:00400650 sw $a1, 0x18+arg_4($fp)
.text:00400654 lw $v1, 0x18+arg_0($fp)
.text:00400658 lw $v0, 0x18+arg_4($fp)
.text:0040065C addu $v0, $v1, $v0
.text:00400660 sw $v0, 0x18+var_10($fp)
.text:00400664 lw $v0, 0x18+var_10($fp)
.text:00400668 move $sp, $fp
.text:0040066C lw $fp, 0x18+var_4($sp)
.text:00400670 addiu $sp, 0x18
.text:00400674 jr $ra
.text:00400678 nop
.text:00400678 # End of function calc

建立一个 emu object

Python>a = EmuMips()

设置模拟地址和参数

Python>a.configEmu(0x00400640,0x00400678,[2,3])
[*] Init registers success...
[*] Init code and data segment success!
[*] Init Stack success...
[*] set args...

起头指令模拟

Python>a.beginEmu()
[*] emulating...
[*] Done! Emulate result return: 0x5

经由Unicorn模拟执行获得sum(2+3)的究竟为0x5。

1.4.3 Qiling

Qiling是一款很年青年头的基于Unicorn的模拟器,专为IOT研究而生。Qiling能够作为IDA pro插件,也能够行使Qiling Unicornalf进行fuzz,还能够模拟IOT设备固件。Qiling用python3斥地,能够直接用pip3 install qiling安装,以下是官方模拟ARMj架构路由器固件的部门代码:

import os, socket, sys, threading
sys.path.append("..")
from qiling import *

def patcher(ql):
...

def nvram_listener():
...

def my_sandbox(path, rootfs):
ql = Qiling(path, rootfs, output = "debug")
ql.add_fs_mapper("/dev/urandom","/dev/urandom")
ql.hook_address(patcher ,ql.loader.elf_entry)
ql.run()

if __name__ == "__main__":
nvram_listener_therad = threading.Thread(target=nvram_listener, daemon=True)
nvram_listener_therad.start()
my_sandbox(["rootfs/bin/httpd"], "rootfs")

能够看到Qiling框架进一步简化了模拟所需代码,同时供应了指令级插桩功能,照样很壮大的。

1.4.4 Firmadyne

Firmadyne是一个主动化和可扩展的系统,用于对基于Linux的嵌入式固件执行仿真和动态剖析。Firmadyne也是是基于Qemu,使用起来大同小异,网上教程也好多,这里首要介绍一款使用Firmadyne的固件灰盒fuzz对象的—Firm-AFL。
Firm-AFL的安装分为用户模式和系统模式,
用户模式:

$ cd user_mode/
$ ./configure --target-list=mipsel-linux-user,mips-linux-user,arm-linux-user --static --disable-werror
$ make

系统模式:

$ cd qemu_mode/DECAF_qemu_2.10/
$ ./configure --target-list=mipsel-softmmu,mips-softmmu,arm-softmmu --disable-werror
$ make

以Dlink DIR-815固件为例,首先安装好Firmadyne,做一些初始化工作:

$ cd firmadyne
$ ./sources/extractor/extractor.py -b dlink -sql 127.0.0.1 -np -nk "../firmware/DIR-815_FIRMWARE_1.01.ZIP" images
$ ./scripts/getArch.sh ./images/9050.tar.gz
$ ./scripts/makeImage.sh 9050
$ ./scripts/inferNetwork.sh 9050
$ cd ..
$ python FirmAFL_setup.py 9050 mipsel

凭据路由器架构点窜image_9050目录中的run.sh:

ARCH=mipsel
QEMU="./qemu-system-${ARCH}"
KERNEL="./vmlinux.${ARCH}_3.2.1"
IMAGE="./image.raw"
MEM_FILE="./mem_file"
${QEMU} -m 256 -mem-prealloc -mem-path ${MEM_FILE} -M ${QEMU_MACHINE} -kernel ${KERNEL} \

然后就能够启动fuzz剧本起头测试:

$ cd image_9050
$ sudo python start.py 9050

1.5 总结

固件研究是IOT破绽研究的根蒂,本篇尽或者全的介绍了固件研究方面的内容,一方面笔者经验有限,还有些点未能涉及,另一方面篇幅有限,很多内容没能进一步睁开,今后有机会再和人人一路商量。下一篇将介绍IOT web破绽研究的相关内容。

参考资料

https://cloud.tencent.com/developer/article/1005700
https://5alt.me/2017/08/某智能设备固件解密/
http://blog.nsfocus.net/hmi-firmware-decryption-0522/
https://www.ershicimi.com/p/8e818120ac6352368837ef614dd496e4
http://blog.nsfocus.net/hmi-firmware-decryption-0522/
https://gorgias.me/2019/12/27/固件提取系列-UBI文件系统提取以及重打包/
https://paper.seebug.org/771/
https://paper.seebug.org/1090/
https://blog.csdn.net/yalecaltech/article/details/104113779
https://dassecurity-labs.github.io/HatLab_IOT_Wiki/firmware_security/firmware_security_tools/IDA_unicorn_base_tool/

出色介绍





FreeBuf微信号:freebuf扫描二维码关注公众号
爱八卦,爱爆料。
小编推荐
  1. NO.1 2019十大暴利行业排行榜(第一名果然是他)

    10、小家电 小家电的售后也是暴利行业,在手机和家电诸多售后服务收费黑洞中,配件价格已经透明化。追根溯源,售后服务行业暴利经营的另一个

  2. NO.2 明星大侦探甄完美谁扮演的 宋妍霏大跳热舞惊艳众人

    《明星大侦探》的nznd破冰演唱会,以及第六案是有关联的。其中,甄完美成为第五季里,最美的被害人。很多网友好奇,甄完美是谁扮演的?后了解

  3. NO.3 球鞋ep是什么意思,知识科普

    曾几何时,在国内进行售卖的耐克篮球鞋盒上经常会印有EP的字样,EP到底是啥意思?有人说广告色!有人说是球员版(难道PE印倒了?),还有人说

  4. NO.4 哪个dns网速快稳定(2019公共DNS服务器地址评估)

    路由器DNS在哪修改? 路由器拨号上网时会默认产生一个DNS,这个DNS一般是当地的DNS,一般情况下没什么问题,所以很多人可能会忽视这里的设置。

  5. NO.5 开的房记录可以消除吗(身份证开放房多久清除)

    一般买房的首付在十几万到二十几万,往往不是所有人都能一下子拿出这么多的现金来,又不想跟别人开口借,开发商允许刷信用卡,但前提手续费

  6. NO.6 怎么发红包有创意(抖音从1岁到26岁红包语)

    所以,想要发好红包、发得你觉得很爽,别人抢得/收得很开心,那还是有技术有姿势的! 01 发红包的时间不要太任性 如果是节假日的时候,发红包

  7. NO.7 高端设计办公室是如何做设计的

    我们深切的希望这个办公楼的设计能承载着企业的文化使命,融入到企业的核心文化上。

  8. NO.8 未央是什么意思时辰(女生取名未央好吗)

    于是就有人要问了,未央到底是什么意思呢?下面是小编带来关于未央是什么意思 ,未央是什么的内容,希望能让大家有所收获!

Copyright2018.天天资讯网资讯站,让大家及时掌握各行各业第一手资讯新闻!