Old Kit, New Kit Part 9: Pivoting — Chisel vs ssh -D / socat
This is the eighth tool-pair actually run in a series testing classic, well-documented Kali tooling against its quieter modern replacements, with a genuine look at what a lab Wazuh deployment sees from each. This pair is different from every one before it: it’s not about scanning or enumerating a target, it’s about pivoting through one — using a foothold to reach a segment that isn’t directly reachable at all. The outline’s classic baseline is actually two tools, ssh -D (SSH’s built-in dynamic SOCKS proxy) and socat (a general-purpose relay), against the modern single-purpose tunneling tool chisel. The predicted detection angle was “moderate: unusual outbound connections/process creation on the pivot host.”
Testing this properly meant building something this series hasn’t needed before: a target that genuinely isn’t reachable except through a pivot, not just a firewall rule pretending to block it.
Building a real pivot scenario
A new isolated segment, vmbr-pivotlab (10.10.20.0/24, no uplink — same pattern as the lab’s other isolated bridges), went in on the Proxmox host. A single Debian VM, hidden-target, sits on it alone, serving a placeholder page over Python’s built-in http.server on port 8080 (the first attempt tried apt-get install nginx and failed outright — the segment genuinely has no internet path, isolation working exactly as intended, not a bug). target-win2022, already used as the SMB target in Part 7 and already carrying an active Wazuh agent, got a second NIC onto the new segment and became the pivot host — chosen specifically over metasploitable2 because it’s the only lab host that can actually generate detection telemetry to check afterward.
Adding that second NIC produced this build’s first real finding: attached as virtio, it never appeared in Get-NetAdapter at all — Windows Server 2022 has no built-in VirtIO driver, so the adapter was invisible to the guest entirely. Switching the model to e1000 (matching the NIC already working on the box) fixed it immediately, no reboot required. Worth remembering for any future Windows VM in this lab: e1000, not virtio, unless VirtIO drivers are actually installed on the guest.
The meatier gotcha showed up before any of that: target-win2022’s existing, previously-working NIC on the main lab segment had simply vanished from its live config since the day before — qm config showed only a disabled adapter on the home LAN bridge, no trace of the vmbr-msflab NIC that had been enrolled as a Wazuh agent and reachable at 10.10.10.50 less than 24 hours earlier. Snapshot history ruled out a rollback as the cause; the real cause was never conclusively identified. Repointing the NIC back to the right bridge didn’t restore the IP either — the fix had to happen from the Proxmox console directly, typed by hand since noVNC has no clipboard. A reminder worth keeping from this series: don’t trust a “last known good” network config on a shared lab VM to still be what’s actually live, even a day later, especially on a box multiple different post series reuse.
With the segment built and the pivot host dual-homed, isolation checked out from Kali1: the hidden target was unreachable directly, the pivot host was reachable as expected. Three tools, one path in.
The classic baseline, part one: ssh -D
SSH’s client ships enabled on Windows Server 2022, but sshd doesn’t — turning it on is a Windows feature toggle (Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0), not dropping in a new binary, which is itself a meaningful point of comparison against the two tools that follow.
That toggle produced a real WinRM gotcha: it failed over the evil-winrm session with “Access is denied,” even as Administrator, even with internet confirmed reachable. This is a known WinRM limitation — PSRemoting hands out a restricted “network logon” token, and servicing operations (DISM/TrustedInstaller-class work, which Add-WindowsCapability is) refuse to run under it. The identical command worked immediately from the Proxmox console instead, where the session token is a real interactive one. Worth remembering as a rule for this lab going forward: DISM/servicing-class changes need the console, not WinRM.
Once sshd was running (its firewall rule auto-created), the actual pivot was almost boring by comparison:
kali1$ ssh -D 1080 -N Administrator@10.10.10.50
kali1$ curl --socks5-hostname 127.0.0.1:1080 http://10.10.20.10:8080
0.08 seconds round-trip to the hidden target once the tunnel was up. One genuinely current detail worth a line on its own: Kali’s OpenSSH client warned that the connection wasn’t using a post-quantum key exchange algorithm — Kali now defaults to preferring one, Windows’ OpenSSH server build doesn’t support one, and the two sides silently fall back to classical key exchange. A small, real sign of where SSH tooling is heading in 2026, showing up in the most mundane possible place.
One honestly-reported accident: the tunnel got left open and idle for over 44 minutes before anyone noticed and closed it — a small, live illustration of exactly how easy it is for a pivot like this to sit forgotten once established.
The classic baseline, part two: socat — a story about deployment cost, not speed
Once running, socat’s relay was exactly as fast as ssh -D’s — 0.08 seconds, identical. Getting to “once running” is where this pair’s real story lives.
The first prebuilt Windows socat binary tried (a release build from 3ndG4me’s GitHub) exited instantly on execution with no console output. Get-MpThreatDetection came back completely empty and the file was still on disk — not an AV kill. echo %errorlevel% returned -1073741515, which decodes to STATUS_DLL_NOT_FOUND. A second, independently-built release (valorisa/socat-1.8.0.1_for_Windows) failed identically. Two different maintainers, two Cygwin-compiled builds, and neither one documents or bundles the cygwin1.dll runtime their own build process actually depends on.
Rather than settle for “socat doesn’t work on Windows” as the finding, the real fix got chased down: a temporary NIC back onto the internet-facing bridge, an official, unattended Cygwin base install (setup-x86_64.exe -q -s <mirror> -R C:\cygwin64 -P base -n, roughly 78 packages), and — this took a second attempt — the whole C:\cygwin64\bin directory on PATH, not just the one DLL copied next to the binary (the build also links against libreadline, OpenSSL, and other pieces from the base install). With that in place, the original 3ndG4me binary ran cleanly. The second binary still failed even with the full fix in place — a different compile with its own unmet dependencies, not chased further once a working binary was already in hand.
Then one more snag: the relay itself (socat.exe TCP-LISTEN:9090,fork TCP:10.10.20.10:8080) started and blocked correctly, but Kali1’s curl just timed out against it. Windows Firewall had never gotten a rule for port 9090 — only port 22 got one, auto-created when the OpenSSH Server feature was enabled. One New-NetFirewallRule later, the relay worked.
Total real cost of a working socat relay: a temporary internet connection, a ~78-package Cygwin install, a PATH fix, and a manual firewall rule — against ssh -D’s single feature toggle (built into the OS already) and its own auto-created firewall rule. Runtime speed between the two “classic” options turned out identical; deployment friction did not, by a wide margin.
The modern tool: chisel — and the opposite problem
Chisel is socat’s deployment story running backwards: a single 11.4MB statically-compiled Go binary (the official jpillora/chisel v1.12.0 Windows release), zero runtime dependencies. scp had it on the box in 8–10 seconds. No Cygwin, no PATH fixes, no missing DLLs.
Windows Defender caught it immediately. The scp transfer reported success, but the file was gone from disk seconds later. Get-MpThreatDetection showed a real, named detection — ThreatName: VirTool:Win64/Chisel.G, DidThreatExecute: False, quarantined within about 24 seconds of the transfer finishing. The contrast with socat is sharp: Defender’s threat log came back completely empty for both socat binaries, despite them being equally unfamiliar network tools to this box. Chisel is simply far more heavily signature-fingerprinted, precisely because it’s the well-known, popular modern pentesting tool — socat’s relative obscurity as a general Unix utility working against it here.
Rather than stop at the Defender catch as the finding, an exclusion went in (Add-MpPreference -ExclusionPath on the exact file path) and a fresh copy was re-pushed, which stuck this time. From there, setup was the cleanest of the three tools: the server needs its --socks5 flag explicit (the first attempt without it failed cleanly with "SOCKS5 is not enabled" — a one-line fix, not a rabbit hole), and once both sides were up the client reported sub-2ms link latency directly (Connected (Latency 1.180076ms)). The relay itself reached the hidden target in 0.04 seconds — the fastest of the three, though on a LAN this small, all three are effectively noise-level apart.
One incidental but genuinely useful finding while watching chisel’s server-side console timestamps: target-win2022’s own local clock is wildly inconsistent with Kali1’s — far beyond the one-hour BST/UTC offset. This is the same clock-skew quirk Part 7 first flagged in a Windows Event Log timestamp, turning up again in a completely unrelated context, which is enough to call it a real, persistent property of this particular VM rather than a one-off. Every piece of Wazuh timing correlation for this pair was anchored on Kali1’s clock, deliberately never on target-win2022’s own.
What Wazuh actually saw
The full session’s alerts for target-win2022 were pulled with an awk-based full-block extraction (awk -v RS="" '/target-win2022/') rather than a plain grep — a plain grep only catches the single header line of a multi-line alert block and silently misses the Rule: line entirely, worth remembering for any future query against this log format. 9142 total alert blocks across the whole session.
The result is almost entirely not attack-signature detection, a clear break from every web-facing pair earlier in this series:
- File Integrity Monitoring noise (rules 752/598/594/750, all low severity) — registry keys and values added or changed, almost entirely a side-effect of installing Cygwin’s ~78 packages and enabling the OpenSSH Server feature. Software got installed; nothing here is attack-shaped.
- Routine, expected authentication audit events — successful logons, logoffs, and the same blanket “possible pass-the-hash” NTLM heuristic Part 7 already established fires for any remote authenticated logon, regardless of what actually happened.
- One almost funny, entirely self-inflicted entry: a “service startup type was changed” alert, which is simply
Add-WindowsCapabilitylogging its own side effect of setting the Windows Modules Installer service to auto-start. - Assorted unrelated background noise — a Microsoft Edge Update crash report, a routine CVE-feed update notice, Windows’ own licensing service scheduling.
Two negative findings are the real payoff of this check.
First: zero Windows process-creation events (event ID 4688) anywhere in the entire 9142-alert session. Process-creation auditing simply isn’t turned on in this lab’s default Windows audit policy — meaning chisel.exe, socat.exe, and every Cygwin binary that actually launched on this box during testing produced zero telemetry of any kind. The outline’s own predicted detection angle for this pair — “process creation on the pivot host” — needs an audit-policy setting that isn’t enabled anywhere in this environment.
Second, and sharper: zero Windows Defender operational-log events (event IDs 1116/1117) anywhere in the session, despite Defender itself catching and naming chisel with a real signature just minutes earlier. Wazuh’s Windows EventChannel collection on this box simply doesn’t forward the Defender operational log. The one thing in this entire test that actually caught a real attacker tool is completely invisible to the SIEM watching the same box.
Verdict
The interesting findings in this pair aren’t about pivot performance at all — once any of the three tunnels was actually up, the differences were noise-level (0.08s, 0.08s, 0.04s). They’re about what it costs to get there and what happens after. ssh -D is close to free, since the capability already ships in the OS and just needs enabling — with the caveat that enabling it needs an interactive session, not WinRM. socat is functionally identical once running but carries a real, multi-step deployment tax on Windows: two independent prebuilt binaries that silently need a Cygwin runtime neither one bundles or documents. chisel flips that entirely — trivial to deploy, a single dependency-free binary — and pays for it in the opposite currency, getting caught and quarantined by name the moment it touches disk, purely because it’s popular enough to be well-signatured.
And the detection layer adds a finding that reaches past this one pair: even where local antivirus does its job and catches something real, that tells you nothing about whether the SIEM watching the same endpoint knows about it too. Wazuh’s Windows ruleset on this box saw plenty of noise from installing tools and authenticating to the box, and nothing at all from either the process creation the outline predicted or the one genuine detection event — Defender’s chisel catch — that actually happened. Detection here depended entirely on audit policies and log-forwarding configuration that this lab, like plenty of real environments, simply doesn’t have turned on by default.