[RPI] Reverse SSH tunnel (SSH port forwarding)

Have you ever wanted to remote login via ssh to your Linux box such as RPI*?
Maybe you ask yourself why should I want to do this. Many good and many bad reasons. However, I will not go deeper into reasons but create simple scenario I’m using to connect to my pPB*. It is realistic that any connection from RPI to the internet will be behind firewall or NAT so a direct connection in most cases will not so simple to achieve. This can be the fastest and most reliable way…

(For some practical usage example you can check this blog: Jenny Knafo.)

I will be using Kali Linux instead Raspbian for pPB.

Let’s make a working scenario I’m using.

Requirements:

  • RPI
  • SD card & adapter for PC
  • Server with static IP and ssh login for remoteuser (any user – I will call it remoteuser)

Download Kali image and write it to SD card:

(Full instructions with details: Kali for RPI)
I’m always downloading via torrent if available so checksum before writing to SD card. Also, take care that it is disk image and not archive – unpack if is.

Also, take care to select the correct device – in my case:

root@tkojemile:kali-linux-2018-4-rpi3-nexmon-img-xz# dd if=kali-linux-2018.4-rpi3-nexmon.img of=/dev/mmcblk0 bs=512k status=progress
4496293888 bytes (4,5 GB, 4,2 GiB) copied, 410 s, 11,0 MB/s
8583+1 records in
8583+1 records out
4499999744 bytes (4,5 GB, 4,2 GiB) copied, 432,504 s, 10,4 MB/s

Start RPI and log in with root:toor.
Clean key hosts:

root@kali:~ rm /etc/ssh/ssh_host_*
root@kali:~ dpkg-reconfigure openssh-server
root@kali:~ service ssh restart

Now you are prepared to start with the tunnel.

First, let’s create key authorization between RPI and server run ssh-keygen, follow instructions but leave the passphrase EMPTY!

root@tkojemile:kali-linux-2018-4-rpi3-nexmon-img-xz# ssh-keygen 
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): key
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in key.
Your public key has been saved in key.pub.
The key fingerprint is:
SHA256:XXXXXXXXXXXXXXXXXXXXXXXXX root@tkojemile
The key's randomart image is:
+---[RSA 2048]----+
|Eo.++=.  ..      |
|.   =oo ..       |
|   o ..- o.      |
|    o . +o       |
|   o . .k . .    |
|  . + . .* + .   |
|   o +  o.r *    |
|    =. ..+.X +   |
|   . .o .o=.+..  |
+----[SHA256]-----+

Login on your remote server and install public key from RPI. (just copy to remote /home/remoteuser/.ssh/authorized_keys or learn how to: CommingSoon)

I want to have more control than just open tunnel so I will create 3 scripts that will allow me to start tunnel on boot, restart tunnel or restart RPI whenever I want to do so. As it is a portable device there is Murphy law that says “if anything can go wrong with reverse ssh tunnel – it will go wrong” so I want to get most of the control without access to the graphical user interface.

Scripts (name it as you wish, remember to adapt cron lines)

  • tunnel.sh – will create tunnel an d
  • kill.sh
  • maintenance.sh

tunnel.sh

Let’s assume that we have access to the remote server with static IP 217.182.22.122 on standard port 22 and user that we have set up passwordless login is remoteuser.
Create script named tunnel.sh in /var/script/ directory (or any based on your practice) and paste following code:

#!/bin/bash
createTunnel() {
  /usr/bin/ssh -N -R *:27001:localhost:22 remoteuser@217.182.22.122 -p 22
  if [[ $? -eq 0 ]]; then
    echo Tunnel to the remote server created successfully
  else
    echo An error occurred creating a tunnel to the remote server. RC was $?
  fi
}

#get current tunnel pid
/bin/pidof ssh
# Checking ssh Tunnel and recreate if down
if [[ $? -ne 0 ]]; then
  echo Creating new tunnel connection
  createTunnel
fi

The script is basically set of checks before actually creating a tunnel.
Let’s explain a bit line that create tunnel:

/usr/bin/ssh -N -R *:27001:localhost:22 remoteuser@217.182.22.122 -p 22

parameters:

-N do not execute a remote command. This is useful for just forwarding ports.
-R tells the tunnel to answer on the remote side (the ssh server)
you can read more in #man ssh

*:12001:localhost:22 – on RPI we will be accepting all users on port 12001 that will come as ssh connection to RPI (in this case ssh server on RPI as localhost on standard port 22)

remoteuser@217.182.22.122 -p 22 – from RPI we will connect to the remote server as remoteuser to enable reverse connection from the remote server to RPI (without IP, as is dynamic)

kill.sh
This script gets pid of the opened tunnel and makes hard process kill in case that connection can’t be established.

ps axf | grep 27001 | grep -v grep | awk '{print "kill -9 " $1}' | sh

maintenance.sh
This script will allow us to restart tunnel or RPI completely in case of some problems.

For proper function, it requires a functional remote web server where we have access to be able to change the file it reads.

#!/bin/bash

var=$(curl -L http://www.tkojemile.com/pi/mod1)

echo $var
if [ $var = "500" ]; then
  echo "Restarting ssh... Tunnel"
  ps axf | grep 27001 | grep -v grep | awk '{print "kill -9 " $1}' |sh
elif [ $var = "404" ]; then
  echo "Restarting RPI..."
  /sbin/reboot
elif [ $var = "200" ]; then
  echo "No change... OK"
else
  echo $var
fi

Changing of file text on the remote web server we can do following:

200 – continue operation, no change needed.
404 – something is really wrong, lets completely restart RPI
500 – the tunnel is blocked or stopped working, restart tunnel

Take care to change all ports for reverse connection in all 3 scripts to your desired port (in my case 27001).

Now lets setup cron jobs to do the job for us:

1) GET info from the file on the remote server

*/1 * * * * /var/script/maintenance.sh >> /var/script/log/operations.log 2>&1

Check status in the remote file every minute (this allows to restart really fast ~1min)

2) Checking ssh Tunnel and recreate if down

*/1 * * * * /var/script/tunnel.sh >> /var/script/log/tunnel.log 2>&1

And that’s it! If all files are in place, cron running, start your RPI, CAT5 it to the router and connect from the remote server;

vedran@server:~$ ssh root@localhost -p 27001

If you want to use wireless – remember that you need to configure access point before you stay without internet (just make sure you have already configured your portable hotspot on smartphone and you will always have a way to configure new wireless AP)

Leave comments, share with needed.

(After some googling… this guy made this commercial 😀 – SSHReverse Charging)

Login from Android phone and ConnectBot:

dictionary
RPI - Raspberry Pi
pPTB - portable penetration box

tkojemile Written by:

Be First to Comment

Leave a Reply

Your email address will not be published. Required fields are marked *