SSH Port Forwarding and Tunneling on Linux
SSH port forwarding turns a compromised Linux host into a pivot point, exposing services in internal network segments that are otherwise unreachable from your attacker machine. Three forwarding modes cover the main use cases: local forwarding to reach an internal service, remote forwarding to expose your listener into the target network, and dynamic forwarding to proxy arbitrary traffic through the host.
All examples assume you have valid SSH credentials or a key for the pivot host.
Local Port Forwarding
Forwards a port on your attacker machine to a host and port reachable from the pivot.
After connecting, traffic to 127.0.0.1:$LPORT on your machine is forwarded through $TARGET_IP to INTERNAL_HOST:INTERNAL_PORT.
Practical example — reaching an internal web admin panel at 10.10.20.5:8080 through a pivot at $TARGET_IP:
Now open http://127.0.0.1:8080 locally. All traffic goes through the pivot.
-N prevents a shell from opening — use it when you only need the tunnel. Drop -N if you want both a shell and the tunnel active.
Local Forwarding to Localhost Services
Use local forwarding to reach services bound to 127.0.0.1 on the pivot host itself — these are invisible from outside:
Then connect your local MySQL client to 127.0.0.1:$LPORT to interact with the remote MySQL as if it were local.
Remote Port Forwarding
Forwards a port on the pivot host back to a listener on your attacker machine. Use this to receive a reverse shell or callback from a host deep inside the network that cannot reach you directly.
Any connection to 127.0.0.1:PIVOT_PORT on the pivot is forwarded back to $LHOST:$LPORT on your machine.
From the pivot, trigger a reverse shell pointing to 127.0.0.1:PIVOT_PORT — the connection comes back to your listener.
Dynamic Port Forwarding — SOCKS Proxy
Dynamic forwarding creates a SOCKS proxy on your attacker machine. All traffic sent through the proxy is forwarded by the pivot to any destination it can reach — no need to specify a single target host and port.
Configure proxychains to use the SOCKS5 proxy. Edit /etc/proxychains4.conf:
[ProxyList]
socks5 127.0.0.1 $LPORT
Then prefix any command with proxychains to route it through the pivot:
SOCKS proxying does not support ICMP — use -Pn with nmap and TCP scan types only.
Keeping Tunnels Alive
SSH tunnels drop when the connection idles. Add keepalive options:
For a persistent tunnel that reconnects on failure, use autossh:
Tunneling Without SSH Access — Chisel
When you have a shell but no SSH access to the pivot (no credentials, port filtered, or SSH not installed), chisel provides the same forwarding capabilities over HTTP.
On your attacker machine:
On the pivot:
This opens a SOCKS proxy on your attacker machine at port 1080 by default. Use with proxychains as above.
Multiple Hops
To reach a host two hops away — through pivot A to pivot B to the target — chain forwards:
Or use the ProxyJump option for cleaner chaining:
ProxyJump is the modern equivalent of the older ProxyCommand nc approach and handles the chaining internally.
References
-
OpenBSD manual page Full reference for -L, -R, -D forwarding options, -N, -J ProxyJump, and connection options.
-
jpillora/chiselgithub.com/jpillora/chisel (opens in new tab)
GitHub Fast TCP/UDP tunnel over HTTP with SOCKS5 proxy support. Used when SSH port forwarding is not available.
-
haad/proxychainsgithub.com/haad/proxychains (opens in new tab)
GitHub proxychains — routes TCP connections through SOCKS4/5 or HTTP proxies.
Was this helpful?
Your feedback helps improve this page.