mirror of
https://github.com/Yamato-Security/WELA.git
synced 2026-10-23 22:53:00 +02:00
Integrate reviewed filesystem and WEF query changes with scoped NTLM auditing
This commit is contained in:
commit
005b249c3b
22 files changed
+1148
-6
No files matched your search
@@ -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).
|
||||
@@ -88,7 +88,9 @@ Mocked tests cover selection, source-specific masks, unsupported consent, source
|
||||
|
||||
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.
|
||||
|
||||
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 [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).
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ ForwardedEvents enablement preserves its size, retention mode and security descr
|
||||
|
||||
[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.
|
||||
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. Use the separate read-only [`wef-query` preflight](wef-query.md) to execute one exact selected QueryList on the local source under the actual caller token, with native Select/Suppress results and distinct empty/failure/partial evidence. It does not test the forwarding service token or remote delivery.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
# Native source QueryList preflight
|
||||
|
||||
`wef-query` executes the exact QueryList from one explicitly selected subscription in an existing WEF **Source** config against local Windows logs. It checks actual native query behavior and the current caller's read access, preserving matching event XML in a new private evidence directory. It changes no Windows settings, contacts no collector and creates no subscription or event.
|
||||
|
||||
```powershell
|
||||
./WELA.ps1 wef-query -WefQueryConfigPath C:\WEF\source.json `
|
||||
-WefQuerySubscriptionId 'WELA Native Security Example' `
|
||||
-WefQueryOutputPath C:\Evidence\query-001 `
|
||||
-WefQueryMaximumEvents 16
|
||||
```
|
||||
|
||||
Use native 64-bit Windows PowerShell 5.1 or PowerShell 7 under the intended reader's session. The observed host must be within WELA's reviewed Windows 11 / Server 2022/2025 build scope, with EventLog and Winmgmt already running. The command does not start services, elevate, impersonate another user or refresh a token. `-Auto`, `-DryRun`, `-WhatIf`, alternate credentials, remote query options and unrelated configuration arguments are rejected. A source's current domain membership does not authorize a remote operation because this command performs none.
|
||||
|
||||
The source JSON and explicitly listed subscriptions use the existing [WEF deployment](wef-deployment.md) schema: collector FQDN/URI, domain-format source SIDs and supported built-in native subscription definitions. Select one exact, case-sensitive subscription ID from that config. The collector identity and requested enabled flag remain recorded operator inputs; neither becomes an observed collector setting or verified identity. An explicitly disabled subscription can still be preflighted against historical local records.
|
||||
|
||||
## Exact query and separate error diagnostics
|
||||
|
||||
The existing parser validates supported subscription structure, native channel paths, Select/Suppress clauses and excluded external providers. The extracted QueryList text is then passed directly to native `EvtQuery`; WELA does not rewrite XPath, remove suppressions, substitute a fixed query or enable tolerance for matching evidence. The query runs in reverse record order. Windows does not support reverse queries on Analytic/Debug channels; those native failures remain failures, without changing channel state or silently choosing another query mode. Every native channel status must be attributable to a selected channel, and every selected channel must have a reported status before a complete result is possible.
|
||||
|
||||
If strict query creation fails, its native error remains the primary outcome. A second, separately labeled native diagnostic query can return per-channel status codes with `EvtQueryTolerateQueryErrors`. Windows may recover only part of a malformed XPath under that flag, so **no records from the diagnostic query are read or accepted as matches**. Missing diagnostic details remain unknown. Numeric error codes are preserved without parsing localized message text.
|
||||
|
||||
| Status | Meaning |
|
||||
| --- | --- |
|
||||
| `MatchesObserved` | Strict query completed, every selected channel status succeeded, and at least one native matching event was retained. |
|
||||
| `ReadAllowedEmpty` | Strict query completed with successful channel statuses and no matching events. Empty is distinct from denial, missing logs or invalid syntax. |
|
||||
| `QueryFailed` | Strict query creation failed; inspect its error and the separate diagnostic channel statuses. |
|
||||
| `Partial` | The strict query opened, but a cap, read failure, channel error or incomplete cleanup prevented completeness. Retained samples remain individual observations. |
|
||||
| `Unverified` | Input, worker, context, provenance or artifact checks failed. Inspect the diagnostic and available evidence. |
|
||||
|
||||
Only the first two statuses return exit 0. A valid query can legitimately return no records, and a broad valid query can exceed the sample limit. A native success establishes behavior for the current local logs and actual caller at observation time; it does not prove that a future event, another account or the forwarding service will have the same result.
|
||||
|
||||
## Bounds and evidence
|
||||
|
||||
Each original input is limited to 1 MiB, with 4 MiB aggregate decoded text. The selected QueryList is limited to 65,536 UTF-16 characters, 16 distinct channels and 128 filters. `WefQueryMaximumEvents` accepts 1–64 (default 16). One extra native record is requested to distinguish an exact-sized result from a cap; the extra record is not rendered or retained. Native XML is bounded to 1 MiB of UTF-16 per record and 4 MiB of aggregate UTF-8 matching XML.
|
||||
|
||||
The fixed worker uses the same installed PowerShell engine and actual caller context. Its native query handles remain on one thread. Each `EvtNext` uses a five-second timeout; the parent bounds the entire worker to 45 seconds, with bounded output draining and termination waits. A timeout or unconfirmed worker termination cannot earn a complete result. Bounded source, native query-status arrays and pipe buffers prevent unconstrained result allocation.
|
||||
|
||||
The new output directory grants access to the current user, SYSTEM and local Administrators. Original inputs and parent ACLs are not changed. Paths must be ordinary local paths accepted by WELA's recovery artifact helpers; existing output directories and observed reparse paths are refused. Raw event payloads can contain sensitive operational data, so retain them as evidence under the intended reader's access policy.
|
||||
|
||||
Outputs include decoded `source-config.json`, `subscription.xml`, exact `query.xml`, the worker `request.json`, `worker.json`, individual `event-NNN.xml` matches and a final `manifest.json`. The manifest records original file paths/hashes, source fingerprints, query hash, actual host/DNS context, engine hash/version, before/after reader and channel observations, strict/diagnostic query results and artifact hashes. The worker retains each XML render’s native `PropertyCount` as information; the Server 2022/2025 validation runs observed 1 even though the API documentation specifies 0 for XML. XML parsing uses bounded UTF-16 byte length and its final terminator, following the string rendering contract, independently of that values-array count. The original byte hashes are distinct from the decoded text artifacts. Unsuccessful runs retain whatever evidence was available; a missing final manifest means the output is incomplete.
|
||||
|
||||
The worker's SID, logon, group attributes and privileges must match the caller and remain stable. Host, input bytes, implementation, engine, channel configuration and saved hashes are rechecked before completeness. Returned event channel/record identity and exact observed local computer names must be consistent; no same-label arbitrary DNS suffix is accepted. These checks are observations rather than an atomic channel snapshot, and hashes establish consistency rather than authenticating an evidence author.
|
||||
|
||||
`ConfigurationChanges` and `ReadyRuleCredit` remain zero. The result does not establish NETWORK SERVICE's effective token, source group membership, policy/SACL generation prerequisites, subscription delivery, origin of historical records, loss, forwarding latency, retention duration or Sigma readiness. Use [channel-read](channel-read.md) for a simple current-token channel read and [wef-arrival](wef-arrival.md) for the separate exact collector-presence workflow. Issue #368 still requires representative multi-host source/collector validation.
|
||||
|
||||
## Native validation
|
||||
|
||||
The disposable Server 2022/2025 workflow runs both PowerShell engines through the public command. It selects an independently read real System record, verifies complete XML equality, suppresses that same record to obtain a genuine empty result, exercises malformed XPath and a mixed missing-channel query, and proves the event cap with an extra native record. An owned standard user and temporary CAPI2 deny ACE exercise actual access denial. The fixture independently restores the original channel descriptor and removes its owned account, then compares profile/loaded-hive inventories, selected channels, services, all audit masks, precedence and the operator token. The alternate-account process explicitly avoids loading a Windows user profile. These temporary fixture changes are absent from the product. No domain setup, event generation or forwarding is claimed by this native suite.
|
||||
|
||||
Microsoft references: [EvtQuery](https://learn.microsoft.com/en-us/windows/win32/api/winevt/nf-winevt-evtquery), [query flags and partial XPath recovery](https://learn.microsoft.com/en-us/windows/win32/api/winevt/ne-winevt-evt_query_flags), [per-channel query information](https://learn.microsoft.com/en-us/windows/win32/api/winevt/nf-winevt-evtgetqueryinfo), [native property types](https://learn.microsoft.com/en-us/windows/win32/api/winevt/ne-winevt-evt_query_property_id), [EvtNext completeness and timeout](https://learn.microsoft.com/en-us/windows/win32/api/winevt/nf-winevt-evtnext), and [native event XML rendering](https://learn.microsoft.com/en-us/windows/win32/api/winevt/nf-winevt-evtrender).
|
||||
Reference in new issue
Block a user