Firewalls are great, but don't rely on them as your only network security!
I've written about SSH before—often even. But for the Linux user, SSH is one of those tools that is so incredibly flexible, everyone should know and understand it inside and out. For this article, I decided to put on my black hat and demonstrate how convenient, and terrifying, SSH can be.
Most articles on SSH start with forwarding X11 traffic or demonstrating the SOCKS proxy feature. I want to start with something a little more creepy and a whole lot more awesome. The premise is this: you have a computer inside a firewalled, NAT'd network, and you want to access it remotely. If you're the sysadmin, you can just forward a port on the firewall into the computer. If you're not, however, you can use SSH to open a tunnel for you automatically. This does require a few things:
You need a server running SSH with a public IP address. I use my co-located Raspberry Pi in Austria, but you can use your home connection as long as you set up a Dynamic DNS entry in case your IP changes.
The firewalled network has to allow outgoing SSH connections. Most do, but if you can't SSH out from inside the firewall, you might have to do something creative like run SSH on port 443 on your server. (That port is usually open for HTTPS traffic, and since it's encrypted, it's tougher to sniff out your naughty deeds.)
You need key pairs set up for password-less logins from the computer inside the firewall to your server with the public IP. (Here's a demo I did back in 2009 on how to set up SSH key pairs: https://www.youtube.com/watch?v=R65HTJeObkI.)
Once you have the prerequisites in place, the process is a simple one-liner. First, the command, then the explanation:
ssh -N -R 0.0.0.0:2222:127.0.0.1:22 user@remotehost
The -N flag tells SSH that you don't want an interactive shell; you just want to establish the connection. That means in order to take the tunnel down, you simply press Ctrl-C. It can become confusing if you have an open terminal connected interactively to a remote server. The tunneling still will work, but if you inadvertently type exit, it logs you out and kills the tunnel.
The -R 0.0.0.0:2222:127.0.0.1:22 portion of the command is where the magic happens. What you're doing is creating a reverse tunnel, which allows anyone who can access your public IP server to ssh in to the server behind the firewall. In English, the command is saying, “Hi remote server, I'm stuck behind a firewall. Will you listen on port 2222 for anyone trying to connect, and if they do, please forward the traffic to me on my port 22.”
The command can get creepier too. In my example, I just forwarded traffic to the public port 2222 to the internal port 22 behind the firewall. But if you were to change the command like this:
ssh -N -R 0.0.0.0:3389:192.168.1.5:3389 user@remotehost
You've now created a public-access tunnel directly to the Windows RDP server on 192.168.1.5 behind the firewall. Anyone on the Internet who connects their RDP client to the remote host's IP address will get the RDP login screen from 192.168.1.5. Freaked out yet?
One of the problems with this setup is the relative instability of the Internet. If the SSH connection is severed, the tunnel collapses, and you no longer can reach the computer inside the firewall. Thankfully, there's a really great tool to help with that too: AutoSSH.
Having a diabolical tunnel to an internal network across the globe is only awesome until it stops working. SSH is a finicky protocol, so the smallest blip over the Internet can cause the connection to fail. If you launch the SSH command with AutoSSH, however, it will monitor your connection and restart it if things go wrong. AutoSSH will keep trying too, so even if the network is down for an extended time, when it comes back up, the SSH connection will be re-established.
AutoSSH is available for just about every major distribution, but it has to be installed on the computer inside the firewall, because that's where the connection has to initiate from. How I do it is basically put something like this in my crontab to run on @reboot:
autossh -M 41000 -f -N -R 0.0.0.0:2222:127.0.0.1:22 user@remotehost
Only two of the flags are for AutoSSH; the others get handed off to SSH itself. Basically, the -M 41000 establishes a monitor port for AutoSSH to use. It's possible to use SSH's built-in ability to monitor a connection, but I've had very bad luck with it. Using AutoSSH's -M flag seems to work the best. It doesn't matter what port you select, as long as it's not currently in use on either computer. The next flag, -f, just tells AutoSSH to run in the background and monitor the connection. The rest of the line is similar to what I showed typed above.
I used to write complex bash scripts to check for connectivity, and kill off then restart SSH, but using AutoSSH is much more efficient and reliable. I've been using it for years, and it is rock-solid. The most I've ever had to do is kill off defunct SSH connections on the public server if for some reason I can't connect. AutoSSH then happily creates a new connection, and I'm back in business.
I personally use this sort of setup to access internal servers that aren't accessible directly from the Internet. I don't like to open ports directly into internal servers if possible, so if I can grant myself access to multiple internal servers by SSH'ing to a remote, unrelated IP on a random port, I feel a little better about it.
I also use this sort of setup to expose multiple Web servers from inside a network to the outside. Figure 1 shows the basic premise. The command looks similar to the example above, but with multiple -R flags.
autossh -M 41000 -f -N -R 0.0.0.0:8001:192.168.1.10:80 \ -R 0.0.0.0:8002:192.168.1.20:80 user@remotehost
To note, that's all on one line, I just used the backslash so it formats better. Basically, by using multiple SSH reverse tunnels (the -R flags), internal Web servers are accessible by pointing the browser to http://remotehost:8001, http://remotehost:8002 and so on. I then use a reverse proxy (see my column in the August 2013 issue for details) to connect to those strange URLs with standard virtual hostnames. SSH is such a powerful, flexible tool, that its uses are seemingly unlimited! With that great power comes great responsibility though, because SSH allows you to do some pretty creepy things.
You may have noticed that using an SSH tunnel provides you only with specific access to specific ports spelled out with the tunnel directives. It is possible to pass multiple -R flags, but it's tough to do that on the fly, because the command is performed on the computer inside the firewall. If you need to access the entire network behind the firewall, that's where sshuttle comes into play.
I've mentioned sshuttle in past issues of Linux Journal, but when used in conjunction with the tunnels I just described how to create, it turns into something that should be impossible, but isn't. Once you have the reverse tunnel established, using the processes above, the command to get you access to the entire firewalled network is another one-liner:
sshuttle -D -r user@remotehost:2222 192.168.1.0/24
As a reminder, this runs on your home workstation, not on the computer behind the corporate firewall. (See Figure 2 for a complete picture.) The -D flag tells sshuttle to run as a dæmon in the background. The -r flag tells it what remote server to connect through—in this case, user@remotehost on port 2222. Then the last part describes the internal network behind the firewall. This is something you'll need to know or figure out from your internal workstation. It will ask you for your sudo password, and then establish a network route through the SSH tunnel.
Basically, you've now not only accessed the workstation inside the firewall, but you have full access to anything that workstation has access to as well—from anywhere on the Internet.
If you are feeling a bit like the nerdy hero in a modern espionage film, well yeah, I get it. There are some legitimate reasons to create tunnels like this, although admittedly an actual VPN is usually the “proper” way to go about it. It's important for those of us in charge of networks to realize how easy it is to gain access to internal systems, however. It's possible to block access like this at the firewall level, but honestly, there's always ways around the firewall if you're able to initiate internally. Plus, using draconian blocking methods will just inconvenience your users to the point of making them revolt. So what's a network admin to do?
Obviously, learning about network security is crucial. The reasons VLANs and NAC (network access control) systems exist is to prevent undesired access to various systems. When you're designing or redesigning your network, don't assume an external firewall will protect you from computers outside your network. Disgruntled employees, malware victims or nerdy employees like me will find a way to access systems from the outside. Make sure their point of entry doesn't give them access to systems they shouldn't have access to in the first place.
Today's little tutorial isn't really hacking. We're not doing anything the protocols aren't designed to do. Heck, all the tools are available pre-packaged in your distribution! I don't want anyone to spend too much effort trying to block my “attack”, because it's not an attack at all. It's just using the tools available in exactly the way they're supposed to be used.
SSH is my favorite command-line utility. It can do so many things, from transferring files to tunneling X11 traffic. As I described here, you also can reroute traffic over tunnels giving you access to systems that shouldn't easily be accessible. Ultimately, I hope learning about SSH will get you interested in network security, because until you understand the danger, there's not much motivation to learning and implementing such systems. Until next time, happy tunneling!