Sn1per Deep Dive Part 8: The Windows Target and What Nuke Mode Never Touched

Part 7 covered a root-verified re-test of Sn1per against three Linux targets: Metasploitable2, a real Apache login form, and a genuine WordPress install. One target was still missing from that lab: Windows. This post covers building it and running Sn1per against it for real, no simulation, no documented-from-source fallback.

Building the target

The box sits on the same isolated vmbr-msflab segment as the rest of the lab, alongside the existing Metasploitable2 host and Kali. Windows Server 2022, Desktop Experience (the first attempt landed on Server Core by mistake, SConfig popping up on every boot instead of a normal desktop, so it got rebuilt with the right edition selected this time).

Two deliberately vulnerable services, plus one that wasn’t deliberate at all:

Elasticsearch 1.1.1 — CVE-2014-3120, the script_mvel_rce vulnerability. A genuinely old release, from 2014, requiring an old JRE to run at all on modern Windows.

Jenkins, current LTS, with security switched off on purpose. Rather than click through the setup wizard by hand, the fastest and most repeatable way to do this is an init.groovy.d script that runs on service start:

import jenkins.model.*
import hudson.security.*

def instance = Jenkins.get()
instance.setSecurityRealm(SecurityRealm.NO_AUTHENTICATION)
instance.setAuthorizationStrategy(AuthorizationStrategy.UNSECURED)
instance.setCrumbIssuer(null)
instance.save()

That’s the modern, scripted equivalent of someone unchecking “Enable security” in Manage Jenkins and never coming back to it, which is a real, still-common misconfiguration rather than a contrived one.

One weak local admin account, for a bruteforce test later, on the theory that Windows has no account lockout threshold enabled by default, unlike the OpenSSH connection throttling that defeated Hydra against the Linux targets back in Part 7.

The one exposure that wasn’t planned: RDP was left enabled on the same interface, using the built-in Administrator account with the same weak password. That happened by oversight, not design, and it stayed in rather than getting quietly fixed before testing. A misconfiguration that survives because nobody meant to leave it there is exactly the kind of thing that shows up on real networks too, and it turned into the more interesting of the two credentialed findings.

Standing it up wasn’t as clean as expected

None of what follows is a Sn1per finding. It’s here because every other lab in this project has been documented honestly, including the parts that didn’t work the first time, and this one had more of those than usual.

Elastic quietly moved the 1.1.1 archive off its current CDN domain onto the legacy one at some point in the last decade. A link that had been confirmed live earlier in this same project turned out to 404, and the fix was the old download.elastic.co host, still serving the same file, untouched since 2018.

Setting JAVA_HOME system-wide so Elasticsearch’s old JRE would install cleanly then broke the Jenkins installer, which picked up that same variable and tried to stand up its Windows service against Java 8. Current Jenkins needs something newer, and the installer’s own auto-detection logic had no good way to tell it otherwise. Installing a separate, modern JDK and passing it to the Jenkins installer explicitly as a command-line property fixed the Java mismatch, only for the install to fail a second time with a generic Windows Installer rollback and a Service Control Manager error that looked like a privileges problem but wasn’t. The real cause, once the verbose install log was actually read rather than guessed at, was the service genuinely failing to start.

It did start, eventually. The last problem was a corrupted init.groovy.d script: Out-File -Encoding utf8 in Windows PowerShell writes a UTF-8 byte-order mark by default, and Groovy’s parser choked on that leading byte, which surfaced in the Jenkins log as a stray ? sitting in front of the first import statement. Rewriting the file without a BOM cleared it.

Three separate bugs, stacked on top of each other, none of them Sn1per’s fault, all of them worth keeping in the record. Reading the actual error at each step instead of assuming the last fix should have worked is the same discipline this whole project has leaned on from Part 1 onward.

Airstrike

airstrike turned out to need a targets file even for a single host, -t on its own gets rejected outright. That’s worth correcting from what the original series inferred by reading the mode’s source; assumed intent and actual CLI behaviour aren’t always the same thing.

Once pointed at a targets file, the scan itself was narrow. Nmap checked port 80, port 443, and a handful of others, found only 8080 open, and moved on. Ports 9200, 3389, and 445, the three real open services on this box, simply weren’t in the set of ports airstrike bothered to check. sc0pe still managed to flag “Strict Transport Security Not Enforced” against https://10.10.10.50:443//, a port the same scan had reported closed two lines earlier, a new inconsistency to add alongside the clickjacking mislabeling and nuclei packaging failure already on record from earlier parts. The score formula held exact again: 0×5+0×4+0×3+1×2+1×1 = 3, printed as 3.

Nuke, and the gap that matters

Nuke’s own initial nmap pass found all four real ports immediately: 445, 3389, 8080, 9200. Good. But nuke’s intrusive, per-port testing loop runs through a long hardcoded list of ports one at a time, 21, 22, 23, 25, 53, and on through several dozen more, and 9200 is never one of them. The most aggressive mode Sn1per Community offers left a live, actively exploitable Elasticsearch RCE completely untested, despite having already detected it as open two steps earlier in the exact same run. Everything nuke did against SMB, RDP, and the web port that follows happened; Elasticsearch simply never came up.

SMB, port 445: an anonymous session was correctly refused, as expected against a hardened SMB 3.1.1 host with signing available. Metasploit’s smb_version scanner fingerprinted the OS correctly as Windows Server 2022 build 10.0.20348. Then came a long run of SMB exploit modules, one after another, every single one denied with STATUS_ACCESS_DENIED, including CVE-2017-7494 (SambaCry, a Linux/Samba vulnerability, fired at a Windows box regardless of relevance) and a buffer-overflow-style module that spent several minutes retrying a hardcoded return address, 0x081ed5f2, against port 139, which was never open at all. That’s the same blind-fire pattern documented against ms03_026_dcom in the original six-part series: nuke doesn’t gate exploit attempts on whether the target could plausibly be affected.

RDP, port 3389, got a properly targeted check for once: a CVE-2019-0708 (BlueKeep) scanner, at least conceptually relevant to RDP rather than fired at random. The CVE itself predates Server 2022 by several OS generations and was never going to apply here, but the targeting was correct in a way the SMB modules weren’t.

Web, port 8080: WhatWeb correctly identified Jenkins[2.568.1] by name and exact version during the HTTP info-gathering phase. That’s worth stating plainly, because it corrects an assumption from earlier in this project that Sn1per has no idea what’s running on an unrecognized port. It does, in this case. The gap is one step further down the pipeline. BlackWidow’s spider then crawled the entire application and listed /manage/script, the exact unauthenticated Groovy Script Console URL, in its URL inventory, sitting there indistinguishable from a few hundred other harmless paths around it. Nothing downstream, not sc0pe, not nuclei, not any Metasploit module, ever recognized it as significant. The tool knew it was looking at Jenkins. It had the exact path to a full remote-code-execution endpoint sitting in a text file. It said nothing.

sc0pe’s own findings for that pass: a HIGH for cleartext HTTP (accurate), a LOW for clickjacking (the same false-positive pattern documented in earlier parts, now reproducing on a third, completely unrelated application, confirming it’s a scoring-engine bug rather than anything app-specific), an INFO for the Jetty server header, and an INFO for the default robots.txt. Nuclei failed with the identical packaging error first documented back in Part 3: no templates provided for scan. The score formula held again: 0×5+1×4+2×2+3×1 = 11, printed as 11.

Nuke also runs its own bruteforce phase automatically, BruteX wrapping Hydra. Against SMB it failed outright with an invalid protocol reply, Hydra’s SMB module couldn’t negotiate this SMB 3.1.1 stack. Against RDP it failed to even establish a connection, repeated freerdp: The connection failed to establish errors from a module Hydra’s own warning banner labels experimental. Against the web port it errored immediately on a malformed path argument before a single request went out. Sn1per’s own credential testing proved nothing, in either direction, on this target.

Manual verification

NetExec against SMB settled it in one line:

SMB    10.10.10.50   445   TARGET-WIN2022   [+] target-win2022\Administrator:Summer2026! (Pwn3d!)

RDP took a little more fighting with FreeRDP’s command-line syntax than expected (a certificate flag that moved to a namespaced /cert:ignore format in recent versions, an auth-only mode that didn’t handle the Kerberos-to-NTLM fallback cleanly), but the same credential landed there too:

RDP    10.10.10.50   3389  TARGET-WIN2022   [+] target-win2022\Administrator:Summer2026! (Pwn3d!)

Network Level Authentication was enabled on the RDP listener (nla:True), which is sometimes assumed to be a meaningful barrier on its own. It isn’t, against a genuinely valid credential. Both the deliberate misconfiguration and the accidental one were fully exploitable within minutes, using tools Sn1per doesn’t ship.

What this leaves standing

Add it up and very little of real consequence on this box was actually found or confirmed by Sn1per itself. Airstrike’s port list missed all three of the ports that mattered. Nuke’s own port list, despite having already detected Elasticsearch as open, still skipped it entirely during the actual testing phase. The one application Sn1per correctly identified by name had its most serious flaw crawled and logged without ever being flagged. Its own bruteforce tooling failed against every protocol it was tried against, for reasons ranging from a decade-old SMB dialect assumption to an experimental RDP client library.

Everything that actually mattered here got found by reading the scan output critically rather than trusting the summary, and by reaching for tools Sn1per doesn’t bundle the moment its own came up short. Part 9 makes that comparison explicit: the same box, worked through with nothing but nmap, curl, and a couple of well-chosen modern tools, timed against what Sn1per’s own automated run actually delivered.