Skip to content

Fix wcc module false negatives on modern Windows defaults and non-DC hosts - #1445

Open
0xf61 wants to merge 1 commit into
Pennyw0rth:mainfrom
0xf61:fix/wcc-false-negatives
Open

0xf61 wants to merge 1 commit into
Pennyw0rth:mainfrom
0xf61:fix/wcc-false-negatives

Conversation

@0xf61

@0xf61 0xf61 commented Sep 25, 2026

Copy link
Copy Markdown

Description

The wcc module treats missing registry values as insecure (KOIfMissing default) and applies override-only or DC-only checks to every host, producing false KO verdicts on stock
modern Windows:

  • SMB signing: requiresecuritysignature is only written when explicitly configured (GPO). Windows 11 24H2 / Server 2025 require SMB signing by default without materializing
    the value, so wcc reported KO on hosts that do require signing, contradicting the signing:True status negotiated from ServerSecurityMode. New check_smb_signing(): the
    registry value stays authoritative when present; when missing, fall back to the signing requirement negotiated with the server.
  • UAC: LocalAccountTokenFilterPolicy absent means remote UAC filtering is enforced (default 0), not disabled.
  • AlwaysInstallElevated: policy key absent means the feature is disabled (default), which is the secure state.
  • WDigest: UseLogonCredential absent means WDigest does not store cleartext credentials (default since Win 8.1 / Server 2012 R2).
  • WSUS: no WUServer configured means updates come from Microsoft Update over HTTPS; only flag non-HTTPS WSUS servers (new check_wsus_config).
  • Lsass PPL: RunAsPPL=2 ("Enabled without UEFI lock") also means PPL is active, accept >= 1.
  • No PowerShell v2: PSCompatibleVersion always lists 2.0 on PowerShell 5.1 (engine compatibility), so the old check could never pass; check the v1/v2 engine registration
    and the PowerShell 2.0 optional feature state instead (new check_powershell_v2).
  • LDAP signing: LDAPServerIntegrity/LdapEnforceChannelBinding only apply to domain controllers; on non-DC hosts report not-applicable instead of KO, and read
    LdapEnforceChannelBinding from NTDS\Parameters (per ADV190023) rather than the NTDS service key (new check_ldap_signing).

Also fixes the negated reason string for custom operators in check_registry (always printed == True) and drops the now-unused startswith/not_ helpers.

Verified read-only against a Windows 11 24H2 (build 26100) host: the eight checks above flipped KO → OK with correct reasons, all other checks unchanged. Defender checks
deliberately untouched: on the verification host a third-party AV is active and WinDefend is stopped, so their KO verdicts are correct and a "missing = default enabled" fallback
would produce false positives.

No third-party dependencies are required for this change.

AI assistance: This PR was prepared with the help of an AI coding assistant (omp agent, model: zai/glm-5.3). Extent of assistance: git branch/commit/push hygiene, applying
the authored patch, fixing two Ruff findings in the patch (raw-string docstring prefix, trailing newlines at EOF), adding the tests/e2e_commands.txt entry, and stub-based
smoke-testing of the new checker logic (19/19 scenarios, no live target involved). The fix design, patch content, and live-target verification were done by the author.

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Deprecation of feature or functionality
  • This change requires a documentation update
  • This requires a third party update (such as Impacket, Dploot, lsassy, etc)
  • This PR was created with the assistance of AI (list what type of assistance, tool(s)/model(s) in the description)

Setup guide for the review

  • Local machine: macOS (arm64), Python 3.14.7, NetExec 1.5.1
  • Target: Windows 11 24H2 (build 26100) with default/stock settings, local admin credentials. No additional software and no GPO changes are needed to reproduce.
  • Reproduce the bug (on main):
    nxc smb <TARGET> -u <ADMIN_USER> -p <ADMIN_PASS> -M wcc
    Before: the eight checks listed above report KO on a stock host — e.g. KO SMB signing enabled (requiresecuritysignature: Value not found) while the host banner itself shows
    signing:True. After this PR: the same checks report OK with accurate reasons, e.g. OK SMB signing enabled (requiresecuritysignature: Value not found, Registry value not set, but SMB signing is required by the server as observed during session negotiation).
  • Optional knobs to exercise the remaining branches (no GPO needed, plain registry/feature state):
    • requiresecuritysignature=1 (e.g. via the "Microsoft network server: Digitally sign communications (always)" GPO) → OK via registry, registry stays authoritative; value 0
      → KO.
    • HKLM\SYSTEM\CurrentControlSet\Control\Lsa\RunAsPPL=2 → still OK (PPL without UEFI lock).
    • Enable the "PowerShell 2.0 Engine" optional feature (InstallState=1) → KO.
    • Configure WUServer with an http:// URL → KO; https:// → OK; no WSUS configured → OK.
    • On a non-DC host the LDAP signing check reports OK "Not a domain controller"; on a DC verify LDAPServerIntegrity=2 and LdapEnforceChannelBinding=2 under
      HKLM\SYSTEM\CurrentControlSet\Services\NTDS\Parameters.

Screenshots

Text before/after on the verification host (replace with real terminal screenshots if desired):

-WCC  <ip>  445  <hostname>  KO SMB signing enabled
+WCC  <ip>  445  <hostname>  OK SMB signing enabled

-WCC  <ip>  445  <hostname>  KO UAC configuration
+WCC  <ip>  445  <hostname>  OK UAC configuration

-WCC  <ip>  445  <hostname>  KO Always install elevated disabled
+WCC  <ip>  445  <hostname>  OK Always install elevated disabled

-WCC  <ip>  445  <hostname>  KO WDigest authentication disabled
+WCC  <ip>  445  <hostname>  OK WDigest authentication disabled

-WCC  <ip>  445  <hostname>  KO WSUS configuration
+WCC  <ip>  445  <hostname>  OK WSUS configuration

-WCC  <ip>  445  <hostname>  KO Lsass run as PPL
+WCC  <ip>  445  <hostname>  OK Lsass run as PPL

-WCC  <ip>  445  <hostname>  KO No Powershell v2
+WCC  <ip>  445  <hostname>  OK No Powershell v2

-WCC  <ip>  445  <hostname>  KO LDAP signing enabled
+WCC  <ip>  445  <hostname>  OK LDAP signing enabled

Checklist

@0xf61
0xf61 marked this pull request as ready for review September 25, 2026 14:19
Copilot AI lite review requested due to automatic review settings September 25, 2026 14:19

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Moderate issues remain in WSUS applicability, WDigest legacy handling, PowerShell detection, and WMI error handling.

Get a fresh assessment by requesting another Copilot review.

Review effort: Lite
Findings: 3 Medium severity

Open (3)
What changed in this PR

Updates the WCC module to recognize modern Windows defaults and avoid false security failures on non-DC hosts.

Changes:

  • Adds default-aware SMB, WSUS, LDAP, and PowerShell checks.
  • Corrects missing-value handling, PPL evaluation, and operator messages.
  • Registers WCC in end-to-end commands.
File Summary
tests/​e2e_commands.txt Adds the WCC end-to-end command.
nxc/​modules/​wcc.py Revises Windows security checks; five moderate issues require changes.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread nxc/modules/wcc.py
Comment thread nxc/modules/wcc.py Outdated
Comment thread nxc/modules/wcc.py
…hosts

The wcc module treats missing registry values as insecure (KOIfMissing
default) and applies override-only or DC-only checks to every host,
producing false KO verdicts on stock modern Windows:

- SMB signing: requiresecuritysignature is only written when explicitly
  configured (GPO). Windows 11 24H2 / Server 2025 require SMB signing
  by default without materializing the value, so wcc reported KO on
  hosts that do require signing, contradicting the signing:True status
  negotiated from ServerSecurityMode. New check_smb_signing(): the
  registry value stays authoritative when present; when missing, fall
  back to the signing requirement negotiated with the server.
- UAC: LocalAccountTokenFilterPolicy absent means remote UAC filtering
  is enforced (default 0), not disabled.
- AlwaysInstallElevated: policy key absent means the feature is
  disabled (default), which is the secure state.
- WDigest: UseLogonCredential absent means WDigest does not store
  cleartext credentials (default since Win8.1/Server2012R2).
- WSUS: no WUServer configured means updates come from Microsoft
  Update over HTTPS; only flag non-HTTPS WSUS servers
  (new check_wsus_config).
- Lsass PPL: RunAsPPL=2 ("Enabled without UEFI lock") also means PPL
  is active, accept >= 1.
- No PowerShell v2: PSCompatibleVersion always lists 2.0 on PowerShell
  5.1 (engine compatibility), so the old check could never pass; check
  the v1/v2 engine registration and the PowerShell 2.0 optional
  feature state instead (new check_powershell_v2).
- LDAP signing: LDAPServerIntegrity/LdapEnforceChannelBinding only
  apply to domain controllers; on non-DC hosts report not-applicable
  instead of KO, and read LdapEnforceChannelBinding from
  NTDS\Parameters (per ADV190023) rather than the NTDS service key
  (new check_ldap_signing).

Also fix the negated reason string for custom operators in
check_registry (always printed '== True') and drop the now-unused
startswith/not_ helpers.

Verified read-only against a Windows 11 24H2 (build 26100) host: the
eight checks above flipped KO->OK with correct reasons, all other
checks unchanged. Defender checks deliberately untouched: on the
verification host a third-party AV is active and WinDefend is stopped,
so their KO verdicts are correct and a "missing = default enabled"
fallback would produce false positives.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Moderate WSUS and PowerShell detection issues remain unresolved.

Get a fresh assessment by requesting another Copilot review.

Review effort: Lite
Findings: 2 Medium severity

Open (2)
Resolved since last review (3)

Comment thread nxc/modules/wcc.py
WUServer must use the https:// scheme.
"""
use_wuserver = self.reg_query_value(self.dce, self.connection, "HKLM\\Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU", "UseWUServer")
if not isinstance(use_wuserver, DCERPCSessionError) and use_wuserver == 0:
Comment thread nxc/modules/wcc.py
Comment on lines +413 to +414
if not isinstance(value, DCERPCSessionError):
return False, [f"PowerShell v2 engine installed (PowerShell\\1\\PowerShellEngine found, PowerShellVersion {value})"]
@azoxlpf

azoxlpf commented Sep 25, 2026

Copy link
Copy Markdown
Collaborator

Thanks for the PR! I think we should merge #893 before this one

@azoxlpf azoxlpf added the bug-fix This Pull Request fixes a bug label Sep 25, 2026
Comment thread nxc/modules/wcc.py
Comment on lines +185 to +186
ConfigCheck("SMB signing enabled", "Checks if SMB signing is enabled", checkers=[self.check_smb_signing]),
ConfigCheck("LDAP signing enabled", "Checks if LDAP signing is enabled", checkers=[self.check_ldap_signing]),

@NeffIsBack NeffIsBack Sep 26, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you removing the Regsitry checks tho and move it to some separate function?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug-fix This Pull Request fixes a bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants