home February 11, 2020

SSH Reverse Tunnel


A Secure, Double Encrypted, SSH Connection

A reverse ssh tunnel can be created to allow an ssh connection from an offsite machine to connect back into the work machine. The tunnel will allow you to use an existing ssh connection initiated from work, through a restrictive corporate firewall, ending at a machine at home. You can then initiate a seperate ssh connection from your home machine to localhost, back through the established ssh tunnel back to your work machine's sshd daemon. This is what we are tying to accomplish:


Initial Tunnel: work  --> WORK FIREWALL --> home port 22 [localhost:12345]

Reverse SSH:    home [localhost:12345] --> SSH TUNNEL --> work localhost:22         

NOTE: We are going to assume the following conditions are true:

The first step is to verify the following sshd forwarding and tunnel options are allowed in sshd_config on your home machine. AllowAgentForwarding and AllowTCPForwarding are "yes" by default. PermitTunnel is "no" by default. All three(3) directives must be set to "yes" in order to setup an ssh tunnel device.

calomel@HOME: vi /etc/ssh/sshd_config

AllowAgentForwarding yes
AllowTCPForwarding yes
PermitTunnel yes

Next, before leaving work for the day, create an ssh tunnel from work to home. Execute the following ssh command on your work machine to setup an ssh tunnel to your home machine going out of the work network on the standard ssh port 22. The ssh command will run in the forground and just sit in the current terminal window. To background the process, add (-f) to the ssh command. On your home machine, port 12345 on localhost will be the end of the tunnel owned by the "home_username" user.

calomel@WORK: ssh -TnN -R 12345:localhost:22 home_username@home_hostname.org

When you arrive at home, you can use the ssh tunnel initiated from work to home on localhost port 12345 to ssh back though the ssh tunnel to the sshd daemon running on your machine at work. Remember the tunnel is open on port 12345 and owned by the "home_username" user.

calomel@HOME: ssh work_username@localhost -p 12345

When you initiate the ssh connection through the tunnel the home machine's ssh client will connect through localhost port 12345 to the sshd daemon on the work machine listening on localhost port 22. You will be asked to authenticate to the work machine's sshd daemon with a username and password or you can setup an ssh key using ssh-copy-id.

Done. You should now have a shell on your work machine.

NOTE: If your organization blocks outgoing ssh check out our HAProxy to tunnel ssh through https tutorial.

Questions?

How is the reverse tunnel double encrypted ?

The initial ssh tunnel created from work to home is encrypted using the cipher negotiated by the work ssh client and home sshd server. The reverse ssh connection started by the home ssh client though localhost port 12345 to the ssh daemon listening on the work machine's localhost is encrypted using a completely separate ssh cipher negotiation.

Can I automatically setup the tunnel with a script ?

If you do not want to manually setup the reverse ssh tunnel each day or if you want the tunnel setup again when the connection is dropped we can use a script through crond.

First, setup an ssh key without a passphrase to initiate an ssh connection from work to your home machine.

calomel@WORK:  ssh-copy-id home_username@home_hostname.org

Next, copy the following script we will call "ssh_reverse_tunnel_monitor.sh" and make the script executable. Edit the script to make sure the if-then ssh command and all paths to the binaries are correct for your system. The script simply checks for the existence of the tunnel by looking for the string "12345:localhost" in the work system's process list. If the string is not found, then the tunnel is assumed to not be running and the script will execute the tunnel ssh command to setup the tunnel as a background process (ssh -f).

#!/bin/sh
set -euf
#
# moneyslow.com
#     https://moneyslow.com/html/webconf/ssh_reverse_tunnel.html
#     SSH Reverse Tunnel Monitor
#
# Run through cron on the work machine initiating
# the ssh reverse tunnel

unset VAR

PROCESS=`/bin/ps -auxf | /bin/grep "[1]2345:localhost"` || true
TEST="12345:localhost"

# if the tunnel does not exist then run the ssh command to
# initiate the reverse tunnel and send a note to syslog.

if [[ $PROCESS =~ $TEST ]];
then
    :
   #echo "DEBUG - True, tunnel running"
else
   #echo "DEBUG - False, tunnel not running"
    /usr/bin/logger "ssh reverse tunnel not running, Initiating tunnel."
    /usr/bin/ssh -f -TnN -R 12345:localhost:22 home_username@home_hostname.org
fi

Lastly, setup a cron job on the work machine to execute the monitor script whenever you wish it to run. For example, the following cron job will run every weekday between 19:00 (7pm) and 23:00 (11pm) as well as every hour on the weekend.

calomel@WORK:  crontab -e

#minute (0-59)
#|   hour (0-23)
#|   |    day of the month (1-31)
#|   |    |   month of the year (1-12)
#|   |    |   |   day of the week (0-6 with 0=Sun)
#|   |    |   |   |   commands
#|   |    |   |   |   |
00 19-23  *   *  1-5  /home/work_username/ssh_reverse_tunnel_monitor.sh
00   *    *   *  6-7  /home/work_username/ssh_reverse_tunnel_monitor.sh