Linksys RVS4000 Hacking – Launching a shell.

Remember when CompUSA went out of business? Well if you don’t then you missed a great opportunity to buy cool gear cheap the last few days they were open. I got quite a haul myself and spent less than $400! This includes my Garmin StreetPilot c580 GPS unit and my Linksys RVS4000 which is the main focus of this article. I used this router for a long while before I got into playing with it after hearing about flaws in the Linksys software allowing shell access. Now I’m spending time trying to figure out what cool stuff could be done with it and I’m going to share my knowledge with you!

In this first article about hacking the RVS4000 I’ll cover how to enable telnet (utelnetd) through the hidden feature in their software. Help you somewhat secure this telnet daemon. I’ll also show you a cool flaw in their front-end web software that could be used to run shell commands if you lock yourself out of telnetd! Note that my version of the RVS4000 firmware is V1.1.14.

*WARNING* – I’m not liable if you brick your router.

I. Starting utelnetd and accessing telnet.

There is a hidden feature inside the RVS4000’s Linksys web interface that can enable telnet (utelnetd). It looks like Linksys hid this feature from their interface, but did not actually remove it from the /www.eng directory where the Linksys interface is stored.

Open your browser and browse to http://192.168.1.1/Hidden_telnet.htm (change ip if using a different subnet). You should bookmark this page in case you need to access it again! You should see a set of radio buttons on this page. Set telnet to “enable” and click “Save Settings”.

*WARNING*Do not stop following this tutorial here! If you do nothing to secure the telnet daemon it WILL allow ANYONE to access the router as the administrative “root” user even on the WAN side of the network! If you are not going to secure it you should either disable it after use or not use it at all!

In my examples I’m going to use a Linux server I host at work, but you can telnet to the router via Windows as well. I believe that PuTTY for Windows can connect via telnet and you can download it here.

Once utelnetd has been enabled you should be able to use the ‘telnet’ binary on your Linux machine (or other telnet client on Windows) to connect to the router:

diamond ~ # telnet –redacted—
Trying –redacted—…
Connected to –redacted—.
Escape character is ‘^]’.

BusyBox v1.00 (2007.09.12-05:31+0000) Built-in shell (ash)
Enter ‘help’ for a list of built-in commands.

#

As you can see you are now at a busybox prompt on your router. Try out some commands:

ls -al /bin/
ls -al /sbin/
ls -al /usr/bin/
ls -al /usr/sbin/

Those are most of the binaries available on the router. You can play around with them to get system info and you should also explore the system later. Note that /www.eng/ contains the web interface which you could also play with! For now I would recommend going to step two of the guide and securing the telnet access!

II. Securing utelnetd via iptables.

Notice: I’m going to assume for this section of the guide that you are at least somewhat familiar with iptables or have at least used it once or twice. It’s probably simple enough for even a total novice to figure out, but I would refrain from messing with anything that I haven’t covered if you’re a newbie. You can definitely break the configuration and make your router’s functionality break.

If you ran the command listing /usr/sbin you would have noticed that there is an ‘iptables’ binary. First check out the iptables setup:

iptables -L -n

This should show you the iptables configuration. You may wish to save the output somewhere. INPUT and OUTPUT chains should be the focus of this part of the guide. They should look something like this depending on your router configuration before we make changes:

# iptables -L INPUT -n
Chain INPUT (policy DROP)
target     prot opt source               destination
ACCEPT       tcp  —  0.0.0.0/0            0.0.0.0/0       tcp dpt:23
ACCEPT     esp  —  0.0.0.0/0            0.0.0.0/0
ACCEPT     udp  —  0.0.0.0/0            0.0.0.0/0          udp dpt:4500
ACCEPT     udp  —  0.0.0.0/0            0.0.0.0/0          udp dpt:500
DROP       tcp  —  0.0.0.0/0            0.0.0.0/0          state NEW tcp flags:!0x16/0x02
ACCEPT     all  —  0.0.0.0/0            0.0.0.0/0          state RELATED,ESTABLISHED
INPUT_UDP  udp  —  0.0.0.0/0            0.0.0.0/0
INPUT_TCP  tcp  —  0.0.0.0/0            0.0.0.0/0
ACCEPT     icmp —  0.0.0.0/0            0.0.0.0/0
ACCEPT     all  —  0.0.0.0/0            0.0.0.0/0          state NEW

And OUTPUT:

# iptables -L OUTPUT -n
Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
ACCEPT     icmp —  0.0.0.0/0            0.0.0.0/0
DROP       icmp —  0.0.0.0/0            0.0.0.0/0          state INVALID

You should figgure out from which computer (and it’s IP) you will be connecting to telnet and if you will be connecting to the router from the LAN or WAN side and what that IP will be. If you will use the computer you are reading this on and it’s not behind your router you should see your IP address at the bottom of this page. If you will use another computer that is also not behind your router you could use ipconfig on Windows or ifconfig on Linux or browse to this site to figure out it’s IP address. If you will use a computer that IS behind your router then use ipconfig via cmd (Start->Run then type ‘cmd’ to open cmd) or ifconfig from shell to find the LAN IP address of that computer.

For the destination (router’s IP address) the ip address you will be connecting to should be either 192.168.1.1 (unless you are using a different subnet) if the computer connecting to the router is behind the router or the router’s WAN IP address (from your ISP) if the computer connecting to the router is outside your network.

At this point you should have two things written down. This is how I will refer to them:

SRC IP = Source IP Address, the address of the computer connecting to the router via telnet as seen by the router it’s connecting to.
DST IP = Destination IP Address, the address of the router as seen by the computer connecting to it.

Example if connecting from within the router’s network:

SRC IP = 192.168.1.100
DST IP = 192.168.1.1

Example if connecting from outside the router’s network:

SRC IP = –redacted—
DST IP = –redacted—

Here are the commands you will need to run on your router (depending on it’s iptables configuration so use your head!):

iptables -I INPUT 2 -p tcp -s 192.168.1.100 -d 192.168.1.1 –sport 513:65535 –dport 23 -m state –state NEW,ESTABLISHED -j ACCEPT

iptables -I OUTPUT 2 -p tcp -s 192.168.1.1 -d 192.168.1.100 –sport 23 –dport 513:65535 -m state –state ESTABLISHED -j ACCEPT

iptables -I INPUT 3 -p tcp -d 192.168.1.1 –dport 23 -j DROP

iptables -D INPUT 1

The reason we are deleting the 1st rule in the INPUT chain at the end is to remove the accept all for port 23. Hopefully you used the right IP’s for your connection and you stayed connected. If you failed and locked your self out you can have Linksys re-add the 1st rule by disabling and re-enabling the telnet daemon via the hidden URL I showed you before. Once you have verified the rules as working you can also add:

iptables -I OUTPUT 3 -p tcp -s 192.168.1.1 –sport 23 -j DROP

To block outbound connections on port 23 as well just in case! You didn’t want to do this before in case you locked your self out, because the Linksys utility would not automatically remove that rule from the chain for you when re-enabling.

Here is what you should be looking at after this process is complete:

# iptables -L INPUT -n
Chain INPUT (policy DROP)
target     prot opt source               destination
ACCEPT     tcp  —  –redacted—         –redacted—       state NEW,ESTABLISHED tcp spts:513:65535 dpt:23
DROP       tcp  —  0.0.0.0/0            –redacted—      tcp dpt:23
ACCEPT     esp  —  0.0.0.0/0            0.0.0.0/0
ACCEPT     udp  —  0.0.0.0/0            0.0.0.0/0          udp dpt:4500
ACCEPT     udp  —  0.0.0.0/0            0.0.0.0/0          udp dpt:500
DROP       tcp  —  0.0.0.0/0            0.0.0.0/0          state NEW tcp flags:!0x16/0x02
ACCEPT     all  —  0.0.0.0/0            0.0.0.0/0          state RELATED,ESTABLISHED
INPUT_UDP  udp  —  0.0.0.0/0            0.0.0.0/0
INPUT_TCP  tcp  —  0.0.0.0/0            0.0.0.0/0
ACCEPT     icmp —  0.0.0.0/0            0.0.0.0/0
ACCEPT     all  —  0.0.0.0/0            0.0.0.0/0          state NEW

And OUTPUT:

# iptables -L OUTPUT -n
Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
ACCEPT     icmp —  0.0.0.0/0            0.0.0.0/0
ACCEPT     tcp  —  –redacted—         –redacted—       state ESTABLISHED tcp spt:23 dpts:513:65535
DROP       tcp  —  –redacted—         0.0.0.0/0          tcp spt:23
DROP       icmp —  0.0.0.0/0            0.0.0.0/0          state INVALID

Your IP’s will be different. I’m using my server to connect to my router’s WAN IP address. You should be able to test that this system worked by trying to connect to the router’s telnet from another machine either to it’s WAN IP or LAN IP. If an IP that you did not add to the rules is able to connect something broke or you forgot to delete that first chain. If you got locked out something broke. Re-read the article! Do not leave your telnet open to the world, because it’s a BAD IDEA!

III. Flaw in Linksys router management web front-end.

This flaw is what allowed finding the Hidden_telnet.htm file and it can help you out if you lock your self out or have other problems. I did not come up with this method, but instead I tried the bug that someone else found on a different Linksys router’s software.

First you will need to browse to http://192.168.1.1/ (or your router’s appropriate subnet) and log in to the router. You should then go to the “Administration” tab. Now select “Diagnostics” from the tab within the “Administration” section. You should see a feature called “TraceRoute Test”. This tool is normally used to run trace routes to other hosts to troubleshoot network info. In reality it just runs the traceroute utility on the server and echoes out the output.

The cool thing (from our perspective) is that Linksys developers did not sanitize any of the data input into this form! This means we can enter something like:

;/bin/ls /www.eng/

In the window that pops up you should now see the files in /www.eng/ after a few seconds. This is where you can see that Hidden_telnet.htm file. In fact you can do everything (other than edit text convienently via vi) that you can via telnet, but it’s not convenient. It can save you if you lock your self out though!

IV. The future!

I’m expecting to write at least one more (if not several) articles on this topic as I further explore the RVS4000 router. I’m curious as to what kind of apps can be ported to it and what we can do with it. I would like to accomplish several things:

1. More binaries found on standard distributions. We need grep, less, nano/pico, wget, cut, find and others!

2. Proper user authentication. There is currently no mkpasswd/passwd binary at all on the server and no /etc/shadow file. Telnet just dumps you to root.

3. More features such as traffic monitoring (preferably with graphs).

4. Traffic monitoring via snort or at least port tcpdump to it!

5. I’d like to run bash as well as I do not like busybox.

Until then I hope someone finds this article of some use and plays around. Any cool results submitted as a comment in my blog would be appreciated!