SSH Port Forwarding Cheatsheet (Graham Helton)
- title
- SSH Port Forwarding Cheatsheet (Graham Helton)
- type
- summary
- summary
- Red-team-flavored walkthrough of SSH's -L/-R/-D/-J/-A/-g/-t flags, the ~? runtime console, and the config-file Match keyword
- parent
- ssh-port-forwarding
- tags
- ssh, networking, security, red-team
- sources
- ssh-cheatsheet-grahamhelton
- created
- 2026-05-21
- updated
- 2026-05-21
Graham Helton's reference page for working through SSH options he learned the hard way during red-team engagements. Three hosts recur throughout: campfire.int (the operator's machine), vuln-server.int (the foothold), internal-web.int (the loopback-only target). Everything is demonstrated against an HTTP service but applies to any TCP service.
The mnemonic running through the whole page: -L keeps the local port on the Left of the address pair, -R keeps the local port on the Right. Once that sticks, the rest is bookkeeping.
The five forwarding shapes
Local (-L): ssh -N -f -L 1337:127.0.0.1:80 root@internal-web.int. Operator binds local port 1337; traffic comes out as port 80 on the SSH server. Used when the target speaks only on its loopback and the operator has SSH there.
Remote (-R): ssh -N -f -R 3000:127.0.0.1:80 root@vuln-server.int. The SSH server (vuln-server.int) binds port 3000; traffic comes out as port 80 on the operator's host. Used to expose a service from a network the operator is inside but the SSH server's network can't directly reach.
Dynamic (-D): ssh -N -f -D 8080 root@vuln-server.int. Operator binds a local SOCKS5 listener; the SSH server is the egress. Pair with /etc/proxychains.conf's socks5 127.0.0.1 8080, or Firefox's "Manual proxy configuration โ SOCKS v5". DNS-over-SOCKS is unreliable enough that Helton uses raw IPs in his curl examples.
Jumphost (-J): ssh -J a@hop1,b@hop2 c@target. Comma-separated chain; auth happens at each hop. The path in the post is campfire.int โ vuln-server.int โ internal-web.int โ dns.int.
Agent forwarding (-A): ssh -A -J root@vuln-server.int root@internal-web.int. Pushes the local ssh-agent socket along the hop chain so the destination can use the operator's loaded keys without a copy. Carries real risk โ see ssh-agent-forwarding-risk.
The triple -N -f shows up in nearly every example. -N says no command, -f backgrounds the session; together they create a forward without a shell tying up the terminal.
The other flags
-g (gateway mode): ssh -N -f -g -L 2222:localhost:22 root@internal-web.int. By default a -L listener binds 127.0.0.1; -g makes it bind 0.0.0.0 so other hosts can hit it. Turns the SSH server into a pivot for anyone on its LAN.
-t (force TTY): ssh user@host -t top. Runs an interactive command on the remote with a real TTY allocated. Without it, curses-style programs fail.
The ~? runtime console
Once inside an SSH session, ~? (tilde-question on a fresh line) opens the escape menu. Two practical uses:
~.โ kill the session immediately. Useful when the shell is wedged.~Cโ open the SSH command-line inside the running session. From there-D 8080retroactively adds a dynamic forward, so a session opened as a normal shell can become a SOCKS pivot mid-session without disconnecting.
This works because tilde-prefixed sequences are intercepted by the local SSH client before they reach the remote side.
SSH config file
~/.ssh/config lets the operator pre-register hosts with their non-default options. Helton's example:
host internal-web.int
User root
IdentityFile /home/smores/ssh_agent/internal-web-no-pw
Port 2222
Lookup order: command-line flags win over config, config wins over defaults. Running ssh graham@internal-web.int overrides the config's User root.
The non-obvious keywords:
ProxyJumpโ same as-J.ForwardAgentโ same as-A.IdentityFileโ same as-i.Matchโ conditional config blocks. Helton's example evaluatesexport | grep PROXYME=TRUEand only applies the block when the grep exits 0. Lets a single host entry behave differently based on environment variables, network, hostname, or any exec test.
scp and most SSH-derived utilities read this file by default; if not, -F ~/.ssh/config forces it.
Key management one-liners
ssh-copy-id -i internal-web user@hostuploads the matching.pubto the remote's~/.ssh/authorized_keys.ssh-keygen -t ecdsa -b 521generates an ECDSA-P521 keypair (RSA is the default; longer/non-RSA is the usual recommendation).ssh-keygen -lf <keyfile>prints fingerprint and bit length.
Why it's a red-team reference
The framing is offensive but the techniques are vendor-neutral OpenSSH behavior. SSH is the canonical living-off-the-land tool โ every Unix-style target has the client, sshd is on most servers, every packet looks like normal admin traffic. The forwarding modes turn it into a layer-4 pivot, a SOCKS proxy, and a credential-replay surface without ever installing anything.
For the agent-forwarding security writeup Helton mentions, see ssh-agent-forwarding-risk.
See also
- ssh-port-forwarding โ the four-flag taxonomy in one place
- ssh-agent-forwarding-risk โ why
-AandForwardAgentneed scrutiny - living-off-the-land โ pre-installed-tool attack patterns
- graham-helton-blog โ the author's site