Julius Kaiser
Leipzig, Germany
jkdata@mailbox.org
Title: Reverse SSH tunnels...
Status: Informational
Published: 30 Nov 2023
Updated: 08 Jan 2024
Here’s how to leverage reverse SSH tunnels to access hosts behind a firewall and/ or (CG)NAT over a public network.
external host | internal network
|
example.com | 192.0.2.50
------------ | ------------ --------------
|ssh-server| | |ssh-client| |winrdp:3389 |
|(ext. IP) |<--ssh--|(int. IP) |--lan--|(int. IP) |
------------ | ------------ --------------
A | B C
"Broker" "Jumphost" "Target"
To allow (remote) port forwarding, set these two options in /etc/ssh/sshd_config
both on Broker (A) and Jumphost (B):
GatewayPorts yes # Allow remote hosts to connect to forwarded ports
AllowTcpForwarding yes # Allow TCP forwarding
Gateway ports
can be omitted on Jumphost (B) if all you need is to reach services that are running directly on it.
The ssh-client command is executed on host B (“Jumphost”):
jumphost$ ssh user@example.com -N -R 5000:192.0.2.50:3389
^^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^^
B A C
ssh
- Invoke ssh-clientuser@example.com
- Connect to Broker (A)-N
- Do not start a shell-R
- Provide a reverse tunnel5000:192.0.2.50:3389
forward all traffic that arrives on Broker (A) port 5000 to Target (C) port 3389.Use any independent host that is able to reach Broker (A) and access a service (Windows RDP in this example) running on Target (C):
mstsc /v example.com:5000
If a service (e.g. a local web server) that you want to make reachable is running directly on Jumphost (B), just use localhost
instead of Target’s (C) IP address:
jumphost$ ssh -N -R 7000:localhost:80 user@example.com
The example above runs the SSH command in the foreground of your TTY, blocking your session on the jumphost. To continue working on the jumphost, e.g. to spawn more tunnels, consider using the ControlMaster & ControlPath functionality of SSH:
-f
- Requests ssh to go to background-M
- Places the ssh client into ‘‘master’’ mode for connection sharing-S
- Specifies the location of a control socket for connection sharingSee man ssh_config
paragraphs ControlMaster & ControlPath for more information.
Example:
jumphost$ ssh user@example.com -f -M -S ~/session1 -N -R 5000:192.0.2.51:3389
jumphost$ ssh user@example.com -f -M -S ~/session2 -N -R 5000:192.0.2.52:3389
To close the tunnels:
jumphost$ ssh -S ~/session1 -O exit example.com
jumphost$ ssh -S ~/session2 -O exit example.com
Instead of using session1
etc. as filenames for the sockets, I like to use the hostnames of my targets.
Internal services are usually not ment to be publicly reachable.
Firewalling Broker (A) to only allow connections to forwarded ports (:5000) from trusted sources substantially minimizes risks here.
Also may consider to use e.g. a shell script that removes tunnels nightly or something like this..