SOCKS5 tunneling over HTTP and HTTPS is now a standard technique in adversary post-exploitation playbooks. When an attacker deploys Chisel or Ligolo-NG on a compromised host, they establish a persistent reverse tunnel that proxies arbitrary TCP traffic through what looks like normal web connections. Endpoint controls and basic network monitoring rarely catch this. If you’re not specifically hunting for tunneling artefacts, it’s easy to miss.

This guide covers the detection approach for both tools across three layers: process behaviour, network telemetry, and host artefacts.

MITRE ATT&CK Coverage

  • T1090.001 — Proxy: Internal Proxy
  • T1090.002 — Proxy: External Proxy
  • T1572 — Protocol Tunneling

Both Chisel and Ligolo-NG implement T1572 by carrying TCP/UDP traffic inside an outer HTTP or WebSocket session. The C2 server side is a relay; the compromised host is the agent. From the network perimeter’s perspective, the tunnel looks like an established HTTPS connection to an external server.

How Chisel Works

Chisel is a Go-based HTTP tunnel tool with SOCKS5 proxy capability. The attacker runs a server (chisel server) on internet-accessible infrastructure and drops a client binary on the compromised host. The client calls back to the server over HTTP/HTTPS with WebSocket upgrade and establishes a bidirectional tunnel. The server can then route arbitrary traffic through the compromised host.

The binary is a single statically compiled Go executable. It doesn’t require administrative privileges for basic operation. In common deployment, the client binary is dropped to a writeable path like %TEMP%, C:\Windows\Temp, or a user’s AppData folder and executed directly.

Default connection string pattern: chisel client https://<attacker>:<port> R:socks

How Ligolo-NG Works

Ligolo-NG is also Go-based, but differs architecturally from Chisel. It uses a dedicated TUN interface on the attacker’s proxy server and routes traffic more cleanly — making the compromised network appear as a directly routed network segment. The agent on the compromised host connects outbound to the attacker’s proxy server; the proxy server creates virtual interface routes that make the internal network accessible without needing to bind SOCKS5 locally.

This design makes Ligolo-NG harder to detect than Chisel because it doesn’t expose a local SOCKS5 port on the compromised host. All tunnel traffic is handled inside the agent process.

Process-Level Detection

Chisel Binary Execution

Chisel leaves detectable process artefacts. The command line will typically contain the server address and the R:socks or socks directive.

Sigma Rule — Chisel Client Execution:

title: Chisel Tunneling Tool Execution
id: 8f2b3a1c-d4e5-4f6a-b7c8-9d0e1f2a3b4c
status: experimental
description: Detects execution of the Chisel HTTP tunneling tool
references:
  - https://github.com/jpillora/chisel
logsource:
  category: process_creation
  product: windows
detection:
  selection_img:
    Image|endswith:
      - '\chisel.exe'
      - '\chisel64.exe'
  selection_cmd:
    CommandLine|contains|all:
      - 'client'
      - 'R:socks'
  selection_cmd_alt:
    CommandLine|contains|all:
      - 'client'
      - ':socks'
  condition: selection_img or selection_cmd or selection_cmd_alt
falsepositives:
  - Legitimate network testing tools with similar command patterns
level: high
tags:
  - attack.command_and_control
  - attack.t1572
  - attack.t1090.002

Ligolo-NG Agent Execution

Ligolo-NG’s agent binary connects to a relay server with a specific -connect flag pattern.

Sigma Rule — Ligolo-NG Agent:

title: Ligolo-NG Agent Execution
id: 2c4d6e8f-0a2b-4c6d-8e0f-1a3b5c7d9e0f
status: experimental
description: Detects execution of the Ligolo-NG tunneling agent
references:
  - https://github.com/nicocha30/ligolo-ng
logsource:
  category: process_creation
  product: windows
detection:
  selection_img:
    Image|endswith:
      - '\agent.exe'
      - '\ligolo.exe'
  selection_cmd:
    CommandLine|contains:
      - '-connect'
      - '-relay'
      - 'ligolo'
  selection_parent_suspicious:
    ParentImage|endswith:
      - '\cmd.exe'
      - '\powershell.exe'
      - '\wscript.exe'
      - '\cscript.exe'
    Image|endswith: '\agent.exe'
  condition: selection_img or selection_cmd or selection_parent_suspicious
falsepositives:
  - Generic agent.exe naming may produce false positives — tune on ParentImage context
level: high
tags:
  - attack.command_and_control
  - attack.t1572

Network-Level Detection

HTTP/WebSocket Upgrade Patterns

Chisel uses WebSocket upgrade requests over HTTP/HTTPS. The upgrade handshake is visible in proxy logs and network captures as an HTTP 101 Switching Protocols response with Upgrade: websocket headers. Long-lived WebSocket connections to newly registered domains or IP addresses should be investigated.

KQL — Defender for Endpoint, Suspicious Long-Lived WebSocket:

DeviceNetworkEvents
| where Timestamp > ago(24h)
| where ActionType == "ConnectionSuccess"
| where RemotePort in (8080, 8443, 9090, 4444, 1080, 3000)
    or RemoteUrl contains "websocket"
| summarize 
    SessionCount = count(),
    TotalBytes = sum(SentBytes + ReceivedBytes),
    Duration = max(Timestamp) - min(Timestamp)
    by DeviceId, DeviceName, RemoteIP, RemotePort, RemoteUrl, InitiatingProcessFileName
| where Duration > 1h
| where InitiatingProcessFileName !in ("chrome.exe", "msedge.exe", "firefox.exe", "Teams.exe", "slack.exe")
| order by TotalBytes desc

SOCKS5 Local Listener (Chisel)

When Chisel establishes its local SOCKS5 listener, it binds a port on loopback or on the local network interface. This is visible in netstat output and in Windows firewall audit logs.

Sigma Rule — SOCKS5 Proxy Port Binding:

title: Unexpected SOCKS5 Proxy Port Binding
id: 5e7f9a1b-3c5d-7e9f-1a3c-5d7e9f1a3c5d
status: experimental
description: Detects processes binding to common SOCKS5 proxy ports (1080, 1081) outside of known proxy software
logsource:
  product: windows
  service: security
  definition: Requires Windows Firewall logging or network connection events
detection:
  selection:
    EventID: 5156
    DestinationPort:
      - 1080
      - 1081
  filter_known:
    Application|contains:
      - 'chrome'
      - 'firefox'
      - 'proxifier'
      - 'widecap'
  condition: selection and not filter_known
falsepositives:
  - Legitimate SOCKS proxy software
level: medium
tags:
  - attack.command_and_control
  - attack.t1090.001

Host Artefact Detection

Unusual Go Binary in Temp Paths

Both tools are statically compiled Go binaries. Go binaries have detectable characteristics: they’re large (typically 5–15MB for a single-tool binary), and they contain Go runtime strings visible in binary analysis. A Go binary appearing in %TEMP%, %APPDATA%, or C:\Windows\Temp with outbound network connections is worth investigating.

KQL — Sentinel/MDE, Executable in Temp Paths with Network Activity:

let SuspiciousPaths = dynamic(["\\Temp\\", "\\AppData\\Roaming\\", "\\AppData\\Local\\Temp\\"]);
DeviceProcessEvents
| where Timestamp > ago(24h)
| where FolderPath has_any (SuspiciousPaths)
| join kind=inner DeviceNetworkEvents on DeviceId
| where DeviceNetworkEvents.InitiatingProcessFileName == ProcessName
| where DeviceNetworkEvents.RemoteIPType == "Public"
| where ProcessName !in ("msiexec.exe", "OneDriveSetup.exe", "WindowsUpdate.exe")
| project Timestamp, DeviceName, ProcessName, FolderPath, RemoteIP, RemotePort
| order by Timestamp desc

Prefetch and Execution Evidence

Windows Prefetch records execution of binaries from non-standard paths. The presence of prefetch entries for chisel.exe, agent.exe, or any Go binary executed from %TEMP% provides forensic evidence of execution even if the binary has been deleted.

Threat Hunting Baseline

For regular hunting sweeps, the following Kusto query identifies persistent outbound connections to low-prevalence external IPs, which is the behavioural signature of a tunneling tool’s keep-alive traffic:

DeviceNetworkEvents
| where Timestamp between(ago(7d) .. now())
| where ActionType == "ConnectionSuccess"
| where RemoteIPType == "Public"
| summarize 
    ConnectionCount = count(),
    UniqueDevices = dcount(DeviceId),
    FirstSeen = min(Timestamp),
    LastSeen = max(Timestamp)
    by RemoteIP, RemotePort, InitiatingProcessFileName
| where ConnectionCount > 50
| where UniqueDevices == 1
| where InitiatingProcessFileName !in (
    "svchost.exe", "chrome.exe", "msedge.exe", "firefox.exe",
    "Teams.exe", "Slack.exe", "OneDrive.exe", "MicrosoftEdgeUpdate.exe"
)
| order by ConnectionCount desc

Single-device, high-frequency connections to a public IP from a non-browser process are a reliable indicator of tunneling or C2 beaconing.

References