Reverse SSH Tunnel

Linux SSH

Das SSH mehr als nur ein simples Protokoll ist, habe ich bereits in einem anderen Blogbeitrag erwähnt.

Hin- und wieder steht man vor der Herausforderung, das man auf Geräte/Dienste zugreifen möchte, welche hinter einer Firewall stehen, welche man nicht selbst konfigurieren kann. Auch ein Setting hinter einem NAT (Network Address Translation) wie zum Beispiel bei dir zu Hause ist denkbar, was den Zugriff von außen verhindert. Allerdings kannst du hier gezielt mit Port-Weiterleitungen einen Zugriff ermöglichen. Jedoch mit einem gravierenden Nachteil – diese Portweiterleitungen stehen dann allen Nutzern im Internet zur Verfügung, da die wenigsten SOHO-Router eine weitergehende Konfiguration ermöglichen und ggf. nur ausgewählte Clients mittels ACL zulassen.

Unser Ziel: Wir wollen von einem Clients aus dem GROBI (GROßes Böses Internet) auf einen Web-Server , der hinter einer Firewall/NAT steht, zugreifen und dessen Dienste nur für uns erreichbar machen. Es geht hier also nicht um einen Webserver, der Inhalte für das WWW bereitstellt, sondern der eher Inhalte nur in deinem heimischen LAN verfügbar halten soll (lokales KODI zum Beispiel). Die eine Möglichkeit ist natürlich, das du eine VPN-Verbindung zu deinem Router herstellen und dann mit einer lokalen IP auf dessen Inhalte zugreifen könntest.

Die andere Möglichkeit, welche ich dir hier zeige, ist, das der Web-Server im heimischen LAN eine SSH-Verbindung zu einem eigenen Server im Internet aufbaut und weitere Dienste (wie zum Beispiel HTTP/HTTPS) durch diese Verbindung durchtunnelt. Prinzipiell lassen sich sämtliche Netzwerk-L4-Protokolle durch diese Verbindung tunneln. Einzige Voraussetzung: die Firewall muss SSH ausgehend (also vom LAN zu WAN) erlauben, ansonsten musst du den SSH-Server dahingehend „verbiegen“, das er auf einen anderen Port lauscht, den die Firewall erlaubt.

Eine solche Technik wird auch von etlichen HAK5-Produkten genutzt, um die gesammlte Daten einer zu testenden IT-Infrastruktur auf die HAK5-Cloud zu bringen. Alle diese Geräte bauen eine Reverse-SSH-Verbindung zu einem zentralen Server auf. Der Pentester, welcher dann wiederum SSH-Zugang zu diesem Cloud-Server hat, kann diese Geräte durch die bestehenden SSH-Reverse-Tunnel administrieren und Daten extrahieren, auch wenn er keinen physikalischen Zugang mehr zu diesen hat. Alles was er sicherstellen sollte, ist, das auch nach einem Reboot die Geräte selbständig eine Reverse-SSH-Verbindung zum Cloud-Server aufbauen.

Ein Reverse-SSH-Tunnel ist also eine vom Remote-Gerät (hinter einer Firewall/NAT) aufgebaute SSH-Verbindung, durch diese der Administrator auf Dienste, die lokal auf diesem Remote-Gerät laufen, zugreifen kann, ohne das überhaupt Ports nach außen (ins WAN) geöffnet wurden. Man muss dem Revese-SSH-Tunnel lediglich die Information mitgeben, welcher lokale Port remote verfügbar gemacht werden soll.

Neugierig? Dann schauen wir uns mal das folgende Lab an:

                                      +----------+
                                      |//////////|
+-----------+       +---------+       |//////////|       +--------+
|ssh/web    |       |ssh      |       |//////////|       |web     |
|client     |  WAN  |server   |  WAN  |/firewall/|  LAN  |server  |
|           +-------+         +-------+//////////+-------+        |
|User: alice| ----> |User: bob| <----------------------- |        |
|2.2.2.2    +-------+3.3.3.3  +-------+//////////+-------+10.0.0.2|
|Port 81    |       |Port 8080|       |///nat////|       |Port 80 |
+-----------+       +---------+       |//////////|       +--------+
                                      |//////////|
                                      +----------+

Wenn auf dem WEBCLIENT (links) im Browser die Seite http://127.0.0.1:81 aufgerufen wird, dann soll die Webseite dargestellt werden, die auf http://10.0.0.2:80 (rechts) zu erreichen ist, also hinter der Firewall/NAT. Der WEBSERVER macht seine Website unter Port 8080 auf dem SSH-SERVER (mitte) bekannt, der WEBCLIENT holt die Seite unter http://3.3.3.3:8080 ab.

Was musst du alles tun, damit du deinen heimischen Webserver aus dem GROBI erreichst, ohne an der Firewall auch nur irendetwas konfigurieren zu müssen?

WEBCLIENTSSH-SERVERWEB-SERVER
– ssh client installieren
– bei Bedarf eine ssh-Verbindung zum ssh-Server aufbauen
– ssh server installieren– ssh client installieren
– web-server installieren
– Reverse-ssh-Verbindung aufbauen und Ports (Dienste) tunneln
– autostart für reverse-ssh einrichten

Dann legen wir mal los:

Zuerst installieren wir auf dem SSH-SERVER den Dienst OPENssh-Server und prüfen, ob dieser läuft.

# apt update
...
# apt install openssh-server
...
# systemctl status ssh
 ssh.service - OpenBSD Secure Shell server
   Loaded: loaded (/lib/systemd/system/ssh.service; enabled; vendor preset: enabled)
   Active: active (running) since Wed 2021-06-16 10:09:55 CEST; 23h ago
     Docs: man:sshd(8)
           man:sshd_config(5)
 Main PID: 546 (sshd)
    Tasks: 1 (limit: 4915)
   Memory: 9.1M
   CGroup: /system.slice/ssh.service
           └─546 /usr/sbin/sshd -D

Ein SSH-Client sollte standardmäßig auf jeden System bereits vorinstalliert sein, wir bauen testweise von beiden Seiten (WEBCLIENT und WEB-SERVER) eine Verbindung zu dem SSH-SERVER auf und testen die Verbindung.

$ ssh root@3.3.3.3
The authenticity of host '3.3.3.3 (3.3.3.3)' can't be established.
ECDSA key fingerprint is SHA256:jCl+n/PrVUuU5WxXFX+hg05a98Ih2LHcPcwqnHi6CuA.
Are you sure you want to continue connecting (yes/no/[fingerprint])?

WELCOME, this is the SSH-SERVER!

ssh-server~$ 

Als nächstes kannst du direkt auf dem SSH-Server dessen Konfiguration dahingehend anpassen, damit unser Reverse-SSH-Tunnel später auch aktiv werden kann.

ssh-server~$ nano /etc/ssh/sshd_config
ClientAliveInterval 30
ClientAliveCountMax 99999
GatewayPorts yes
AllowTcpForwarding yes

ssh-server~$ exit
$

Die beiden ClientAlive-Zeilen stellen sicher, das die Verbindung nicht einfach wegen Inaktivität abgebaut wird. GatewayPorts yes erlaub es, den SSH-SERVER als Gateway zu nutzen, sprich IP-Pakete werden vom WEBCLIENT zum WEB-SERVER duchgereicht. AllowTcpForwarding yes erlaubt das Tunneln anderer Protokolle wie z.B. https innerhalb des SSH-Tunnel. Das war es auch schon. Datei mit STRG-X speichern und beenden. Anschließend kann die Verbindung zum SSH-SERVER getrennt werden.

Als nächtes konfigurierst du den Reverse-SSH-Tunnel auf dem WEB-SERVER (rechte Seite):

$ ssh bob@3.3.3.3 -L 8080:10.0.0.2:80

Nach Eingabe des Passworts für Bob wird eine ssh-Verbindung zum SSH-SERVER augebaut und der http-Port des WEB-SERVER als Port 8080 durch die bstehende ssh-Verbindung getunnelt und dort verfügbar gemacht. Glaubst du nicht? Dann logge dich mal auf dem SSH-SERVER ein und rufe dort im Browser http://127.0.0.1:8080 auf. Da Port 8080 an den SSH-Tunnel und am Tunnelende an Port 80 gebunden ist, siehst du im Web-Browser des SSH-Server die Weboberfläche des WEB-Server. Du kannst auch mittels des Befehls curl (falls du keine grafische Oberfläche auf dem SSH-SERVER hast) dir die Seite anzeigen lassen:

$ curl http://127.0.0.1:8080 #oder
$ curl http://localhost:8080

Dein Ziel ist jedoch, vom SSH-CLIENT diese Webseite aufzurufen. Also loggst du dich am SSH-CLIENT ein und startest mit folgendem Befehl einen Reverse Tunnel zum SSH-SERVER

$ ssh bob@3.3.3.3 -R 81:localhost:8080

Rufst du jetzt im Webbrowser des SSH-CLIENT http://127.0.0.1:81 auf, siehst du ebenfalls die Weboberfläche des WEB-SERVER. BAAMMM!

Das Prinzip und Syntax des Tunneling ist immer wieder dieselbe:

  • ssh user@ip ssh-Verbindung zum Ziel aufbauen
  • -L (lokaler Tunnel) oder -R (reverse Tunnel)
  • tport:ip:sport Tunnel-Port (tport), gefolgt von IP und Quellport (sport)

Du kannst dein ssh-Kommando auch mit weiteren Optionen verfeinern. Einige der wichtigeren möchte ich hier kurz erläutern:

-p2020 bedeutet, das ein anderer Port (2020) als der Standard-Port für ssh (default 22) genutzt wird. Gerade wenn mehrere reverse-Tunnel aufgebaut werden sollen, muss für jede Verbindung ein anderer Port genutzt werden.
-f bedeutet, das ssh im Hintergrund laufen soll, das Terminal-Fenster kann anschließend also geschlossen werden
N bedeutet, das lediglich der Tunnel aufgebaut wird, aber über ssh keine Remote-Befehle entgegen genommen werden
C komrimiert die zu übertragende Daten. Abhängig von dem zu tunnelnden Protokoll kan sich das ungünstig auf die performance auswirken

Als nächtes solltest du sicherstellen, das der WEB-SERVER von sich aus, z.B. nach jedem Neustart einen Tunnel zum SSH-SERVER aufbaut. Dazu testen wir zunächst unsere Konfiguration mit allen notwendigen Optionen für einen autarken Start.

$ ssh -fNC -L 8080:10.0.0.2:80 bob@3.3.3.3

Durch diesen Aufruf mit der Option -f sollte der Tunnel auch stehen, wenn du das Terminalfenster schließt und keinen permanenten Zugang zum WEB-SERVER mehr hast (also von unterwegs).

Funktioniert? Die Herausforderung ist jetzt, das du im autarken Betrieb keine Passwortabfrage zu Gesicht bekommen wirst. Deshalb solltest du dein Zugriff auf den SSH-Server mit Zertifikaten absichern. Wie das geht, habe ich hier erläutert und führe ich jetzt nicht noch einmal explizit auf. Allerdings solltest du die Schlüssel OHNE Passphrase generieren, sonst hast du erneut das Problem mit der Benutzer-Interaktion (Abfrage Passphrase).

Als nächsten installierst du dir Autossh und schreibst ein passendes Skript, damit autossh sich um die Verbindung kümmert:

$ sudo apt install autossh
...
$ nano tunnel.sh

#!/bin/bash
/usr/bin/autossh -fNC -L 8080:10.0.0.2:80 bob@3.3.3.3

Als nächtes passt du die Rechte des Skripts (Ausführungsrechte hinzufügen) an und modifizierst die crontab:

$ chmod +x tunnel.sh
$ crontab -e

@reboot /home/bob/tunnel.sh

Das sollte es gewesen sein.

Im übrigen kannst du auf diese Art nahezu jedes andere TCP-Protokoll durch SSH tunneln, selbst SSH durch SSH, was ungeahnte Möglichkeiten eröffnet – gerade wenn eine Firewall/NAT „im Weg steht“. Viel Spaß beim Tunneling 🙂

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert