Reverse Engineering Router Firmware TP-Link TD-W8970

Screenshot: dd to extract router filesystem

This is a blog post on reverse engineering TP Link  TD-W8970v3 router firmware.

Requirements:

      • Router Firmware  [ TP-Link TD-W8970 v3 ]
      • Linux Tools – binwalk, unsquashfs, dd, strings
      • Optional: “John” a.k.a john the ripper (for Brute forcing passwords)

Disclaimer:

This is strictly for educational purposes ONLY and not be used for conducting any illegal activities. I hold no responsibility for misuse of this information.

Download the firmware:

First, we need to download the firmware that we need to reverse engineer. I am using the TP Link TD-W8970 v3 firmware.

To download the firmware, go to the below link. -Select “V3” as the version and click on “Firmware”.

https://www.tp-link.com/us/support/download/td-w8970/

TP Link TD-W8970 firmware download page

 

Download the firmware.

TP Link TD-W8970 select latest firmware

Time to dig around!!

Copy the firmware to a new location and extract it.

mkdir ~/firmware
cp ~/Downloads/TD-W8970_V3_150427.zip ~/firmware/
cd firmware/
unzip TD-W8970_V3_150427.zip
cd TD-W8970\(UN\)_V3_150427/

So, here we can see the firmware upgrade image itself with the “.bin” extension along with the firmware upgrade guide.

$ ls -l
total 8296
-rw-rw-r-- 1 extr3me extr3me  317017 Dec 25  2013 'How to upgrade TP-LINK ADSL Modem Router - Copy.pdf'
-rw-rw-r-- 1 extr3me extr3me 8174304 Apr 27  2015 'TD-W8970v3_0.9.1_1.2_up_boot(150427)_2015-04-27_17.48.51.bin'
extr3me@op3n TD-W8970(UN)_V3_150427 $

For sanity purposes, I removed the firmware upgrade guide which I don’t need here.

$ rm How\ to\ upgrade\ TP-LINK\ ADSL\ Modem\ Router\ -\ Copy.pdf

Inspecting the binary with “file” command shows that it of type “data”.

$ file TD-W8970v3_0.9.1_1.2_up_boot\(150427\)_2015-04-27_17.48.51.bin
TD-W8970v3_0.9.1_1.2_up_boot(150427)_2015-04-27_17.48.51.bin: data

Below is a screenshot:

 

checking the binary using "file" command

I tried to run hexdump and filter out some data but did not get any useful info here yet.

$ hexdump -C TD-W8970v3_0.9.1_1.2_up_boot\(150427\)_2015-04-27_17.48.51.bin | head -10
00000000  03 00 00 00 76 65 72 2e  20 32 2e 30 00 ff ff ff  |....ver. 2.0....|
00000010  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
*
00000030  ff ff ff ff 08 97 00 03  00 00 00 35 00 00 00 00  |...........5....|
00000040  9c e8 56 2f 7d cd f2 5a  80 92 27 b5 dd 23 66 ea  |..V/}..Z..'..#f.|
00000050  00 00 00 00 ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00000060  ff ff ff ff ff ff ff ff  80 01 00 00 80 2e 00 20  |............... |
00000070  00 7e 02 00 00 00 02 00  00 13 d6 d3 00 13 d6 e0  |.~..............|
00000080  00 67 e0 00 00 00 00 00  00 00 e3 90 55 aa 01 02  |.g..........U...|
00000090  a5 00 09 01 55 d1 51 bb  ff ff ff ff ff ff ff ff  |....U.Q.........|

Now, use the tools “strings” to print out all the human readable strings in the binary. Here, I filtered the 1st 10 lines.

-The output does show two strings that seemed interesting.

$ strings TD-W8970v3_0.9.1_1.2_up_boot\(150427\)_2015-04-27_17.48.51.bin | head -10
ver. 2.0
79!8
@ !<
6H!$
cfe-v
e=192.168.1.1:ffffff00 h=192.168.1.100 g= r=f f=vmlinux i=bcm963xx_fs_kernel d=1 p=0
96361I2
  c
!P%@
!H$5)

A bit off topic. But out of curiosity, I searched online for “bcm963xx_fs_kernel” and came across a PDF document “Broadcom BCM963xx CFE Boot Loader and Flash Memory Structure Application Notes”‘ from Jan 2006.

search result

Here is a screenshot of the document itself:

broadcom CFE PDF document

So, it looks like the router firmware has “Broadcom” and we now know the bootloader and we can get more information from the PDF.

Here is a link to the document: Broadcom CFE Link

cfe-v
e=192.168.1.1:ffffff00 h=192.168.1.100 g= r=f f=vmlinux i=bcm963xx_fs_kernel d=1 p=0

The strings output also shows “cfe-v” which looks to “Common Firmware Environment”.

It also has information on the CFE bootloader flash memory:

Broadcom bootloader flash memory architecture

In Page 5 of the Broadcom documentation, it does refer to the TFTP flashing method and could see some similarties from the output of the “strings” command.

minicom update via TFTP

T his is what I could come up so far, comparing the screenshot and the below line:

e=192.168.1.1:ffffff00 h=192.168.1.100 g= r=f f=vmlinux i=bcm963xx_fs_kernel d=1 p=0“,

e=192.168.1.1:ffffff00     => "192.168.1.1" => Board IP. I assume "ffffff00" => subnet mask 255.255.255.0 or CIDR.
h=192.168.1.100            => "192.168.1.100" => Host IP
g=                         => "empty" => Gateway IP
r=f                        => "f" => Run from Flash
f=vmlinux                  => "vmlinux" | Default run hostfilename is "vmlinux"
i=bcm963xx_fs_kernel       => "bcm963xx_fs_kernel" | Default flash filename is "bcm963xx_fs_kernel"
d=1                        => "1" | Delay = 1
p=0                        => "0" | [I have no idea what this is.]

So, the e, h, g, r, f, i, d and p seems to be variables that would be used during the flashing procedure via minicom to emulate a serial device.

If you would like to dig deeper, you could read about CPE by clicking here.

Extracting Router Filesystem:

To check what is in the router firmware binary, I have used “binwalk“. Below is output of binwalk:

$ binwalk TD-W8970v3_0.9.1_1.2_up_boot\(150427\)_2015-04-27_17.48.51.bin

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
13300         0x33F4          LZMA compressed data, properties: 0x6D, dictionary size: 4194304 bytes, uncompressed size: 220576 bytes
66572         0x1040C         LZMA compressed data, properties: 0x6D, dictionary size: 4194304 bytes, uncompressed size: 3876096 bytes
151315        0x24F13         MySQL MISAM index file Version 4
1366752       0x14DAE0        Squashfs filesystem, little endian, non-standard signature, version 4.0, compression:gzip, size: 6806057 bytes, 594 inodes, blocksize: 65536 bytes, created: 2015-04-27 09:45:54

The Ahaaa moment!

So, here we see this binary contains a squashfs filesystem starting at decimal “1366752”.

binwalk binary squashfs

We can extract the squashfs filesystem alone from the firmware binary using the “dd” command by skiping up to “1366752” using the “skip” flag.

$ dd if=TD-W8970v3_0.9.1_1.2_up_boot\(150427\)_2015-04-27_17.48.51.bin skip=1366752 bs=1 of=router-fs.squashfs
6807552+0 records in
6807552+0 records out
6807552 bytes (6.8 MB, 6.5 MiB) copied, 8.81061 s, 773 kB/s

Here, we are providing the input file as the router firmware, setting the block size to “1” and getting data from “1366752” to the end of the binary and storing it to a file “router-fs.squashfs”. Here, if we dont specify the “bs” the copy would most likely fail.

So, the squashfs file system is about ~6.5MB in size compressed.

$ ls -lh
total 15M
-rw-rw-r-- 1 extr3me extr3me 6.5M Jun 10 00:05  router-fs.squashfs
-rw-rw-r-- 1 extr3me extr3me 7.8M Apr 27  2015 'TD-W8970v3_0.9.1_1.2_up_boot(150427)_2015-04-27_17.48.51.bin'

Screenshot: dd to extract router filesystem

– Now, Checking the file shows as “data”.

$ file router-fs.squashfs
router-fs.squashfs: data
  • For verification, check the unpacked binary “router-fs.squashfs” and it does show as “squashfs filesystem”.
$ binwalk router-fs.squashfs

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             Squashfs filesystem, little endian, non-standard signature, version 4.0, compression:gzip, size: 6806057 bytes, 594 inodes, blocksize: 65536 bytes, created: 2015-04-27 09:45:54

Now, we can extract the filesystem using “unsquashfs”.

$ unsquashfs router-fs.squashfs

-You may see some error such as below:

“create_inode: could not create character device squashfs-root/dev/bcmadsl0, because you’re not superuser!”

These logs can be safely ignored. Here is the output for reference:

$ unsquashfs router-fs.squashfs 
[130/91284]
Parallel unsquashfs: Using 8 processors
546 inodes (811 blocks) to write
create_inode: could not create character device squashfs-root/dev/bcmadsl0, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/bcmarl, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/bcmfap, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/bcmvlan, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/bcmxtmcfg0, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/bpm, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/brcmboard, because you're not superuser!
create_inode: could not create block device squashfs-root/dev/caldata, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/console, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/dk0, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/fcache, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/flash0, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/gmac, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/gpio, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/gpio1, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/ingqos, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/led, because you're not superuser!
create_inode: could not create block device squashfs-root/dev/mtd, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/mtd0, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/mtd1, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/mtd2, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/mtd3, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/mtd4, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/mtd5, because you're not superuser!
create_inode: could not create block device squashfs-root/dev/mtdblock0, because you're not superuser!
create_inode: could not create block device squashfs-root/dev/mtdblock1, because you're not superuser!
create_inode: could not create block device squashfs-root/dev/mtdblock2, because you're not superuser!
create_inode: could not create block device squashfs-root/dev/mtdblock3, because you're not superuser!
create_inode: could not create block device squashfs-root/dev/mtdblock4, because you're not superuser!
create_inode: could not create block device squashfs-root/dev/mtdblock5, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/net/tun, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/null, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/pmap, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/ppp, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/pppox_iptables, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/ptmx, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/ptyp0, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/ptyp1, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/ptyp2, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/pwrmngt, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/qostype, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/random, because you're not superuser!
create_inode: could not create block device squashfs-root/dev/sda, because you're not superuser!
create_inode: could not create block device squashfs-root/dev/sda1, because you're not superuser!
create_inode: could not create block device squashfs-root/dev/sda2, because you're not superuser!
create_inode: could not create block device squashfs-root/dev/sdb, because you're not superuser!
create_inode: could not create block device squashfs-root/dev/sdb1, because you're not superuser!
create_inode: could not create block device squashfs-root/dev/sdb2, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/tty, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/tty0, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/ttyACM0, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/ttyACM1, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/ttyACM10, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/ttyACM11, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/ttyACM12, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/ttyACM13, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/ttyACM14, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/ttyACM15, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/ttyACM2, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/ttyACM3, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/ttyACM4, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/ttyACM5, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/ttyACM6, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/ttyACM7, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/ttyACM8, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/ttyACM9, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/ttyS0, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/ttyUSB0, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/ttyUSB1, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/ttyUSB10, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/ttyUSB11, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/ttyUSB12, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/ttyUSB13, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/ttyUSB14, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/ttyUSB15, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/ttyUSB2, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/ttyUSB3, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/ttyUSB4, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/ttyUSB5, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/ttyUSB6, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/ttyUSB7, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/ttyUSB8, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/ttyUSB9, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/ttyp0, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/ttyp1, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/ttyp2, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/urandom, because you're not superuser!
create_inode: could not create character device squashfs-root/dev/watchdog, because you're not superuser!

create_inode: could not create character device squashfs-root/dev/zero, because you're not superuser!
[====================================================================================================================================================================================================| ] 722/811 89%

created 370 files
created 48 directories
created 87 symlinks
created 0 devices
created 0 fifos

-Now, we should see a folder named “squashfs-root

$ ls -l
total 14636
-rw-rw-r--  1 extr3me extr3me 6807552 Jun 10 00:05  router-fs.squashfs
drwxrwxr-x 13 extr3me extr3me    4096 Apr 27  2015  squashfs-root
-rw-rw-r--  1 extr3me extr3me 8174304 Apr 27  2015 'TD-W8970v3_0.9.1_1.2_up_boot(150427)_2015-04-27_17.48.51.bin'

Now, change into the folder ”

$ cd squashfs-root/

-Listing the files shows that we have the router’s filesystem.

$ ls -a
.  ..  bin  dev  etc  lib  linuxrc  mnt  proc  sbin  sys  tmp  usr  var  web

-To value a view of the filesystem in a tree like format, I have used the command “tree” and piping it to less:

$ tree -C | less -R

Guessing the Linux Kernel version:

-Checking the files with “.ko” extension for keyword “vermagic” would be the best guess to the Linux kernel version.

$ strings ./lib/modules/NetUSB.ko | grep vermagic
vermagic=2.6.30 SMP preempt mod_unload MIPS32_R1 32BIT

Now, that I know the kernel version I could then check for exploits that affect this kernel version.

For example: Check for CVEs that affect this version. [Link]

Some random things worth checking:

-The list of libraries installed can be found under:

$ tree -C lib/ | less -R

– So, the chrooted environment were the user inputs commands seems to be via a binary “usr/bin/cli” or could be translating the user commands to the actual deamon.

$ strings ./usr/bin/cli | less

-Btw, I found a blooper while checking this binary. Searching this binary, I did find a few misspelled words. Example: “histroy” instead of “history” 😛

serial
wan2lan
start
exit
clear
clear screen
enter config mode
enable
enter privilege mode
leave to the privious mode
help
help info
history
show histroy commands

Guessing GCC Version:

$ strings ./usr/bin/cli | grep GCC
GCC: (GNU) 3.3.2
GCC: (Buildroot 2010.02-git) 4.4.2

 

Cracking password from the router’s filesystem:

-Looking at the filesystem, I could see a file “passswd.bak” under etc/ directory.

-Reading the file shows there are two users with has shell access.

$ cat etc/passwd.bak
admin:$1$$iC.dUsGpxNNJGeOm1dFio/:0:0:root:/:/bin/sh
nobody:*:0:0:nobody:/:/bin/sh

Here:

      Username indicated in green.
      Hashed password indicated in orange.
Assigned shell indicated in pink.

This looks to be the “shadow” file usually located under etc/shadow which my assumption is to be copied to etc/shadow during upgrade.

Here is something wierd. Why does user “nobody” has /bin/bash shell ? Manufacturer backdoor??Mmmmm….! We will come to that later.

Messing around  – Cracking passwords:

Before cracking the password, lets understand something about the hash+salt. Here, the “$” signs are special

passwd.bak file

admin:$1$$iC.dUsGpxNNJGeOm1dFio/:0:0:root:/:/bin/sh

The string that we require is the following:

$1$$iC.dUsGpxNNJGeOm1dFio/

The string is specificied in the following format:

$id$salt$encrypted

$1 => Indicates that  MD5 is used to create the hash the password. Below is a table of the list of possible values for the 1st section.

--------------------
| 1  | MD5         |
--------------------
| 2  | Blowfish    |
--------------------
| 2a | eksBlowfish |
--------------------
| 5  | SHA-256     |
--------------------
| 6  | SHA-512     |
--------------------

For testing purposes, I was able to crack the password with John the ripper.

If the passwords had complex salts + hashing methods, for ex SHA-512 it may take longer than expected. [Again, this is for educational purposes ONLY!]

$ john etc/passwd.bak
Loaded 1 password hash (md5crypt [MD5 32/64 X2])
No password hashes left to crack (see FAQ)

– To view the cracked password, you could use the –show flag along with the input file etc/passwd.bak

$ john --show etc/passwd.bak
admin:1234:0:0:root:/:/bin/sh
1 password hash cracked, 0 left

 

cracked password using john the ripper

-So, the password “admin” user is “1234”.

The user “nobody”:

Coming back to the user “nobody”.

Ideally, for security purposes “nobody” user is used with a combination of a non existing directory along with a nologin shell. Below is a sample of an acceptable configuration to me:

nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin

However, in the router’s FS, it seems wierd that the user “nobody” seems to have “/” or the actual root as mount along with “/bin/bash”.

nobody:*:0:0:nobody:/:/bin/sh

Anyways, may be this is just my paranoia/spidey sense kicking in. 😛

 

If you read this far. Thanks a ton! Hope you learned something from this article. Do bookmark this page for future references. Cheers

 

Regards,
ΞXΤЯ3МΞ

References:

https://openwrt.org/docs/techref/bootloader/cfe
https://en.wikipedia.org/wiki/Common_Firmware_Environment
https://www.cvedetails.com/version/81666/Linux-Linux-Kernel-2.6.30.html
https://charlesreid1.com/wiki/John_the_Ripper/Shadow_File
https://www.openwall.com/john/doc/EXAMPLES.shtml

Click to access bcm963xx_bootloader_appnote.pdf

http://plastilinux.blogspot.com/2009/11/how-to-know-version-of-kernel-without.html
ase1590

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.