mirror of
https://github.com/Yamato-Security/WELA.git
synced 2026-10-07 23:14:45 +02:00
Integrate current dev with intended-reader EVTX verification
This commit is contained in:
commit
4598bb36f7
175 files changed
+11391
-70
No files matched your search
@@ -13,7 +13,7 @@ Run copies native System32 `cmd.exe` into the protected output directory with a
|
||||
|
||||
A bounded query requires exactly one native AppLocker 8002 (allowed) or 8003 (allowed, would block under enforcement) with the expected provider, version, computer, EXE collection, actual user SID, owned process ID, exact file path and time window. The report retains the distinct event ID; 8002 does not demonstrate a would-block decision. Policy, service, channel, reader, host and executable bytes are checked before and after. Denied, absent, capped, duplicate or drifted results fail with a retained diagnostic. Component hashes establish consistency, not authenticity or a signature.
|
||||
|
||||
`NativeExeEventObserved` proves only this event in this local channel at this time. It grants **zero Sigma readiness credit**. Scripts, MSI, DLL, packaged applications, forwarding, translated queries and backend matches require separate evidence. Client builds and managed/CSP deployments require lab acceptance beyond hosted-server CI.
|
||||
`NativeExeEventObserved` proves only this event in this local channel at this time. It grants **zero Sigma readiness credit**. The [separate Script probe](applocker-script-probe.md) collects Windows PowerShell5.1 Script8005/8006 evidence. MSI, DLL, packaged applications, forwarding, translated queries and backend matches require separate evidence. Client builds and managed/CSP deployments require lab acceptance beyond hosted-server CI.
|
||||
|
||||
The Windows test explicitly opts into temporary changes on disposable GitHub-hosted Server 2022/2025 VMs under Windows PowerShell 5.1 and PowerShell 7. It accepts only a non-domain host with initially empty, understood local/effective GP policies, prepares one AuditOnly policy through the native cmdlet in the test fixture, temporarily enables/runs the existing verified native PolicyConverter task when disabled, runs a bounded computer Group Policy refresh and requires native 8001 policy-application evidence followed by a real 8003. Hosted images can contain enrollment/provider keys; these are recorded and preserved, and CSP policy remains Unknown. This fixture tests the probe, not production importer acceptance: the production importer continues to block observed management entries. It restores and refreshes the original local policy, verifies both local and effective GP snapshots, and restores channel enablement and the exact PolicyConverter task definition/enabled setting with no task invocation left running or queued, and leaves service startup mode untouched. If Windows refuses to stop its protected AppIDSvc, the test records that running-state boundary and relies on disposal of the VM; it does not claim service-state rollback. Never run that fixture on a production host.
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
# Native AppLocker Script probe
|
||||
|
||||
Related to #381. `applocker-script-probe` runs one fixed, locally generated `.ps1` file through native 64-bit Windows PowerShell 5.1 and looks for its actual AppLocker Script-collection decision. WELA itself can run in Windows PowerShell 5.1 or PowerShell 7. This command adds no AppLocker policy, starts no service, changes no execution policy or channel, and grants no Sigma readiness credit. Sysmon is out of scope.
|
||||
|
||||
```powershell
|
||||
.\WELA.ps1 applocker-script-probe
|
||||
.\WELA.ps1 applocker-script-probe -AppLockerScriptAction Run -AppLockerScriptOutputPath C:\Evidence\new-script-probe -AppLockerScriptTimeoutSeconds 30
|
||||
```
|
||||
|
||||
Plan reads prerequisites without launching a child or writing files. Run requires a new private directory on a local fixed drive, with an existing parent. Only reviewed Windows 11 builds and Server 2022/2025 member hosts are accepted; domain controllers are excluded. Client and managed-environment acceptance remains separate from hosted-server CI.
|
||||
|
||||
The effective Group Policy Script collection must already contain rules in `AuditOnly` mode. Local and effective GP policy, management observations, AppIDSvc state and MSI and Script channel configuration must be readable. Direct service observations require Winmgmt, EventLog and AppIDSvc to be running before any CIM connection; the channel must already be enabled. AppLocker CSP policy remains **Unknown**: the native GP cmdlets do not enumerate that authority. Existing enforcement in other collections is preserved and can prevent the fixed native host from starting.
|
||||
|
||||
Run creates only the reviewed worker template with a fresh filename and nonce. It launches System32's `WindowsPowerShell\v1.0\powershell.exe` with `-NoLogo -NoProfile -NonInteractive -File`; there is no operator-supplied command, profile loading or execution-policy override. The existing execution policy must permit that locally generated unsigned file. For example, Restricted or AllSigned may prevent completion; that is an unverified result. The report records existing native execution-policy registry values and the inherited process preference, without equating these observations to all application-control authorities.
|
||||
|
||||
The worker emits its fixed ready marker, actual Windows PowerShell 5.1 version and language mode, waits for its fixed release marker, emits completion and exits. Before releasing it, WELA observes the real child primary token and compares its user, logon LUID, group attributes and privilege attributes with the actual current caller. Impersonated or restricted callers are refused. Caller token identity and modification state are checked throughout child execution and event queries. Metadata and output preparation precede that interval; final configuration observations are checked separately.
|
||||
|
||||
Native PowerShell and generated script files are held read-locked during execution, with SHA256 and volume/file identity checks. Source fingerprints bind the compiled helper to its exact source bytes and are rechecked before launch and after collection. These are consistency observations, not a signature or protection from a local administrator. The generated file is retained with the evidence.
|
||||
|
||||
The query starts from an actual current record boundary in `Microsoft-Windows-AppLocker/MSI and Script`. A match requires the reviewed provider GUID, event version, channel, computer, Script collection, actual user SID, child PID, exact unique script path and a native precise-UTC timestamp within the actual process interval. It accepts exactly one of these separate outcomes:
|
||||
|
||||
| Event | Report decision | Meaning |
|
||||
|---|---|---|
|
||||
| 8005 | `Allowed` | A Script rule allowed this file. |
|
||||
| 8006 | `AllowedWouldBlockIfEnforced` | The audit-only Script policy would block this file if enforced. |
|
||||
|
||||
8005 does not prove a would-block decision. 8007, MSI events sharing the channel, other processes, older records, stale paths, duplicates, unknown versions and timestamps outside the exact interval are rejected. Missing, denied, incomplete, capped or drifted results remain `Unverified` with a nonzero exit code. The bounded query refuses its 256-event or one-MiB cap; only matched XML or at most four candidates containing the owned filename are exported. Child startup is bounded to thirty seconds, completion to ten seconds after release, output drain to five seconds and event polling to the selected 1–30 seconds; individual native event reads have finite timeouts. Owned child termination is attempted and checked on failure. Raw process output is bounded.
|
||||
|
||||
`NativeScriptEventObserved` means only that this one local Windows PowerShell 5.1 script generated the retained event under the observed context. It does not prove PowerShell 7 script behavior, other Script formats, MSI/DLL/packaged-app coverage, enforcement behavior, forwarding or backend rule matches. The [separate EXE probe](applocker-probe.md) covers EXE events.
|
||||
|
||||
The dedicated Windows workflow requires explicit opt-in on disposable non-domain GitHub-hosted Server 2022/2025 VMs, each under both WELA host engines. It requires initially empty and understood local/effective GP policies. The fixture prepares one Script AuditOnly policy at a time, invokes the verified native PolicyConverter task and a bounded computer-policy refresh, then requires genuine public-command 8006 and 8005 records, source/receipt hashes and unchanged product context. Mocked fixtures never substitute for those events. It restores original local/effective GP policy, channel enablement and the exact PolicyConverter task definition/enabled state and preserves service startup mode. If Windows refuses to stop protected AppIDSvc, the cleanup receipt explicitly records the remaining running state and relies on disposal of that VM; it does not claim full service-state restoration. This fixture must not be run on production hosts.
|
||||
|
||||
Microsoft references: [Script rule formats and host enforcement semantics](https://learn.microsoft.com/en-us/windows/security/application-security/application-control/app-control-for-business/applocker/script-rules-in-applocker), [AppLocker event IDs](https://learn.microsoft.com/en-us/windows/security/application-security/application-control/app-control-for-business/applocker/using-event-viewer-with-applocker), [native policy refresh and verification](https://learn.microsoft.com/en-us/windows/security/application-security/application-control/app-control-for-business/applocker/refresh-an-applocker-policy), [Application Identity service](https://learn.microsoft.com/en-us/windows/security/application-security/application-control/app-control-for-business/applocker/configure-the-application-identity-service).
|
||||
@@ -65,9 +65,16 @@ behavior or policy persistence.
|
||||
|
||||
Fixture tests cover absent/typed values, threshold preservation, role/source and
|
||||
ADMX/channel gates, stale plans, races, failed/ignored writes, final drift,
|
||||
idempotence, dry-run and command dispatch. Windows Server 2022/2025 CI observes
|
||||
native registry/CIM/channel state without changing policy, under PowerShell 5.1
|
||||
and 7. This is not a Windows 11, DC or AD CS event-generation test.
|
||||
idempotence, dry-run and command dispatch. The original Windows smoke observes native registry/CIM/channel state read-only.
|
||||
A separate explicitly opted-in disposable Server 2022/2025 fixture runs public
|
||||
SecurityWarning Plan, DryRun and Configure under PowerShell 5.1/7. It exercises
|
||||
absent, zero and higher thresholds, preserves an earlier threshold, verifies
|
||||
idempotence and refuses a real non-DWORD value. It checks typed original journals,
|
||||
readback and exact cleanup while preserving other Security-key values/ACL,
|
||||
channel enablement/size/retention, Event Log service state, OneSettings,
|
||||
CrashOnAuditFail and all 59 audit masks. It never fills or clears a log, changes
|
||||
retention, tests warning generation, or supplies OneSettings/Windows 11/DC/AD CS
|
||||
acceptance.
|
||||
|
||||
Before closing issue #378, retain isolated Windows 11 and Server 2022 evidence of
|
||||
an authorized benign OneSettings attempt with exact build/patch, policy, channel,
|
||||
|
||||
@@ -88,3 +88,7 @@ For recovery, review the journal and restore the exact prior registry value/type
|
||||
RSoP schema references: [registry policy](https://learn.microsoft.com/en-us/previous-versions/windows/desktop/policy/rsop-registrypolicysetting), [numeric security setting](https://learn.microsoft.com/en-us/previous-versions/aa375064(v=vs.85)), and [security registry value](https://learn.microsoft.com/en-us/previous-versions/aa375052(v=vs.85)). Tests use these actual property shapes; they do not substitute a shared synthetic schema.
|
||||
|
||||
Targeted file/registry SACL prerequisites are included as a read-only companion plan. See [targeted SACL planning](targeted-sacl-planning.md) for per-user gaps, source distinctions and `-SaclMode Skip`.
|
||||
|
||||
The stronger profile's optional IPsec Main Mode control additionally requires positive local native prerequisite evidence during shared planning/configuration. See [conditional IPsec prerequisites](ipsec-prerequisites.md) for scope, statuses and fresh pre-write checks.
|
||||
|
||||
A separate [public custom-profile native acceptance fixture](custom-audit-profiles.md#verification-and-recovery) exercises the shared configuration/precedence engine with actual writes on disposable Server 2022/2025 hosts. It verifies all 59 effective masks and exact cleanup without claiming full baseline, GPO, event or Sigma acceptance.
|
||||
@@ -0,0 +1,34 @@
|
||||
# Fixed local CAPI2 certificate-chain probe
|
||||
|
||||
`capi2-probe` measures one built-in source on Windows Server 2022/2025: an offline native chain build for a newly generated ephemeral self-signed certificate, followed by one matching CAPI2 Operational event 11. The expected chain outcome is an untrusted root. Success means that this local operation and event were observed; it does not mean that the certificate is trusted.
|
||||
|
||||
```powershell
|
||||
./WELA.ps1 capi2-probe -Capi2ProbeAction Plan
|
||||
./WELA.ps1 capi2-probe -Capi2ProbeAction Run -Capi2ProbeOutputPath C:\Evidence\new-capi2-probe
|
||||
```
|
||||
|
||||
Plan reads prerequisites and creates no files. Run requires a new directory on a local fixed drive; its evidence directory blocks inherited broad access. Use an existing token that can read `Microsoft-Windows-CAPI2/Operational`. The channel must already be enabled. Winmgmt, CryptSvc and EventLog must already be running; observing the host or building the chain may not implicitly start them. The probe does not change channel configuration, audit policy, services, certificate stores, trust settings or reader permissions. Existing native-channel configuration commands remain separate.
|
||||
|
||||
Run launches the same PowerShell executable in a fresh worker with a parent-generated nonce and a twenty-second process deadline. The worker creates an unnamed ephemeral Microsoft Software Key Storage Provider RSA-2048 key, signs an in-memory certificate with `CN=WelaCapi2Probe_<nonce>` and a ten-minute validity interval, then calls `CertGetCertificateChain` once. The certificate has no AIA, CRL or other extensions. The key is disposed and never exported; the retained PEM/DER contains only the public certificate.
|
||||
|
||||
The fixed native flags are `0x80002104`: `CERT_CHAIN_CACHE_ONLY_URL_RETRIEVAL`, `CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY`, `CERT_CHAIN_DISABLE_AIA` and `CERT_CHAIN_DISABLE_AUTH_ROOT_AUTO_UPDATE`. No revocation-check request, additional store, custom trust engine or end-certificate caching is selected. These per-call flags prevent network retrieval by the chain operation; no machine-wide network or trust policy is altered.
|
||||
|
||||
Evidence must agree on the actual worker PID, caller SID/logon/group context, before/after token observations, generated DER/subject/thumbprint/SHA-256 and nonce. A native precise UTC interval surrounds the chain call; the event must fall within those exact inclusive bounds and after the observed channel record boundary. The matcher requires provider GUID, channel, event11 version0, native task/opcode/keywords, source computer, security SID, certificate references, offline flags, one certificate element and the expected untrusted-root result. Incomplete, ambiguous, capped or changed-context evidence remains `Unverified` and exits nonzero.
|
||||
|
||||
Collection waits up to 15 seconds by default (`-Capi2ProbeTimeoutSeconds 1..30`), queries at most 64 candidates and requires exactly one match. The bundle retains before/after context, worker operation including public certificate DER, public certificate PEM, raw matched event XML and artifact hashes. Failed matching retains up to four bounded candidate XML records. These local hashes detect altered artifacts; they are not a remote attestation or signed chain of custody.
|
||||
|
||||
This probe grants no ready-rule credit. It does not exercise TLS, remote connections, revocation retrieval, certificate enrollment, WEF delivery, the existing CAPI2 pack's event70 mapping, a Sigma rule or backend translation. Issues #386 and #367 have broader remaining acceptance criteria. Sysmon and external telemetry are excluded.
|
||||
|
||||
## Validation
|
||||
|
||||
`tests/Capi2Probe.Tests.ps1` validates certificate binding, native-result constraints, prerequisite guards, exact XML source/field checks and UTC boundaries with portable fixtures. `tests/Capi2Probe.Cli.Tests.ps1` checks public option isolation. Synthetic fixtures do not prove Windows telemetry.
|
||||
|
||||
`tests/Capi2Probe.Windows.Tests.ps1 -AllowDisposableChannelWrite` is restricted to opted-in disposable GitHub-hosted standalone Server 2022/2025. It invokes three independent public probes under Windows PowerShell 5.1 and PowerShell 7. Only the fixture may temporarily enable CAPI2; it retains the original and restored channel configuration, checks CurrentUser/LocalMachine My, Root and CA inventories, preserves all probe bundles and writes cleanup evidence even on failure. Native results must be assessed from the current workflow artifacts. The first complete native checkpoint at `a5f674e` passed all four matrix jobs with 40 assertions and three independent public probes per job ([workflow evidence](https://github.com/Shirofune-Security/WELA/actions/runs/35580490435)). All twelve public certificate identities, sixty artifact hashes and four original/restored channel and selected-store inventories were independently checked.
|
||||
|
||||
## Microsoft API references
|
||||
|
||||
- [CertGetCertificateChain flags and ownership](https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certgetcertificatechain)
|
||||
- [CERT_CHAIN_PARA](https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/ns-wincrypt-cert_chain_para), [CERT_CHAIN_CONTEXT](https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/ns-wincrypt-cert_chain_context), [CERT_SIMPLE_CHAIN](https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/ns-wincrypt-cert_simple_chain) and [CERT_TRUST_STATUS](https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/ns-wincrypt-cert_trust_status)
|
||||
- [Unnamed CngKey creation is ephemeral](https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.cngkey.create)
|
||||
- [CertificateRequest.Create with a signature generator](https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.x509certificates.certificaterequest.create)
|
||||
- [GetSystemTimePreciseAsFileTime](https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimepreciseasfiletime)
|
||||
@@ -0,0 +1,40 @@
|
||||
# Reviewed native channel recovery
|
||||
|
||||
`channel-recovery` restores **one completed `channel-settings` operation** on one exact channel from the bundled Microsoft WEF Appendix C profile. It can restore the original enabled state and size, and remove only the exact Event Log Readers read ACE that operation added. It does not restore other configuration commands, partially completed original writes, event records, subscriptions or arbitrary channels. Sysmon is excluded.
|
||||
|
||||
```powershell
|
||||
./WELA.ps1 channel-recovery -ChannelRecoveryJournalPath C:\WELA\original\before.jsonl `
|
||||
-ChannelRecoveryOriginalResultsPath C:\WELA\original-results.json `
|
||||
-ChannelRecoveryChannel 'Microsoft-Windows-CAPI2/Operational' `
|
||||
-ChannelRecoveryOutputPath C:\WELA\recovery-plan
|
||||
|
||||
# Inspect plan.json and manifest.json; independently retain manifest PlanHash.
|
||||
./WELA.ps1 channel-recovery -ChannelRecoveryAction Restore `
|
||||
-ChannelRecoveryPlanPath C:\WELA\recovery-plan\plan.json `
|
||||
-ChannelRecoveryPlanHash REVIEWED_SHA256 `
|
||||
-ChannelRecoveryOutputPath C:\WELA\recovery-run `
|
||||
-ChannelRecoveryAllowShrink -ChannelRecoveryAllowDisable -ChannelRecoveryAllowRevoke
|
||||
```
|
||||
|
||||
Supply only the consent switches the reviewed plan requires. **Shrinking can discard records; disabling stops channel generation; removing a read grant can interrupt collection.** These are separate decisions. Plan is read-only apart from new protected evidence files. Restore accepts a reviewed plan/hash and a new output directory; `-Auto`, `-DryRun`, `-WhatIf` and unrelated command options are rejected. There is no automatic rollback or continuation after a partial failure.
|
||||
|
||||
The original journal must contain exactly one matching entry, with the same typed `Before`, `Desired` and target as one `Applied` result. The command independently rebuilds the enable/minimum-size/read-grant transformation from the current bundled profile. Unknown schemas, Boolean values in text/size fields, duplicate JSON properties, mismatched journals, unexplained post-write changes, missing read-grant authorization and unchanged operations are refused. The selected operation may be recovered even when another channel failed during the original invocation; it must itself be completed and fully consistent.
|
||||
|
||||
Current settings must exactly match the original confirmed after-state. For descriptors, equality means the complete binary descriptor, including owner, group, SACL, DACL, resource-manager control and all ACE bytes/order. The canonical read-grant planner must reproduce the exact original addition, and SDDL conversion must round-trip without loss. An unrelated new ACE or another changed setting requires manual review; recovery never removes it. A previous read grant that was already present is preserved.
|
||||
|
||||
Only originally changed fields are written, in size, descriptor, then enablement order. Each write has a flushed pending receipt, a fresh complete settings/metadata check and actual primary-token check, native `wevtutil` exit validation, independent readback, and a confirmed receipt. Other channel properties, including retention, path, provider parameters and isolation, must remain unchanged. A final read checks the full target. Recovery changes no other channel, audit policy, group membership, service or forwarding configuration.
|
||||
|
||||
| Result | Meaning |
|
||||
| --- | --- |
|
||||
| `ReviewRequired` | A new plan and hash were retained; no native write occurred. |
|
||||
| `Refused` | Evidence, consent or current context did not authorize a write. |
|
||||
| `RestoredAndVerified` | Every selected original field was restored and observed with preservation checks. |
|
||||
| `RestoreAttemptedUnverified` | At least one native write was attempted; inspect pending, observed, confirmed and failure-state receipts before manual action. |
|
||||
|
||||
`ConfirmedFields` identifies steps whose immediate readback succeeded; a later failure does not establish that those settings stayed unchanged. Loss of power, process termination or output-storage failure can leave pending evidence without a final manifest. A read-grant removal could succeed even if the caller subsequently cannot read metadata; that remains unverified, without rollback. There is no atomic Windows compare-and-set, so another administrator can race the final check.
|
||||
|
||||
Inputs and outputs must use ordinary local paths supported by WELA's protected recovery artifact helpers. Current host identity, actual operator/logon, source files and native executable/reader assembly hashes are bound to the plan. Plan and Restore must use the same installed implementation and PowerShell version. **Old version-1 journals contain only historical ComputerName; current guards do not authenticate historical ownership.** Treat original evidence as trusted operator records. Updating WELA invalidates older review plans; create and review a new plan rather than editing its fingerprints.
|
||||
|
||||
Windows validation uses explicit disposable GitHub-hosted Server 2022/2025 fixtures under Windows PowerShell 5.1 and PowerShell 7. The fixture calls public Configure then Plan/Restore for actual CAPI2 enable/size changes, with and without the optional read ACE. It tests each missing consent, actual later size drift, replay, unsupported preview options, other-channel preservation, retained hashes, and exact original fixture configuration/all audit masks at cleanup. Shrinking during fixture cleanup can discard intervening records. Windows 11, domain/DC/CA forwarding identities, event generation, persistence through policy refresh, retention duration and backend Sigma evaluation remain separate acceptance work. No rule-readiness credit is granted.
|
||||
|
||||
See [native channel configuration](native-channel-access.md) for original journal creation and [actual channel reads](channel-read.md) for separate current-token query evidence. [Microsoft's `wevtutil` contract](https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/wevtutil) documents channel enablement, maximum size and channel access; buffer configuration is not a retention guarantee.
|
||||
@@ -18,6 +18,10 @@ or result-file error also exits with status 1.
|
||||
.\WELA.ps1 configure -Auto -ResultsPath .\results.json
|
||||
```
|
||||
|
||||
Unknown named options and other arguments left unbound by PowerShell are rejected before command dispatch. This includes unsupported `-WhatIf`, `-Confirm` and misspelled `-DryRun` options, even with `-Auto`. Use each command's `-Help` for its supported preview options; `-DryRun` is accepted only where documented. Valid positional binding and PowerShell's unambiguous parameter abbreviations remain supported.
|
||||
|
||||
`WELA.ps1` is a plain PowerShell script and does not accept PowerShell common parameters such as `-ErrorAction`, `-Verbose`, `-WarningAction` or `-InformationAction`. Earlier versions silently ignored those unbound options; they now produce exit code 1 before any command runs, including read-only commands. Remove them from automation wrappers and use WELA's exit code and structured results to check the outcome. The explicitly declared WELA `-Debug` switch remains supported where documented.
|
||||
|
||||
Keep the complete WELA directory, including `scripts/Configuration.ps1`. Choose a
|
||||
recovery path whose parent directory is writable only by the operators who manage
|
||||
these settings. The backup directory must not already exist. Without `-BackupPath`,
|
||||
|
||||
@@ -110,7 +110,14 @@ undo partially applied changes, restore a GPO, or invoke policy refresh. Re-run
|
||||
assessment after GPO/MDM refresh to verify effective state.
|
||||
|
||||
Tests exercise malformed files, preservation modes, validation ordering, mocked
|
||||
writes, prompt-time file changes and final drift. Windows CI performs real read-only
|
||||
custom-profile audits on Server 2022/2025 with PowerShell 5.1/7. Configuration and
|
||||
benign event/backend acceptance on Windows 11, DC and AD CS labs remain separate;
|
||||
writes, prompt-time file changes and final drift. Windows CI also exercises the actual public Plan, DryRun, Configure and Audit
|
||||
commands on disposable Server 2022/2025 hosts with PowerShell 5.1/7. A fixture-owned
|
||||
custom file selects four canonical controls: minimum and exact masks, an explicit
|
||||
optional control, and Not Configured preservation. Tests compare all 59 masks,
|
||||
typed precedence, source fingerprints, native channels and original journals,
|
||||
then verify exact fixture restoration. Invalid role selection is refused before
|
||||
configuration, and repeated configuration makes no further native change.
|
||||
These are hosted standalone servers classified by the shared profile engine as
|
||||
MemberServer; no domain join or GPO refresh is simulated. Configuration and
|
||||
benign event/backend acceptance on Windows 11, domain-joined servers, DC and AD CS labs remain separate;
|
||||
no clean-install or detection-coverage claim is made.
|
||||
@@ -0,0 +1,32 @@
|
||||
# Reviewed event-log size and retention recovery
|
||||
|
||||
`eventlog-recovery` restores the size and retention mode immediately before one completed WELA profile operation. It supports administrative and operational channels in the bundled event-log profiles on reviewed Windows 11 / Server 2022 and 2025 builds. This is part of issues #379 and #365; it does not recover records already lost.
|
||||
|
||||
Use the original `before.jsonl` and final results from `configure-eventlogs` or the same profile helper used by `configure`. The selected result must be `Applied`, with both the initial and `ImmediatePreWrite` journal entries and matching final `BeforeWrite`. Failed, overridden, incomplete, legacy scalar writes and unexplained changes require manual investigation. Other journaled controls are not restored.
|
||||
|
||||
```powershell
|
||||
./WELA.ps1 eventlog-recovery -EventRecoveryJournalPath C:\Evidence\original\before.jsonl `
|
||||
-EventRecoveryOriginalResultsPath C:\Evidence\original-results.json `
|
||||
-EventRecoveryLog ForwardedEvents -EventRecoveryOutputPath C:\Evidence\recovery-plan
|
||||
|
||||
# Inspect plan.json: current and original sizes, modes, channel guard and consent flags.
|
||||
# Supply the exact PlanHash shown by Plan after reviewing that file.
|
||||
./WELA.ps1 eventlog-recovery -EventRecoveryAction Restore `
|
||||
-EventRecoveryPlanPath C:\Evidence\recovery-plan\plan.json `
|
||||
-EventRecoveryPlanHash '<reviewed SHA256>' -EventRecoveryOutputPath C:\Evidence\recovery-run `
|
||||
-EventRecoveryAllowShrink -EventRecoveryAllowRetentionChange
|
||||
```
|
||||
|
||||
The last two switches are separate consent for the effects actually identified by the plan. Omit them when inapplicable. **Shrinking can discard existing events.** Changing to Circular allows older records to be overwritten; changing to Retain can discard incoming records when full; leaving AutoBackup stops automatic archival. Review storage and recovery requirements before consenting. Plan writes review evidence but changes no Windows settings. Restore does not export or clear logs, restore an archive, alter channel enablement/ACL/path/provider settings or restart services.
|
||||
|
||||
Each output must be a fresh directory on a local fixed drive, with an existing parent. Evidence is protected for the current operator, Administrators and SYSTEM. The plan is bound to the actual current host/MachineGuid, operator logon, original input bytes and implementation/catalog hashes. Use the same checkout and elevated operator logon for Restore. Winmgmt and EventLog must already be running; host observations use the existing reviewed-build gate. The original version-1 journal records only historical ComputerName: current host bindings and hashes do not authenticate that history.
|
||||
|
||||
The plan is rebuilt from original evidence on Restore. Minimum-size writes are checked against the immediate-prewrite size so an independent increase during prompting is preserved. An unexplained larger final size is refused. Current size/mode/enable state must match the confirmed post-configuration state. Current channel path, ACL, isolation, type, owning provider and classic-log flag are captured when planning and must remain unchanged. Live event count and EVTX file allocation are intentionally not treated as configuration guards.
|
||||
|
||||
Restore flushes a Pending receipt before one fixed local `wevtutil sl` operation, rechecks the inputs and current channel, changes only the required size/mode arguments, and records final native readback. There is no atomic compare-and-set in this interface. A concurrent policy refresh or writer can still intervene, and verified values do not prove persistence.
|
||||
|
||||
`RestoredAndVerified` means the requested size/mode and preserved configuration matched during readback. `Refused` means no native write was attempted. `RestoreAttemptedUnverified` means a write may have partly succeeded; inspect the Pending receipt and any after-state evidence before further action. Automatic rollback and replay against the already-restored state are refused. A fatal evidence-write error may leave only a Pending receipt; keep it for investigation.
|
||||
|
||||
The Windows fixture uses genuine public configuration of the disposable runner's ForwardedEvents channel, then public planning, consent refusal, actual drift refusal, restoration and replay refusal. It restores the original channel configuration and compares every original audit mask. Matrices cover Server 2022/2025 and PowerShell 5.1/7; the test proves configuration behavior, not historical record preservation, achieved retention, forwarding or Sigma readiness. Sysmon is excluded.
|
||||
|
||||
Reference: [Microsoft wevtutil size, retention and auto-backup options](https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/wevtutil).
|
||||
@@ -0,0 +1,26 @@
|
||||
# Native local failed-logon probe
|
||||
|
||||
`failed-logon-probe` checks whether one fixed native local authentication failure can be correlated with its Security4625 event. It does not enable auditing. Sysmon is outside this workflow.
|
||||
|
||||
```powershell
|
||||
.\WELA.ps1 failed-logon-probe
|
||||
.\WELA.ps1 failed-logon-probe -FailedLogonAction Run -FailedLogonOutputPath C:\Evidence\failed-logon-01
|
||||
```
|
||||
|
||||
The default Plan reads prerequisites and the actual latest Security record. It creates no files and makes no authentication attempt. Run requires a new private output directory and an elevated, unimpersonated 64-bit primary token. Existing Logon failure auditing, DWORD1 `SCENoApplyLegacyAuditPolicy`, an enabled/readable Security channel and running native observation/authentication services are prerequisites. Reviewed Windows11 and Server2022/2025 clients, standalone and member servers are accepted. Domain controllers are excluded because their account database is the domain database; native CI covers disposable workgroup Server2022/2025 under PowerShell5.1 and7, not client/domain policy variants.
|
||||
|
||||
Run generates a20-character account name from a fresh GUID and calls `NetUserGetInfo` against the local database. Only exact `NERR_UserNotFound` permits the next step. A fixed native `LogonUserW` call uses domain `.` (local account database only), network logon type3 and the NTLM provider2. The actual local native event identifies its package as `MICROSOFT_AUTHENTICATION_PACKAGE_V1_0`, which the matcher requires exactly; the provider choice does not imply that the XML field is the literal `NTLM`. A fixed public dummy string is not a real credential. There is exactly one attempt, with no retry, account creation, remote target or user-selected credential. The expected native result is failure1326. Any unexpected success closes the returned token without using it and remains unverified. The worker never impersonates.
|
||||
|
||||
The worker uses the current PowerShell executable and process-only execution-policy Bypass to load its fixed script. It has a20-second process bound. The optional `-FailedLogonTimeoutSeconds 1..30` controls event-delivery polling only; it never repeats authentication. Precise native UTC timestamps bound the actual authentication call without padding. A fresh Security record boundary, worker process/path, caller SID/logon session, exact generated account/domain, logon type/provider, and failure status/substatus must match exactly one provider/version0 Security4625. Provider schema differences, missing events, duplicate matches, denied reads, caps, token changes, policy/source/host/channel drift and a backwards record boundary remain unverified.
|
||||
|
||||
Evidence includes a durable `intent.json` before launching, the native receipt, before/after observations, exact raw XML, and a manifest with SHA256 artifact hashes. A timeout or failed receipt leaves the intent so an operator can see that an attempt may have occurred; absence of a successful report does not establish that no attempt happened. Record boundaries and hashes detect selected inconsistencies; they are not a tamper-proof log-continuity or machine-attestation mechanism. Keep the entire directory together. No policy, channel, service, account or trust configuration is written by the product.
|
||||
|
||||
The observed result proves this one local nonexistent-account failure only. It does not prove remote or domain authentication, real-account password failures, lockout handling, forwarding, SIEM parsing, every failed-logon variant or Sigma rule readiness. `ReadyRuleCredit` remains0. The attempt creates expected authentication telemetry and may be visible to local monitoring.
|
||||
|
||||
## Validation and references
|
||||
|
||||
Portable fixtures test exact100ns time boundaries, account/status/process/token mismatches, malformed XML, duplicate events, source drift, caps, failures and public CLI guards. The native workflow prepares only the disposable fixture's Logon failure mask and audit precedence, executes two independent public runs, validates actual4625 XML/receipt hashes, verifies unchanged local accounts and restores all59 audit masks and the original typed precedence.
|
||||
|
||||
Microsoft documents the local-domain behavior and native return contract in [LogonUserW](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-logonuserw), account lookup in [NetUserGetInfo](https://learn.microsoft.com/en-us/windows/win32/api/lmaccess/nf-lmaccess-netusergetinfo), and the event fields/statuses in [4625: An account failed to log on](https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-10/security/threat-protection/auditing/event-4625).
|
||||
|
||||
The local package behavior is described in Microsoft's [MSV1_0 authentication package documentation](https://learn.microsoft.com/en-us/windows/win32/secauthn/msv1-0-authentication-package). Exact event-package spelling is additionally verified from retained native XML.
|
||||
@@ -0,0 +1,31 @@
|
||||
# One-byte local file access probe
|
||||
|
||||
`file-access-probe` checks whether one explicit read of one existing file produces an attributable local Security 4663 event. Plan observes prerequisites without reading file data. Run opens the same selected leaf in a fixed worker, reads exactly one byte once, clears that buffer and retains no file contents. It changes no audit policy, ACL, service, channel setting or file data. A native read can update access metadata and can trigger existing monitoring.
|
||||
|
||||
Run elevated in native 64-bit Windows PowerShell 5.1 or PowerShell 7. Select an ordinary, nonempty file on a fixed local drive using its exact absolute DOS path (at most 240 characters). UNC/device input paths, alternate streams, wildcards, reparse components, multiple hard links, EFS, offline/recall files and directories are refused. Targets inside the canonical WELA source tree, the active PowerShell executable and aliases are refused by an initial metadata-only check before implementation/engine hashing. The token must already hold the security privilege needed to inspect the SACL; observation enables that existing privilege only around handle acquisition and restores its prior state before the data read. No privilege is granted and backup semantics are not used.
|
||||
|
||||
The File System subcategory must already include Success, `SCENoApplyLegacyAuditPolicy` must be typed DWORD 1, and the enabled Security channel must be readable. One existing ordinary success ReadData audit ACE must apply directly to the user SID or an enabled, non-deny-only group. Inherit-only and conditional/callback ACEs cannot establish this prerequisite. EventLog, Winmgmt and RpcSs must already be running. This command does not install a SACL or repair prerequisites.
|
||||
|
||||
```powershell
|
||||
.\WELA.ps1 file-access-probe -FileProbePath C:\Audit\existing-file.txt
|
||||
.\WELA.ps1 file-access-probe -FileProbeAction Run `
|
||||
-FileProbePath C:\Audit\existing-file.txt `
|
||||
-FileProbeOutputPath C:\Evidence\new-file-probe `
|
||||
-FileProbeTimeoutSeconds 15
|
||||
```
|
||||
|
||||
Run requires a fresh private evidence directory outside the code tree. Only dedicated options are accepted; no `-Auto`, `-DryRun`, generic `-WhatIf` or extra positional arguments. `FileProbeTimeoutSeconds` accepts 1–30 seconds for polling after the worker; worker execution has a separate 20-second limit. Native query work and cleanup add elapsed time.
|
||||
|
||||
The request binds actual host/build/MachineGuid, engine and implementation hashes, token groups and privileges, all effective audit masks, precedence, Security configuration and full selected-file metadata/security. A held existing-file handle prevents concurrent write/delete opens. Volume/file ID, creation and last-write times, size, attributes, link count and full current SDK security descriptor must agree before and after the operation. Both DOS and NT volume names are observed from that same handle and bound to this identity. Path comparison is case-insensitive; other volume names or paths are not inferred or accepted. Some volumes can emit Removable Storage Task 12812 even when `DriveInfo` reports Fixed, as observed on a hosted runner data volume. This probe accepts only File System Task 12800; those other events remain unverified.
|
||||
|
||||
Before launch, the parent writes and flushes `before.json` and `intent.json`. The worker inherits the existing execution policy without an override; a blocked worker remains unverified with its prior intent retained. The fixed worker independently rebuilds the request state, verifies its primary token, performs one native `ReadFile` call requesting one byte and returns a receipt with exact PID, handle and precise `StartedUtc`, `ReadReturnedUtc` and `CompletedUtc` timestamps. Its fixed `OneByteReadAndHeldIdentityReadback` phase spans the one read and the existing same-handle identity/security readback; the immediate `ReadFile` return remains separately visible. Times must satisfy start <= read return <= phase completion <= parent observation. No sleep or timestamp padding is added. The parent retains `operation.json`, the original matching `event.xml`, `after.json` and their SHA-256 hashes in `manifest.json`. These artifacts contain file paths, SIDs, security descriptors and audit context, but no target contents or target-content hashes. The manifest is not self-hashed.
|
||||
|
||||
Success requires exactly one fresh version-1 Security 4663 from the expected provider, computer, user SID/logon ID, worker PID/executable, native handle, selected DOS or NT path and ReadData mask/access token. Event time must fall within that actual measured read/readback phase, with no padding; it need not fall inside the `ReadFile` call itself. The query stops at 256 events and bounds individual XML size; hitting a cap, missing/duplicate evidence, drift, changed reader context or failed persistence prevents verified success. The final Security record boundary must not move backwards.
|
||||
|
||||
`PrerequisitesObserved` (Plan) and `FileReadObserved` (Run) exit 0. `Unverified` exits 1 and explains the observed gap. A stopped or failed worker may already have attempted the read; durable intent alone does not prove completion. An interrupted process may leave only partial evidence, and a manifest-write failure fails outward while earlier receipts remain. Inspect retained artifacts before deciding whether to run another probe in a different fresh directory.
|
||||
|
||||
This is evidence for that one current-token local ReadData success. It does not prove Failure auditing, other rights/users/files, child inheritance, forwarded delivery, backend parsing, Sigma readiness or general detection coverage. Security 4663 has no Failure variant. No Sigma/EVTX coverage points are added.
|
||||
|
||||
The disposable Windows fixture owns its files in a fresh private system-volume directory and its separate evidence directory, explicitly establishes the test SACL/policy, exercises the public Plan/Run path twice, verifies all artifact hashes and unchanged file content/security, tests missing-SACL/policy and file-replacement refusals, then restores all effective audit masks, typed precedence and token state. It removes only its owned target directory and retains cleanup evidence. Server 2022/2025 and PowerShell 5.1/7 run independently; these fixture changes are not product behavior.
|
||||
|
||||
Microsoft references: [4663 event semantics and fields](https://learn.microsoft.com/en-us/windows/security/threat-protection/auditing/event-4663), [ReadFile](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile), and [same-handle DOS/NT path observation](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfinalpathnamebyhandlew).
|
||||
@@ -0,0 +1,59 @@
|
||||
# Guarded firewall text-log recovery
|
||||
|
||||
`firewall-recovery` plans and explicitly restores the four local logging fields for **one** Domain, Private or Public profile from a completed WELA `firewall-logging -FirewallAction Configure` operation. It uses built-in Windows functionality; Sysmon is out of scope. It does not grant event-generation, delivery, retention or Sigma readiness credit.
|
||||
|
||||
The restored fields are `LogAllowed`, `LogBlocked`, `LogMaxSizeKilobytes` and `LogFileName` in `PersistentStore`. The original values can disable logging or reduce its size: review the complete proposed tuple before restoring. Microsoft distinguishes local persistent settings from the resultant `ActiveStore` policy. Recovery reports the selected effective tuple separately and does not change its policy authority. See [Set-NetFirewallProfile](https://learn.microsoft.com/en-us/powershell/module/netsecurity/set-netfirewallprofile?view=windowsserver2025-ps).
|
||||
|
||||
## Prepare and review
|
||||
|
||||
Keep the genuine original `before.jsonl` and final results from [firewall logging configuration](firewall-logging.md). The selected row must have final status `Applied`, dedicated scope `firewall-text-logging-only`, a matching version-1 journal entry and matching original Before/Desired/Target values. Failed, partial, ambiguous and no-op operations are not automatically recoverable.
|
||||
|
||||
Use elevated native 64-bit Windows PowerShell 5.1 or PowerShell 7 on reviewed Windows 11 builds 22000/22621/22631/26100/26200 or Server 2022/2025 builds 20348/26100. Winmgmt, MpsSvc and BFE must already be running before native provider reads. The plan and restoration must use the same engine version, machine identity and actual elevated operator/logon context. Impersonation is refused. Original version-1 configuration journals recorded only the computer name, so they do **not** prove historical MachineGuid or operator identity. The operator must establish that the original evidence belongs to this installation; current identity binding starts with the recovery plan.
|
||||
|
||||
Create new local output directories under an existing parent, outside the WELA source tree. WELA applies private output permissions and never overwrites an old evidence directory.
|
||||
|
||||
```powershell
|
||||
./WELA.ps1 firewall-recovery -FirewallRecoveryProfile Domain `
|
||||
-FirewallRecoveryJournalPath C:\Evidence\configure-backup\before.jsonl `
|
||||
-FirewallRecoveryResultsPath C:\Evidence\configure-results.json `
|
||||
-FirewallRecoveryOutputPath C:\Evidence\firewall-recovery-plan
|
||||
```
|
||||
|
||||
Review `plan.json`, especially `Control.Expected` (the confirmed original local After values), `Control.RecoverTo` (the exact original local Before values), the selected profile, source hashes and preserved settings. Record the reported `PlanSha256` after review. Plan reads configuration and writes evidence only.
|
||||
|
||||
```powershell
|
||||
# Replace this placeholder with the SHA256 from the reviewed plan.
|
||||
$reviewedHash = '<64 lowercase hexadecimal characters>'
|
||||
./WELA.ps1 firewall-recovery -FirewallRecoveryAction Restore `
|
||||
-FirewallRecoveryPlanPath C:\Evidence\firewall-recovery-plan\plan.json `
|
||||
-FirewallRecoveryPlanHash $reviewedHash -DryRun
|
||||
|
||||
./WELA.ps1 firewall-recovery -FirewallRecoveryAction Restore `
|
||||
-FirewallRecoveryPlanPath C:\Evidence\firewall-recovery-plan\plan.json `
|
||||
-FirewallRecoveryPlanHash $reviewedHash `
|
||||
-FirewallRecoveryOutputPath C:\Evidence\firewall-recovery-result
|
||||
```
|
||||
|
||||
Restoration prompts before the single native setter. `-Auto` explicitly skips that prompt; it does not skip any evidence or state guards. Dry run creates no output directory and does not call a setter. An exact already restored tuple returns `AlreadyRestored` without another write.
|
||||
|
||||
## Guards and outcomes
|
||||
|
||||
WELA independently rebuilds the selected operation from unchanged journal/result bytes and checks the separately supplied plan hash. It accepts explicit local `True`/`False` logging flags, an integer size from 1 through 32767 KiB and an ordinary local path. Only `%SystemRoot%` and `%windir%` variables are supported. UNC/device paths, alternate streams, dot segments, wildcards, reparse paths and unknown values are refused. `NotConfigured` is documented for GPO use and requires manual review instead of automatic local replay. The original command's Preserve/CisV4 path and maximum-size behavior must explain the recorded After tuple exactly.
|
||||
|
||||
The current local tuple must equal the selected confirmed After tuple, or the exact original tuple for idempotence. A new plan binds current host/operator context, source files and native NetSecurity module files. It preserves the other two profiles in both stores, every nonlogging field of the selected profiles, and bounded native rule/filter configuration fingerprints. Filters are queried separately because conditions are exposed through filter objects; see [Get-NetFirewallPortFilter](https://learn.microsoft.com/en-us/powershell/module/netsecurity/get-netfirewallportfilter?view=windowsserver2025-ps). Inventories cap each class/store at 4096 objects and 16 MiB of canonical data. Unknown native property types, unreadable inventories or caps refuse recovery. Volatile rule operational diagnostics are excluded from configuration fingerprints.
|
||||
|
||||
After a durable `pending.json` receipt, WELA rechecks inputs and current state before the one fixed `Set-NetFirewallProfile -PolicyStore PersistentStore` call. It then verifies the exact local tuple, preserved configuration and fresh/final context, retaining `confirmed.json` and `result.json`. It never changes firewall enforcement, rule definitions, other profiles, Group Policy, destination ACLs, services or shares. There is no automatic rollback.
|
||||
|
||||
| Result | Meaning |
|
||||
| --- | --- |
|
||||
| `Planned` / `WouldRestore` | Reviewable plan / read-only current guard checks passed. |
|
||||
| `LocalLoggingRestored` | Exact selected local tuple and preserved configuration passed readback and final checks. |
|
||||
| `AlreadyRestored` | Original local tuple is already present; no setter was called. |
|
||||
| `Refused` | A prerequisite or guard failed before a setter was attempted. |
|
||||
| `WriteAttemptedUnverified` | A setter was attempted but completion or subsequent verification failed. Preserve the receipts and investigate manually. |
|
||||
|
||||
`EffectiveMatchesLocal` compares the selected effective and local tuples after restoration. False can represent an effective policy override; local success does not imply effective logging was restored. Destination write authorization, actual firewall text records, future policy refresh, forwarding and long-term retention need separate acceptance. Path checks do not prove destination writability or historical file identity. Native APIs do not offer an atomic transaction over all these inventories: observed drift fails closed, but concurrent external changes between reads cannot be excluded.
|
||||
|
||||
## Validation
|
||||
|
||||
Focused fixtures cover strict original evidence, typed values, changed plans, stale settings, operator/source drift, post-prompt changes, partial writes, preserved enforcement and local/effective separation. The gated disposable Windows workflow uses the public Configure command to produce genuine journals, then public Plan, dry run, drift refusal, Restore and idempotence on Server 2022/2025 under both engines. Its fixture changes only logging values and a new owned log directory, restores all original logging fields, and compares complete preserved native configuration before removing that directory. It never generates traffic or changes enforcement. Windows 11, domain policy refresh and backend acceptance remain separate deployment tests.
|
||||
@@ -40,7 +40,9 @@ WELA does not attempt to broaden ACLs, resolve arbitrary group membership, imper
|
||||
|
||||
Each snapshot also reports the firewall profile's `Enabled` value. A compliant logging configuration on a disabled/inactive profile is preparation for that profile, not proof of traffic events. WELA never changes that enforcement state. Text logs and Security EVTX audit events are separate sources; increasing an EVTX buffer does not configure these text logs, and a WEF subscription alone does not collect arbitrary text files.
|
||||
|
||||
## Manual recovery
|
||||
## Guarded and manual recovery
|
||||
|
||||
For one completed `Applied` operation with matching original journal and results, use the explicit [guarded firewall logging recovery](firewall-logging-recovery.md) Plan/Restore workflow. It verifies the current confirmed local After values, restores the original four local logging fields and preserves enforcement, other profiles and bounded native rule/filter configuration. Partial, ambiguous, drifted and unsupported operations still require manual investigation.
|
||||
|
||||
There is no automatic rollback. Preserve `before.jsonl` and the results JSON. Before recovery, review failed versus applied controls, concurrent operator changes and GPO/MDM ownership. Restore the **local** snapshot, not the effective snapshot; applied policy may continue overriding it. Example for one reviewed journal entry:
|
||||
|
||||
@@ -60,7 +62,7 @@ Do not blindly replay a journal: a failed write can have left the old state unto
|
||||
|
||||
## Validation and remaining integration evidence
|
||||
|
||||
The automated suite uses mocked firewall writes and temporary recovery files to check all profiles, larger limits, path preservation/CIS selection, effective-versus-local conflicts, idempotence, journal ordering, unknown permissions, read/write errors, prompt races and final drift. Windows CI runs these checks under PowerShell 5.1 and 7, plus actual read-only ActiveStore/PersistentStore and ACL inspection and a dry run. It does not alter runner firewall policy or generate traffic.
|
||||
The original automated suite uses mocked firewall writes and temporary recovery files to check all profiles, larger limits, path preservation/CIS selection, effective-versus-local conflicts, idempotence, journal ordering, unknown permissions, read/write errors, prompt races and final drift. Its Windows smoke performs read-only ActiveStore/PersistentStore and ACL inspection and a dry run. The separate guarded-recovery workflow explicitly changes logging fields in a disposable owned fixture through the public Configure/Restore commands, then verifies exact restoration under PowerShell 5.1 and 7 on Server 2022/2025. Neither suite changes firewall enforcement or generates traffic.
|
||||
|
||||
Before closing issue #375, capture evidence from an isolated Windows client/server lab: OS build, PowerShell version, WELA commit, before/after JSON, effective/local settings and service ACLs. On each applicable active network profile, generate one benign allowed connection and one controlled blocked connection against a disposable endpoint, confirm corresponding `ALLOW`/`DROP` text records and timestamps, and confirm the expected source path and parser in the actual collector. Test log creation and rotation under the actual service token, policy refresh/override behavior, and manual recovery. Do not weaken production filtering to create this evidence. These traffic/rotation/ingestion tests remain unperformed; no end-to-end detection claim is made.
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
# Conditional IPsec Main Mode auditing
|
||||
|
||||
The built-in `microsoft-stronger-reviewed-2026-09` profile enables IPsec Main Mode Success and Failure only when the operator selects `-IncludeOptional` **and** WELA observes a positive native prerequisite on the local Windows host. Other profiles and operator-owned custom profile requirements keep their existing meanings.
|
||||
|
||||
```powershell
|
||||
# Observe the actual local host and retain the evidence in the shared plan.
|
||||
./WELA.ps1 plan -Profile microsoft-stronger-reviewed-2026-09 -IncludeOptional -PlanPath ipsec-plan.json
|
||||
|
||||
# Review the complete stronger profile before configuring it: this profile also selects other audit subcategories.
|
||||
./WELA.ps1 configure -Profile microsoft-stronger-reviewed-2026-09 -IncludeOptional -DryRun -ResultsPath preview.json
|
||||
./WELA.ps1 configure -Profile microsoft-stronger-reviewed-2026-09 -IncludeOptional -Auto -BackupPath new-backup -ResultsPath result.json
|
||||
```
|
||||
|
||||
WELA uses the built-in NetSecurity module to read `Get-NetIPsecRule -PolicyStore ActiveStore` and `Get-NetIPsecMainModeSA`. It makes no connection-security, firewall, authentication, service or network changes. The existing configuration engine changes only the selected audit requirements and their advanced-audit precedence prerequisite.
|
||||
|
||||
| Observation | Meaning and conditional configuration behavior |
|
||||
| --- | --- |
|
||||
| `Applicable` | Both inventories completed with recognized records, and either an enabled, healthy, non-exemption ActiveStore rule or a current main-mode SA was observed. With explicit optional selection, the audit setting can be assessed/applied. |
|
||||
| `NotObservedWithinScope` | Both inventories completed, with no qualifying rule or SA. Preserve the audit setting and report `Skipped`, including when the existing mask already equals S+F. This is **not** a claim that all IPsec is unused. |
|
||||
| `Unknown` | Offline scenario, failed/partial/malformed/duplicate/capped inventory, or an enabled securing rule with uncertain health. A selected configuration control fails without writing that audit setting. Independent profile controls retain their normal behavior. |
|
||||
|
||||
Disabled rules and rules with both `InboundSecurity` and `OutboundSecurity` set to `None` do not establish the prerequisite. Rule names, enabled/security/health values, qualification, association names/endpoints, timestamps, host and separate source outcomes remain in `conditionalPrerequisite` in the plan. Each source is limited to 4096 records; exceeding the limit is Unknown. The inventory is sequential and point-in-time, not an atomic system snapshot. Native calls have the operating system's normal completion behavior; this feature does not impose a wall-clock query timeout.
|
||||
|
||||
An enabled healthy rule in the effective store establishes **configured policy**, not that its address/profile/interface filters currently match traffic, that authentication succeeds, or that any event is emitted. WELA does not inspect the associated filters as an enforcement proof. Absence does not exclude legacy policy, VPN use, other IPsec providers or an idle deployment. Investigate those separately; use a reviewed custom profile if your intended exact audit requirement is independently established outside this automatic scope.
|
||||
|
||||
Offline plans retain Unknown and never query the machine running the planner. Live public `plan`, `audit-settings -Profile` and `configure -Profile` collect only for this built-in stronger-profile condition. A role/build scenario for a different host remains offline. The optional flag is still necessary when positive evidence exists; no extra setting is selected automatically. Offline GPO/Intune exports retain their existing operator-selected deployment semantics and do not claim that endpoint prerequisites have been observed.
|
||||
|
||||
The public configuration runner retains fresh native observations in the control's `PrerequisiteObservations`. It checks before assessment, after the operator prompt and recovery journal immediately before the native policy write, after application and during final verification. Losing the prerequisite after planning or confirmation prevents that write; losing it after a completed write produces a failed verification with the recorded evidence and recovery journal. The direct shared profile executor also checks its selected condition initially and immediately before mutation. No lock prevents concurrent changes after the final check, and no automatic policy rollback is performed. Existing audit recovery procedures still apply.
|
||||
|
||||
The read-only inventory itself requires access to the local native providers; configuration requires elevation. Records can contain policy identifiers and peer IP addresses, so retain exported reports with your other administrator evidence.
|
||||
|
||||
## Validation boundaries
|
||||
|
||||
Portable tests exercise disabled/exempt rules, malformed/failed/capped observations, offline planning, explicit optional selection, source-profile isolation, both configuration paths and prerequisite loss after a prompt. The gated native fixture uses fresh rules between documentation-only IP addresses, exercises the public plan/dry-run/configure commands, and removes its owned rule after confirmation to test native pre-write refusal. It restores all 59 original audit masks, the typed precedence value or its absence, and the original rule inventory. The fixture generates no network traffic or main-mode negotiation.
|
||||
|
||||
Native CI covers Server 2022/2025 under Windows PowerShell 5.1 and PowerShell 7. Actual SA-positive collection, Windows 11, domain-managed/legacy/VPN scenarios, successful and failed negotiation XML, event volume, collection and detection acceptance remain separate. This advances the prerequisite-detection part of issue #370; it does not close that issue or establish any Sigma eligibility. Sysmon is excluded.
|
||||
|
||||
Sources: Microsoft's [stronger audit recommendations](https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/plan/security-best-practices/audit-policy-recommendations), [effective IPsec rule inventory and security semantics](https://learn.microsoft.com/en-us/powershell/module/netsecurity/get-netipsecrule?view=windowsserver2025-ps), [current main-mode associations](https://learn.microsoft.com/en-us/powershell/module/netsecurity/get-netipsecmainmodesa?view=windowsserver2025-ps), and [native rule/filter creation semantics](https://learn.microsoft.com/en-us/powershell/module/netsecurity/new-netipsecrule?view=windowsserver2025-ps).
|
||||
@@ -30,15 +30,17 @@ The planner uses [RawSecurityDescriptor](https://learn.microsoft.com/en-us/dotne
|
||||
|
||||
The shared configuration runner writes `before.jsonl` before each native mutation, capturing the original enabled state, exact size, full descriptor and retention mode. A fresh read must match both the plan and the journal snapshot before `wevtutil sl` executes. Only changed `/e:true`, `/ms:...` and explicitly authorized `/ca:...` arguments are sent. Native failure, failed readback, descriptor mismatch and final drift produce a nonzero result. There is no atomic Windows compare-and-set; another writer can still race the final check. Re-run after policy refresh to check persistence. No automatic rollback occurs.
|
||||
|
||||
Recovery is manual: review each journal `Before` against the current settings, identify the affected channel, and restore only the intended previous values using `wevtutil sl "CHANNEL" /e:true|false /ms:ORIGINAL_BYTES /ca:"ORIGINAL_SDDL"`. Pass the descriptor as one argument in PowerShell, for example `& wevtutil.exe sl $entry.Target.Channel ("/ca:" + $entry.Before.SecurityDescriptor)` after loading and reviewing the relevant JSONL entry. Restoring a smaller limit can discard events. Existing retention is not intentionally modified; investigate any changed mode before choosing recovery actions. Use a new backup directory for each run.
|
||||
For a completed `channel-settings` operation, use [reviewed single-channel recovery](channel-recovery.md) to reconstruct the original changed fields, require exact current after-state and request separate shrink/disable/read-revocation consent. Partially completed originals and later drift still require manual review. For manual recovery, review each journal `Before` against the current settings, identify the affected channel, and restore only the intended previous values using `wevtutil sl "CHANNEL" /e:true|false /ms:ORIGINAL_BYTES /ca:"ORIGINAL_SDDL"`. Pass the descriptor as one argument in PowerShell, for example `& wevtutil.exe sl $entry.Target.Channel ("/ca:" + $entry.Before.SecurityDescriptor)` after loading and reviewing the relevant JSONL entry. Restoring a smaller limit can discard events. Existing retention is not intentionally modified; investigate any changed mode before choosing recovery actions. Use a new backup directory for each run.
|
||||
|
||||
## Native WEF prerequisites and validation
|
||||
|
||||
The checked-in inventory maps source query IDs to 12 baseline channels and 8 suspect channels (18 unique combined). Baseline queries 12 (EMET) and 39 (Sysmon) are explicitly excluded. Native-only scope excludes external agents; channel settings do not create subscriptions, add service identities to groups or configure WinRM/collectors. The Microsoft [source prerequisite guidance and sample queries](https://learn.microsoft.com/en-us/windows/security/operating-system-security/device-management/use-windows-event-forwarding-to-assist-in-intrusion-detection) remain a starting point for reviewing role applicability. The report always lists token/group membership, producer configuration, representative event generation and forwarding/ingestion as unverified; required disabled or missing channels remain visible. Other inventoried channels are not automatically enabled.
|
||||
|
||||
Safe tests exercise the actual command/JSON/runner with mocked Windows setters. Windows PowerShell 5.1 and PowerShell 7 CI additionally exercise real descriptor serialization and read-only CLI inspection. Release packaging already includes the whole `config`, `modules` and `scripts` directories.
|
||||
Safe tests exercise the actual command/JSON/runner with mocked Windows setters. Windows PowerShell 5.1 and PowerShell 7 CI also exercise real descriptor serialization and read-only CLI inspection. A separate four-way disposable Server 2022/2025 suite exercises the public Plan, Configure with DryRun, Configure without a reader grant, explicit read-only grant, and repeated idempotent configuration. It verifies exact native descriptor bytes, recovery journal contents, preservation of an existing 2 GiB buffer, all other channel XML fields, and restoration of the original channel settings and all 59 audit masks. Hashed artifacts retain original/configured XML, reports, journal and cleanup evidence.
|
||||
|
||||
**Isolated Windows acceptance evidence is still pending; related to issue #367, not sufficient to close it.** On patched Windows 11, member server, DC and ADCS snapshots where the channels exist:
|
||||
That fixture changes only the three declared channels on explicitly opted-in GitHub-hosted disposable VMs. Restoring the original smaller sizes can discard events generated during the test; it does not restore event records or prove retention duration. It never supplies production forwarding-token access, event generation, collector arrival, policy-refresh persistence or Sigma evidence. Do not run the mutating fixture on ordinary machines. Release packaging already includes the whole `config`, `modules` and `scripts` directories.
|
||||
|
||||
**Broader Windows acceptance remains pending; related to issue #367, not sufficient to close it.** Hosted server configuration checks do not cover Windows 11 or domain-specific access and forwarding behavior. On patched Windows 11, member server, DC and ADCS snapshots where the channels exist:
|
||||
|
||||
1. Save the plan, channel metadata, descriptor and policy context. Review capacity and the intended forwarding identity. Capture the actual identity/token memberships separately.
|
||||
2. Apply the opt-in profile, retain the journal/results, then independently read enablement, exact bytes and full SDDL. Compare all original ACEs plus owner/group/SACL/flags and repeat after policy refresh.
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
# Public filesystem SACL lifecycle validation
|
||||
|
||||
The `Native public filesystem SACL lifecycle` workflow validates the public `targeted-sacl` command against its real built-in per-user Signal directory definition. It runs on disposable Server 2022/2025 hosts with Windows PowerShell 5.1 and PowerShell 7. It uses an owned redirected folder, its existing ordinary descendants and a protected subtree, then runs the public `file-access-probe` against one inherited leaf SACL.
|
||||
|
||||
## Owned fixture boundary
|
||||
|
||||
The test creates a fresh private directory on the system volume, a newly saved hive mounted under a nonce-derived synthetic SID, and a matching new `ProfileList` entry. The entry contains only its ownership marker and typed `ProfileImagePath`. Its loaded hive supplies a redirected `AppData` known-folder value. The ordinary catalog must independently discover exactly that SID's Signal directory and classify it `Redirected`; no alternate catalog, arbitrary target switch or mocked resolver supplies selection authority.
|
||||
|
||||
The synthetic SID is a fixture identity, not a created Windows account or proof of another user's effective access. The read worker uses the actual elevated runner account. Existing users, offline hives and system catalog targets are not modified. Profile registration, hive loading, initial unrelated ACE/protection setup and temporary audit policy are test-only operations; public WELA commands do not perform them.
|
||||
|
||||
The test alone prepares File System success/failure auditing and typed advanced-audit precedence. It requires a complete observation of all 59 masks, the original full process token and the complete bounded `ProfileList` key/value inventory. Profile values retain their registry types and unexpanded data. The test never restores a whole saved system registry tree over current state.
|
||||
|
||||
## Public operations and retained proof
|
||||
|
||||
The fixture exercises this sequence with bounded, separately launched public WELA processes:
|
||||
|
||||
1. Discover the actual redirected catalog target. Plan without child consent must block inheritance.
|
||||
2. Plan with explicit child consent must capture the exact parent and all four existing descendants: one ordinary directory/leaf pair and one protected directory/leaf pair.
|
||||
3. DryRun must leave every descriptor unchanged and create no recovery directory.
|
||||
4. Create one owned unreviewed child. Configure using the earlier plan must refuse before journaling or writing. Remove that fixture child and generate a fresh plan.
|
||||
5. Configure the fresh selection. A successful result must contain one `Applied` row and matching distinct Pending, Confirmed and descendant-observation records.
|
||||
6. Independently read the parent and children. Exactly one required root ACE is added; its unrelated ACE, owner, group, DACL and other observed descriptor components remain. Two ordinary descendants show the inherited ACE, while both protected descendants retain their original security.
|
||||
7. A fresh Plan/Configure reports `AlreadyCompliant`, adds no duplicate ACE or receipt, and preserves the complete observed tree.
|
||||
8. Public file-probe Plan/Run on the ordinary leaf must observe the existing inherited ReadData SACL and exactly one attributable local Security 4663. The protected leaf must remain uncovered and its read probe must refuse before a read operation.
|
||||
|
||||
The probe retains raw XML and binds the actual worker PID, handle, subject SID/logon, native file identity/path, access mask and measured one-byte-read/held-identity-readback phase. It reads exactly one byte and retains no file content. Only the fixture hashes its known harmless files to check byte preservation. The public configuration still reports `GenerationReadiness=Conditional` and `UsableRuleCredit=0`; the probe grants no Sigma credit.
|
||||
|
||||
Review `fresh-plan.json`, `results.json`, `journal/`, the independent before/after/final descendant snapshots, `probe-result.json`, `probe/event.xml`, `cleanup.json` and `artifact-hashes.json` together. A process exit or printed status alone is insufficient. A failed run can retain partial evidence and is not a successful lifecycle result.
|
||||
|
||||
## Cleanup and limits
|
||||
|
||||
Cleanup restores the original selected audit mask and exact typed precedence, then independently compares every original audit mask, full token, `ProfileList` inventory/data and loaded-hive names. The ProfileList adapter removes only its exact unchanged two-value, childless, marker-owned entry. Changed ownership or partial setup prevents unproven deletion and is retained as a cleanup error. The owned hive is unloaded, its original seed removed, and the private hive files/target tree removed only after profile and hive restoration is verified. Each independent verification is guarded so one failure does not hide other cleanup observations. Registry parent last-write metadata is not restored or claimed unchanged.
|
||||
|
||||
This proves the observed fixture cases on the tested builds. It does not establish arbitrary redirected-user access, remote shares, offline profiles, future children, an atomic tree transaction, Windows 11, domain/DC/CA behavior, forwarding, retention or backend Sigma execution. No receipt authorizes removing inherited ACEs from production descendants. The selected command's existing concurrency and partial-write limits still apply.
|
||||
|
||||
The system-volume fixture is deliberate: some hosted data volumes emit the Removable Storage task even when `DriveInfo` reports Fixed. The existing probe accepts File System task 12800 only. Neither a protected branch nor another volume receives event credit from the successful ordinary leaf.
|
||||
|
||||
See [selected SACL configuration](selected-sacl-configuration.md), [file-access probe](file-access-probe.md) and the separate [public registry lifecycle](native-registry-sacl-validation.md). Microsoft documents [SetSecurityInfo inheritance behavior](https://learn.microsoft.com/en-us/windows/win32/api/aclapi/nf-aclapi-setsecurityinfo) and the [4663 access-use event fields](https://learn.microsoft.com/en-us/windows/security/threat-protection/auditing/event-4663).
|
||||
@@ -0,0 +1,28 @@
|
||||
# Native provider configuration acceptance
|
||||
|
||||
The dedicated `Native provider configuration acceptance` workflow tests the public `provider-packs` command on disposable GitHub-hosted Windows Server 2022 and 2025, separately under Windows PowerShell 5.1 and PowerShell 7. It complements the read-only manifest inventory and mocked failure tests described in [the provider-pack guide](native-provider-packs.md).
|
||||
|
||||
This fixture is destructive to the selected channels' temporary configuration and can discard records when restoring smaller buffers. It requires `-AllowDisposableProviderWrite`, `GITHUB_ACTIONS=true` and `RUNNER_ENVIRONMENT=github-hosted`; do not run it on ordinary machines. Production behavior is unchanged; only this opted-in disposable fixture prepares and restores the temporary test settings.
|
||||
|
||||
## Actual public behavior checked
|
||||
|
||||
- The real provider/channel registrations and expected event schemas must permit all four explicitly selected client-side packs: `dns-client`, `capi2`, `winrm` and `rdp-client`. Missing or incompatible metadata fails the fixture; it is never replaced with a mock or skipped success.
|
||||
- Plan and Configure with `-DryRun` preserve prepared native settings. Unsupported preview and reader-grant options are refused before a recovery directory is created.
|
||||
- Configure actually enables the four channels and applies their exact minimum buffers. A prepared 2 GiB WinRM buffer stays larger, and a prepared CAPI2 `Retain` mode stays intact. The complete descriptor is preserved; provider packs never request an Event Log Readers grant.
|
||||
- Every Applied result and its original journal entry are compared with independent native before/after observations. Repeated Configure is idempotent and creates no write journal.
|
||||
- Both manual DNS packs refuse configuration. The hosted image must genuinely lack the DNS Server service, and `dns-server-audit` must refuse that missing prerequisite. No DNS role is installed or removed to manufacture the result.
|
||||
- A mixed CAPI2/manual-DNS invocation performs one real selected change and reports the other failure with a nonzero overall exit and exactly one journal entry. Partial application is explicit.
|
||||
|
||||
The fixture does not issue DNS queries, RDP connections or WinRM sessions, change service configuration, or intentionally generate test events. Ordinary background Windows events may occur while the channels are enabled. All rules retain zero Ready credit; enabling a source does not establish event fields, effective reader access, ingestion or matching backend queries.
|
||||
|
||||
## Preservation, cleanup and evidence
|
||||
|
||||
Before preparation, the fixture captures native settings and complete `wevtutil gl /f:xml` configuration for registered catalog channels and additional unselected Security, System, Application, AppLocker and DriverFrameworks controls. During public configuration it compares every selected XML field except the permitted enabled flag and maximum size; unselected registered channels must remain byte-for-byte equivalent at the XML level. It also compares the state/start type of EventLog, Winmgmt, WinRM, TermService and DNS, and all 59 effective audit masks.
|
||||
|
||||
Each selected channel has independent cleanup that restores original enablement, exact byte limit, descriptor and retention/backup mode. A failure restoring one channel does not skip the remaining channels. Final observations compare original full XML, service state and audit masks. Cleanup failure prevents a passing result. Owned child commands have bounded execution and output, and termination failures remain in the cleanup receipt.
|
||||
|
||||
`original.json`, public JSON reports, command output, actual journals, `completed.json`, `cleanup.json` and a SHA256 manifest are retained for seven days by the workflow. The manifest binds the fixture, product helpers, catalog, corpus and full reviewed rule-source bytes. Event records are not restored, and no retention-duration, Windows 11, domain/DC/ADCS, positive installed-DNS, forwarding or Sigma acceptance is implied. This advances issues #386 and #366 without closing their broader acceptance work.
|
||||
|
||||
The underlying enablement, size, retention and backup options follow Microsoft's [wevtutil command reference](https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/wevtutil). The product's existing channel floors and schema gates remain unchanged.
|
||||
|
||||
The first native run exposed a WinRM manifest bug: an unrelated event ID `3221734403` overflowed the reader's signed 32-bit cast and made the whole provider schema unknown. The reader now compares [EventMetadata.Id in its native Int64 domain](https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.eventing.reader.eventmetadata.id), then parses only the exact reviewed event/channel templates. Focused tests also require refusal when only unrelated large IDs exist; schema gates are unchanged.
|
||||
@@ -47,7 +47,7 @@ Successful channel configuration says nothing about benign operation generation,
|
||||
|
||||
Every attempted native write first records the original enabled flag, exact buffer size, retention and complete descriptor in `before.jsonl`. Restore only the recorded selected channel values using an elevated `wevtutil sl` after reviewing concurrent GPO/administrator changes; do not replace an entire descriptor with an example. No automatic rollback overwrites later changes. Event loss/volume and long-term storage requirements require a measured deployment plan.
|
||||
|
||||
The mocked regression suite exercises missing fields/providers, unsupported types/builds, role/service gates, journal-before-write, dry-run, decline, idempotence, preserved ACL/retention/larger buffers, native failure/false success, prompt races and final schema drift. Windows Server 2022/2025 CI on PowerShell 5.1/7 reads real provider manifests and the public CLI plan and checks that channel settings stay unchanged. It creates no DNS queries, log entries, services or subscriptions. Windows 11/DC/CA event-generation and actual backend/collector validation remain pending acceptance work for issue #386.
|
||||
The mocked regression suite exercises missing fields/providers, unsupported types/builds, role/service gates, journal-before-write, dry-run, decline, idempotence, preserved ACL/retention/larger buffers, native failure/false success, prompt races and final schema drift. Windows Server 2022/2025 CI on PowerShell 5.1/7 reads real provider manifests and the public CLI plan and checks that channel settings stay unchanged. It creates no DNS queries, log entries, services or subscriptions. Windows 11/DC/CA event-generation and actual backend/collector validation remain pending acceptance work for issue #386. A separate [disposable native configuration acceptance suite](native-provider-acceptance.md) now exercises actual public Configure, dry-run, idempotence, refusal, partial outcomes, journals and exact cleanup for the four client-side packs. It supplies configuration proof only.
|
||||
|
||||
Primary references: [Microsoft WEF Appendix C/F](https://learn.microsoft.com/en-us/windows/security/operating-system-security/device-management/use-windows-event-forwarding-to-assist-in-intrusion-detection), [DNS logging and diagnostics](https://learn.microsoft.com/en-us/windows-server/networking/dns/dns-logging-and-diagnostics), [EventMetadata](https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.eventing.reader.eventmetadata?view=windowsdesktop-10.0), [EventLogLink](https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.eventing.reader.eventloglink?view=windowsdesktop-10.0), [Windows 11 release families](https://learn.microsoft.com/en-us/windows/release-health/windows11-release-information), and [Windows Server release families](https://learn.microsoft.com/en-us/windows/release-health/windows-server-release-info). The WEF sample identifies event/channel candidates; it does not validate these rule definitions or this implementation on every build.
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
# Public registry SACL lifecycle acceptance
|
||||
|
||||
The `Native public registry SACL lifecycle` workflow tests the existing public `targeted-sacl` command on disposable GitHub-hosted Windows Server 2022 and 2025 runners, each with native Windows PowerShell 5.1 and PowerShell 7. It is an acceptance fixture, not a new configuration command. Native job results and retained artifacts must be reviewed before claiming a particular matrix passed.
|
||||
|
||||
## Owned target and public lifecycle
|
||||
|
||||
The fixture creates a nonce-marked seed key below its own HKCU, saves it to a new private file, and loads that file under a new synthetic SID below HKU. It never loads an existing user's offline hive or modifies a catalog system key. Existing backup/restore privileges are enabled only around the native save/load/unload calls and their prior attributes are restored. Impersonation and name collisions are refused. The unchanged public catalog resolves the loaded SID's RunOnce definition from `asd-native-2021-10`; the missing ProfileList metadata remains explicit in user-inventory diagnostics.
|
||||
|
||||
Only the fixture prepares typed audit precedence and the Registry success/failure subcategory. It creates a sentinel DWORD and a distinct SYSTEM QueryValue success audit ACE before exercising the selected target through actual `WELA.ps1` processes:
|
||||
|
||||
- Plan with missing inheritance consent is blocked and Configure refuses before creating a journal.
|
||||
- A reviewed Plan captures the exact selected SID/path, native descriptor and complete empty descendant inventory.
|
||||
- DryRun leaves the descriptor unchanged and creates no write journal.
|
||||
- Configure appends exactly the reviewed audit ACE. Independent native readback verifies original owner/group/DACL/control flags, original binary audit ACEs and the unrelated typed value. Pending, Confirmed and descendant-observation receipts agree with the independent observations.
|
||||
- Replaying the stale plan fails before another journal. A fresh plan and Configure report `AlreadyCompliant`, preserve exact state and write no mutation receipts.
|
||||
- Removing the prerequisite Registry audit bits makes planning blocked and Configure fail before journaling; the public command does not enable auditing.
|
||||
|
||||
The chosen RunOnce target has no child keys. Populated and protected subtree behavior remains covered separately by the existing descendant fixture. This fixture does not establish production-tree, redirected-user, DC/CA or future-child behavior.
|
||||
|
||||
## One actual registry event
|
||||
|
||||
After public Configure succeeds, the fixture records a native Security event watermark, then performs exactly one `RegSetValueExW` call to create a fresh nonce REG_SZ. It reads the value's type and exact bytes back on that same native handle. Precise UTC receipts separately record write start, return and completion of this measured write/readback phase; no timestamp padding is added.
|
||||
|
||||
A bounded native Security query must return exactly one matching 4657 from the observed phase, with the exact provider/version/task/success keyword, computer, newer record ID, subject SID/logon ID, process ID/executable, raw registry handle, native object path, value name, creation operation, REG_SZ type and nonce value. Event candidates, exact XML, operation receipt and artifact hashes are retained. Portable negative fixtures reject wrong attribution, old/out-of-window records, duplicate fields and DTD-bearing XML. A missing or ambiguous event fails acceptance; it does not relax attribution.
|
||||
|
||||
This is evidence for one local registry **value** creation under the fixture's prepared policy. It does not prove all registry operations, production persistence, downstream forwarding, collector access or Sigma execution. Public reports retain `GenerationReadiness=Conditional` and `UsableRuleCredit=0`.
|
||||
|
||||
## Cleanup and evidence
|
||||
|
||||
Cleanup runs even after an assertion fails. It restores the original selected Registry audit mask and original precedence type/value or absence, then compares every one of the 59 audit masks. It checks the entire primary-token groups/privilege snapshot, unloads only the marker-verified owned hive, removes only its exact unchanged seed, and compares the complete original HKU mount inventory. The private backing files are deleted only after unload and inventory verification. Failure to restore or unload fails the job and remains explicit in `cleanup.json`.
|
||||
|
||||
The artifact retains public reports/journals, independent before/after descriptors, exact event XML, native operation and cleanup evidence, and SHA-256 hashes. Successful cleanup retains no backing hive file. This test-only helper is not imported by WELA and is not packaged as a product hive-management feature.
|
||||
|
||||
Primary references: Microsoft [RegSaveKeyExW](https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regsavekeyexw), [RegLoadKeyW](https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regloadkeyw), [RegUnLoadKeyW](https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regunloadkeyw), and [Security event 4657](https://learn.microsoft.com/en-us/windows/security/threat-protection/auditing/event-4657).
|
||||
@@ -0,0 +1,22 @@
|
||||
# Scoped outgoing NTLM auditing
|
||||
|
||||
`outgoing-ntlm` audits or configures only `HKLM\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0\RestrictSendingNTLMTraffic`. The separate broad `configure` workflow retains its existing behavior. Use elevated 64-bit PowerShell for Configure on reviewed Windows 11 builds (22000/22621/22631/26100/26200) or Server 2022/2025 (20348/26100); observed role/build and the existing key are required. Role overrides are refused.
|
||||
|
||||
```powershell
|
||||
./WELA.ps1 outgoing-ntlm -NtlmAction Audit -ResultsPath audit.json
|
||||
./WELA.ps1 outgoing-ntlm -NtlmAction Plan -ResultsPath plan.json
|
||||
./WELA.ps1 outgoing-ntlm -NtlmAction Configure -DryRun -ResultsPath preview.json
|
||||
./WELA.ps1 outgoing-ntlm -NtlmAction Configure -Auto -BackupPath ./before -ResultsPath result.json
|
||||
# Explicitly replace a previously reviewed Deny all value with auditing:
|
||||
./WELA.ps1 outgoing-ntlm -NtlmAction Configure -OutgoingNtlmMode Audit -BackupPath ./before-reviewed -ResultsPath reviewed.json
|
||||
```
|
||||
|
||||
The default `PreserveOrAudit` mode sets only DWORD **1 (Audit all)** when absent or DWORD0. Existing DWORD1 is already compliant. Existing DWORD **2 (Deny all)** is reported as `PreservedEnforcement` and skipped; exit0 for this preserved case does not mean auditing was enabled. Explicit `Audit` authorizes replacing a known DWORD2 with1. Unknown types/values fail without writes in either mode. `Deny` is refused by this scoped command. It never changes incoming/domain NTLM policy, exceptions, audit subcategories, channel settings, services, or authentication restrictions other than the explicit conversion of a known outgoing deny to audit.
|
||||
|
||||
Plan is a live read-only assessment, not an importable authorization file. Audit/Plan reject mutation options. Configure re-reads the actual host and typed value, journals before mutation, refuses pre-write drift, and verifies immediate/final readback. A race after the final pre-write read remains possible; these observations are not atomic with GPO or another administrator. RSoP is explicitly last-applied and potentially stale, never proof of the current registry writer. Skipped, Failed and Overridden results remain distinct. No automatic rollback occurs.
|
||||
|
||||
For manual recovery, inspect the selected successful result and its original `before.jsonl` entry. The original typed registry state is `Before.Policy`; preserve current policy ownership and review drift before restoring that one value/type or removing that value if it was originally absent. Never remove the parent MSV1_0 key or replay another journal kind. Failed/partial attempts require individual inspection. Keep the original journal and result together.
|
||||
|
||||
Native acceptance uses disposable unjoined Server2022/2025 hosts under PowerShell5.1/7, exercises actual absence/allow→audit, original journals, dry run, repeat, readback and exact cleanup. Existing enforcement and malformed values are never installed on a native runner merely for testing; portable regressions verify those preservation/refusal paths, prompt-time drift and failures. Native tests preserve incoming/domain policy, siblings/access descriptor, channels, service and all59 audit masks. Windows11/DC/ADCS acceptance, authentication behavior, representative NTLM events, GPO persistence and collector delivery remain separate work for #362. No Sigma credit is inferred. Built-in Windows only; Sysmon is excluded.
|
||||
|
||||
Microsoft distinguishes outgoing audit from deny, describes GPO precedence and identifies the NTLM Operational log for validation: [outgoing NTLM policy](https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-10/security/threat-protection/security-policy-settings/network-security-restrict-ntlm-outgoing-ntlm-traffic-to-remote-servers).
|
||||
@@ -60,6 +60,8 @@ One configuration control journals the original typed machine/current-user value
|
||||
|
||||
`Applied`/`AlreadyCompliant` mean the machine policy and directory observations passed these checks. They do not prove transcript generation or access for another identity. `Failed` covers read/write problems, unsafe/unknown destination state and verification errors; `Overridden` covers later detected policy drift. `Skipped` includes dry runs and operator-declined changes. Exit 0 means no failed or overridden controls, including runs with skips; it is not a transcript-generation or CIS-wide compliance result.
|
||||
|
||||
For a completed `Applied` local-directory configuration, [transcription-recovery](transcription-recovery.md) provides reviewed typed restoration with durable receipts and explicit temporary-suspension consent. Failed/partial configuration runs and unsupported original values still require manual review.
|
||||
|
||||
If a later write fails, an earlier `OutputDirectory` write can remain. Review `before.jsonl`, the current policy and the authoritative GPO/MDM source. To recover, restore **only** `OutputDirectory` and `EnableTranscripting` from `Before.Policy[0].Machine`, preserving each original value's registry type; remove a value when its original `ValueExists` was false. If necessary, temporarily set `EnableTranscripting` to DWORD `0` while restoring the previous location, then restore its original value/type or absence last. Leave invocation-header and unrelated values untouched. Remove a newly created `Transcription` key only if it was originally absent and is still empty; do not delete a whole policy subtree or restore old ACLs over later changes. The journal contains policy paths/security information and should be protected as administrator recovery data.
|
||||
|
||||
## Evidence and limits
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
# Reviewed registry SACL recovery
|
||||
|
||||
`registry-sacl-recovery` removes one explicit registry-root audit ACE proven to have been appended by one completed public `targeted-sacl` operation. The original operation must have selected exactly one built-in registry target with `-TargetSaclIncludeChildren`, and every historical and current descendant inventory must be complete and empty. A populated tree, a pending-only operation, an already-present ACE or an arbitrary registry path is outside this command's scope.
|
||||
|
||||
## Review the original evidence
|
||||
|
||||
Keep these four distinct files from the original operation:
|
||||
|
||||
| Input | Required evidence |
|
||||
| --- | --- |
|
||||
| Original selected plan | One `ChangeRequired` registry row, its original descriptor and complete empty descendant snapshot. |
|
||||
| `<target-id>.pending.json` | Original descriptor and intended addition, recorded before the original write. |
|
||||
| `<target-id>.confirmed.json` | The same operation's verified after-state and empty descendant observations. |
|
||||
| Final original result | A successful, non-dry-run result with exactly one matching `Applied` row and complete verification. |
|
||||
|
||||
Keep the named Pending and Confirmed files inside the original result's recorded backup directory. The command checks their names and locations, timestamps, schemas, native descriptor bytes, source fingerprints, host context and exact correspondence with the plan and final result. Each input is limited to 4 MiB. Missing, edited, mismatched, incomplete or unsupported records are refused.
|
||||
|
||||
The target, principal, mask and inheritance flags are rebuilt from the current bundled catalog and original selection. The descriptors must prove exactly one ordinary explicit audit ACE was appended, with the original ACE order and unrelated descriptor components preserved. A matching ACE that already existed does not establish removal authority.
|
||||
|
||||
```powershell
|
||||
./WELA.ps1 registry-sacl-recovery `
|
||||
-RegistryRecoveryOriginalPlanPath C:\WELA\original-plan.json `
|
||||
-RegistryRecoveryPendingPath C:\WELA\original-backup\sacl-REPLACE_WITH_TARGET_ID.pending.json `
|
||||
-RegistryRecoveryConfirmedPath C:\WELA\original-backup\sacl-REPLACE_WITH_TARGET_ID.confirmed.json `
|
||||
-RegistryRecoveryOriginalResultsPath C:\WELA\original-results.json `
|
||||
-RegistryRecoveryOutputPath C:\WELA\registry-recovery-review
|
||||
```
|
||||
|
||||
Replace both receipt filenames with the actual matching target ID; do not rename the original files. `Plan` is the default action. It observes the key and creates protected `plan.json` and `manifest.json` files in a new ordinary local output directory. It makes no registry configuration change. Inspect the complete plan, including the exact binary ACE to remove, the original evidence paths and hashes, and current context. Independently retain the reviewed `PlanHash` from the manifest.
|
||||
|
||||
Original version-1 records do not authenticate historical operator identity. **Hashes check consistency with trusted records; they do not authenticate their author.** Supply original evidence whose provenance you trust. The current native registry path and last-write metadata also cannot prove durable historical key identity: they do not establish that a key was never deleted and recreated.
|
||||
|
||||
## Explicit removal
|
||||
|
||||
```powershell
|
||||
./WELA.ps1 registry-sacl-recovery -RegistryRecoveryAction Restore `
|
||||
-RegistryRecoveryPlanPath C:\WELA\registry-recovery-review\plan.json `
|
||||
-RegistryRecoveryPlanHash REVIEWED_LOWERCASE_SHA256 `
|
||||
-RegistryRecoveryOutputPath C:\WELA\registry-recovery-run `
|
||||
-RegistryRecoveryAllowAuditReduction `
|
||||
-RegistryRecoveryAllowInheritance
|
||||
```
|
||||
|
||||
Both consent switches are required. Removing the selected ACE reduces auditing. Windows inheritance processing can affect concurrently created children even when the recorded and freshly observed child inventories are empty. Consent does not authorize descendant ACE removal or a populated-tree rollback. `Restore` accepts the reviewed plan/hash and a new output directory; it obtains the original four paths from that plan. `-Auto`, `-DryRun`, `-WhatIf`, arbitrary target overrides and unrelated options are rejected. Use `Plan` for the preview.
|
||||
|
||||
Run elevated in native 64-bit Windows with the observation services already running. The plan binds the actual host, supported role/build context, full primary-token/logon observations, source files, all 59 audit masks and typed audit-precedence state. The command rebuilds the plan from the original files and checks the supplied lowercase SHA256 before writing. Changes to the implementation or bound context require renewed assessment; editing a fingerprint does not make old evidence eligible.
|
||||
|
||||
The current full descriptor and registry path/last-write identity must exactly match the original completed after-state. Even a benign value edit that changes the key's last-write time causes refusal. Missing keys, links, new children, changed ACEs and unreadable or incomplete observations also refuse recovery. There is no timestamp relaxation or option to overwrite newer changes.
|
||||
|
||||
A flushed `pending.json` records removal intent before the one native SACL-only write. Fresh checks on the opened key precede removal of the uniquely proven ACE. Readback verifies all remaining ACE bytes, counts and order, owner, group, DACL, resource-manager control and preserved control flags. The command changes no registry values, audit policy or service configuration, and restores the temporary privilege state. Final checks revalidate the empty child state, native after-state, current context, original inputs, reviewed plan and retained artifact hashes.
|
||||
|
||||
## Interpret the result
|
||||
|
||||
| Status | Meaning |
|
||||
| --- | --- |
|
||||
| `ReviewRequired` | A plan and review hash were retained; no native write occurred. |
|
||||
| `Refused` | The evidence, consent or current state did not authorize removal. |
|
||||
| `AddedAceRemoved` | The proven ACE was removed and preservation/readback checks succeeded. |
|
||||
| `WriteAttemptedUnverified` | A write or cleanup outcome is uncertain; inspect retained observations and receipts before manual action. |
|
||||
|
||||
Successful recovery retains `reviewed-plan.json`, `pending.json`, `after.json`, `confirmed.json` and `manifest.json`. The manifest records actual `WriteAttempted`, observed `Before`/`After`, diagnostics and artifact hashes. An unsuccessful run may contain only some of these files. A pending receipt proves intent, not successful removal; process termination, power loss or storage failure can leave no final manifest. There is no automatic rollback or continuation. Replaying a successful recovery plan is refused because its expected pre-state no longer exists.
|
||||
|
||||
**`AddedAceRemoved` does not promise the exact historical descriptor bytes.** A formerly absent or null SACL may remain present and empty or null after the ACE is removed. `OriginalDescriptorBytesMatch` separately reports byte-for-byte equality with the descriptor before the original addition. Preserving the other current descriptor components takes precedence over replacing the full descriptor to reproduce that historical representation.
|
||||
|
||||
The checks do not atomically lock the registry tree against another writer. Use an isolated change window and investigate partial outcomes manually; matching inherited ACEs do not establish ownership. Recovery grants no event-generation, forwarding or Sigma readiness credit.
|
||||
|
||||
## Native validation boundary
|
||||
|
||||
The gated disposable Windows suite exercises the public original Plan/Configure and recovery Plan/Restore on an owned mounted hive under Server 2022/2025 and Windows PowerShell 5.1/PowerShell 7. It checks missing consent, stale-plan refusal, actual value-edit and child-creation refusal, unrelated ACE/value preservation, retained evidence and fixture cleanup. The fixture alone prepares audit policy and loads/unloads its owned hive, then verifies the original hive inventory, token, all audit masks and typed precedence. Those fixture operations are absent from the product command. Production identities, populated trees, policy refresh, event generation and backend Sigma evaluation require separate validation.
|
||||
|
||||
See [selected SACL configuration](selected-sacl-configuration.md) for original evidence creation and [native registry SACL validation](native-registry-sacl-validation.md) for the separate original-configuration and event-evidence boundary.
|
||||
|
||||
Primary API references: Microsoft [SetSecurityInfo and propagation](https://learn.microsoft.com/en-us/windows/win32/api/aclapi/nf-aclapi-setsecurityinfo), [RegOpenKeyExW](https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regopenkeyexw), and [RegQueryInfoKeyW](https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regqueryinfokeyw).
|
||||
@@ -57,6 +57,8 @@ Each attempted change first creates `<target-id>.pending.json`, containing the o
|
||||
|
||||
For recovery, review the receipts and a fresh descriptor first. Remove only the explicit ACE demonstrated to have been added by this run; do not remove a matching ACE that was already present. Preserve the existing owner, group, DACL, protection flags and all newer audit entries. If Windows propagated inheritance, use the child snapshots and observations for manual assessment; a matching inherited ACE does not establish that this run owns it. No automatic full-descriptor replacement or bulk rollback is provided by this command. Pending receipts cannot establish that an ACE belongs to WELA; retain them for manual investigation.
|
||||
|
||||
For one completed registry-root addition with complete empty historical and current descendant observations, the separate [registry SACL recovery command](registry-sacl-recovery.md) checks the original plan, named Pending/Confirmed receipts and final successful result. A reviewed recovery hash and both audit-reduction/inheritance consents authorize removal of only the proven explicit ACE. Populated trees, pending-only records and full-descriptor rollback remain outside that command's scope.
|
||||
|
||||
Windows security updates are not a compare-and-swap transaction against other administrators or GPO. Fresh-state checks and handle-bound mutation reduce races but do not lock out concurrent SACL writers. Use an isolated change window; no later policy persistence or race-free inheritance guarantee is claimed.
|
||||
|
||||
## Reviewed descendant evidence
|
||||
@@ -84,7 +86,11 @@ The Windows disposable fixture now uses populated file and registry trees, verif
|
||||
|
||||
Mocked tests cover selection, source-specific masks, unsupported consent, source/plan/target races, denied reads, partial writes, non-SACL drift, pending/confirmed receipts, idempotence and public command guards. The Windows workflow explicitly permits mutations only on GitHub-hosted disposable Server 2022/2025 runners: it creates owned temporary file/registry targets, temporarily enables their two audit subcategories and precedence, adds audit ACEs through the real adapter, and searches for benign 4663/4657 events matching the exact targets. It restores all original audit masks and typed precedence and removes only owned targets. This fixture does not modify any catalog system target.
|
||||
|
||||
Native CI results must be reviewed before claiming those test cases passed. Windows 11, DC/CA, user redirection, large/changing production trees, forwarding and actual Sigma/backend execution remain separate acceptance work. Every report remains `GenerationReadiness=Conditional` with `UsableRuleCredit=0`.
|
||||
The separate [public registry lifecycle fixture](native-registry-sacl-validation.md) mounts a newly saved, fixture-owned hive under a fresh synthetic user SID. The unchanged public catalog resolves its RunOnce key, then actual CLI Plan/DryRun/Configure calls exercise the reviewed lifecycle and one exact local 4657. Only the fixture loads/unloads hives and prepares auditing; the product behavior above is unchanged. This leaf fixture does not replace populated-tree inheritance validation.
|
||||
|
||||
The [public filesystem lifecycle fixture](native-filesystem-sacl-validation.md) resolves a genuine built-in Signal target through an owned synthetic profile and redirected known folder. It exercises actual public selection, Plan/DryRun/Configure, stale-child refusal and idempotence on a populated tree, checks protected descendants, and matches one public leaf-read probe to local4663 XML. Only the disposable fixture registers its profile and mounts its hive.
|
||||
|
||||
Native CI results must be reviewed before claiming those test cases passed. Windows 11, DC/CA, other user-redirection/access scenarios, large/changing production trees, forwarding and actual Sigma/backend execution remain separate acceptance work. Every report remains `GenerationReadiness=Conditional` with `UsableRuleCredit=0`.
|
||||
|
||||
Primary API references: [GetSecurityInfo](https://learn.microsoft.com/en-us/windows/win32/api/aclapi/nf-aclapi-getsecurityinfo), [SetSecurityInfo and inheritance](https://learn.microsoft.com/en-us/windows/win32/api/aclapi/nf-aclapi-setsecurityinfo), [registry open/link behavior](https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regopenkeyexw), [file handle and sharing flags](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew).
|
||||
|
||||
|
||||
@@ -30,6 +30,8 @@ Microsoft's Policy CSP pages list **26100.3613** as the availability floor for t
|
||||
|
||||
## Policy registry versus effective runtime
|
||||
|
||||
The separate explicit [`smb-runtime` activation command](smb-runtime-activation.md) can activate the six native audit Booleans through reviewed SMB setters, with policy-conflict and complete configuration guards. This policy command does not invoke it automatically. Both operations keep event generation and policy persistence separate from current configuration observations.
|
||||
|
||||
Reports keep `Policy` (the actual policy-registry value/type) separate from `Runtime` (the corresponding property of `Get-SmbServerConfiguration` or `Get-SmbClientConfiguration`). WELA never substitutes the policy DWORD for a runtime observation:
|
||||
|
||||
- `Observed`: the getter exposes an actual Boolean. `RuntimeState=Active` means that Boolean was True, not that representative events were generated. False is `NotActive` before the desired policy exists, or `PendingVerification` when the policy registry contains DWORD 1. A correctly written/read-back policy therefore succeeds even when the runtime Boolean remains False. Pending verification does **not** assert propagation delay, a future activation deadline, or that a policy refresh/restart will fix the discrepancy. Its cause and activation timing are unknown; investigate and repeat Audit independently. WELA performs no refresh/restart and never weakens security to make a Boolean change.
|
||||
@@ -70,3 +72,11 @@ On isolated supported client/server snapshots, retain OS build/revision, PowerSh
|
||||
Microsoft documents the policy-to-registry mappings and the SMB configuration cmdlets, but the cited pages do not establish synchronous propagation of a direct policy-registry write into the getter or promise that refreshing Group Policy resolves any discrepancy. WELA makes neither assumption.
|
||||
|
||||
Sources: [LanmanServer Policy CSP mappings](https://learn.microsoft.com/en-us/windows/client-management/mdm/policy-csp-lanmanserver), [LanmanWorkstation Policy CSP mappings](https://learn.microsoft.com/en-us/windows/client-management/mdm/policy-csp-lanmanworkstation), [SMB signing and encryption auditing](https://learn.microsoft.com/en-us/windows-server/storage/file-server/smb-signing-overview), [SMB feature availability](https://learn.microsoft.com/en-us/windows-server/storage/file-server/file-server-smb-overview), [SMB configuration getter](https://learn.microsoft.com/en-us/powershell/module/smbshare/get-smbclientconfiguration?view=windowsserver2025-ps), [SMB server audit parameters](https://learn.microsoft.com/en-us/powershell/module/smbshare/set-smbserverconfiguration?view=windowsserver2025-ps), and [issue #377](https://github.com/Yamato-Security/WELA/issues/377).
|
||||
|
||||
## Native public configuration acceptance
|
||||
|
||||
The separately opted-in `SmbPolicyConfigure.Windows.Tests.ps1` fixture runs public Plan, DryRun and Configure on disposable, unjoined Server 2022/2025 hosts with PowerShell 5.1/7. Server 2022 must skip all six unsupported controls without policy writes. On Server 2025, exact local ADMX and runtime observations must qualify before preparing six DWORD 0 values. Public Configure then writes six DWORD 1 values, preserves every unrelated native SMB configuration property, siblings, access descriptors, service state and all 59 audit masks, records exact typed original journals, and repeats without writes. Cleanup restores the original values and removes only fixture-created empty policy keys. Native results retain the actual build/UBR and PowerShell version.
|
||||
|
||||
This acceptance establishes policy registry behavior only. It generates no SMB traffic, performs no runtime activation or policy refresh, and does not establish Windows client/DC/AD CS, event, forwarding or Sigma readiness.
|
||||
|
||||
On the measured Server2025 CI images, the six getter audit Booleans changed from False to True after registry configuration and returned to their original values after cleanup. The fixture records these separately and compares them with the public report; it preserves all other runtime properties. This observed result does not establish synchronous activation on other builds or after future policy refresh, and no SMB setter/restart or traffic is invoked.
|
||||
@@ -0,0 +1,32 @@
|
||||
# Explicit native SMB audit activation
|
||||
|
||||
Related to #377. `smb-runtime` explicitly activates the six reviewed native SMB audit switches when their actual runtime Booleans are False. It complements `smb-auditing`, which configures policy DWORDs and reports runtime state separately. Sysmon is excluded.
|
||||
|
||||
```powershell
|
||||
.\WELA.ps1 smb-runtime
|
||||
.\WELA.ps1 smb-runtime -SmbRuntimeAction Activate -DryRun
|
||||
.\WELA.ps1 smb-runtime -SmbRuntimeAction Activate -SmbRuntimeOutputPath C:\Evidence\new-smb-activation -Auto
|
||||
```
|
||||
|
||||
The default Plan and Activate dry-run only read. Activate requires a new evidence directory outside the source tree on a local fixed drive with an existing parent. It protects that directory for the actual user, Administrators and SYSTEM. Without `-Auto`, each required change asks for explicit consent. Existing True flags are checked without invoking their setters. Activation requires permissions to use the native SMB configuration cmdlets.
|
||||
|
||||
Only native 64-bit Windows 11 24H2/25H2 (builds 26100/26200) and Server 2025 (26100, including DC product type) are reviewed. Each switch also requires the exact local machine ADMX mapping, genuine Windows `SmbShare` module location, an actual Boolean setter parameter and a native CIM Boolean getter property. Missing definitions, properties, unsupported builds, unreadable values and unexpected configuration types stop the operation. Windows 11 and DC deployment acceptance remain separate from hosted member-server testing.
|
||||
|
||||
| Native command | Only permitted parameters |
|
||||
| --- | --- |
|
||||
| `Set-SmbServerConfiguration` | `AuditClientDoesNotSupportEncryption`, `AuditClientDoesNotSupportSigning`, `AuditInsecureGuestLogon` |
|
||||
| `Set-SmbClientConfiguration` | `AuditServerDoesNotSupportEncryption`, `AuditServerDoesNotSupportSigning`, `AuditInsecureGuestLogon` |
|
||||
|
||||
Every selected value is set to Boolean True, one at a time. The command does not set signing/encryption requirements, enable guest access, modify shares, change services, restart Windows, refresh policy, change channels or generate traffic. It changes no registry-policy value. A current absent policy value is compatible and stays absent; a present policy must be DWORD 1. Any conflicting or malformed policy blocks the entire activation before writes. Absence does not establish local ownership or rule out future GPO/MDM changes. This is an explicit local runtime configuration operation, not a GPO edit or a promise of persistence.
|
||||
|
||||
The plan captures all six typed policy tuples, local ADMX hashes, host/build identity, native module/source fingerprints and every supported property exposed by both native configuration getters. Before each setter, WELA compares the complete current snapshot, writes and flushes a Pending receipt to disk, then checks the snapshot again after any prompt. The only permitted readback difference is that single audit Boolean becoming True. Every other native configuration property and policy tuple must remain unchanged before a Confirmed receipt is written. A final complete readback is required for `RuntimeAuditingActive`.
|
||||
|
||||
The evidence directory retains `plan.json`, numbered Pending/Confirmed receipts and `result.json`. Failure, drift, declined changes or incomplete readback produce a nonzero result. After a failed operation, remaining flags are skipped; earlier successful changes stay recorded. A setter may have changed its flag before throwing or before a receipt failure, so Pending alone is not proof of either success or no change. There is no automatic rollback. Reports and hashes establish observed consistency, not historic authenticity or protection against an administrator replacing the evidence. No atomic lock against concurrent Windows policy/configuration writers is claimed.
|
||||
|
||||
For manual recovery, select one original flag and compare its Pending/Confirmed receipts with fresh native configuration and policy. Restore only that flag's original Boolean through the matching native setter after reviewing concurrent changes and policy authority. Do not replay the entire configuration object or copy getter values into arbitrary setter parameters. Retain the recovery readback separately. Restoring a getter value does not prove the exact historical registry representation or future policy persistence.
|
||||
|
||||
**Runtime activation grants zero Sigma readiness credit.** The command neither generates nor verifies representative SMB events, forwarding, a backend query, guest behavior or persistence after policy refresh. Keep #377 open until its remaining secure-peer event and ingestion acceptance is completed; never weaken signing/encryption or enable guest access solely to manufacture test evidence.
|
||||
|
||||
Focused tests exercise typed configuration, policy conflicts, idempotence, durable-receipt failure, prompt/prewrite/final drift and partial native failures. The explicitly gated disposable GitHub VM fixture prepares only these audit flags as False on Server 2025, invokes the public CLI to activate all six, checks dry-run/idempotence and restores their original native values. It compares every other exposed native configuration property, all policy tuples and source context before/after. Server 2022 tests actual unsupported refusal. Both run under Windows PowerShell 5.1 and PowerShell 7. The fixture performs no SMB traffic or policy changes, and must never run on production.
|
||||
|
||||
Microsoft sources: [SMB client audit parameters](https://learn.microsoft.com/en-us/powershell/module/smbshare/set-smbclientconfiguration?view=windowsserver2025-ps), [SMB server audit parameters](https://learn.microsoft.com/en-us/powershell/module/smbshare/set-smbserverconfiguration?view=windowsserver2025-ps), [signing and encryption audit events](https://learn.microsoft.com/en-us/windows-server/storage/file-server/smb-signing-overview), [LanmanServer policy mappings](https://learn.microsoft.com/en-us/windows/client-management/mdm/policy-csp-lanmanserver), [LanmanWorkstation policy mappings](https://learn.microsoft.com/en-us/windows/client-management/mdm/policy-csp-lanmanworkstation).
|
||||
@@ -0,0 +1,53 @@
|
||||
# Recover Windows PowerShell transcription policy
|
||||
|
||||
`transcription-recovery` reviews and restores the two machine values changed by one completed `powershell-transcription -TranscriptionAction Configure` run. It requires that run's original `before.jsonl` and final JSON result, exactly one `Applied` control named `PowerShellTranscription/CisV4L2`, and current policy/directory observations that still match its final `After` evidence. Status, control, target and registry-type discriminators require actual strings; schema and outcome counters require integers. Boolean values cannot stand in for those fields. Failed, partial, skipped and already-compliant configuration records require manual review.
|
||||
|
||||
```powershell
|
||||
./WELA.ps1 transcription-recovery -TranscriptRecoveryAction Plan `
|
||||
-TranscriptRecoveryJournalPath C:\Recovery\original\before.jsonl `
|
||||
-TranscriptRecoveryOriginalResultsPath C:\Recovery\original-result.json `
|
||||
-TranscriptRecoveryOutputPath C:\Recovery\new-plan
|
||||
|
||||
# Review every step in plan.json, including RequiresTemporarySuspension.
|
||||
$reviewedHash = (Get-FileHash C:\Recovery\new-plan\plan.json -Algorithm SHA256).Hash.ToLowerInvariant()
|
||||
./WELA.ps1 transcription-recovery -TranscriptRecoveryAction Restore `
|
||||
-TranscriptRecoveryPlanPath C:\Recovery\new-plan\plan.json `
|
||||
-TranscriptRecoveryPlanHash $reviewedHash -DryRun `
|
||||
-TranscriptRecoveryAllowTemporarySuspension
|
||||
|
||||
./WELA.ps1 transcription-recovery -TranscriptRecoveryAction Restore `
|
||||
-TranscriptRecoveryPlanPath C:\Recovery\new-plan\plan.json `
|
||||
-TranscriptRecoveryPlanHash $reviewedHash `
|
||||
-TranscriptRecoveryOutputPath C:\Recovery\new-attempt `
|
||||
-TranscriptRecoveryAllowTemporarySuspension -Auto
|
||||
```
|
||||
|
||||
Omit `-TranscriptRecoveryAllowTemporarySuspension` when the reviewed plan does not require it. `-Auto` accepts the ordinary confirmation; it never supplies suspension consent. `DryRun` validates all bindings and consent, returns the proposed steps and creates no directory. Plan and real Restore require new private output directories. All evidence and transcript directory paths must be literal absolute paths on local fixed drives. UNC paths, mapped drives, alternate streams and observed reparse components are rejected.
|
||||
|
||||
## Supported restoration and ordering
|
||||
|
||||
The target is the existing shared machine registry key `HKLM\SOFTWARE\Policies\Microsoft\Windows\PowerShell\Transcription`. The command supports original `OutputDirectory` REG_SZ values or absence, and original `EnableTranscripting` DWORD `0`, DWORD `1`, or absence. Other original types and values require manual recovery. Both Registry64 and Registry32 must agree. Recovery retains the existing key, removes only values that were originally absent, and never deletes policy subtrees.
|
||||
|
||||
When the original enablement was DWORD `0`, recovery restores that disabled state before changing the destination. If a destination change is followed by restoring DWORD `1` or removing the enablement value, the plan requires explicit temporary suspension: write DWORD `0`, restore the destination, then restore the original enablement or absence. An originally absent destination is supported only with original DWORD `0`; enabled/default-user destinations require manual recovery.
|
||||
|
||||
**Temporary suspension can leave machine transcription disabled.** By supplying `-TranscriptRecoveryAllowTemporarySuspension`, you accept that a write error, drift refusal or terminated process after the disable step and before final restoration can leave `EnableTranscripting=0`, even when the recovery target enables transcription. There is no automatic rollback or re-enable. A handled failure reports an incomplete attempt and stops subsequent writes; a terminated process may leave only pending/confirmed receipts without a final result. Inspect those receipts and the current native policy, verify the destination, and manually recover the intended enablement before relying on automatic transcription again. Do not re-enable blindly with an unverified destination.
|
||||
|
||||
Computer policy takes precedence over user policy, and policy-enabled transcription applies to PowerShell sessions. Removing a machine value can expose user/default policy; the command restores the recorded registry state without asserting session adoption. Manual `Start-Transcript` remains possible when automatic policy transcription is disabled. [Microsoft Windows PowerShell policy documentation](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_group_policy_settings?view=powershell-5.1). `HKLM\SOFTWARE\Policies` is shared across the registry views; recovery writes through Registry64 once and verifies both observations. [Microsoft WOW64 registry documentation](https://learn.microsoft.com/en-us/windows/win32/winprog64/shared-registry-keys).
|
||||
|
||||
Existing sessions are not stopped or restarted. Transcript files, their ACLs, shares, retention, collection, module logging, script-block logging, invocation-header preferences, current-user policy and all unrelated PowerShell policy values are preserved. The command inventories the other machine/current-user PowerShell policy tree with explicit bounds and stops when it changes.
|
||||
|
||||
## Evidence and failure handling
|
||||
|
||||
The reviewed plan binds original file hashes, the exact current host/MachineGuid and OS context, the elevated primary-token user/group/logon observations, current implementation hashes, both registry views, and the old/new directory observations. Restore verifies the separately supplied plan hash and independently rebuilds the plan from its original evidence and current observations. It checks those bindings after the prompt, before each write, during readback and at completion. A changed directory, policy, reader, source, plan or implementation stops the run.
|
||||
|
||||
Version-1 Configure journals record only the historical `ComputerName`. Current MachineGuid/logon/code bindings do **not** establish historical identity or authenticate supplied records. Hashes establish consistency. Keep original evidence and the reviewed hash under administrator control, review the authoritative GPO/MDM policy separately, and do not treat local registry restoration as proof of policy ownership or persistence.
|
||||
|
||||
Each mutation has a flushed, new `NNN-pending.json` receipt written before it and a separate `NNN-confirmed.json` only after verified readback. `result.json` contains actual observed final policy and confirmed steps. A pending receipt without confirmation is an uncertain step; inspect current native policy and preserve all receipts before manual recovery. A write may have succeeded even when its readback/receipt failed. Failed attempts and replay after a completed restore are refused by the original final-state guard; this command does not resume partial attempts or accept a new baseline silently. Failure to persist the result fails outward while existing evidence remains.
|
||||
|
||||
These are bounded point-in-time checks, not an atomic registry/filesystem lock. Another administrator or policy refresh may change state after a check. Private output guards observe ACL and directory identity metadata; they do not provide adversarial filesystem locking or central storage authorization proof.
|
||||
|
||||
## Validation scope
|
||||
|
||||
Portable tests exercise typed restoration, absent values, ordering, consent, preview, unsupported history, duplicate JSON, plan/source/host/directory/policy drift, prompt-time races and partial failures. The explicitly gated disposable native matrix targets Server 2022/2025 with Windows PowerShell 5.1 and PowerShell 7 as WELA hosts. It performs actual public Configure/Plan/Restore, checks native typed values and preserved policy, captures receipts, tests real drift refusal, and restores the fixture's exact original policy in `finally`. A fresh Windows PowerShell 5.1 session checks a benign transcript marker at the restored private local destination. Artifacts retain that fixture evidence and `cleanup.json`; PowerShell 7 remains only a WELA host.
|
||||
|
||||
`Restored` means the selected typed registry values passed final verification. Production transcript generation, existing/future session behavior, other identities, client/DC roles, central read/modify authorization, collection and retention remain separate validation. The report grants `SigmaEvtxCredit=0`; transcript text is separate from 4103/4104 EVTX. This advances recovery for [issue #376](https://github.com/Yamato-Security/WELA/issues/376) without completing its central authorization/ingestion acceptance.
|
||||
@@ -0,0 +1,29 @@
|
||||
# Reviewed WEC source authorization
|
||||
|
||||
`wec-authorization` plans and applies the explicit source SID allow list of one **already disabled**, existing source-initiated HTTP/native-event subscription. This supplies the authorization update missing from the create-only collector command, query/description updater and separate Enabled transition. Related to #368; built-in Windows only, with no Sysmon.
|
||||
|
||||
```powershell
|
||||
# Invoke the PowerShell script directly when supplying an array of SIDs.
|
||||
.\WELA.ps1 wec-authorization -WecAuthorizationId 'Reviewed subscription' `
|
||||
-WecAuthorizationSourceSid 'S-1-5-21-111-222-333-1234','S-1-5-21-111-222-333-1235' `
|
||||
-WecAuthorizationOutputPath C:\Evidence\authorization-plan
|
||||
|
||||
# Review plan.json, including its complete original XML and desired source list.
|
||||
# Retain its PlanHash from manifest.json before applying those exact bytes.
|
||||
.\WELA.ps1 wec-authorization -WecAuthorizationAction Apply `
|
||||
-WecAuthorizationPlanPath C:\Evidence\authorization-plan\plan.json `
|
||||
-WecAuthorizationPlanHash '<reviewed SHA256>' `
|
||||
-WecAuthorizationOutputPath C:\Evidence\authorization-apply
|
||||
```
|
||||
|
||||
Plan reads native configuration and writes review artifacts. Apply takes the subscription and desired list only from the reviewed plan. Both require a new private evidence directory on a local fixed drive. The actual elevated, non-impersonated reader, supported patched Server 2022/2025 standalone/member host, running Wecsvc/WMI/EventLog services, destination channel settings and implementation sources are observed and bound. No service is started, subscription enabled, channel changed or AD membership modified. Unknown options, mixed Plan/Apply inputs, `-Auto`, `-DryRun` and `-WhatIf` are refused; use Plan for review.
|
||||
|
||||
The desired list contains 1–32 unique canonical `S-1-5-21-A-B-C-RID` strings with native-range subauthorities. Order is normalized; duplicate SIDs, aliases, arbitrary SDDL, null/empty/default authorization and non-domain/certificate settings are refused. The existing descriptor must already be the same supported explicit allow-list form. WELA neither resolves these strings nor verifies that they identify domain computer accounts or groups. Obtain and independently verify intended identities and group membership before review. Adding a SID can broaden future authorization; removing one entry does not establish that a machine lacks access through another allowed group.
|
||||
|
||||
Apply checks the complete original definition and current context, flushes a pending receipt, opens only an existing native subscription and uses one `EcSubscriptionAllowedSourceDomainComputers` setter followed by save. The native adapter rechecks disabled/source-initiated state and selected native fields through a fresh handle. Native readback must match the desired list while all other observed XML fields, actual token, services and destination settings stay unchanged. Matching authorization returns `AlreadyMatches` without a save. Successful changes report `AuthorizationChangedAndVerified`; failures before save report `Refused`. Once save has been attempted, incomplete readback or preservation reports `SaveAttemptedUnverified` and retains available native after-XML.
|
||||
|
||||
An enabled subscription is refused, including a no-op request. Use the separately reviewed [Enabled transition](wec-state.md) when an intentional interruption or activation is required. To restore an authorization list, make a fresh plan against the current disabled definition using the original retained SIDs. There is no automatic rollback or native compare-and-swap: another administrator can race the pre-save observations. Coordinate changes and inspect retained evidence after partial results. Plan hashes check consistency and do not authenticate an untrusted evidence author.
|
||||
|
||||
The native CI fixture creates one uniquely named disabled subscription with inert SIDs, exercises public no-op/add/remove/restore, wrong-hash/stale/enabled refusals and a native fresh-handle drift check, then verifies original subscription inventory, service startup/state and complete channel restoration. Temporary service/channel changes belong only to explicitly opted-in disposable fixtures. These tests do not resolve or authenticate a source, change AD groups, verify forwarding or bookmarks, or award Sigma readiness credit.
|
||||
|
||||
Microsoft documents the [authorization property](https://learn.microsoft.com/en-us/windows/win32/api/evcoll/ne-evcoll-ec_subscription_property_id), [source-initiated subscription settings](https://learn.microsoft.com/en-us/windows/win32/wec/creating-a-source-initiated-subscription), [existing-only open flags](https://learn.microsoft.com/en-us/windows/win32/api/evcoll/nf-evcoll-ecopensubscription) and [activation on saving enabled subscriptions](https://learn.microsoft.com/en-us/windows/win32/api/evcoll/nf-evcoll-ecsavesubscription).
|
||||
@@ -0,0 +1,22 @@
|
||||
# Native collector subscription observations
|
||||
|
||||
The existing `wec-collector` Audit and Plan commands now enumerate subscription names through the local Windows Event Collector API and read selected XML through the shared bounded Unicode reader. This avoids treating PowerShell console output, including a BOM-only empty result, as subscription identity. Non-ASCII descriptions and XPath literals remain intact in the report.
|
||||
|
||||
```powershell
|
||||
.\WELA.ps1 wec-collector -WefAction Audit `
|
||||
-WefConfigPath C:\Reviewed\collector.json -ResultsPath C:\Evidence\collector-audit.json
|
||||
.\WELA.ps1 wec-collector -WefAction Plan `
|
||||
-WefConfigPath C:\Reviewed\collector.json -ResultsPath C:\Evidence\collector-plan.json
|
||||
```
|
||||
|
||||
Use the explicit collector configuration described in [WEF deployment](wef-deployment.md). These commands observe the selected local subscriptions and prerequisites. They do not create, save, enable or delete subscriptions. Existing Configure remains create-only and retains its domain, listener, ingress and hardening prerequisites.
|
||||
|
||||
A successful complete enumeration can establish `ObservedSubscription.Exists: false`; its `ObservedEnabled` remains null. An enumeration error, cap, duplicate/invalid native name, vanished or unreadable selected definition, mismatched XML identity or unsupported authorization remains unknown, with `ObservationError` and an `Unknown` control. Failed observations never authorize creation. A valid disabled definition is reported as disabled even when the requested XML says enabled. A readable difference requires manual review rather than a replacement.
|
||||
|
||||
Enumeration preserves exact native UTF-16 names, including Unicode and whitespace; it does not trim names or parse localized command output. It is limited to 4,096 names, 1,023 UTF-16 characters per name and 1,048,576 total characters including terminators. Exceeding a bound fails the observation instead of returning a partial list. Selected subscription IDs continue to use the existing supported ASCII ID syntax, and native XML reads retain their ten-MiB and thirty-second bounds. Native API errors are preserved as failures. The loaded enumeration helper is bound to its implementation bytes.
|
||||
|
||||
Enumeration and XML readback are sequential observations, not a transaction or protection against another administrator. A disappearing subscription is unknown for that observation; retry with a fresh audit. A complete configuration match still does not establish source identity, effective source access, runtime health, event arrival, bookmark continuity or Sigma coverage. Collector-local channel observations describe only the collector.
|
||||
|
||||
The disposable native suite exercises the actual public commands on Server 2022/2025 with Windows PowerShell 5.1 and PowerShell 7. It uses one uniquely owned disabled subscription with Unicode description and XPath, verifies absence, exact observation, requested/observed state separation, changed-description review and authorization-mismatch uncertainty, then removes only the owned subscription and restores original service startup/state. It preserves the destination channel and original subscription inventory. The real standalone fixture remains `Incomplete` with exit 1 for domain deployment prerequisites; those checks are neither mocked nor counted as domain or forwarding proof. Native name-buffer, cap, duplicate and read-failure regressions supplement that Windows acceptance.
|
||||
|
||||
Microsoft references: [subscription enumeration](https://learn.microsoft.com/en-us/windows/win32/api/evcoll/nf-evcoll-ecenumnextsubscription), [enumeration handles](https://learn.microsoft.com/en-us/windows/win32/api/evcoll/nf-evcoll-ecopensubscriptionenum), and [wecutil XML/read-only commands](https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/wecutil).
|
||||
@@ -0,0 +1,44 @@
|
||||
# Reviewed collector firewall ingress
|
||||
|
||||
`wec-ingress` creates one new local Windows Firewall rule for a prepared Windows Event Collector. It addresses the collector ingress portion of #368. It is optional and separate from source configuration, subscription installation and `wec-update`.
|
||||
|
||||
The command supports elevated native 64-bit Windows Server 2022/2025 standalone or member servers. The Domain firewall must already be enabled, permit inbound/local rules, and have running BFE/MpsSvc services. WinRM and Wecsvc must be installed; the command does not start them. Domain membership and an active Domain network are not required for preparation, but an inactive Domain profile means the new rule does not currently allow traffic. Domain controllers and Windows clients are outside this command's initial support.
|
||||
|
||||
## Review and apply
|
||||
|
||||
Run in the same elevated operator logon on the collector, from the same WELA checkout. Replace the example local address with an address actually assigned to the collector and choose remote source scopes appropriate for your network:
|
||||
|
||||
```powershell
|
||||
./WELA.ps1 wec-ingress -WecIngressName WELA-WEC-BranchSources `
|
||||
-WecIngressLocalAddress 10.20.30.40 -WecIngressRemoteAddress 10.20.40.0/24 `
|
||||
-WecIngressOutputPath C:\WelaEvidence\ingress-plan
|
||||
|
||||
# Inspect plan.json, including every address and the actual host/profile context.
|
||||
# Supply the PlanHash printed by Plan after reviewing that exact file.
|
||||
./WELA.ps1 wec-ingress -WecIngressAction Apply `
|
||||
-WecIngressPlanPath C:\WelaEvidence\ingress-plan\plan.json `
|
||||
-WecIngressPlanHash '<reviewed SHA256>' `
|
||||
-WecIngressOutputPath C:\WelaEvidence\ingress-apply
|
||||
```
|
||||
|
||||
The parent evidence directory must exist; each output directory must be new on a local fixed drive. Output is protected for the operator, Administrators and SYSTEM. Plans are strict, size-bounded JSON and SHA256 binds their exact bytes. SHA256 is an integrity comparison, not a signature or independent authorization.
|
||||
|
||||
Select 1–8 exact local IPv4 addresses currently in Preferred state and 1–16 remote IPv4 literals or aligned `/24`–`/32` CIDRs. The initial implementation deliberately restricts scope size. It rejects wildcard/DNS/range/IPv6 addresses, host bits in networks, duplicate canonical addresses, loopback, unspecified and multicast/reserved destinations. Expand future address support with native validation rather than editing a generated plan.
|
||||
|
||||
The fixed rule is enabled, inbound Allow, Domain profile only, TCP local port 5985, remote port Any, with exactly the reviewed local/remote addresses. Edge traversal and block-rule override are disabled. The rule has no application, service, user or machine filter, so it also permits other HTTP/WinRM uses of port 5985 within that scope. `Authentication=NotRequired` and `Encryption=NotRequired` describe the new firewall rule's IPsec criteria; they do not modify WinRM authentication, transport or encryption settings.
|
||||
|
||||
The name must begin `WELA-WEC-`. It must be absent from both PersistentStore and ActiveStore, checked again immediately before native creation. The command never updates an existing rule. Windows duplicate-name rejection protects against a competing local creation. A Group Policy refresh or a later policy change can still supersede a local rule; configuration verification is a point-in-time observation, not a lock or persistence guarantee.
|
||||
|
||||
## Evidence and failure handling
|
||||
|
||||
Plan reads actual host/build/patch, MachineGuid, elevated operator SID/logon/groups, firewall profiles, assigned IPv4 addresses and service state, plus implementation hashes. Apply requires the same context, writes and flushes a Pending receipt before mutation, rechecks inputs, then uses `New-NetFirewallRule` once. It verifies PersistentStore and ActiveStore rule properties and all associated native filter classes. Native dotted netmasks are canonicalized for comparison. The existing `wec-collector` ingress prerequisite also compares explicit IP/network identities, so the same reviewed `/24` configuration recognizes Windows' dotted-netmask readback. Its existing broader IPv4/IPv6 CIDR support is preserved; this does not expand the narrower address selection of `wec-ingress`. Different networks, prefixes, IPv6 scope IDs, extra addresses, dynamic aliases and malformed masks remain mismatches or unreadable evidence. Raw native address strings remain in the reports.
|
||||
|
||||
`CreatedAndVerified` means the new rule's selected properties and filters matched during readback. `Refused` means no create attempt was made. `CreateAttemptedUnverified` means a rule may have been created: retain the Pending receipt and any after-state artifacts, inspect the named rule and correct or remove it explicitly. There is no automatic rollback or reuse of an existing rule, and replay of an applied plan is refused. Evidence filesystem failures are fatal and may leave only the already-flushed Pending receipt.
|
||||
|
||||
Other existing rules may allow broader access. This command does not claim that the collector's overall exposure is restricted to these addresses. It creates no WinRM listener, subscription, source GPO or service configuration and performs no network probe. Use the existing collector/source prerequisite and arrival checks separately. It grants zero Sigma readiness credit. Sysmon is excluded.
|
||||
|
||||
## Validation
|
||||
|
||||
Portable tests cover strict address/plan validation, source/context/hash drift, duplicate names, durable-before-write ordering, broader readback and partial failures. Public CLI guards reject unrelated options. The disposable Windows matrix uses Server 2022/2025 and PowerShell 5.1/7, an actual assigned local address and documentation remote subnet `192.0.2.0/24`; it exercises public Plan/Apply, native collision rejection, both policy stores and replay, checks that the real existing collector prerequisite accepts the reviewed `/24` and rejects `/25`, then removes only its uniquely named test rule and checks original rule properties, profiles and services. This is configuration evidence, not packet, listener or WEF delivery evidence.
|
||||
|
||||
References: [Microsoft New-NetFirewallRule](https://learn.microsoft.com/en-us/powershell/module/netsecurity/new-netfirewallrule?view=windowsserver2025-ps), [Get-NetFirewallRule and associated filters](https://learn.microsoft.com/en-us/powershell/module/netsecurity/get-netfirewallrule?view=windowsserver2025-ps), [firewall security filters](https://learn.microsoft.com/en-us/powershell/module/netsecurity/get-netfirewallsecurityfilter?view=windowsserver2025-ps).
|
||||
@@ -0,0 +1,36 @@
|
||||
# Reviewed local WEC HTTP listener
|
||||
|
||||
`wec-listener` plans and creates one new native WinRM listener for the WEC collector prerequisites. It supports an explicitly selected IPv4 address assigned to the actual local Server 2022/2025 standalone or member server. WinRM, WMI and the firewall services must already be running. Existing WinRM policy values require manual review and cause refusal. Domain controllers, remote hosts and listener updates are outside this command's scope.
|
||||
|
||||
```powershell
|
||||
# Use an actual assigned local IPv4 address and a new private directory.
|
||||
.\WELA.ps1 wec-listener -WecListenerComputerName $env:COMPUTERNAME `
|
||||
-WecListenerLocalAddress 192.0.2.10 -WecListenerOutputPath C:\WELA-Evidence\listener-plan
|
||||
|
||||
# Review plan.json, manifest.json and the retained configuration snapshots.
|
||||
# Retain the SHA256 from that review before applying the same file.
|
||||
.\WELA.ps1 wec-listener -WecListenerAction Apply `
|
||||
-WecListenerPlanPath C:\WELA-Evidence\listener-plan\plan.json `
|
||||
-WecListenerPlanHash '<reviewed SHA256>' -WecListenerOutputPath C:\WELA-Evidence\listener-apply
|
||||
```
|
||||
|
||||
Plan writes review artifacts, including `plan.json` and `manifest.json` with `PlanHash`, and makes no Windows configuration change. Apply takes the computer and address from the reviewed plan. A separate new output directory retains its evidence. Mixed Plan/Apply inputs, unrelated options, `-Auto`, `-DryRun`, `-WhatIf` and unrecognized trailing arguments are rejected. Use Plan to review the proposed creation.
|
||||
|
||||
The fixed desired listener is `Address=IP:<selected IPv4>`, transport `HTTP`, port `5985`, URL prefix `wsman`, enabled, with blank hostname and certificate thumbprint. Wildcard listeners, any existing HTTP5985 listener and an existing selected Address/Transport pair prevent creation. WELA leaves those listeners in place for manual review. It does not narrow, replace, disable or remove an existing endpoint.
|
||||
|
||||
The plan binds the actual machine, operator/logon context, assigned address, implementation and original WinRM configuration/policy/listeners and firewall observations. Apply checks the reviewed hash and fresh context, writes pending evidence before its single creation attempt, then checks actual native configuration and `ListeningOn`. The fixed local creation worker uses the trusted native Windows PowerShell 5.1 engine under both Windows PowerShell 5.1 and PowerShell 7 hosts, with the fixed native 5.1 module directory and no execution-policy override. Its actual process, token and engine are retained as evidence. A host that cannot run this fixed adapter must resolve that prerequisite before applying.
|
||||
|
||||
| Result | Meaning |
|
||||
| --- | --- |
|
||||
| `ReviewRequired` | Plan artifacts are ready for review; no listener was created. |
|
||||
| `CreatedAndVerified` | The new listener and expected native readback were observed, with the required preservation checks. |
|
||||
| `Refused` | Preconditions, evidence or context failed before a creation attempt. |
|
||||
| `CreateAttemptedUnverified` | The adapter started and creation was attempted or cannot be ruled out; the final state could not be completely verified. Review the pending/native evidence and current listeners before taking further action. |
|
||||
|
||||
No atomic Windows compare-and-set is available; another administrator or policy process can race observation and creation. There is no automatic rollback. An interrupted process can leave pending evidence and a created listener without a completed report. Use the retained original and current snapshots to identify what changed; this command never deletes a listener as a recovery shortcut.
|
||||
|
||||
Creating this listener exposes a standard WinRM endpoint on the selected address. It does not restrict the endpoint to event forwarding. Existing authentication and authorization still apply. WELA preserves authentication, services, existing listeners and firewall settings; it does not run `winrm quickconfig`, `Enable-PSRemoting`, alter TrustedHosts or grant remote users access. Use the separate [reviewed firewall ingress command](wec-ingress.md) where an approved firewall rule is needed.
|
||||
|
||||
This is one prerequisite for [collector deployment](wef-deployment.md). Listener readback does not prove remote reachability, client authentication, domain source membership, a subscription, collector arrival, sustained retention or Sigma readiness. Built-in Windows only; Sysmon is excluded. The disposable Windows tests exercise creation/collision/readback and fixture cleanup; connected domain-source acceptance remains separate.
|
||||
|
||||
Microsoft documents the native [WinRM listener selectors and configuration](https://learn.microsoft.com/en-us/windows/win32/winrm/installation-and-configuration-for-windows-remote-management) and the [event-forwarding deployment prerequisites](https://learn.microsoft.com/en-us/windows/security/operating-system-security/device-management/use-windows-event-forwarding-to-assist-in-intrusion-detection).
|
||||
@@ -0,0 +1,39 @@
|
||||
# Reviewed enable/disable of an existing WEC subscription
|
||||
|
||||
`wec-state` reviews and changes only the **Enabled** Boolean of one existing native source-initiated HTTP subscription to ForwardedEvents. It completes the local pause/resume configuration step around [disabled query updates](wec-update.md). Disabling interrupts collection; enabling and saving activates the subscription. Review the source authorization, query, ReadExistingEvents setting and collection impact before Apply. No subscription is created, replaced or deleted, and no listener, firewall, service, channel, source authorization or query is changed.
|
||||
|
||||
```powershell
|
||||
# Native 64-bit Windows PowerShell 5.1 or PowerShell 7 on the collector.
|
||||
./WELA.ps1 wec-state -WecStateId 'Reviewed native subscription' `
|
||||
-WecStateSourceSid 'S-1-5-21-111111111-222222222-333333333-1234' `
|
||||
-WecStateDesired Disabled -WecStateOutputPath C:\Evidence\disable-plan
|
||||
|
||||
# Review plan.json and record its PlanHash from the planning result.
|
||||
./WELA.ps1 wec-state -WecStateAction Apply `
|
||||
-WecStatePlanPath C:\Evidence\disable-plan\plan.json `
|
||||
-WecStatePlanHash '<reviewed 64-character lowercase SHA256>' `
|
||||
-WecStateOutputPath C:\Evidence\disable-apply
|
||||
|
||||
# Resuming requires a fresh plan against the current definition:
|
||||
./WELA.ps1 wec-state -WecStateId 'Reviewed native subscription' `
|
||||
-WecStateSourceSid 'S-1-5-21-111111111-222222222-333333333-1234' `
|
||||
-WecStateDesired Enabled -WecStateOutputPath C:\Evidence\enable-plan
|
||||
```
|
||||
|
||||
Plan is the default and performs read-only native observations plus new evidence files. State is always explicit. Apply requires the reviewed file and separately supplied SHA256. `-Auto`, `-DryRun`, hypothetical host/role overrides and unrelated configuration options are rejected. An already matching state performs no native save: saving an enabled subscription could otherwise reactivate/retry it.
|
||||
|
||||
The actual collector must be a standalone or member Server 2022/2025 with Wecsvc already running. Enabling additionally requires ForwardedEvents already enabled; its observed configuration is included in the review/context guards. Explicit domain source SIDs must match its existing narrow authorization exactly; this does not prove those sources exist or can connect. Supported definitions use the existing strict native subscription parser: exact built-in channel filters, source-initiated HTTP5985, ForwardedEvents, a standard delivery preset, explicit content format/locale and ReadExistingEvents. Certificate/non-domain sources, arbitrary delivery properties and Sysmon/EMET are excluded. Dedicated domain/Kerberos deployment remains a separate [WEF configuration](wef-deployment.md) operation.
|
||||
|
||||
The reviewed plan binds complete original subscription XML, desired Boolean, actual host/build/role and operator identity/logon, service state and implementation hashes. Plan and Apply may run in separate processes in the same Windows logon; a different logon needs a fresh plan. Each operation also compares full native token statistics, including token/modification identifiers, to reject token or privilege changes during that operation. Hashes establish consistency, not authenticated approval or an untrusted evidence author's identity.
|
||||
|
||||
Apply uses `EC_OPEN_EXISTING` and requires the complete current definition to match its reviewed pre-state. A private Pending receipt is flushed and verified before mutation. Immediately before saving it rechecks evidence, source files, host/reader/token/service and full XML; a freshly opened native view also checks Enabled, query, description and authorization. The only property passed to `EcSetSubscriptionProperty` is `EcSubscriptionEnabled`. Readback requires the desired state and every other observed XML element to remain semantically identical, including native Delivery/EventSources expansion. Raw original/after XML is retained without rewriting it. A changing source inventory can therefore leave the configuration result unverified even when the requested Enabled value is observed.
|
||||
|
||||
Windows exposes no subscription lock, generation identity or atomic compare-and-swap. Concurrent administrators, source updates or an identical delete/recreate cannot all be excluded by these observations. Coordinate the operation on a quiescent subscription. The command makes no automatic rollback: reversing a state change requires another reviewed plan against the current definition. Failed saves or differing readback return `SaveAttemptedUnverified`, retaining the native error code and a best-effort post-failure definition/runtime observation. An activation failure can still persist Enabled; failure never implies rollback; retain the pending receipt and inspect actual Windows state before deciding what to do next. `NativeSaveAttempted` records whether the native save call was reached, including its failures. Pre-save refusals do not receive that flag.
|
||||
|
||||
Output must be a new directory under an existing local fixed-drive parent. UNC/device paths, streams and observed reparse points are rejected through the shared evidence-path helper. The new directory is restricted to the operator, SYSTEM and Administrators; existing paths and ACLs remain unchanged. Files use exclusive creation, flushed readback and SHA256 checks before the final manifest. These are sequential observations, not protection against a competing administrator. Reports contain sensitive source/host/account metadata. A missing final manifest means the evidence is incomplete.
|
||||
|
||||
`ReviewRequired`, `AlreadyMatches` and `StateChangedAndVerified` are configuration results. Separate bounded `RuntimeBefore`/`RuntimeAfter` objects reuse [typed native runtime observations](wec-runtime.md), capped at 32 sources; their Unknown/Partial statuses remain visible and do not become healthy-delivery claims. Active, heartbeat or an enabled setting proves neither event arrival nor uninterrupted collection. Bookmark continuity, backlog, transmission latency, source authorization effectiveness, retention and Sigma readiness remain unverified; `ReadyRuleCredit` is always zero. The command does not create an event or refresh a source.
|
||||
|
||||
Portable tests exercise stale plans, wrong hashes/types/authorization, duplicate JSON, unsupported queries, host/token/source drift, false native success, preservation/evidence failures, and idempotence. The gated disposable Server 2022/2025 × Windows PowerShell 5.1/PowerShell 7 fixture creates one uniquely owned subscription authorized to a fictional SID, uses the public CLI for actual enable/disable and idempotent transitions, checks complete preservation and stale-plan refusal, temporarily enables ForwardedEvents as a fixture prerequisite, then removes only the owned subscription and restores exact channel settings plus service state/startup. It creates no listener or real source. Native CI validates local state transitions only; connected Windows 11/member/DC/ADCS sources, actual event arrival, disable/resume gaps and bookmarks remain isolated multi-host acceptance for issue #368.
|
||||
|
||||
References: Microsoft [subscription property types](https://learn.microsoft.com/en-us/windows/win32/api/evcoll/ne-evcoll-ec_subscription_property_id), [existing-only open](https://learn.microsoft.com/en-us/windows/win32/api/evcoll/nf-evcoll-ecopensubscription), [access/open constants](https://learn.microsoft.com/en-us/windows/win32/wec/windows-event-collector-constants), [save activation/retry semantics](https://learn.microsoft.com/en-us/windows/win32/api/evcoll/nf-evcoll-ecsavesubscription) and [token statistics](https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-token_statistics).
|
||||
+1
-1
@@ -21,7 +21,7 @@ The reviewed plan binds the complete original XML, explicit desired values, actu
|
||||
|
||||
Concurrent changes, enabled subscriptions, unsupported definitions, denied reads and changed plans fail rather than broadening scope. If save is attempted but fails or readback differs, the manifest says `SaveAttemptedUnverified`; no automatic rollback can overwrite an intervening administrator change. Preserve the receipt and inspect the actual subscription. Restoring original values requires a fresh plan against its current state using the original recorded query/description. Windows exposes no compare-and-swap or subscription lock here: the pre-save checks narrow but cannot eliminate a concurrent administrative write between observation and save. Coordinate a maintenance window; hashes are consistency checks, not signatures or authenticated approval.
|
||||
|
||||
The subscription remains disabled, and authorization, destination, delivery, locale, transport, ReadExistingEvents and other observed settings must remain unchanged. This first version deliberately requires disabled state: Microsoft documents that saving an enabled subscription activates it. Active-source delivery and bookmark continuity require separate lab acceptance before extending that scope. A successful disabled update grants **zero Sigma readiness credit** and proves neither delivery nor retention.
|
||||
The subscription remains disabled, and authorization, destination, delivery, locale, transport, ReadExistingEvents and other observed settings must remain unchanged. This first version deliberately requires disabled state: Microsoft documents that saving an enabled subscription activates it. Use the separate [reviewed Enabled transition](wec-state.md) command to disable or enable an existing subscription. Active-source delivery and bookmark continuity require separate lab acceptance. A successful disabled update grants **zero Sigma readiness credit** and proves neither delivery nor retention.
|
||||
|
||||
Tests include malformed/duplicate JSON, stale plans, changed context, unexpected enablement, preservation failure, native error, false success, idempotence and pending receipt ordering. Disposable Server 2022/2025 × Windows PowerShell 5.1/PowerShell 7 CI creates one unique disabled subscription with no real source, changes and restores query/description through the public command, rejects the stale plan, verifies other properties and restores subscription inventory plus original Wecsvc state/startup. It does not validate active sources or bookmarks.
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# Native WEF source configuration and collector subscriptions
|
||||
|
||||
For a missing collector listener, use the separately reviewed [`wec-listener` Plan/Apply](wec-listener.md) to create one assigned-IPv4 HTTP5985 listener. It refuses existing listeners and preserves WinRM authentication, services and firewall settings. Collector configuration still requires its own validated prerequisites; listener creation does not prove source arrival.
|
||||
|
||||
`wef-source` and `wec-collector` are separate, opt-in commands for a bounded domain/Kerberos topology: source-initiated subscriptions over HTTP 5985 to a dedicated domain member Windows Server collector. They require an operator JSON file with the actual collector FQDN/URI, explicitly permitted source computer/group SIDs, and selected native subscription XML files. Sysmon and EMET are excluded. Local channel enablement or successful configuration does not establish forwarding or add usable Sigma-rule credit.
|
||||
|
||||
This implements source configuration and collector subscription creation, not every WEF topology or all acceptance evidence for issue #368. HTTPS/certificate enrollment, workgroups/cross-domain trust, collector-initiated/custom-delivery subscriptions, listener/firewall creation, remote GPO management, updating/deleting existing subscriptions and automatic rollback are outside this command's initial scope. Dedicated workload isolation, network logon rights, capacity and actual event collection remain operator responsibilities.
|
||||
@@ -40,7 +42,7 @@ On a domain controller, BUILTIN group membership has domain/AD authority rather
|
||||
|
||||
The local host must be a domain member server whose observed DNS name equals `CollectorFqdn`. WinRM and Wecsvc can be set to Automatic and started. WELA never runs `winrm quickconfig`, `wecutil qc` or `Enable-PSRemoting`, and never creates or broadens listeners/firewall rules.
|
||||
|
||||
Before enabling ForwardedEvents or creating a subscription, WELA requires one existing listener matching `ListenerAddress`, HTTP, enabled state, port 5985 and URL prefix `wsman`; one named effective ActiveStore ingress rule matching inbound Allow, Domain profile, TCP 5985 and the exact `IngressLocalAddresses`/`IngressRemoteAddresses`; running Automatic services; enabled collector Kerberos; and the two assessed ASD hardening settings below. Supply explicit IP/CIDR address lists, not `Any` or `/0`. The check verifies the selected definitions, not actual packet acceptance, reachability, profile activation or the absence of other broad rules. Listener/rule evidence is retained in JSON.
|
||||
Before enabling ForwardedEvents or creating a subscription, WELA requires one existing listener matching `ListenerAddress`, HTTP, enabled state, port 5985 and URL prefix `wsman`; one named effective ActiveStore ingress rule matching inbound Allow, Domain profile, TCP 5985 and the exact `IngressLocalAddresses`/`IngressRemoteAddresses`; running Automatic services; enabled collector Kerberos; and the two assessed ASD hardening settings below. Supply explicit IP/CIDR address lists, not `Any` or `/0`. The check verifies the selected definitions, not actual packet acceptance, reachability, profile activation or the absence of other broad rules. Listener/rule evidence is retained in JSON. Explicit address scopes are compared by IP/network identity, recognizing native IPv4 dotted-netmask spelling and equivalent IPv6 compression while preserving network size, address family and scope ID. Raw native strings remain visible; dynamic aliases, malformed masks and different scopes never become an ingress match.
|
||||
|
||||
`Hardening: "ApplyASD"` explicitly permits setting `WSMan:\localhost\Service\Auth\CbtHardeningLevel` to `Strict` and `WSMan:\localhost\Shell\AllowRemoteShellAccess` to `false`. Disabling remote shells prevents new remote-shell sessions; review this on a dedicated collector using local/out-of-band administration. `AssessOnly` records unmet hardening and blocks subscription creation. Policy-owned mismatches are refused; WELA does not rewrite their controlling GPO. No Basic, CredSSP, TrustedHosts, authentication fallback or firewall access setting is changed.
|
||||
|
||||
@@ -48,6 +50,8 @@ ForwardedEvents enablement preserves its size, retention mode and security descr
|
||||
|
||||
## Subscription XML and evidence
|
||||
|
||||
[Native collector observations](wec-collector-observation.md) use complete bounded WEC name enumeration and strict Unicode XML reads. Failed or partial observations remain unknown; they never become permission to create a subscription. Raw Unicode descriptions/filters and actual disabled state are retained independently of the requested settings.
|
||||
|
||||
The supported input is the native Subscription namespace, SourceInitiated type, native EventLog URI, HTTP transport, ForwardedEvents destination and Normal/MinLatency/MinBandwidth delivery preset. Enabled, ReadExistingEvents, content format and locale must be explicit. QueryList uses unique numeric Query IDs, exact native channel paths and nonempty Select/Suppress XPath expressions. Wildcard/provider channel names, external-provider channels, Sysmon/EMET, DTDs, unknown settings and custom delivery are rejected. This checks supported structure, not Windows XPath execution; native `cs` remains the final syntax validator.
|
||||
|
||||
An empty `AllowedSourceDomainComputers` input is filled from the explicit `SourceSids`; a nonempty value must match that authorization exactly. No empty authorization reaches `wecutil`, avoiding Windows' broader default authorization. Non-domain/certificate authorization is not supported. The example Security 4740 filter is illustrative and is not a complete baseline or a recommendation to lock an account for testing.
|
||||
@@ -56,11 +60,13 @@ Readback equality covers ID, enabled state, selected delivery preset, ReadExisti
|
||||
|
||||
JSON retains exact filters, disabled flags, local channel enablement/mode/ACL, local configuration results, native `wecutil gr` output and its errors, and unverified prerequisites. A separate [`TypedRuntime`](wec-runtime.md) object adds native activity/error/time fields and bounded per-source observations; its Unknown/Partial status stays independent of local configuration success. On collectors, local channel metadata is explicitly labeled **collector only**; it does not describe remote source states. Localized runtime text is preserved as evidence without inferring connected-source counts or arrival success. `LocalConfigurationStatus: RequestedSettingsMatch` describes the selected local settings only. A non-dry-run with unmet prerequisites, failed writes or mismatched final settings exits nonzero and is incomplete.
|
||||
|
||||
Use the separate [reviewed authorization update](wec-authorization.md) to change an explicit source SID list on an already disabled existing subscription. It preserves the other observed fields and supplies no SID-resolution or forwarding proof.
|
||||
|
||||
## Recovery and lab acceptance
|
||||
|
||||
`before.jsonl` is written before each mutation. Review its exact Target/Before/Desired and the results before recovery. For a newly created subscription, it records absence and stores the prepared XML; remove that exact ID only after verifying its current definition still belongs to this run. Existing subscriptions are never edited. For the new SubscriptionManager value, compare the current value with Desired before removing only that value; keep other list entries and parent keys. Restore WSMan values and service start/running states only after verifying their present state and current policy authority. Remove only the newly added group SID after comparing the full membership snapshot; DC membership is never changed by this workflow. For channel restoration, use the channel journal and descriptor-preservation guidance. Recovery is deliberately manual so a newer operator/GPO change is not overwritten.
|
||||
|
||||
Safe fixture tests exercise the public command/report, journals, readback failures, occupied slots, explicit authorization, native create failures, configuration drift, DC group protection and blocked prerequisites. Windows PowerShell 5.1/PowerShell 7 CI adds real **read-only** channel, service, WSMan, firewall and ADMX assessment. These tests do not deploy subscriptions or prove forwarding.
|
||||
Safe fixture tests exercise the public command/report, journals, readback failures, occupied slots, explicit authorization, native create failures, configuration drift, DC group protection and blocked prerequisites. Windows PowerShell 5.1/PowerShell 7 CI adds real **read-only** channel, service, WSMan, firewall and ADMX assessment. Those read-only smoke tests do not deploy subscriptions or prove forwarding. The separate [native observation fixture](wec-collector-observation.md) now exercises public Audit/Plan against one owned disabled subscription on standalone Server 2022/2025 runners, preserving real unmet domain prerequisites and exact fixture cleanup; it does not test domain deployment or delivery.
|
||||
|
||||
Before closing issue #368, an isolated domain lab must configure a dedicated collector and Windows 11/member-server/DC/AD CS sources, verify source identity/token read access (including any required token/service refresh), preserve runtime status, and demonstrate native events matching each selected query arriving with the expected source identity/timestamps. Include disabled-query, denied-source, absent-channel, GPO refresh, idempotence, drift and recovery cases. Use a deliberately chosen benign native Application/System event or a controlled test account/object relevant to the query; record actual events, not merely a successful command or ACE. Forwarded Sigma coverage remains unassessed until those events and the processing pipeline are validated.
|
||||
|
||||
|
||||
+2
-2
@@ -17,7 +17,7 @@ Use native 64-bit Windows PowerShell 5.1 or PowerShell7 on a reviewed Windows11/
|
||||
|
||||
The process token observation includes user SID/name, logon-session LUID, authentication/impersonation information, group SIDs with native attributes, and privilege LUIDs/attributes. Disabled and deny-only groups do not establish a matching success audit ACE. The shared descriptor reader temporarily enables an already assigned `SeSecurityPrivilege` and restores it; the probe verifies its token is unchanged afterward. It does not assign rights. A runtime-created self-impersonation token is accepted only when its SID, logon LUID, complete group attributes and privilege attributes equal the process token; its source/type remain recorded. Different or restricted tokens are refused before a child is launched. No token is reverted or replaced. An ACE match alone does not prove effective namespace access; the fixed read and event observations are separate.
|
||||
|
||||
The worker uses the same PowerShell executable as WELA with `-NoProfile -NonInteractive`. It connects only to `\\.\<selected-namespace>` and executes `SELECT Name FROM __Namespace WHERE Name='WelaReadProbe_<random-guid>'`. It must return zero rows. This avoids retrieving a namespace inventory, creating an instance or invoking a provider method. The child has a twenty-second limit; a stuck owned child is terminated. The configured 1–30-second timeout is the subsequent event-arrival polling limit, not a deadline for all host/descriptor observations. Ordinary native prerequisite APIs can still wait on WMI/Windows availability.
|
||||
The worker uses the same PowerShell executable as WELA with `-NoProfile -NonInteractive`. It connects only to `\\.\<selected-namespace>` and executes `SELECT Name FROM __Namespace WHERE Name='WelaReadProbe_<random-guid>'`. It must return zero rows. This avoids retrieving a namespace inventory, creating an instance or invoking a provider method. Parent launch/observation and worker start/completion timestamps use Windows [GetSystemTimePreciseAsFileTime](https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimepreciseasfiletime). The worker records that clock contract; missing/coarse-clock receipts, times preceding launch, backwards intervals and future completion times are refused. This avoids mixing a coarse .NET Framework clock with higher-resolution event timestamps. The event interval remains exact, with no positive-match padding; a clock change or missing event stays unverified. The child has a twenty-second limit; a stuck owned child is terminated. The configured 1–30-second timeout is the subsequent event-arrival polling limit, not a deadline for all host/descriptor observations. Ordinary native prerequisite APIs can still wait on WMI/Windows availability.
|
||||
|
||||
Source/helper and PowerShell executable fingerprints are recorded and checked before/after, alongside full descriptor, host, channel and policy state. The worker records its own before/after token; its user/logon/group context must match the parent, and its privilege state must remain unchanged. A changed state, denied read, failed child, missing evidence, unknown schema or query cap remains `Unverified` with exit1 and available recovery evidence. `LocalNamespaceAccessObserved` requires successful verification; it grants **zero usable Sigma-rule credit**.
|
||||
|
||||
@@ -33,7 +33,7 @@ The Security query accepts at most255 candidates; reaching the256-record cap fai
|
||||
|
||||
The fixture suite exercises the public report flow with native boundaries explicitly mocked, including source/event mismatches, denied reads, missing prerequisites, state drift, caps and protected new output. Public CLI guards are checked separately. Native code is never dot-sourced from those mock fixtures.
|
||||
|
||||
`tests/WmiProbe.Windows.Tests.ps1 -AllowDisposableNamespaceWrite` requires a disposable GitHub-hosted workgroup Server2022/2025. It creates exactly one random `root\WelaReadTest_<GUID>` namespace with CreateOnly, uses the real existing SACL writer with the ASD root-default definition on that owned namespace, temporarily enables Other Object Access success auditing and precedence, and invokes the public CLI. It requires correlated raw native4662 evidence and unchanged namespace security. It then restores the original subcategory and exact typed precedence, verifies all59 audit masks, and deletes only the namespace it created. Failures preserve the primary exception and a private cleanup receipt; restoration failures fail the job. Private temporary evidence remains on the disposable runner until that VM is discarded.
|
||||
`tests/WmiProbe.Windows.Tests.ps1 -AllowDisposableNamespaceWrite` requires a disposable GitHub-hosted workgroup Server2022/2025. It creates exactly one random `root\WelaReadTest_<GUID>` namespace with CreateOnly, uses the real existing SACL writer with the ASD root-default definition on that owned namespace, temporarily enables Other Object Access success auditing and precedence, and invokes the public CLI three independent times by default. Every run must pass; there are no success-on-retry semantics. It requires correlated raw native4662 evidence and unchanged namespace security. It then restores the original subcategory and exact typed precedence, verifies all59 audit masks, and deletes only the namespace it created. Failures preserve the primary exception and a private cleanup receipt; restoration failures fail the job. Private temporary evidence remains on the disposable runner until that VM is discarded.
|
||||
|
||||
The native matrix passed on Server 2022 and Server 2025 under both Windows PowerShell 5.1 and PowerShell 7 in [run 35539528097](https://github.com/Yamato-Security/WELA/actions/runs/35539528097), at implementation commit `89aa345`. Each combination passed the then-current 108 fixture assertions, 10 public CLI checks and 19 native assertions, including two matching WMI namespace-read records and exact cleanup. The raw records use `ObjectType=WMI Namespace`, `ObjectServer=WMI`, read mask `0x1` and event version 0. This evidence verifies those disposable cases; inspect the final-head workflow before merging later changes. Windows11, production namespaces, domain/DC/CA token behavior, remote WMI, inheritance propagation, forwarding and backend execution remain separate acceptance work. No domain infrastructure is required by this fixture.
|
||||
|
||||
|
||||
Reference in new issue
Block a user