IoT vulnerability research (Part 1) Firmware basics

0 37
With the arrival of the 5G era, the role of the Internet of Things is becoming m...

With the arrival of the 5G era, the role of the Internet of Things is becoming more and more important, and more security risks are also accompanying it. IOT security involves a wide range of content. This series of articles will discuss the author's understanding of IOT vulnerability research from a technical level. The author will discuss from five dimensions: firmware, web, hardware, IOT protocol, and mobile application. Due to limited ability, welcome everyone to correct and supplement any inaccuracies or omissions.

IoT firmware basics

The reason why firmware is the first topic to be discussed is that it is relatively basic, and IOT vulnerability research generally cannot bypass it. The following will introduce four parts: firmware decryption (if encrypted), unpacking and packaging, simulation, and overall security assessment of the firmware.

1.1 Firmware decryption

IoT vulnerability research (Part 1) Firmware basics

Some IOT devices encrypt the firmware even sign it to increase the research threshold and security during upgrades, because encryption and decryption consume a lot of resources. These devices are generally configured to be higher, such as some routers and firewalls.

1.1.1 Firmware encryption judgment

It is relatively simple to determine whether the firmware is encrypted. With some experience, opening a binary editor can help see the characteristics. Generally, the following characteristics will exist.

Except for the firmware header not having visible characters, (excluding the header) the data is expanded in binary 01 frequency is basically consistent
binwalk(-e) cannot parse the firmware structure, and (-A) does not recognize any CPU architecture instructions

If the above characteristics are met, it is guessed that the firmware has been encrypted. Firmware decryption usually starts from these perspectives, but is not limited to the following methods.

1.1.2 Hardware key acquisition

This method is limited to firmware that always exists in an encrypted state, and is only decrypted and unpacked into flash when the system boots, and the device lacks dynamic debugging means such as (UART/JTAG). Since there is a complete decryption process in flash, it is possible to read flash with a programmer, reverse engineer the decryption algorithm and key, and achieve the purpose of decrypting the firmware. For example, the flash memory distribution of a device is as follows:

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

It is obvious that the encryption process we need is in the boot section, and we need to find the encryption algorithm and key from it. Generally, encryption adopts public block ciphers such as AES, and the key is to find the block mode, IV (non-ECB), and key. Load the boot into IDA pro, and it does not automatically identify:
It can be manually identified by comparing the interrupt vector table structure at the beginning of the ARM code, the common entry code is as follows.

.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

Afterwards, we can reverse engineer to obtain the encryption algorithm as AES, and the key is obtained through the sha256 hash of the device serial number.
The identification of this structure through IDA pro will be discussed when discussing RTOS later, and the devices using this firmware encryption method have a very high security level, and general devices only perform decryption verification during the upgrade.

1.1.3 Debugging Direct Reading

This method is the easiest to understand, that is, after the device starts, use UART, JTAG, Console, or network means to transmit the firmware (packaged) back, thus bypassing the decryption process. It is worth noting that these interfaces need to be provided by the device, and the specific methods vary from device to device, and the use of these interfaces will be introduced in the hardware section.

1.1.4 Compare the boundary version

This method is suitable for manufacturers who did not adopt an encryption scheme at first, that is, the old version of the firmware is not encrypted, and a decryption program was added during an upgrade, and then the upgrade used encrypted firmware. In this way, we can find the boundary version between encrypted and unencrypted firmware in a series of firmware, and unpack the last unencrypted version to reverse the upgrade program to restore the encryption process.
By downloading the firmware of a router as shown in the figure above, unpacking it, and locating the upgrade program location by searching for combinations containing keywords such as "firmware", "upgrade", "update", "download", etc., of course, there are debugging methods that can also be used to view the process update during the upgrade to locate the upgrade program and parameters:

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

By quickly reversing the encimg program with IDA pro, the code for encryption and decryption processes is obtained, which adopts the AES CBC mode:

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 returned by the previous function
   const AES_KEY *key,
   // initialization vector
   unsigned char *ivec,
   // is encryption or decryption
   const int enc
)

1.1.5 Reverse Upgrade Program

This method is suitable for those who have already obtained the upgrade program through an interface or boundary version. You can use the box detection tool of the grouping algorithm to distinguish the encryption algorithm and locate the position. Of course, binwalk can also parse certain simple cases, such as some industrial control HMI firmware:

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

Load the upgrade program directly, locate the openssl call, and it's easy to get the decryption command:

1.1.6 Key Acquisition via Vulnerability

If you can't find the boundary version and can't find the debug interface or are not familiar with hardware debugging, you can consider using historical version vulnerabilities to first obtain device control rights, and then obtain the upgrade program and reverse the encryption algorithm. This method is rather cunning and requires the device to have a historical firmware with an RCE vulnerability. Through the downgrade operation, the vulnerability is planted to obtain permissions, download the required upgrade program, and then reverse to obtain the encryption algorithm.

1.2 Firmware Unpacking

Newcomers to IOT security research may find firmware unpacking quite simple, just directlybinwalk -Meis enough, but as the saying goes, ideals are beautiful, reality is cruel. After testing many firmware, it will be found that binwalk cannot unpack in many cases.
IOT firmware is generally divided into two categories, one that existsFile systemMostly based on linux/BSD, and another type of firmware is an integral part, that is, the RTOS(Real-time operating system) we mentioned.

1.2.1 File system exists

Everyone should be familiar with binwalk, using binwalk can directly obtain the rootfs file system information, which will not be elaborated here. The author believes that the powerful point of binwalk lies in its ability to parse and identify headers of multiple formats, providing a reference for unpacking. The following will introduce several cases that require some detours, of course, firmware varies greatly, depending on the designer's design, and cannot be listed one by one.

1.2.1.1 UBI(Unsorted Block Image)

Firmware in UBI format is relatively common, binwalk cannot unpack it directly, but there are ready-made tools on the Internetubi_readerHere is a point to note:

UBI_reader unpacking, the UBI file must be a multiple of 1024 bytes, and content needs to be added or deleted

For example, by analyzing a router, it is found that its rootfs is in UBI format:

# 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

First, install 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

or directly

$ sudo pip install ubi_reader

Then, the UBI structure will be extracted according to the address, usingubireader_extract_files [options] path/to/fileit can be unpacked.

1.2.1.2 PFS

Some firmware can be identified by binwalk, but it cannot be unpacked, such as the following firmware

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

After running binwalk and checking the results, no recognizable items were found. At this point, manual analysis can be performed or some related tools can be searched.
Found onlineRelated toolsUse the command directly according to the prompt to extract the firmware.

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/

Let's take a simple look at the key code of firmware unpacking. The key is to find a header similar to '\xA5\xA5\xA5\x5A\xA5\x5A', and then unpack and decompress according to the specific format. Therefore, firmware unpacking is essentially data format analysis.

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

It may not be very appropriate to parse Lua structure here during unpacking, but in view of the large user base of Openwrt, a brief mention is made here. Lua is a lightweight scripting language that is convenient for embedding and can be extended. It is used in Openwrt development. It is worth noting that the Lua on some devices is not pure text and exists in obfuscated form, andluadecDecompile.
The Lua scripts in OpenWrt and the traditional luajit compiled ones are a bit different, and several patches are needed to use luadec for decompilation normally. The command is as follows:

$ 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 https://www.freebuf.com/articles/patches/*.patch; do patch -p1 <$i ; done
$ for i in https://www.freebuf.com/articles/endpoint/patches/*.patch; do patch -p1 <$i ; done
$ make linux

Modify 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)

Then execute:

$ make linux
 $ ldconfig
 $ cd https://www.freebuf.com/articles/luadec
 $ make LUAVER=5.1
 $ sudo cp luadec /usr/local/bin/

Use luadec to display the code structure:

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

Use luadec to decompile the specified function (function 0 contains sub-functions):

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

It should be noted that luadec compilation is related to the architecture, and the official luadec cannot parse lua files under arm environment, but there are also corresponding ones on the InternetTools, which will not be elaborated here.

1.2.2 RTOS

Many IOT devices adopt RTOS (Real-Time Operating System) architecture, and the firmware itself is an executable file without a file system, which is directly appended to the running process after startup. The most important points for analyzing RTOS are two:

(I) Firmware program entry
(II) Firmware program symbols

1.2.2.1 vxworks

Firstly, from the widely used and套路 can be followedvxworksTo mention, VxWorks is a real-time operating system launched by Wind River Systems Company, widely used in communication, military, aviation, aerospace embedded equipment fields. Because of the standard, it is easy to identify. Take the following firmware as an example:

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 has identified the firmware as Vxworks 5.5.1 and provided the symbol table location. First, we need to identify the firmware entry point. If the firmware is encapsulated in ELF format, the base address can be obtained directly using readelf, which is not applicable here.

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

Throughbinwalk -AGet the firmware architecture is ARM, directly load it into IDA pro:

Analyze the jump judgment at the beginning of the firmware to determine that the load address is 0x1000. For Vxworks, there are generally several methods to judge the base address:

Analyze the initialization code in the firmware header to find the first function usrInit of vxworks starting
Find the BSS boundary according to the initialization characteristics of the BSS area, and calculate the firmware load address based on the offset

Then, according to the position indicated by binwalk, repair the symbol table name.
The function table stores function names and function addresses. By locating both, the correctness of the base address can also be verified in reverse, such as the function name 0x00c813f8 shown in the figure above:
0x009aa0f4 is the function address:
Since the base address is related to the architecture, it will not be expanded in detail here. For the analysis of vxworks, we can use a plugin that can automatically repair the entry and symbols--vxhunter.
Taking Ghidra as an example, after loading the firmware, directly select the vxhunter_firmware_init.py plugin and the vxworks version, and the entry and symbols can be automatically repaired:
1.2.2.2 U-boot

Boot firmware of the boot class is also a type of file system-free firmware that we often encounter, for example, many IOT devices adoptU-bootAct as a boot, because U-boot is open source, we can refer to the source code analysis. For some architectures, U-boot can also adopt a fixed routine, such as MIPS can use the $gp register, etc.

1.2.2.3 Chip firmware

Some IOT firmware has no documentation, making reverse engineering difficult, for example, the firmware of an ARM chip shown below was loaded into IDA pro and no functions were identified:
In this way, we need to have an overall analysis of the firmware. We find that the position of 0x100 in the firmware is very interesting:
After 4-byte alignment, they all start with 0x2. This is neither code nor data, so it is very likely to be an address. It should be a table, so the base address is very likely to be 0x200000. We will rebase and view the strings after that:
Many strings similar to function names can be seen, and after finding the specific location, 0x16852A is searched in the binary of the firmware (little-endian), which is the address of wlc_probresp_attach.
It can be seen that the search was successful, and it is also a table structure:
Find the location in IDA pro according to the base address:
It can be seen that part of the cross-reference has been completed, and the subsequent analysis is relatively complex, so it will not be expanded here. In fact, the 0x100 position is the function address table, and there are many such tables in this firmware. Therefore, similar to address tables, strings are an important clue for analyzing the firmware base address and functions.

1.3 Firmware Packaging

It's easy to take apart and hard to put together, and this principle also applies to firmware packaging. If the device has a debugging interface, it is generally not necessary to perform packaging operations, as security research is mainly based on reverse thinking.
Sometimes, due to the lack of debugging means, we have to manually add it to the unpacked firmware. Generally, cross-compiled telnetd, dropbear(sshd), and gdb are placed in the firmware file, and then the boot script is replaced and packaged.
There are many boot scripts in Linux, especially in IOT devices. Here, I generally adopt a more cunning method, such as determining that the /sbin/xxxd service will boot up, and can replace it:

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

After that, add in /sbin/xxxd:

#!/bin/sh

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

When booting up, xxxd will run telnetd first.

1.3.1 Cross-compilation

Of course, it is the most convenient to package from the perspective of positive development, which is the matter of cross-compilation. In some of the devices I have studied, the router firmware mainly followsGPLThis is the open-source part of the code software (usually based on open-source tools), and provides the binary files of the remaining software and the packaging tool (method) for the entire firmware.
For example, some open-source downloads were provided for a router device previously studied:
Download the zip package, compile the rootfs according to your needs, and finally package it using the tools provided in the zip package:

https://www.freebuf.com/articles/endpoint/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(fmkIt may be the most commonly used unpacking tool based on binwalk, but due to long-time lack of updates, its usage scenarios are limited.
The installation and usage of fmk are quite simple, as shown below:

# 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
# Use
$ https://www.freebuf.com/articles/endpoint/extract-firmware.sh firmware.bin //unpacking
$ cp new-telnetd fmk/rootfs/usr/sbin/telnetd //modify as needed
$ https://www.freebuf.com/articles/endpoint/build-firmware.sh //packaging

1.3.3 Manual Analysis

The difficulty of packaging lies in that the firmware must be consistent with the original firmware and pass various checks, otherwise it may fail to flash the device at best, or brick the device at worst. The author previously had an article aboutnetgear upnp vulnerability article, involving the netgear firmware packaging process, those who are interested can take a look.
Firmware is generally divided into many sections, for the convenience of parsing, each section will have an indicator header, which may store flags, size, and crc check information, etc., which are the basis for unpacking.
For example, you can first get the firmware size (in hexadecimal), split the bytes according to the firmware size, usually 4 bytes, then find similar bytes on the firmware header (the indicated length on the firmware header will be reduced by the header length), and then analyze the bytes from the indicated size to clarify the format, which is very similar to the process of analyzing network protocols.
Of course, most headers are standardized, and can be matched one by one according to the standard format. It is worth noting that some manufacturers may sign the firmware, which will increase the difficulty of packaging. At this time, we can look for some official packaging tools that follow the GPL, or use openssl to generate a public and private key pair, cover the verification public key in the device, of course, there must be a vulnerability, otherwise it will fall into the chicken and egg cycle. Of course, there is also a better and cheaper method --- firmware simulation.

1.4 Firmware Simulation

Firmware simulation may have the following 3 scenarios according to different needs:

(One) Just simulate an application, such as web, upnpd, dnsmasq, etc., the purpose is to debug the application. At this time, you can directly run the program with the simulation tool, and only need to consider whether the dynamic library can be loaded.
(二) 需要模拟固件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) https://www.freebuf.com/articles/endpoint/rootfs/
iot@attifyos ~/Document> sudo chroot https://www.freebuf.com/articles/endpoint/rootfs /qemu-arm-static /bin/busybox

BusyBox v0.47 (2018.08.30-14:14+0000) 多调用二进制文件 -- GPL2

用法:busybox [函数] [参数]...
   或:[函数] [参数]...

	BusyBox是一个多调用二进制文件,它结合了许多常见的Unix
	将各种实用工具集成到一个可执行的文件中。大多数人会创建一个
	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 simulated shell

Using qemu to simulate sh is similar to the above situation, you can first mount proc to make ps show processes more realistically:

iot@attifyos ~/Document> cd https://www.freebuf.com/articles/endpoint/rootfs
iot@attifyos ~/Document> rm -rf proc
iot@attifyos ~/Document> sudo mount -t proc /proc https://www.freebuf.com/articles/endpoint/proc
iot@attifyos ~/Document> cd ..
iot@attifyos ~/Document> sudo chroot https://www.freebuf.com/articles/endpoint/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 simulates a system

qemu has powerful functions, which can install systems like in 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 https://www.freebuf.com/articles/Downloads/vmlinuz-3.2.0-4-vexpress -initrd https://www.freebuf.com/articles/Downloads/initrd.gz -append "root=/dev/ram" -no-reboot

The most conventional way to simulate a complete firmware using qemu is to make the rootfs into an img or qcow2 file, and then use the corresponding architecture of qemu to simulate execution. Here, we introduce the previously mentioned 'nested' method.
First downloadDebian officialARM architecture system image.
Mount the qcow2 image, copy rootfs to the qcow2 image:

$ sudo apt-get install libguestfs-tools
# Use guestmount to mount the qcow2 image
$ guestmount -a debian_wheezy_armel_standard.qcow2 -m /dev/sda1 /mnt
# Copy rootfs
$ cp -rf https://www.freebuf.com/articles/endpoint/rootfs /mnt/root/rootfs
$ guestunmount /mnt

Then start the qcow2 file:

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"

Utilize the 'chroot' 'nested' system:

$ chroot -u https://www.freebuf.com/articles/endpoint/rootfs /bin/sh

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

/ #

Using the pre-existing qcow2 image of Debian can save the process of configuring the network card and other settings, thus improving simulation efficiency.
It is worth noting that qemu is often used for black-box testing of programs, such as AFL's qemu_mode, which will be discussed in the following chapters. Of course, AFL can also use unicorn_mode, which uses the simulator unicorn introduced below.

1.4.2 Unicorn

UnicornA CPU instruction simulation framework based on Qemu, which can simulate any CPU instructions. We generally can use the Unicorn instruction-level simulation feature:

Fuzz testing for (IOT) programs
For gdb plugin, or code instrumentation for code simulation execution, modifying code logic
Simulate execution of some complex obfuscated code to improve manual reverse engineering efficiency

There are many tutorials on modifying code logic for Unicorn simulation execution, so we will not elaborate on them here. Below is introduced a plugin based on Unicorn:IDA pro pluginThe plugin can be simulated in IDA pro and the execution results can be obtained, related content of UnicornFuzz will be introduced in the following chapters.

#include <stdlib.h>

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

}

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

The very simple calculator C code provided by the plugin is an official example, and its mipsel IDA pro disassembly code is as follows:

.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

Create an emu object

Python>a = EmuMips()

Configure simulation address and parameters

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

Start instruction simulation

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

The result of simulating the execution of sum(2+3) using Unicorn is 0x5.

1.4.3 Qiling

QilingIt is a relatively young simulator based on Unicorn, specifically designed for IOT research. Qiling can be used as an IDA pro plugin, can utilize Qiling Unicornalf for fuzzing, and can also simulate IOT device firmware. Qiling is developed using python3 and can be used directlypip3 install qilingThe following is part of the official code for simulating ARMj architecture router firmware installation:

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_thread = threading.Thread(target=nvram_listener, daemon=True)
    nvram_listener_thread.start()
    my_sandbox(["rootfs/bin/httpd"], "rootfs")

It can be seen that the Qiling framework further simplifies the code required for simulation and provides instruction-level instrumentation, which is still very powerful.

1.4.4 Firmadyne

Firmadyneis an automated and scalable system for simulating and performing dynamic analysis on embedded firmware based on Linux. Firmadyne is also based on Qemu, with similar usage, and there are many tutorials online. Here, we mainly introduce a firmware gray-box fuzz tool that uses Firmadyne --Firm-AFL.
The installation of Firm-AFL is divided into user mode and system mode,
User mode:

$ cd user_mode/
$ https://www.freebuf.com/articles/endpoint/configure --target-list=mipsel-linux-user,mips-linux-user,arm-linux-user --static --disable-werror
$ make

System mode:

$ cd qemu_mode/DECAF_qemu_2.10/
$ https://www.freebuf.com/articles/endpoint/configure --target-list=mipsel-softmmu,mips-softmmu,arm-softmmu --disable-werror
$ make

Taking the Dlink DIR-815 firmware as an example, first install Firmadyne and do some initial work:

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

Modify the run.sh in the image_9050 directory according to the router architecture:

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

Then you can start the fuzz script to begin testing:

$ cd image_9050
$ sudo python start.py 9050

1.5 Summary

Firmware research is the foundation of IoT vulnerability research. This article tries to introduce the content of firmware research as comprehensively as possible. On the one hand, the author's experience is limited, and some points have not been covered. On the other hand, due to the limited space, many contents have not been further expanded. We will discuss them together in the future opportunities. The next article will introduce the relevant content of IoT web vulnerability research.

References

https://cloud.tencent.com/developer/article/1005700
https://5alt.me/2017/08/Decryption_of_firmware_of_some_intelligent_device/
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/Firmware_Extract_Series_UBI_File_System_Extract_and_Repacking/
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/

你可能想看:

Different SRC vulnerability discovery approach: Practical case of HTTP request splitting vulnerability

Announcement regarding the addition of 7 units as technical support units for the Ministry of Industry and Information Technology's mobile Internet APP product security vulnerability database

Ensure that the ID can be accessed even if it is guessed or cannot be tampered with; the scenario is common in resource convenience and unauthorized vulnerability scenarios. I have found many vulnerab

Analysis of PyTorch library RPC framework deserialization RCE vulnerability (CVE

Article 2 of the Cryptography Law clearly defines the term 'cryptography', which does not include commonly known terms such as 'bank card password', 'login password', as well as facial recognition, fi

89% of the use of enterprise generative AI goes unnoticed by the IT department, exposing data security vulnerabilities

d) Adopt identification technologies such as passwords, password technologies, biometric technologies, and combinations of two or more to identify users, and at least one identification technology sho

In-depth analysis of cross-domain vulnerability chain: from postMessage to the precise attack path of CSRF

In-depth Analysis and Practice: Analysis of Apache Commons SCXML Remote Code Execution Vulnerability and POC EXP Construction

Distributed Storage Technology (Part 2): Analysis of the architecture, principles, characteristics, and advantages and disadvantages of wide-column storage and full-text search engines

最后修改时间:
admin
上一篇 2025年03月30日 13:00
下一篇 2025年03月30日 13:22

评论已关闭