Map
โ†‘SSH port forwarding

SSH Port Forwarding Cheatsheet (Graham Helton)

Wiki summarysshnetworkingsecurityred-team โ†ณ show in map Markdown
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
tags
ssh, networking, security, red-team
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 8080 retroactively 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 evaluates export | grep PROXYME=TRUE and 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@host uploads the matching .pub to the remote's ~/.ssh/authorized_keys.
  • ssh-keygen -t ecdsa -b 521 generates 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