Bypassing corporate firewall with reverse ssh port forwarding

Probably lots of you are behind some sort of very restrictive corporate firewall. Unable to access your office pc from home because of firewall policies. In normal cases this scenario is more than welcomed. No outsiders should be allowed to access internal parts of secure network! Ideally companies will setup secure VPN access thus allowing its employees to access their work computers and do some work remotely. What if you aren’t one of the lucky ones having such option? You desperately need to access your office pc?

The problem

current


As shown on the picture above, we have our office PC behind very restrictive corporate firewall connected to Internet. Firewall will not allow any traffic originating from Internet to internal network except previously initiated traffic. Meaning you can contact remote hosts on Internet from your office PC and they can respond, but remote computers can’t initiate connection to your office PC. This is of course huge problem if you have to access your work materials on office PC from your home. Additionally corporate firewall will only allow certain traffic from your office PC to remote hosts. Meaning you can only establish FTP, SSH, HTTP, POP3… communications, all other ports are blocked.

So how can you access your office PC? One way is to setup corporate VPN access allowing secure connections to internal network. Another method is to setup a port forwarding on corporate firewall so it redirects certain ports to your office PC. But if you don’t have the means to accomplish any of this then the only way to do it is to use ssh tunnels and reverse port forwarding.

The solution

So if we can only contact remote hosts on certain ports, the solution would be to contact remote hosts via allowed port and piggyback the connection on already established link.

reverese-ssh

Something like shown on the picture above. Fortunately we can do this with ssh, all we need to do is met some requirements.

Real life example

I will assume that home PC is connected via dynamically assigned IP address. First thing you will need to make sure you have ssh server installed on your home PC and it should be accessible from Internet. If you have some NAT routers, be sure to forward port 22 to your home PC. Secondly you will need to setup a dyndns account so you can connect to your home PC regardless of IP address changes. Now the goal will be to connect to ssh server on our office PC. so the port in question will be 22 if you wish to forward another port change it in your configuration accordingly.

For the purpose of this example i will name my home PC: bhome.dyndns.com office computer name will be bwork.office.com

bwork computer uses private IP range of 192.168.0.0/24 with address 192.168.0.100

So if the firewall is preventing outside connections to our bwork computer we must initiate connection from it.

We can do this with simple ssh command:

ssh -R 2210:localhost:22 bhome.dyndns.com

So what just happened here?

We are initiating ssh connection “ssh” with reverse port forwarding option “-R” which will then open listening port “2210:” who is going to be forwarded back to localhost‘s port “:22″ and all this will happen on remote computer “bhome.dyndns.com”.

This connection represents the green line in the diagram above, and it’s a legit connection as far as corporate firewall is concerned.

So if we now open up a terminal on bhome computer, and type in:

ssh -p 2210 localhost

we will try to connect to localhost (bhome.dyndns.com) on port 2210. Since that port is setuped by remote ssh connection it will tunnel the request back via that link to the bwork.office.com computer. This is the red line on the diagram above. Looking from firewall’s perspective it’s a legit traffic, since it is responding traffic on already initiated link from bwork computer.

Real life example 2

What if your home computer is not always on-line? Or perhaps you wish to access your office computer from multiple locations? For this you will have to have some dedicated server or VPS outside the corporate firewall.

reverese-ssh2So to accomplish this we will use the same command as previously, only this time we will open up a reverse ssh tunnel to remote server or VPS.

For the purpose of this example we will name the server bserver.outside.com with IP 89.xxx.xx.4

ssh -R 2210:localhost:22 bserver.outside.com

again this will open up reverse ssh tunnel to the machine 89.xxx.xx.4 (bserver.outside.com). So when we login to the server and issue the command:

ssh -p 2210 localhost 

we will end up with bwork computer’s ssh login prompt.

Can I use this previously established reverse ssh tunnel to the server to directly connect to my office computer?


Of course, but some slight modifications are required.

By default ssh tunnels only bind to local address, and can be accessible only locally. Meaning, in the example above, you can’t just type:

ssh -p 2210 bserver.outside.com

on your home PC and be connected to your office PC

If you run:

netstat -ntl 

on bserver you will see that the port 2210 is only listening on 127.0.0.1 IP address. To get it listen on interface connected to Internet we must enable GatewayPorts option in ssh server’s configuration.

By default GatewayPorts are disabled in sshd, we can simply enable them:

nano /etc/ssh/sshd_config

then add:

GatewayPorts clientspecified

save the file and restart sshd:

/etc/init.d/ssh restart

we could have just enable GatewayPorts by typing On instead of clientspecified, that would route any ssh tunnel to network interface. This way we can control which tunnel will be accessible from outside, and on which interface.

So if we initiate reverse ssh tunnel like this:

ssh -R 89.xxx.xx.4:2210:localhost:22 bserver.outside.com

we will have bserver listening on port 2210 on network interface bound to ip 89.xxx.xx.4 and forwarding all traffic via established tunnel to bwork computer. If you omit the 89.xxx.xx.4 address from the command above server will again listen on port 2210 only on local loopback interface. If you have multiple network interfaces on server be sure to select the one you can connect to.

reverese-ssh3So now when we run:

ssh -p 2210 bserver.outside.com 

from our home PC we will initiate ssh connection on port 2210 towards server bserver.outside.com (blue line). Server will then forward that traffic to office PC (red line) via the previously established reverse ssh tunnel (gren line). Of course you will have to open up port 2210 on server’s firewall to be able to connect.

Some more fun with reverse tunnels.

But i have a printer behind that corporate firewall. How can i connect to it? Easy… remember the first example? the command ssh -R is taking 5 arguments of which 4 are mandatory

ssh -R [bind_address:]port:host:hostport

bind_address is the network address on which port will be listening, and forwarded to host (connected to network from which reverse tunnel originated) on hostport.

so if we issue the command like this on our bwork pc:

ssh -R 89.xxx.xx.4:2211:192.168.0.10:631 bserver.outside.com

we will get something like this:

reverese-ssh4so again we have previously established reverse ssh tunnel listening on port 2210 to channel the ssh connection towards office PC. Now with this new command we established the reverse ssh tunnel (yellow line) towards bserver which will listen for incoming connections on port 2211. When the home pc makes a data connection to port 2211 on bserver (brown line) it is then forwarded to office PC (black line) which is then redirected towards office printer at address 192.168.0.10 on port 631 (violet line). Remember, all this traffic is passing trough corporate firewall as legit traffic, even if the illustration perhaps shows otherwise.

Automating the task

So by now we should have covered the basics on how to bypass corporate firewall in order to get to your office computer and network equipment. Now ssh -R isn’t really practical, it consumes one terminal, and as soon as it shuts down there is no tunnel and no outside connectivity for that matter. The easiest thing to do is putting a cron job that will connect to remote server if the connection fails, office computer reboots etc.

First of all generate ssh keys, and add them to ssh-agent so that script won’t ask you for remote server’s password all the time.

Next we will add two extra parameters to our command -N and -f so that the connection goes into the background.

the command will look like:

ssh -N -f -R [bind_address:]port:host:hostport 

next we need a shell script that will be triggered by the cron. For this example we will use the Real life example 2.

#!/bin/sh
COMMAND="ssh -N -f -R 89.xxx.xx.4:2210:localhost:22 bserver.outside.com"
pgrep -f -x "$COMMAND" > /dev/null 2>&1 || $COMMAND

now edit this code so it suits your needs, and save it in your home dir as reverse_ssh_tunnel.sh
Now we need to add a crontab entry which will trigger this script every 5 minutes.

crontab -e

and add:

*/5 * * * * /bin/sh /home/username/reverse_ssh_tunnel.sh

If you are connecting to different user name on remote server you can edit your commands so they look like:
ssh -R [bind_address]:port:host:host_port username@remote_host

Related posts:

  1. SSH port forwarding
  2. Secure synergy setup
  3. SSH basics
  4. Howto create rsync server

  1. Fantastic post!
    Thank you very much!

    That GatewayPorts option was exactly what I have been after for years now!
    Thank you.

    Rather than cron, have you thought about autossh ?
    http://www.harding.motd.ca/autossh/

  2. I’m glad it helps you. Yes, autossh actualy looks very nice for this job. I will try it out and include it in original post. Tnx for the info.

  3. Once you have the SSH connection established, would it be possible to initiate a VNC connection over it?

  4. Yes you just have to correct those commands to suit your port range. Virtualy any trafic can be tunneled this way.

    • Mike C
    • December 17th, 2009

    You Rock! Awesome site.

    FWIW, I was reverse tunneling and could only connect via localhost (connections to the remote nic kept failing).

    mike@go:/etc/ssh$ telnet localhost 4007
    Trying 127.0.0.1…
    Connected to localhost.
    Escape character is ‘^]’.
    ^]

    telnet> close
    Connection closed.
    mike@go:/etc/ssh$ telnet myDomainName.com 4007
    Trying 72.14.188.90…
    telnet: Unable to connect to remote host: Connection refused

    I discovered the GatewayPorts option in ssh_config (client!) and put it in my client config. Of course this didn’t work. Then I put it in the sshd_config per your instruction with the clientspecified value. After an sshd restart, everything is good!

    Thank you!

    • Justin
    • January 2nd, 2010

    I am having a few issues with this setup.
    I CAN establish a reverse tunnel from officeComputer to remoteServer However I am unable to connect to officeComputer THRU remoteServer using the ssh -p 2210 remoteServer example.

    However if I ssh in to the remoteServer i can ssh -p officeComputerPORT localhost

    I changed the GatewayPorts on remoteServer and restarted with no change.

    when my officeComputer connects to remoteServer and I do a netstat -tnl it still shows only the l27.0.0.1 as the listening port.

    Any suggestions?

    • Can you specify what command you are using to establish a reverese tunnel from office Computer?

      • Branko, this is a great post, thank you. However I have the same issue as Justin. Let’s say I have a server (the middle man) with an IP address of 174.2.2.2, from my office box, I run:

        ssh -R 178.2.2.2:1200:localhost:22 bijan@178.2.2.2

        It connects with no problem. I also put “GatewayPorts clientspecified” in /etc/ssh/ssh_config. When I issue “netstat -an | grep LISTEN”, I see it’s listening on port 1200 for 127.0.0.1

        The problem as Justin mentioned is that when I issue:

        ssh -p 1200 officeUser@178.2.2.2

        I get the following error: “ssh: connect to host 178.2.2.2 port 1200: Connection refused”. However if I ssh into 178.2.2.2 (to port 22 with a user on it) and then issue:

        ssh -p 1200 officeUser@localhost

        It’s no problem, I login like a charm! I should say I disabled iptables, so, is it really a filtering problem or something wrong with me?

        • You should set “GatewayPorts clientspecified” in /etc/ssh/sshd_config not in /etc/ssh/ssh_config

          /etc/ssh/ssh_config is config for ssh client and /etc/ssh/sshd_config is config for ssh server running on that machine.

    • sandeep
    • January 13th, 2010

    haii,
    i am studying in college…at college computer i can’t use bit-TORRENT .because i suppose that it is blocked by college firewall………
    pls tell me how i download torrent file on college computer….

    pls help…………

    • As far as I know this setup will not work for you in this way.

      If you reverse proxy the connections trough your home computer than all traffic will go trough that tunnel, and that beats the purpose of what your trying.

    • abuiles
    • January 25th, 2010

    Hi there.

    Normally in my university 22 port is blocked, so being there I can’t get connected to my ssh account, ( I have a VPS )

    So I tried to do some port forwarding in my server, to send all the incoming request in certain port to port 22, i tried the following command.

    ssh -nNT -R somePort:myip:22 myuser@myip.com

    it didn’t work, certainly I’m doing wrong, do you know if it is possible to do something like that ?

    Any help would be really appreciated.

    • What you need to do is make sure Gatewayports are set to clientspecified in /etc/ssh/sshd_config

      On your vps run this command:

      ssh -nNT -R 0.0.0.0:2222:localhost:22 username@localhost

      Make sure you replace port 2222 with a port that is opened on your university, and replace username with your local vps username.

      After doing so make sure your vps firewall is permitting traffic on the port of your choice (2222 in this example).

      Do a quick nestat -ntl on yoiur vps, and it should show something like this:

      tcp 0 0 0.0.0.0:2222 0.0.0.0:* LISTEN

    • Christian Rishøj
    • March 5th, 2010

    Excellent post! Thorough, explanatory and extremely useful. You saved the day!

    • thehidden
    • July 23rd, 2010

    thank you for the good howto. i tried your idea with the reverse tunnel and every think works find. except of create an additional dynamic tunnel als socks proxy. can you explain please, how to do that? the tunnel is up, but no http traffic flows through. :-(

    kind regards
    thehidden

  1. July 3rd, 2009
  2. February 14th, 2010
  3. February 16th, 2010
  4. March 15th, 2010
  5. May 24th, 2010
  6. August 13th, 2010