Thursday, February 20, 2014

Breaking down the Asus router bug

Tuesday I wrote about an apparent bug in the ASUS RT-AC66R and RT-AC66U routers that prevents them from recognizing a new firmware version is available. After investigating further, the root cause turned out to be a simple matter of ASUS not updating the file on their live updates server that reports the latest firmware for each router model. Depending on the specific model, ASUS wireless routers download a text file (strangely labeled as a zip file) from http://dlcdnet.asus.com/pub/ASUS/LiveUpdate/Release/Wireless or /Wireless_SQ. This file lists all supported models of router, along with the latest firmware version for each. These files appear to have not been updated since October 9, 2013, the date of the 3.0.0.4.374.979 firmware release.

This report is one in a series I have written on ASUS wireless router features and vulnerabilities. Others of interest:

Now for a slightly technical explanation, which sheds some light on the inner workings of ASUS wireless routers.

To check for updates through the admin GUI, one would follow a few links on the admin GUI or simply browse to http://[router]/Advanced_FirmwareUpgrade_Content.asp and press the "Check" button. Some magic happens behind the scenes, then the router either reports that it has the latest version, or prompts you to upgrade.


That magic begins with some JavaScript in Advanced_FirmwareUpgrade_Content.asp. If you were to view the source of that page, you will see something like this:


var webs_state_update = '1';
var webs_state_upgrade = '';
var webs_state_error = '0';
var webs_state_info = '3004_374_979-gbc8961e';
.
.
.
function detect_firmware(){
.
.
.
  if(isNewFW(webs_state_info)){
    $('update_scan').style.display="none";
    $('update_states').style.display="none";
    if(confirm("There is a new firmware version available. Upgrade?")){
      document.start_update.action_mode.value="apply";
      document.start_update.action_script.value="start_webs_upgrade";
      document.start_update.submit();
      return;
    }
  }
  else{
    $('update_states').innerHTML="The router's firmware is current.";
    $('update_scan').style.display="none";
  }
 }


This is in turn dependent on the isNewFW() function, which is contained within the included file http://[router]/state.js:


var isNewFW = function(FWVer){
  var Latest_firmver = FWVer.split("_");
  if(typeof Latest_firmver[0] !== "undefined" && typeof Latest_firmver[1] !== "undefined" && typeof Latest_firmver[2] !== "undefined"){
    var Latest_firm = parseInt(Latest_firmver[0]);
    var Latest_buildno = parseInt(Latest_firmver[1]);
    var Latest_extendno = parseInt(Latest_firmver[2].split("-g")[0]);
    current_firm = parseInt('3.0.0.4'.replace(/[.]/gi,""));
    current_buildno = parseInt('374');
    current_extendno = parseInt('4422-gc83c78f'.split("-g")[0]);
    if((current_buildno < Latest_buildno) || (current_firm < Latest_firm && current_buildno == Latest_buildno) || (current_extendno < Latest_extendno && current_buildno == Latest_buildno && current_firm == Latest_firm)) {
      return true;
    }
  }
  return false;
}


But we are missing something. Where do the values for webs_state_update, webs_state_upgrade, webs_state_error, and webs_state_info come from? And where do the values isNewFW() compares them to come from? Something is happening on the backend before the web service serves up these pages to the browser.

So we dig deeper. Telnet into the router (which requires enabling the telnet daemon) and poke around. It turns out the asp and js files reside at /www, and they look a bit different from the client-side appearance.

Specifically, instead of hard values for state and version information, they look a bit like this:


var webs_state_update = '<% nvram_get("webs_state_update"); %>';
var webs_state_upgrade = '<% nvram_get("webs_state_upgrade"); %>'
var webs_state_error = '<% nvram_get("webs_state_error"); %>';
var webs_state_info = '<% nvram_get("webs_state_info"); %>';


nvram_get is not found on the filesystem, but nvram is, and it accepts a parameter of get. Each of the variables above is a valid argument for nvram get. So that explains where the web configuration files get the values to evaluate. It also explains why the web config script believes the firmware is up to date: 


[email protected]:/bin# nvram get webs_state_info
3004_374_979-gbc8961e


isNewFW() is comparing the existing firmware (currently 3004_374_2050) against the value returned by nvram, and since 2050 is newer than 979, the web script says we're good. That would be fine, except that ASUS released 3004_374_4422 last week to fix a serious flaw in the AiCloud service. So, is 3004_374_979-gbc8961e erroneously hard-coded into this version of the firmware?

That was my first though, but no. I deleted the webs_state_info value from nvram and ran the check again, and the value was set back to the erroneous value. It was getting that value from somewhere. Back to the drawing board.

I did not have a non-switching hub handy, so could not easily insert a sniffer between the router and my ISP. Netstat on the router never showed any connection on the WAN side - it only showed LAN-side connections. But the router log give me a clue: at the moment that I ran the update check, the following showed up in the log:


Feb 19 11:46:04 rc_service: httpd 323:notify_rc start_webs_update


Back to telnet. I found a script /usr/sbin/webs_update.sh. This script uses wget (a handy command-line "web browser") to retrieve the file http://dlcdnet.asus.com/pub/ASUS/LiveUpdate/Release/Wireless/wlan_update_v2.zip
(note that webs_update.sh has some logic to select from among 4 files, depending on the state of the router). The contents of this file are:

RT-AC68U#FW3004100#EXT0-g0f3bacc#URL#UT4208
RT-AC66U#FW3004374#EXT979-gbc8961e#URL#UT4208
RT-AC56U#FW3004374#EXT339-gfa80738#URL#UT4208
RT-AC53U#FW3004100#EXT0-g0f3bacc#URL#UT4208
RT-AC52U#FW3004100#EXT0-g0f3bacc#URL#UT4208
RT-N66U#FW3004374#EXT979-gbc8961e#URL#UT4208
RT-N65U#FW3004374#EXT1317-g17e5f52#URL#UT4208
RT-N56U#FW3004374#EXT979-gbc8961e#URL#UT4208
RT-N53#FW3004374#EXT311-g6d4f56e#URL#UT4208
RT-N18U#FW3004100#EXT168-g50fb114#URL#UT4208
RT-N16#FW3004374#EXT979-gbc8961e#URL#UT4208
RT-N15U#FW3004374#EXT168-g50fb114#URL#UT4208
RT-N14U#FW3004374#EXT1667-g0005ce2#URL#UT4208
RT-N14UHP#FW3004374#EXT1631-gf2dd1d9#URL#UT4208
RT-N10PV2#FW3004100#EXT168-g50fb114#URL#UT4208
DSL-N55U#FW3004374#EXT1397-g3827650#URL#UT4208
DSL-N55U-B#FW3004374#EXT1397-g3827650#URL#UT4208
WL-330NUL#FW3-0-0-30#EXT0-46e615099#URL#UT1-0-3-2
DSL-N66U#FW1063#EXT#URL#UT4208
DSL-N55U-C1#FW1049#EXT#URL#UT4208
DSL-N16U#FW1059#EXT#URL#UT4208
DSL-N14U#FW1058#EXT#URL#UT4208
DSL-N12E-C1#FW1058#EXT#URL#UT4208
DSL-N12U-C1#FW1058#EXT#URL#UT4208
DSL-N10-C1#FW1049#EXT#URL#UT4208
AiCam#FW10109_194#EXT#URL#UT

This explains the failure to detect the new firmware: ASUS never updated the server files, so the server was reporting that a firmware 3 revs back was the latest available.

More significantly though, I discovered that the router update scripts (/usr/sbin/webs_update.sh and /usr/sbin/webs_upgrade.sh) use a cleartext, non SSL query to http://dlcdnet.asus.com/pub/ASUS/wireless/ASUSWRT/ for updated firmware, and that there is no validity check after downloading. The only check the router performs is to confirm the downloaded firmware is appropriate to the router model. There is no check to verify the firmware in fact came from ASUS and not a malicious third party. In this scenario, if an attacker inserted themselves between the router and the ISP, they could easily conduct a MITM attack to provide a malicious firmware upgrade to consumers.

At a minimum, ASUS needs to provide sha1 or md5 hashes for all updates, and needs to keep the wlan_update files current with the latest firmware revision. It would be preferable to also sign the updates with a digital certificate, and to have the router verify the certificate before installing updates.

So for now, my recommendation if you use an ASUS wireless router with the stock ASUS firmware, is to manually install the newest firmware available from support.asus.com/download. For the more technically inclined, DD-WRT or Tomato are open-source alternatives - just keep in mind that if you don't follow the instructions correctly, loading an alternative firmware is a great way to brick a device.

02/24/2014 update - It looks like Asus has updated their server table, and released a newer firmware update that gives a notification when a newer firmware is available. Definitely a step in the right direction. I'll be curious to see how quickly (or if) they address the lack of code validation. It is still possible to serve a malicious firmware to an ASUS RT- series router.

Version 3.0.0.4.374.4561
DescriptionASUS RT-AC66R Firmware version 3.0.0.4.374.4561
Security related issues:
- Force changing FTP from anonymous to account mode after firmware upgraded.
- Patched IPv6 user interface from Merlin's build.

UI
- Fixed IE and Firefox compatibility issues.
- Network map will show notification when newer firmware available.
File Size
25,53 (MBytes)2014.02.21 update

Do you have something to add? A question you'd like answered? Think I'm out of my mind? Join the conversation below, reach out by email at david (at) securityforrealpeople.com, or hit me up on Twitter at @dnlongen

4 comments:

  1. Is it me or does the javascrip on the Asus site in the search not work?

    ReplyDelete
  2. Yes there is definitely a problem to search at ASUS website. I found it by going here: http://www.asus.com/Networking/RTN66U/#support and then selecting Windows 8 (some work, others dont load anything).

    ReplyDelete
  3. Do you by any change run Bitcoin-Qt on your computers? There is some very odd behaviour on it, even after the latest patch.

    I posted the following on Ars:

    ---
    I have an update on this one. It seems that it also affected the way I browse and the speed I am getting for certain things.

    I came home from a holiday, the same day this article was posted. Today, I started my Bitcoin client to download blocks and be up to date. The speed of the download of blocks was so to say extremely slow. We are looking at 2+ min per block. I am used to getting at least 1 block a sec on my current network.

    At some point the block completely stopped working.

    For some reason I remembered this article, checked by N66U router firmaware and decided to upgrade. Voila! 3 minutes later, the Bitcoin client goes wild and starts downloading blocks in the same speed I am used to.

    Related problem? Certainly seems to be, as the download started the very same moment I was done upgrading.

    Disclosure: I dont have any of the AI Cloud, or any other Cloud services enabled. My router was doing nothing but router my traffic. No USB harddrive connected to it, no anything out of the ordinary simple useage.

    Edit 1: I just went and upgraded the router one more time after posting this. It seems that it doesnt automatically download the latest version, but up to the latest possible version. I am now apprently fully up to date after trying to upgrade one more time and it finally told me I am on the latest version. Everything seems to be working smooth still.
    ---

    This was before I saw a post to your blog, where I downloaded the file manually and installed it on my router. The result is however that my Bitcoin-Qt application is now back into slow mode, not being able to sync up with the network, even if I manually connect to a supposed fast seed node.

    It would not surprise me this attack is Bitcoin related as thats what they go for these days. Just FYI, as everything runs smooth, but that I am back to having discrepancies with Bitcoin.

    ReplyDelete

Whois David?

My photo

I have spent the better part of two decades in information technology and security, with roots in application developer support, system administration, and network security. My specialty is cyber threat intelligence - software vulnerabilities and patching, malware, social networking risks, etc. In particular, I strive to write about complex cyber topics in a way that can be understood by those outside the infosec industry.

Why do I do this? A common comment I get from friends and family is that complex security topics give them headaches. They want to know in simple terms how to stay safe in a connected world. Folks like me and my peers have chosen to make a profession out of hacking and defending. I've been doing this for the better part of two decades, and so have a high degree of knowledge in the field. Others have chosen different paths - paths where I would be lost. This is my effort to share my knowledge with those that are experts in something else.

When not in front of a digital screen, I spend my time raising five rambunctious teens and pre-teens - including two sets of twins. Our family enjoys archery, raising show and meat rabbits, and simply enjoying life in the Texas hill country.

For a decade I served as either Commander or a division leader for the Awana Club in Dripping Springs, Texas; while I have retired from that role I continue to have a passion for children's ministry. At the moment I teach 1st through 3rd grade Sunday School. Follow FBC Dripping Springs Kids to see what is going on in our children's ministries.