Why?.. #
..would one even need to scan using a bastion host instead of directly scanning?
For me, this was a challenge in a customer engagement. We were provided with a bastion host and even the ability to add tooling. But installing a lot of tools can be noisy, slow and cumbersome. And due to network restrictions on the customer’s end, installing a Nessus agent and centrally coordinating it was not feasible. For most tools, using a tool like proxychains-ng can enable network actions to be routed through a SOCXS proxy. This comes with a few caveats.
SOCKS does not support ICMP, it only provides a TCP proxy service - and SOCKS 5 added UDP. But still. No ICMP. Many offensive security specialists had, at some point in their career or education, also tried to use nmap and some variant of proxychains to scan through a SOCKS proxy and found some of the other restrictions there: Connect scans can work, SYN scans cannot work. SOCKS proxies don’t forward raw packets.
And then there’s all the headaches of hooking calls to sockets. LD_PRELOAD - which proxychains-ng uses - works great for dynamically linked programs using libc funcitons. But not all programs use libc or are dynamically linked.
Nessus, for one, is one of the tools that do not.
How ligolo-ng solves these issues #
Instead of hooking into shared libraries, ligolo-ng creates a network interface and relies on routing rules. It is fully decoupled from the achitecture of tools. If they use the operating system for routing, they’re compatible.
Secondly, it applies some rules to packages it receives. If an nmap scan sends SYN packages, they are translated to connect() on the bastion host and successful connects are translated back to SYN-ACK on the server. It’s just smart enough to solve common issues with pivoting via a bastion host to be useful without trying to do more that one would expect.
Requirements #
Requirements are kept to a minimum. You will need permissions to create a network interface and routing rules on the side of your scanning host. On the bastion host, the only requirements are being able to run a binary and creating an outbound connection to your scanning host. Precompiled binaries are available for virtually all desktop platforms.
Setup - Scanning host #
This guide is tested on Kali linux, where ligolo-ng is available upstream.
Excellent documentation for building from source is available in the excellent documentation maintained by nicocha30.
For laboratory environments, it’s fine to use self signed certificates. In production environments, you should use properly signed certificates with trusted certificate authorities to avoid connecting to rogue servers.
# Install ligolo-ng
sudo apt install ligolo-ng
# Set up the network interface
sudo ip tuntap add user [your_username] mode tun ligolo
sudo ip link set ligolo up
# Replace the IP range with the target range to reach via your bastion host
sudo ip route add 10.10.0.0/16 dev ligolo
# Start ligolo
ligolo-proxy -selfcert
# wait for an agent to connect
# then, enter the session.
session
# select your session, usually it will be `1`
# and once selected, start the tunneling
tunnel_start --tun ligoloSetup - Bastion host #
This boils down to getting the agent binary either from the official GitHub repo or compiling from source - or install them via apt on Kali machines.
For laboratory environments, it’s fine to use self signed certificates. In production environments, you should use properly signed certificates with trusted certificate authorities to avoid connecting to rogue servers.
# The default listening port of ligolo-ng is 11601
ligolo-agent -connect [your.scan.server.ip]:11601 -ignore-certCleanup #
On the bastion host, cleanup is effectively complete with termination of the agent. Optionally, the agent can also be removed from the system.
On the server side, the cleanup is as simple as the setup.
killall ligolo-proxy
sudo ip route del 10.10.0.0/16 dev ligolo
sudo ip tuntap del mode tun ligoloWhat did we gain? #
We now have a fully set up machine which routes all traffic for routes created in the setup via our bastion host. In this setup, 10.10.0.0/16 was chosen.
No matter the tooling, from Nessus over nmap to netcat or telnet, connections to IPs in that range will be routed through the bastion host.
This allowed us to effectively bring our tooling to the customer without time intensive setups and debugging. There are some limitations as there always are with tunneling traffic. We found this to be immensely useful, especially in restrictive environments where adding tools must follow a struct process including whitelisting of the files’ fingerprints. One agent can help us increase capabilities massively without large modifications to the bastion host.
Conclusion #
Setting up ligolo-ng is painless and fast.
While it’s still advantageous to have your tools closer to the actual data and infrastructure, pivoting with ligolo-ng is often cheaper than building a full setup inside the customer’s location and avoids discussions about assessments being “unrealistic” due to excessive tooling. Yes, we had those discussions in the past, they happen.
There also are a lot of features, configurations and more advanced use cases which ligolo-ng can support and the best place to find out more is in their documentation.
If this was useful to you, send me a ping over on LinkedIn!