Port Forwarding — Complete Reference

What Is Port Forwarding?

Port forwarding redirects a network connection from one IP:port to another. In OSCP/pentesting, it lets you reach services on networks you can’t access directly — by bouncing traffic through a compromised pivot host.

[Attacker] ──→ [Pivot:LISTEN_PORT] ──→ [Internal Target:TARGET_PORT]

Local vs Remote Forwarding

TypeWho ListensWhat HappensUse Case
LocalYour attacker machineTraffic on your local port → pivot → internal targetReach an internal service from Kali
RemoteThe pivot/remote hostTraffic on pivot’s port → back to your machineExpose your listener through a pivot
Relay / HopThe pivot itselfPivot forwards traffic without involving Kali as SSH hostChain through a host with no SSH to Kali

Local Forward — Reach an internal service from Kali

Kali:LOCAL_PORT ──→ Pivot ──→ Internal:TARGET_PORT

You connect to 127.0.0.1:LOCAL_PORT on Kali and reach the internal target.

Remote Forward — Expose a port on the pivot

Pivot:LISTEN_PORT ──→ back to Kali:LOCAL_PORT

The pivot listens and forwards traffic back to Kali. Used when an internal machine needs to connect out to you.


📌 1) SSH Port Forwarding

See SSH Tunneling for the full SSH pivot reference.

Local Port Forward (-L) — Reach internal service from Kali

# Syntax: -L LOCAL_PORT:TARGET_HOST:TARGET_PORT pivot_user@PIVOT_IP
ssh -L 8080:172.16.0.10:80 user@PIVOT_IP -N -f
 
# Access the internal web server:
curl http://127.0.0.1:8080
gobuster dir -u http://127.0.0.1:8080 -w wordlist.txt
 
# Forward RDP to internal host
ssh -L 3389:172.16.0.10:3389 user@PIVOT_IP -N -f
xfreerdp3 /u:Administrator /p:Password1 /v:127.0.0.1:3389
 
# Multiple forwards in one SSH command
ssh -L 8080:172.16.0.10:80 -L 4433:172.16.0.10:443 user@PIVOT_IP -N -f
 
# Forward to a host only the pivot can reach (not the pivot itself)
ssh -L 8080:192.168.1.50:80 user@PIVOT_IP -N -f

Remote Port Forward (-R) — Expose your listener on the pivot

# Syntax: -R PIVOT_PORT:LOCAL_HOST:LOCAL_PORT pivot_user@PIVOT_IP
ssh -R 4444:127.0.0.1:4444 user@PIVOT_IP -N -f
 
# Now any process on the pivot connecting to 127.0.0.1:4444
# reaches your Kali listener on port 4444
 
# Real reverse shell use case:
# Kali listener:
nc -lvnp 4444
# On pivot: set up the -R tunnel:
ssh -R 4444:127.0.0.1:4444 kali@KALI_IP -N -f
# Trigger reverse shell on internal target → it hits pivot:4444 → goes to Kali
 
# Expose pivot's own port to Kali
ssh -R 8080:127.0.0.1:80 user@PIVOT_IP -N -f
# Now curl http://127.0.0.1:8080 on Kali reaches the pivot's own port 80

-N = don’t run a command (tunnel only), -f = go to background.

Add a tunnel to an existing SSH session (no reconnect)

# Press: Enter ~C (that's tilde then capital C) inside an active SSH session
# You'll see: ssh>
ssh> -L 8080:172.16.0.10:80
ssh> -R 4444:127.0.0.1:4444

📌 2) Socat — Port Relay (Linux & Windows)

See Socat for the full socat reference.

Socat needs no SSH — it just relays raw TCP. Useful when you have a shell but no SSH.

Basic TCP relay (local → internal target)

# On the pivot: listen on port 8080, forward to internal target
socat TCP4-LISTEN:8080,fork TCP4:172.16.0.10:80
 
# On Kali:
curl http://PIVOT_IP:8080    # Reaches 172.16.0.10:80
 
# Relay RDP
socat TCP4-LISTEN:3389,fork TCP4:172.16.0.10:3389

Relay chain (Kali → Pivot 1 → Pivot 2 → Target)

# On Pivot 1: relay toward Pivot 2
socat TCP4-LISTEN:8080,fork TCP4:PIVOT2_IP:9090
 
# On Pivot 2: relay toward internal target
socat TCP4-LISTEN:9090,fork TCP4:192.168.1.50:80
 
# On Kali:
curl http://PIVOT1_IP:8080    # Reaches 192.168.1.50:80 via two hops

Run in background

socat TCP4-LISTEN:8080,fork TCP4:172.16.0.10:80 &
# Kill it later:
kill %1   # or: pkill socat

Windows socat (no install needed — use static binary)

REM Transfer socat.exe via HTTP, certutil, etc.
socat.exe TCP4-LISTEN:8080,fork TCP4:172.16.0.10:80

📌 3) iptables DNAT — Linux Built-in (Root Required, No Binary)

iptables DNAT rewrites the destination of incoming packets — a true kernel-level port forward. No extra tools needed, just root.

Step 1 — Enable IP forwarding

# Enable temporarily (resets on reboot)
echo 1 > /proc/sys/net/ipv4/ip_forward
 
# Or with sysctl (also temporary unless added to /etc/sysctl.conf)
sysctl -w net.ipv4.ip_forward=1
 
# Verify
cat /proc/sys/net/ipv4/ip_forward    # Should output: 1

Step 2 — Add DNAT rule

# Forward all incoming traffic on pivot's port 8080 → internal target:80
iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 172.16.0.10:80
 
# Also need MASQUERADE so return traffic routes correctly
iptables -t nat -A POSTROUTING -j MASQUERADE
 
# On Kali: access via the pivot's IP
curl http://PIVOT_IP:8080    # Reaches 172.16.0.10:80
 
# Allow forwarded traffic (if iptables FORWARD chain is DROP by default)
iptables -A FORWARD -p tcp -d 172.16.0.10 --dport 80 -j ACCEPT
iptables -A FORWARD -p tcp -s 172.16.0.10 --sport 80 -j ACCEPT

Clean up

# List rules with line numbers
iptables -t nat -L --line-numbers -n -v
 
# Delete a specific rule (e.g. rule 1 in PREROUTING)
iptables -t nat -D PREROUTING 1
 
# Flush all NAT rules (careful — removes everything)
iptables -t nat -F

Local redirect (traffic from the pivot itself)

# Redirect traffic from the pivot's localhost:8080 → internal target
iptables -t nat -A OUTPUT -p tcp --dport 8080 -j DNAT --to-destination 172.16.0.10:80

📌 4) rinetd — Persistent Config-Based Forwarder (Linux)

rinetd is a lightweight TCP/UDP port forwarding daemon configured via a file. Good for persistent or multiple rules.

Install

sudo apt install rinetd

Configure /etc/rinetd.conf

# Format: bindaddress bindport connectaddress connectport
# Bind on all interfaces, port 8080 → forward to 172.16.0.10:80
0.0.0.0 8080 172.16.0.10 80

# Forward RDP
0.0.0.0 33890 172.16.0.10 3389

# Forward SMB
0.0.0.0 4450 172.16.0.10 445

# Bind on specific interface only
10.10.10.5 8080 172.16.0.10 80

Run / Reload

# Start
sudo rinetd -c /etc/rinetd.conf
 
# Or run without modifying the system config
rinetd -c /tmp/rinetd.conf
 
# If already running as a service
sudo systemctl restart rinetd
sudo systemctl status rinetd
 
# Check it's listening
ss -tlnp | grep rinetd
netstat -tlnp | grep rinetd

One-liner (no config file — use socat or SSH instead)

Note: rinetd requires a config file — for truly temporary single-port forwarding, socat is simpler.


📌 5) Netcat Relay (No Additional Tools)

Useful when netcat is the only tool available. Uses mkfifo to create a bidirectional pipe.

Basic relay

# On pivot: relay port 8080 → internal target:80
mkfifo /tmp/backpipe
nc -lvnp 8080 < /tmp/backpipe | nc 172.16.0.10 80 > /tmp/backpipe
 
# Kali now connects to PIVOT_IP:8080 and reaches 172.16.0.10:80

With timeout / one-shot (nc without -k)

# Each connection spawns a new relay (nc closes after one connection)
# Use a loop for persistence:
while true; do
  mkfifo /tmp/bp
  nc -lvnp 8080 < /tmp/bp | nc 172.16.0.10 80 > /tmp/bp
  rm /tmp/bp
done &

Limitation: Standard netcat relays are one-connection-at-a-time. Use socat with fork for concurrent connections.

Ncat (nmap’s netcat) — persistent relay

# ncat supports --keep-open for multiple connections
ncat -l 8080 --keep-open --sh-exec "ncat 172.16.0.10 80"

📌 6) Chisel — Specific Port Forwards

See Chisel for the full Chisel reference.

Chisel can do specific port forwards (not just SOCKS) over HTTP.

# Kali server
chisel server -p 8000 --reverse
 
# Pivot client — forward specific port
# Format: R:KALI_PORT:TARGET_HOST:TARGET_PORT
chisel client KALI_IP:8000 R:8080:172.16.0.10:80
 
# Kali now reaches 172.16.0.10:80 via 127.0.0.1:8080
 
# Multiple forwards in one command
chisel client KALI_IP:8000 R:8080:172.16.0.10:80 R:3389:172.16.0.10:3389
 
# Forward without reverse (if Kali can reach pivot directly)
chisel server -p 8000           # On pivot
chisel client PIVOT_IP:8000 8080:172.16.0.10:80   # On Kali

📌 7) netsh portproxy — Windows Built-in (No Binary)

See Windows Tunneling for the full Windows tunneling reference.

REM Local forward: listen on Windows pivot, forward to internal host
netsh.exe interface portproxy add v4tov4 listenport=8080 listenaddress=0.0.0.0 connectport=80 connectaddress=172.16.0.10
 
REM Allow through firewall
netsh advfirewall firewall add rule name="fwd8080" protocol=TCP dir=in localport=8080 action=allow
 
REM View all rules
netsh.exe interface portproxy show all
 
REM Delete a rule
netsh.exe interface portproxy delete v4tov4 listenport=8080 listenaddress=0.0.0.0
 
REM Clean up firewall rule
netsh advfirewall firewall delete rule name="fwd8080"
 
REM Flush all port proxy rules
netsh.exe interface portproxy reset

📌 8) Meterpreter portfwd

See Meterpreter for the full Meterpreter reference.

# Inside a meterpreter session:
 
# Local forward — Kali port 8080 → internal target:80
meterpreter > portfwd add -l 8080 -r 172.16.0.10 -p 80
 
# List forwards
meterpreter > portfwd list
 
# Delete a forward
meterpreter > portfwd delete -l 8080
 
# Flush all
meterpreter > portfwd flush
 
# Then on Kali:
curl http://127.0.0.1:8080    # Reaches 172.16.0.10:80

📌 9) Plink.exe — Remote/Local Forward (Windows, No OpenSSH)

See Windows Tunneling for the full Plink reference.

REM Local forward — Windows pivot → Kali SSH → internal target
echo y | plink.exe -l kali_user -pw password -L 8080:172.16.0.10:80 KALI_IP -N
 
REM Remote forward — expose Windows port 3389 on Kali port 9090
echo y | plink.exe -l kali_user -pw password -R 9090:127.0.0.1:3389 KALI_IP -N

📌 Quick Scenario Reference

ScenarioBest ToolCommand
Kali can SSH to Linux pivotSSH -Lssh -L 8080:INTERNAL:80 user@PIVOT -N -f
Need to expose Kali listener via pivotSSH -Rssh -R 4444:127.0.0.1:4444 user@PIVOT -N -f
No SSH, binary upload possible (Linux)Socatsocat TCP4-LISTEN:8080,fork TCP4:INTERNAL:80
No SSH, no binary, root on Linuxiptables DNATiptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to 172.16.0.10:80
Multiple persistent rules on Linuxrinetd/etc/rinetd.conf0.0.0.0 8080 172.16.0.10 80
Truly nothing available on LinuxNetcat relaymkfifo /tmp/bp; nc -lvnp 8080 < /tmp/bp | nc 172.16.0.10 80 > /tmp/bp
Windows pivot, no binary, admin shellnetsh portproxynetsh interface portproxy add v4tov4 ...
Windows pivot, binary upload possibleChisel.exechisel.exe client KALI:8000 R:8080:INTERNAL:80
Windows pivot, old, no SSH clientPlink.exeplink.exe -L 8080:INTERNAL:80 kali@KALI_IP -N
Metasploit session openMeterpreterportfwd add -l 8080 -r INTERNAL -p 80
HTTP/firewall bypass neededChiselchisel client KALI:8000 R:8080:INTERNAL:80

📌 Quick OSCP Cheat Sheet (Copy/Paste)

# ─── LOCAL FORWARD (reach internal service from Kali) ──────────────────
 
# SSH
ssh -L 8080:172.16.0.10:80 user@PIVOT_IP -N -f
 
# Socat (on pivot)
socat TCP4-LISTEN:8080,fork TCP4:172.16.0.10:80 &
 
# iptables (on Linux pivot, root)
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 172.16.0.10:80
iptables -t nat -A POSTROUTING -j MASQUERADE
 
# Chisel (on pivot, Kali runs server)
chisel server -p 8000 --reverse          # Kali
chisel client KALI_IP:8000 R:8080:172.16.0.10:80   # Pivot
 
# Meterpreter
portfwd add -l 8080 -r 172.16.0.10 -p 80
 
# netsh (Windows pivot, admin)
netsh.exe interface portproxy add v4tov4 listenport=8080 listenaddress=0.0.0.0 connectport=80 connectaddress=172.16.0.10
 
# ─── REMOTE FORWARD (expose your listener on the pivot) ────────────────
 
# SSH
ssh -R 4444:127.0.0.1:4444 user@PIVOT_IP -N -f
 
# Plink (Windows)
echo y | plink.exe -l kali_user -pw password -R 4444:127.0.0.1:4444 KALI_IP -N
 
# ─── CLEANUP ───────────────────────────────────────────────────────────
 
# Kill background socat
pkill socat
 
# Remove iptables rule
iptables -t nat -F
 
# Remove netsh rule (Windows)
netsh.exe interface portproxy reset