Modifying Firmware On Embedded Devices

Lately I have been analyzing some embedded devices such as routers, and want to share how to emulate, extract, and modify firmware.

We may want to do this for several reasons, such as enabling SSH/telnet to debug a service remotely, adding new features and looking for security vulnerabilities.

If you want to dump the firmware from a physical device, you will want to use something such as the CH341A, but it won’t be covered here.

Prerequisites

We will need some tools to analyze and emulate firmware, but thankfully the nice folks at Attify have made a specialized VM for analyzing embedded devices.

It comes with Firmware Analysis Toolkit which we will use to emulate the Netgear WNAP320 firmware, since it works well, and this way buying the hardware is not required to follow along.

AttifyOS

Running the firmware

Now that you have the VM downloaded, and running, open Terminator:

1
2
[email protected]:~$ mkdir WNAP320 && cd WNAP320
[email protected]:~/WNAP320$ wget http://www.downloads.netgear.com/files/GDC/WNAP320/WNAP320_V3.7.11.4.zip

Now we want to run the firmware, and for that we will use Firmware Analysis Toolkit. From their GitHub:

Firmware Analysis Toolkit (FAT henceforth) is based on Firmadyne with some changes. Firmadyne uses a PostgreSQL database to store information about the emulated images. However just for the core functionality i.e. emulating firmware, PostgreSQL is not really needed. Hence FAT doesn’t use it.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[email protected]:~/WNAP320/firmware$ cd ~/tools/firmware-analysis-toolkit/
[email protected]:~/tools/firmware-analysis-toolkit$ ./fat.py ~/WNAP320/WNAP320_V3.7.11.4.zip 

                               __           _
                              / _|         | |
                             | |_    __ _  | |_
                             |  _|  / _` | | __|
                             | |   | (_| | | |_
                             |_|    \__,_|  \__|

                Welcome to the Firmware Analysis Toolkit - v0.3
    Offensive IoT Exploitation Training http://bit.do/offensiveiotexploitation
                  By Attify - https://attify.com  | @attifyme
    
[+] Firmware: WNAP320_V3.7.11.4.zip
[+] Extracting the firmware...
[+] Image ID: 1
[+] Identifying architecture...
[+] Architecture: mipseb
[+] Building QEMU disk image...
[+] Setting up the network connection, please standby...
[+] Network interfaces: [('brtrunk', '192.168.0.100')]
[+] All set! Press ENTER to run the firmware...
[+] When running, press Ctrl + A X to terminate qemu

Press ENTER and wait a bit, then visit 192.168.0.100 on your browser to make sure everything worked.

Analyzing the firmware

For this firmware, it seems the interesting stuff are inside a tar archive. It’s usually not that simple.

Let’s extract it:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
[email protected]:~/WNAP320$ unzip WNAP320_V3.7.11.4.zip 
Archive:  WNAP320_V3.7.11.4.zip
  inflating: wnap320_V3.7.11.4_firmware.tar  
  inflating: wnap320_V3.7.11.4_firmware_Release_Notes.html  
[email protected]:~/WNAP320$ mkdir firmware
[email protected]:~/WNAP320$ tar -xvf wnap320_V3.7.11.4_firmware.tar -C firmware
vmlinux.gz.uImage
rootfs.squashfs
enc_dec.config
root_fs.md5
kernel.md5

The files ending in .md5 are not important, they are hashes of the files to check their integrity:

1
2
3
4
[email protected]:~/WNAP320/firmware$ cat root_fs.md5 
55e71f05c4dfdcf1ea1a611f05ca371b  -
[email protected]:~/WNAP320/firmware$ md5sum rootfs.squashfs 
55e71f05c4dfdcf1ea1a611f05ca371b  rootfs.squashfs

The two files of interest here are: rootfs.squashfs and vmlinux.gz.uImage.

Whenever we encounter a file format that we’re unsure about, we can use binwalk.

binwalk will scan the unknown file or archive for file signatures, and is often able to extract it by itself:

1
2
3
4
5
[email protected]:~/WNAP320/firmware$ binwalk rootfs.squashfs 

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             Squashfs filesystem, big endian, lzma signature, version 3.1, size: 6329666 bytes, 1417 inodes, blocksize: 65536 bytes, created: 2018-10-25 08:11:35

Great, it is simply a squashfs filesystem. This is a compressed read-only filesystem often used in embedded systems. We will extract it later.

1
2
3
4
5
6
[email protected]:~/WNAP320/firmware$ binwalk vmlinux.gz.uImage 

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             uImage header, header size: 64 bytes, header CRC: 0x8DD2855, created: 2018-10-25 08:11:29, image size: 983040 bytes, Data Address: 0x80020000, Entry Point: 0x8020E000, data CRC: 0x3663CBB2, OS: Linux, CPU: MIPS, image type: OS Kernel Image, compression type: gzip, image name: "Linux Kernel"
64            0x40            gzip compressed data, has original file name: "vmlinux.bin", from Unix, last modified: 2018-10-25 08:11:29

It seems this firmware uses U-Boot as a boot loader, which is very common in embedded devices. We also have the Linux kernel there. We also can see it’s meant to run on MIPS devices. Most embedded devices run either on ARM or MIPS architectures, as they are more energy efficient.

Extracting squashfs

This is a very easy task, we can either use unsquashfs or binwalk to extract it:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
[email protected]:/home/iot/WNAP320/firmware# unsquashfs rootfs.squashfs 
Reading a different endian SQUASHFS filesystem on rootfs.squashfs
Parallel unsquashfs: Using 1 processor
1318 inodes (1319 blocks) to write

[=============================================================\] 1319/1319 100%

created 1053 files
created 99 directories
created 217 symlinks
created 48 devices
created 0 fifos
[email protected]:/home/iot/WNAP320/firmware# binwalk -e rootfs.squashfs 

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             Squashfs filesystem, big endian, lzma signature, version 3.1, size: 6329666 bytes, 1417 inodes, blocksize: 65536 bytes, created: 2018-10-25 08:11:35

[email protected]:/home/iot/WNAP320/firmware/squashfs-root# ls
bin  dev  etc  home  lib  linuxrc  proc  root  rw  sbin  tmp  usr  var

Doing modifications

Now that we have access to the filesystem, we can do several things such as look for security vulnerabilities or modify the firmware.

This particular firmware has ssh enabled, and I don’t know what the default password for root is, so I will add another user:

1
2
3
4
5
6
[email protected]:/home/iot/WNAP320/firmware/squashfs-root/etc# openssl passwd -1 -salt salt super_secret_password
$1$salt$GmyU7Z0gGyVy6JmSUPqHy1
[email protected]:/home/iot/WNAP320/firmware/squashfs-root/etc# chmod 777 passwd
[email protected]:/home/iot/WNAP320/firmware/squashfs-root/etc# vim passwd
user:$1$salt$GmyU7Z0gGyVy6JmSUPqHy1:0:0:root:/root:/bin/sh
[email protected]:/home/iot/WNAP320/firmware/squashfs-root/etc# chmod 444 passwd

The reason I didn’t change the password of the root user directly, is because firmadyne appears to change the password.

Now that we finished our modification, we need to create a squashfs archive again.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
[email protected]:/home/iot/WNAP320/firmware# mkdir firmware_modified
[email protected]:/home/iot/WNAP320/firmware# mv squashfs-root/ firmware_modified/
[email protected]:/home/iot/WNAP320/firmware# mv enc_dec.config kernel.md5 root_fs.md5 vmlinux.gz.uImage firmware_modified/
r[email protected]:/home/iot/WNAP320/firmware# cd firmware_modified/
[email protected]:/home/iot/WNAP320/firmware/firmware_modified# mksquashfs squashfs-root/ rootfs.squashfs -comp lzma
Parallel mksquashfs: Using 1 processor
Creating 4.0 filesystem on rootfs.squashfs, block size 131072.
[============================================================================================================================================================/] 880/880 100%

Exportable Squashfs 4.0 filesystem, lzma compressed, data block size 131072
	compressed data, compressed metadata, compressed fragments, compressed xattrs
	duplicates are removed
Filesystem size 5868.07 Kbytes (5.73 Mbytes)
	22.66% of uncompressed filesystem size (25892.87 Kbytes)
Inode table size 8537 bytes (8.34 Kbytes)
	18.17% of uncompressed inode table size (46988 bytes)
Directory table size 12655 bytes (12.36 Kbytes)
	41.43% of uncompressed directory table size (30546 bytes)
Number of duplicate files found 320
Number of inodes 1417
Number of files 1053
Number of fragments 54
Number of symbolic links  217
Number of device nodes 48
Number of fifo nodes 0
Number of socket nodes 0
Number of directories 99
Number of ids (unique uids + gids) 1
Number of uids 1
	root (0)
Number of gids 1
	root (0)

[email protected]:/home/iot/WNAP320/firmware/firmware_modified# cd ..
[email protected]:/home/iot/WNAP320/firmware# tar -cvf firmware_modified.tar firmware_modified/

Now let’s emulate our new firmware:

1
[email protected]:~/tools/firmware-analysis-toolkit$ ./fat.py ~/WNAP320/firmware/firmware_modified.tar

Trying to SSH with user/super_secret_password:

1
2
3
4
5
6
7
[email protected]:/home/iot/WNAP320/firmware# ssh [email protected]
The authenticity of host '192.168.0.100 (192.168.0.100)' can't be established.
RSA key fingerprint is SHA256:tK8/SfB/lQb+8MCX32XWyrTTYjiEHZZ6cAGs+FcO0Ug.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.0.100' (RSA) to the list of known hosts.
[email protected]'s password: 
[[email protected] /root]# 

Using chroot

I want to show another way of doing the same thing, by making use of QEMU to chroot onto the firmware filesystem.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
[email protected]:/home/iot/WNAP320/firmware/squashfs-root# cp /usr/bin/qemu-mips-static usr/bin
[email protected]:/home/iot/WNAP320/firmware/squashfs-root# chroot . /bin/sh
/ # uname -a
Linux attifyos 4.15.0-88-generic #88-Ubuntu SMP Tue Feb 11 20:11:34 UTC 2020 mips unknown
/ # adduser -G root -s /bin/sh -h /root user 
adduser: /root: File exists
Changing password for user
New password:
Retype password:
Password for user changed by root
/ # cat /etc/passwd | grep user
user:x:1001:1001:Linux User,,,:/root:/bin/sh
/ # sed -i 's/1001/0/g' /etc/passwd
/ # cat /etc/passwd | grep user
user:x:0:0:Linux User,,,:/root:/bin/sh
/ # su user
/ # whoami
root
/ # 

Wrapping up

Not every manufacturer will publish their firmware online, and in those cases you may have to dump it from the device. Other manufacturers will sometimes encrypt their firmware. Even if you can download the firmware and it’s not encrypted, it’s not always a simple tar archive: in those cases, binwalk is your friend.

And of course, always backup the firmware of devices you are going to modify.

updatedupdated2023-03-192023-03-19