TryHackMe: Dumping Router Firmware
This is a write-up of the room Dumping Router Firmware from TryHackMe.
Task 1: Preparation
Let’s first download the router firmware from this repository.
Then make sure that binwalk has JFFS2 with the following commands:
~ sudo pip3 install cstruct
~ git clone https://github.com/sviehb/jefferson
~ cd jefferson && sudo python3 setup.py install
Task 2: Investigating Firmware
Analyse the firmware with strings by typing:
~ strings FW_WRT1900ACSV2.img
Linksys WRT1900ACS Router
@ #!
!1C "
-- System halted
Attempting division by 0!
Uncompressing Linux...
decompressor returned an error
done, booting the kernel.
invalid distance too far back
invalid distance code
invalid literal/length code
incorrect header check
unknown compression method
invalid window size
invalid block type
invalid stored block lengths
too many length or distance symbols
invalid code lengths set
invalid bit length repeat
invalid literal/lengths set
invalid distances set
incorrect data check
...
You will notice that in the output, there is some clear text allowing for further analysis with binwalk. Here we can see that the first line is:
~ Linksys WRT1900ACS Router
And that the device is running Linux.
Next we will use binwalk to analyse further. To get the available commands we run:
~ binwalk -h
Binwalk v2.2.0
Craig Heffner, ReFirmLabs
https://github.com/ReFirmLabs/binwalk
Usage: binwalk [OPTIONS] [FILE1] [FILE2] [FILE3] ...
Disassembly Scan Options:
-Y, --disasm Identify the CPU architecture of a file using the capstone disassembler
-T, --minsn=<int> Minimum number of consecutive instructions to be considered valid (default: 500)
-k, --continue Don't stop at the first match
...
Extraction Options:
-e, --extract Automatically extract known file types
...
We see from the output that -e
allows us to extract files from the firmware image.
So we can now run:
binwalk -e FW_WRT1900ACSV2_2.0.3.201002_prod.img
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
0 0x0 uImage header, header size: 64 bytes, header CRC: 0xFF40CAEC, created: 2020-04-22 11:07:26, image size: 4229755 bytes, Data Address: 0x8000, Entry Point: 0x8000, data CRC: 0xABEBC439, OS: Linux, CPU: ARM, image type: OS Kernel Image, compression type: none, image name: "Linksys WRT1900ACS Router"
64 0x40 Linux kernel ARM boot executable zImage (little-endian)
2380 0x94C device tree image (dtb)
17280 0x4380 device tree image (dtb)
22528 0x5800 device tree image (dtb)
26736 0x6870 gzip compressed data, maximum compression, from Unix, last modified: 1970-01-01 00:00:00 (null date)
4214256 0x404DF0 device tree image (dtb)
6291456 0x600000 JFFS2 filesystem, little endian
We can see that the first item extracted is uImage header
and the creation date is 2020-04-22 11:07:26
.
We can also see that the CRC is 0xABEBC439
, the image size is 4229755 bytes
and it is an ARM device.
You will notice that binwalk created two new files, 600000.jffs2
and 6870
.
If we run string on 6879
, we get the following output:
~ strings 6870
Q 0X
Q!PU
PFV8@-
ARMv7 Processor
Tainted:
6A_p
6A_p
6A_p
Q8@-
;p@-
...
PACKET
standard
filter
INPUT
FORWARD
OUTPUT
PREROUTING
OUTPUT
POSTROUTING
*@+T
L2CAP
named UNIX socket
tcp NFSv4.1 backchannel
PPPOL2TP
atst
nl80211
mlme
config
scan
regulatory
...
You’ll notice that there is some clear text in this file so we can run:
~ binwalk -e 6870
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
492 0x1EC device tree image (dtb)
1904228 0x1D0E64 SHA256 hash constants, little endian
4112676 0x3EC124 SHA256 hash constants, little endian
5877920 0x59B0A0 Linux kernel version 3.10.3
6176102 0x5E3D66 Unix path: /var/run/rpcbind.sock
6261498 0x5F8AFA MPEG transport stream data
6261758 0x5F8BFE MPEG transport stream data
6902132 0x695174 Unix path: /dev/vc/0
6993884 0x6AB7DC xz compressed data
7027944 0x6B3CE8 Unix path: /lib/firmware/updates/3.10.39
7194599 0x6DC7E7 Copyright string: "Copyright 2005-2007 Rodolfo Giometti <[email protected]>"
7218153 0x6E23E9 Copyright string: "Copyright(c) Pierre Ossman"
7301128 0x6F6808 Unix path: /etc/init.d/ipv6_react_to_ra.sh
7304520 0x6F7548 Neighborly text, "NeighborSolicits6InDatagrams"
7304540 0x6F755C Neighborly text, "NeighborAdvertisementsorts"
7309086 0x6F871E Neighborly text, "neighbor %.2x%.2x.%pM lost rename link %s to %s"
7946423 0x7940B7 LZMA compressed data, properties: 0xC0, dictionary size: 0 bytes, uncompressed size: 64 bytes
7970360 0x799E38 ASCII cpio archive (SVR4 with no CRC), file name: "dev", file name length: "0x00000004", file size: "0x00000000"
7970476 0x799EAC ASCII cpio archive (SVR4 with no CRC), file name: "dev/console", file name length: "0x0000000C", file size: "0x00000000"
7970600 0x799F28 ASCII cpio archive (SVR4 with no CRC), file name: "root", file name length: "0x00000005", file size: "0x00000000"
7970716 0x799F9C ASCII cpio archive (SVR4 with no CRC), file name: "TRAILER!!!", file name length: "0x0000000B", file size: "0x00000000"
7996352 0x7A03C0 CRC32 polynomial table, little endian
8075823 0x7B3A2F LZMA compressed data, properties: 0xC0, dictionary size: 0 bytes, uncompressed size: 32 bytes
8227376 0x7D8A30 Copyright string: "Copyright 2000~2013, Marvell International Ltd."
8275455 0x7E45FF LZMA compressed data, properties: 0xC0, dictionary size: 0 bytes, uncompressed size: 192 bytes
You’ll dicover that is is running Linux kernel version 3.10.3
.
Task 3: Mounting and Analysis of the Router’s Filesystem
Follow the instructions to mount the filesystem:
#Step 1
#If /dev/mtdblock0 exists, remove file/directory and re-create the block device
rm -rf /dev/mtdblock0
mknod /dev/mtdblock0 b 31 0
#Step 2
#Create a location for the jffs2 filesysystem to
mkdir /mnt/jffs2_file/
#Step 3
#Load required kernel modules
modprobe jffs2
modprobe mtdram
modprobe mtdblock
#Step 4
#Write image to /dev/mtdblock0
dd if=/root/Router/600000.jffs2 of=/dev/mtdblock0
#Step 5
#Mount file system to folder location
mount -t jffs2 /dev/mtdblock0 /mnt/jffs2_file/
#Finally
cd /mnt/jffs2_file/
Note: You will need to change some of the paths. After that is mounted you can list the files by typing:
~ ls -la
total 3
drwxr-xr-x 17 root root 0 Jan 1 1970 .
drwxr-xr-x 1 root root 20 Jun 10 19:28 ..
drwxr-xr-x 2 root root 0 Apr 22 12:10 bin
drwxr-xr-x 2 root root 0 Apr 22 12:44 cgroup
drwxr-xr-x 2 root root 0 Apr 22 12:44 dev
drwxr-xr-x 17 root root 0 Apr 22 12:42 etc
drwxr-xr-x 2 root root 0 Apr 22 12:42 home
drwxr-xr-x 3 root root 0 Apr 22 12:39 JNAP
drwxr-xr-x 2 root root 0 Apr 22 12:44 lib
lrwxrwxrwx 1 root root 11 Apr 22 12:10 linuxrc -> bin/busybox
lrwxrwxrwx 1 root root 8 Apr 22 12:42 mnt -> /tmp/mnt
-r--r--r-- 1 root root 20 Apr 22 12:44 .mtoolsrc
lrwxrwxrwx 1 root root 8 Apr 22 12:42 opt -> /tmp/opt
drwxr-xr-x 2 root root 0 Apr 22 12:42 proc
drwxr-xr-x 2 root root 0 Apr 22 12:42 root
drwxr-xr-x 2 root root 0 Apr 22 12:44 sbin
drwxr-xr-x 2 root root 0 Apr 22 12:42 sys
drwxr-xr-x 2 root root 0 Apr 22 12:42 tmp
drwxr-xr-x 2 root root 0 Apr 22 12:36 usr
lrwxrwxrwx 1 root root 8 Apr 22 12:42 var -> /tmp/var
drwxr-xr-x 2 root root 0 Apr 22 12:37 www
We can see from the output that linuxrc
links to /bin/busybox
and that mnt
, opt
and var
link to /tmp/
.
www
would store the HTTP Server.
We can now look at bin
.
By listing the files we can see that most of them point to busybox
:
~ ls -la
total 1357
drwxr-xr-x 2 root root 0 Apr 22 12:10 .
drwxr-xr-x 17 root root 0 Jan 1 1970 ..
lrwxrwxrwx 1 root root 7 Apr 22 12:10 addgroup -> busybox
lrwxrwxrwx 1 root root 7 Apr 22 12:10 adduser -> busybox
lrwxrwxrwx 1 root root 7 Apr 22 12:10 ash -> busybox
-rwxr-xr-x 1 root root 7112 Apr 22 12:44 attr
-rwxr-xr-x 1 root root 593280 Apr 22 12:44 busybox
lrwxrwxrwx 1 root root 7 Apr 22 12:10 cat -> busybox
lrwxrwxrwx 1 root root 7 Apr 22 12:10 catv -> busybox
-rwxr-xr-x 1 root root 8644 Apr 22 12:44 chacl
lrwxrwxrwx 1 root root 7 Apr 22 12:10 chgrp -> busybox
lrwxrwxrwx 1 root root 7 Apr 22 12:10 chmod -> busybox
lrwxrwxrwx 1 root root 7 Apr 22 12:10 chown -> busybox
lrwxrwxrwx 1 root root 7 Apr 22 12:10 cp -> busybox
lrwxrwxrwx 1 root root 7 Apr 22 12:10 cpio -> busybox
-rwxr-xr-x 1 root root 88232 Apr 22 12:44 curl
-rwxr-xr-x 1 root root 6039 Apr 22 12:16 curl-config
lrwxrwxrwx 1 root root 7 Apr 22 12:10 date -> busybox
lrwxrwxrwx 1 root root 7 Apr 22 12:10 dd -> busybox
...
We can see from the output that sqlite3
would be running.
We can now look at etc
:
~ ls -la
total 325
drwxr-xr-x 17 root root 0 Apr 22 12:42 .
drwxr-xr-x 17 root root 0 Jan 1 1970 ..
-r-xr-xr-x 1 root root 1226 Apr 22 11:47 24G_power_table_AP
-r-xr-xr-x 1 root root 1036 Apr 22 11:47 24G_power_table_AU
-r-xr-xr-x 1 root root 1036 Apr 22 11:47 24G_power_table_CA
-r--r--r-- 1 root root 1226 Apr 22 11:47 24G_power_table_CE
-r--r--r-- 1 root root 1036 Apr 22 11:47 24G_power_table_FCC
-r-xr-xr-x 1 root root 1036 Apr 22 11:47 24G_power_table_PH
-r-xr-xr-x 1 root root 860 Apr 22 11:47 5G_power_table_AP
-r-xr-xr-x 1 root root 860 Apr 22 11:47 5G_power_table_AU
-r-xr-xr-x 1 root root 860 Apr 22 11:47 5G_power_table_CA
-r--r--r-- 1 root root 380 Apr 22 11:47 5G_power_table_CE
-r--r--r-- 1 root root 860 Apr 22 11:47 5G_power_table_FCC
-r-xr-xr-x 1 root root 860 Apr 22 11:47 5G_power_table_PH
-rw-r--r-- 1 root root 16 Apr 22 12:44 builddate
-rw-r--r-- 1 root root 10 Apr 22 12:44 builddate.timet
-rw-r--r-- 1 root root 113 Apr 22 12:44 builddetails
-rw-r--r-- 1 root root 6 Apr 22 12:44 buildrev
drwxr-xr-x 3 root root 0 Apr 22 12:44 certs
-r--r--r-- 1 root root 46 Apr 22 12:43 cloud_dns_names
...
We can get the date is was built by running:
~ cat builddate
2020-04-22 11:44
Note: this time won’t work. Try 2020-04-22 11:07:26
instead.
We can see that SSH is running on dropbear
.
Cisco developed the media server from mediaserver.ini
.
We can view services and ports by running:
~ cat services
# Network services, Internet style
#
# Note that it is presently the policy of IANA to assign a single well-known
# port number for both TCP and UDP; hence, officially ports have two entries
# even if the protocol doesn't support UDP operations.
#
# Updated from http://www.iana.org/assignments/port-numbers and other
# sources like http://www.freebsd.org/cgi/cvsweb.cgi/src/etc/services .
# New ports will be added on request if they have been officially assigned
# by IANA and used in the real-world or are needed by a debian package.
# If you need a huge list of used numbers please install the nmap package.
tcpmux 1/tcp # TCP port service multiplexer
echo 7/tcp
echo 7/udp
discard 9/tcp sink null
discard 9/udp sink null
systat 11/tcp users
daytime 13/tcp
daytime 13/udp
...
system_defaults
contain default settings.
We can get the firmware version by running:
~ cat version
2.0.3.201002
Note: Once again thisvalue won’t work. Use 2.0.2.188405
instead.
We can get the networks by running:
~ ls -la
total 109
drwxr-xr-x 5 root root 0 Apr 22 12:39 .
drwxr-xr-x 3 root root 0 Apr 22 12:39 ..
-r--r--r-- 1 root root 6274 Apr 22 12:39 core_server.lua
-r--r--r-- 1 root root 1486 Apr 22 12:39 ddns_server.lua
-r--r--r-- 1 root root 2242 Apr 22 12:39 devicelist_server.lua
-r--r--r-- 1 root root 3767 Apr 22 12:39 diagnostics_server.lua
-r--r--r-- 1 root root 5247 Apr 22 12:39 dynamicportforwarding_server.lua
-r--r--r-- 1 root root 2786 Apr 22 12:39 dynamicsession_server.lua
-r--r--r-- 1 root root 5144 Apr 22 12:39 firewall_server.lua
-r--r--r-- 1 root root 1874 Apr 22 12:39 firmwareupdate_server.lua
-r--r--r-- 1 root root 2004 Apr 22 12:39 ftpserver_server.lua
drwxr-xr-x 2 root root 0 Apr 22 12:39 guest_lan
-r--r--r-- 1 root root 488 Apr 22 12:39 guestnetworkauth_server.lua
-r--r--r-- 1 root root 6156 Apr 22 12:39 guestnetwork_server.lua
-r--r--r-- 1 root root 1446 Apr 22 12:39 httpproxy_server.lua
drwxr-xr-x 2 root root 0 Apr 22 12:39 lan
-r--r--r-- 1 root root 2296 Apr 22 12:39 locale_server.lua
-r--r--r-- 1 root root 983 Apr 22 12:39 macfilter_server.lua
-r--r--r-- 1 root root 1644 Apr 22 12:39 networkconnections_server.lua
-r--r--r-- 1 root root 2216 Apr 22 12:39 networktraffic_server.lua
...
The three networks are guest_lan, wan, lan
And that is the room complete!