Validate typed source inputs and preserve caller scope in query reader

This commit is contained in:
Shirofune-Security committed 2026-09-22 12:10:03 +09:00
1 parent 54f9d6bf51
commit f27238ebd5
9 files changed
+109 -4

No files matched your search

+1 -1
View File
@@ -41,7 +41,7 @@ jobs:
Copy-Item -Recurse -Path ./scripts -Destination release-binaries/
Copy-Item -Recurse -Path ./modules -Destination release-binaries/
New-Item -ItemType Directory -Path release-binaries/docs -Force | Out-Null
Copy-Item -Path ./docs/gpo-audit-packages.md, ./docs/gpo-package-deployment.md, ./docs/gpo-creation.md, ./docs/wmi-probe.md, ./docs/firewall-logging.md, ./docs/firewall-logging-recovery.md, ./docs/ipsec-prerequisites.md, ./docs/wec-state.md, ./docs/wec-update.md, ./docs/wec-runtime.md, ./docs/wef-deployment.md, ./docs/native-channel-access.md, ./docs/eventlog-settings.md, ./docs/channel-read.md, ./docs/native-rule-eligibility.md, ./docs/native-validation.md, ./docs/wef-arrival.md, ./docs/smb-runtime-activation.md, ./docs/smb-auditing.md, ./docs/wec-ingress.md, ./docs/capi2-probe.md, ./docs/powershell-transcription.md, ./docs/transcription-recovery.md, ./docs/eventlog-recovery.md, ./docs/failed-logon-probe.md, ./docs/wec-listener.md, ./docs/file-access-probe.md, ./docs/applocker-script-probe.md, ./docs/applocker-probe.md, ./docs/selected-sacl-configuration.md, ./docs/registry-sacl-recovery.md, ./docs/targeted-sacl-planning.md, ./docs/native-registry-sacl-validation.md, ./docs/wec-authorization.md, ./docs/channel-recovery.md, ./docs/outgoing-ntlm.md, ./docs/wec-collector-observation.md, ./docs/native-provider-packs.md, ./docs/native-provider-acceptance.md -Destination release-binaries/docs/
Copy-Item -Path ./docs/gpo-audit-packages.md, ./docs/gpo-package-deployment.md, ./docs/gpo-creation.md, ./docs/wmi-probe.md, ./docs/firewall-logging.md, ./docs/firewall-logging-recovery.md, ./docs/ipsec-prerequisites.md, ./docs/wec-state.md, ./docs/wec-update.md, ./docs/wec-runtime.md, ./docs/wef-deployment.md, ./docs/wef-query.md, ./docs/native-channel-access.md, ./docs/eventlog-settings.md, ./docs/channel-read.md, ./docs/native-rule-eligibility.md, ./docs/native-validation.md, ./docs/wef-arrival.md, ./docs/smb-runtime-activation.md, ./docs/smb-auditing.md, ./docs/wec-ingress.md, ./docs/capi2-probe.md, ./docs/powershell-transcription.md, ./docs/transcription-recovery.md, ./docs/eventlog-recovery.md, ./docs/failed-logon-probe.md, ./docs/wec-listener.md, ./docs/file-access-probe.md, ./docs/applocker-script-probe.md, ./docs/applocker-probe.md, ./docs/selected-sacl-configuration.md, ./docs/registry-sacl-recovery.md, ./docs/targeted-sacl-planning.md, ./docs/native-registry-sacl-validation.md, ./docs/wec-authorization.md, ./docs/channel-recovery.md, ./docs/outgoing-ntlm.md, ./docs/wec-collector-observation.md, ./docs/native-provider-packs.md, ./docs/native-provider-acceptance.md -Destination release-binaries/docs/
- name: Set Artifact Name
if: contains(matrix.info.os, 'windows') == true
+2
View File
@@ -4,6 +4,8 @@
**改善:**
- 読み取り専用の `wef-query` を追加しました。選択したソースのQueryListをそのままネイティブAPIで実行し、Select/Suppressの動作、チャネル別の失敗診断、上限付きの一致イベントXML、実際の操作者・ホスト・ソースの整合性を確認します。空の結果、アクセス拒否、未存在、不正クエリ、上限到達、状態変化を区別し、破棄可能なWindows環境で実イベントの選択・抑制と標準ユーザーの拒否、完全な後片付けを検証します。転送サービスのアクセス権、配送、Sigmaの準備完了は推定しません。 (Related #368) (@Shirofune-Security)
- 明示的な `registry-sacl-recovery` を追加しました。整合する4つの元記録、レビュー済み計画のハッシュ、過去・現在ともに空の子キー観測、監査縮小と継承への個別同意を必須とし、追加が証明されたレジストリルートの明示的な監査ACEを1つだけ削除します。SACLのみのネイティブ書き込みで他の記述子フィールドとACEの順序を保持し、部分的な書き込みの証跡と元の記述子バイトとの一致を別々に報告します。過去のキー・操作者の同一性認証、ツリー全体の原子性、イベント生成、Sigmaの準備完了は保証しません。 (Related #373) (@Shirofune-Security)
- Server 2022/2025とPowerShell 5.1/7でSMBポリシー設定の公開CLIを検証します。対応ホストで6項目の適用・再読取・再実行、非対応ホストのスキップ、元の型付き記録、無関係な設定の維持と完全な復元を確認します。イベント生成と実行時の有効化は別途検証します。(関連 #377) (@Shirofune-Security)
+2
View File
@@ -4,6 +4,8 @@
**Improvements:**
- Added read-only `wef-query` preflight for one exact selected source QueryList, with strict native Select/Suppress execution, separate per-channel failure diagnostics, bounded matching XML and actual caller/host/source guards. Empty, denied, missing, invalid, capped and drifted results remain distinct; disposable native tests cover real record selection/suppression and standard-user denial with exact cleanup. No forwarding-service access, delivery or Sigma credit is inferred. (Related #368) (@Shirofune-Security)
- Added opt-in `registry-sacl-recovery` for one proven explicit registry-root audit ACE, requiring four matching original records, a reviewed plan hash, empty historical/current descendants and separate audit-reduction/inheritance consent. Native SACL-only removal preserves unrelated descriptor fields and ACE order, retains partial-write evidence and reports original-byte equality separately; no authenticated historical key/operator identity, atomic-tree, event or Sigma claim. (Related #373) (@Shirofune-Security)
- Add native public SMB policy configuration acceptance on Server 2022/2025 and PowerShell 5.1/7: six-policy apply/readback and idempotence on supported hosts, unsupported-host skips, typed original journals, unrelated-state preservation and exact cleanup. Event generation and runtime activation remain separate. (Related #377) (@Shirofune-Security)
+1 -1
View File
@@ -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.
+50
View File
@@ -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. 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 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 selected channels, services, all audit masks, precedence and the operator token. 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).
+12 -2
View File
@@ -34,18 +34,28 @@ function Get-WelaWefQueryTokenKey {
Get-WelaWefQueryKey ([pscustomobject][ordered]@{Sid=$Token.Sid;Name=$Token.Name;AuthenticationId=$Token.AuthenticationId;AuthenticationType=$Token.AuthenticationType;Groups=$Token.Groups;Privileges=$Token.Privileges})
}
function Assert-WelaWefQueryUInt {param($Value) if(($Value -isnot [int] -and $Value -isnot [long] -and $Value -isnot [uint32]) -or $Value -lt 0 -or $Value -gt [uint32]::MaxValue){throw 'Expected a native unsigned integer.'}}
function Assert-WelaWefQuerySourceConfig {
param($Config)
Assert-WelaArrivalObject $Config @('SchemaVersion','Role','CollectorFqdn','CollectorUri','Authentication','SourceSids','SubscriptionFiles','Hardening','SubscriptionManagerSlot','RefreshSeconds','GrantNetworkServiceRead','ApplyChannelProfile','GrantCapi2Read')
foreach($name in @('SchemaVersion','SubscriptionManagerSlot','RefreshSeconds')){if($Config.$name -isnot [int] -and $Config.$name -isnot [long]){throw 'Source config requires integer schema/slot/refresh fields.'}}
foreach($name in @('Role','CollectorFqdn','CollectorUri','Authentication','Hardening')){if($Config.$name -isnot [string]){throw 'Source config requires typed text fields.'}}
foreach($name in @('SourceSids','SubscriptionFiles')){if($Config.$name -isnot [array]){throw 'Source config requires explicit SID/file arrays.'};foreach($value in $Config.$name){if($value -isnot [string] -or -not $value){throw 'Source config requires nonempty SID/file strings.'}}}
foreach($name in @('GrantNetworkServiceRead','ApplyChannelProfile','GrantCapi2Read')){if($Config.$name -isnot [bool]){throw 'Source config requires explicit Boolean permission settings.'}}
}
function Import-WelaWefQuerySelection {
param([string]$ConfigPath,[string]$SubscriptionId)
if(-not $ConfigPath -or -not $SubscriptionId -or $SubscriptionId.Length -gt 256 -or $SubscriptionId -match '[\x00-\x1f]'){throw 'An exact source config path and subscription ID are required.'}
$capture=@{Files=[Collections.Generic.List[object]]::new();Bytes=0;Texts=[Collections.Generic.List[string]]::new()}
# This synchronous callback retains the caller's script scope. GetNewClosure
# creates a dynamic module that cannot see script-local artifact helpers.
$reader={param($path)
$file=Read-WelaWecUpdateFile $path 1048576
if($capture.Files.Path -contains $file.Path){throw 'Duplicate input file path.'}
if($capture.Files.Count -eq 0){$json=ConvertFrom-WelaArrivalJson $file.Text;if($json.SchemaVersion -isnot [int] -and $json.SchemaVersion -isnot [long]){throw 'WEF schema version must be an integer.'}}
if($capture.Files.Count -eq 0){$json=ConvertFrom-WelaArrivalJson $file.Text;Assert-WelaWefQuerySourceConfig $json}
$capture.Bytes+=[Text.Encoding]::UTF8.GetByteCount($file.Text);if($capture.Bytes -gt 4194304){throw 'WEF input text exceeds four MiB aggregate.'}
$capture.Files.Add([pscustomobject]@{Path=$file.Path;Sha256=$file.Hash});$capture.Texts.Add($file.Text)
$file.Text
}.GetNewClosure()
}
$model=Import-WelaWefConfig -Path $ConfigPath -Role Source -ReadText $reader
$selected=@($model.Subscriptions|Where-Object Id -CEQ $SubscriptionId)
if($selected.Count -ne 1){throw 'Select one exact subscription ID from the source config.'};$selected=$selected[0]
+37
View File
@@ -52,9 +52,46 @@ try{
Reject {Import-WelaWefQuerySelection $path 'WELA Native Security Example'} 'Duplicate config properties refused.'
[IO.File]::WriteAllText($path,$original.Replace('"SchemaVersion": 1','"SchemaVersion": true'))
Reject {Import-WelaWefQuerySelection $path 'WELA Native Security Example'} 'Boolean schema rejected.'
foreach($field in @('Role','Hardening','CollectorFqdn','CollectorUri','Authentication')){$config=ConvertFrom-WelaArrivalJson $original;$config.$field=$true;[IO.File]::WriteAllText($path,(Get-WelaWefQueryKey $config));Reject {Import-WelaWefQuerySelection $path 'WELA Native Security Example'} "Boolean text cannot pass source config $field"}
foreach($field in @('SourceSids','SubscriptionFiles')){$config=ConvertFrom-WelaArrivalJson $original;$config.$field=@($true);[IO.File]::WriteAllText($path,(Get-WelaWefQueryKey $config));Reject {Import-WelaWefQuerySelection $path 'WELA Native Security Example'} "Typed source array $field"}
[IO.File]::WriteAllText($path,$original)
[IO.File]::AppendAllText($subscription,' ');Reject {Assert-WelaWefQueryInputs $selected} 'Original subscription byte drift invalidates evidence.'
}finally{Remove-Item -LiteralPath $temp -Recurse -Force}
$stream=[IO.StringReader]::new('abcdef');try{Reject {[Wela.WefQuery.Native]::ReadPipe($stream,5).GetAwaiter().GetResult()} 'Bounded pipe rejects excess before growing without limit.'}finally{$stream.Dispose()}
# Exercise complete command outcomes and changed evidence through real local artifacts.
$script:lifecycle=@{Case='';HostReads=0;ChannelReads=0;Config='';Xml=$xml}
function Get-WelaWefQueryHost {$script:lifecycle.HostReads++;[pscustomobject]@{Computer=$(if($script:lifecycle.Case -eq 'HostDrift' -and $script:lifecycle.HostReads -gt 1){'Other'}else{'Host'});DnsHostName='Host';DnsSuffix='example.test'}}
function Get-WelaWefQueryEngine {[pscustomobject]@{Path='fixture-engine';Sha256=('a'*64);Version='7.0';ModulePath='fixture-modules'}}
function Get-WelaWefQueryToken {[pscustomobject]@{Sid='S-1-5-21-1-2-3-1001';Name='Host\Reader';AuthenticationId='0x123';AuthenticationType='Fixture';ImpersonationLevel='None';TokenSource='Process';Groups=@([pscustomobject]@{Sid='S-1-5-32-545';Attributes=7});Privileges=@()}}
function Get-WelaWefQueryChannelState {param($Channels) $script:lifecycle.ChannelReads++;[pscustomobject]@{Name='System';State=$(if($script:lifecycle.Case -eq 'ChannelDrift' -and $script:lifecycle.ChannelReads -gt 1){'Disabled'}else{'Enabled'})}}
function Start-WelaWefQueryWorker {
param($Engine,$RequestPath,$RequestHash)
$request=ConvertFrom-WelaArrivalJson ([IO.File]::ReadAllText($RequestPath));$result=[pscustomobject]@{Opened=$true;Complete=$true;Capped=$false;CleanupConfirmed=$true;NativeError=$null;Diagnostic='';Channels=@([pscustomobject]@{Channel='System';Error=0});DiagnosticChannels=@();DiagnosticNativeError=$null;Events=@($script:lifecycle.Xml)}
if($script:lifecycle.Case -eq 'Empty'){$result.Events=@()}
if($script:lifecycle.Case -eq 'Partial'){$result.Complete=$false;$result.Capped=$true}
if($script:lifecycle.Case -eq 'MissingStatus'){$result.Channels=@()}
if($script:lifecycle.Case -eq 'DuplicateEvents'){$result.Events=@($script:lifecycle.Xml,$script:lifecycle.Xml)}
if($script:lifecycle.Case -eq 'FailedQuery'){$result.Opened=$false;$result.Complete=$false;$result.NativeError=5;$result.Channels=@();$result.Events=@()}
$receipt=[pscustomobject]@{SchemaVersion=1;Kind='WelaWefQueryWorker';Nonce=$request.Nonce;ProcessId=4242;Engine=$Engine;ModulePath=$Engine.ModulePath;StartedUtc='2026-01-01T00:00:00Z';CompletedUtc='2026-01-01T00:00:01Z';ReaderBefore=(Get-WelaWefQueryToken);ReaderAfter=(Get-WelaWefQueryToken);Host=$request.Host;Sources=$request.Sources;QuerySha256=$request.QuerySha256;Result=$result}
if($script:lifecycle.Case -eq 'TokenDrift'){$receipt.ReaderAfter.AuthenticationId='0x999'}
if($script:lifecycle.Case -eq 'ReceiptBoolean'){$receipt.Kind=$true}
if($script:lifecycle.Case -eq 'InputDrift'){[IO.File]::AppendAllText($script:lifecycle.Config,' ')}
if($script:lifecycle.Case -eq 'ArtifactDrift'){[IO.File]::AppendAllText((Join-Path (Split-Path $RequestPath -Parent) 'query.xml'),' ')}
[pscustomobject]@{Started=$true;ProcessId=4242;ExitCode=0;TimedOut=$false;TerminationConfirmed=($script:lifecycle.Case -ne 'Termination');Receipt=$receipt;Diagnostic=''}
}
$temp=Join-Path ([IO.Path]::GetTempPath()) ('wela-query-lifecycle-'+[guid]::NewGuid().ToString('N'));$null=New-Item -ItemType Directory $temp
try{
Copy-Item (Join-Path $script:ScriptRoot 'config/wef-examples/*') $temp
$script:lifecycle.Config=Join-Path $temp 'source.json';$originalConfig=[IO.File]::ReadAllText($script:lifecycle.Config)
$subscription=Join-Path $temp 'native-security.xml';$doc=Read-WelaWefXml ([IO.File]::ReadAllText($subscription));$doc.DocumentElement.SelectSingleNode('*[local-name()="Query"]').InnerText='<QueryList><Query Id="0" Path="System"><Select>*</Select></Query></QueryList>';[IO.File]::WriteAllText($subscription,$doc.OuterXml)
foreach($case in @('Match','Empty','Partial','FailedQuery','MissingStatus','DuplicateEvents','TokenDrift','ReceiptBoolean','InputDrift','ArtifactDrift','Termination','HostDrift','ChannelDrift')){
$script:lifecycle.Case=$case;$script:lifecycle.HostReads=0;$script:lifecycle.ChannelReads=0;[IO.File]::WriteAllText($script:lifecycle.Config,$originalConfig)
$report=Invoke-WelaWefQuery $script:lifecycle.Config 'WELA Native Security Example' (Join-Path $temp $case)
$expected=switch($case){Match{'MatchesObserved'};Empty{'ReadAllowedEmpty'};Partial{'Partial'};FailedQuery{'QueryFailed'};default{'Unverified'}}
Assert ($report.Status -ceq $expected) ("Public lifecycle $case expected $expected : "+$report.Diagnostic)
Assert ($report.ExitCode -eq $(if($case -in @('Match','Empty')){0}else{1}) -and $report.ReadyRuleCredit -eq 0 -and $report.ConfigurationChanges -eq 0) "Public lifecycle $case exit/credit boundaries."
Assert (Test-Path -LiteralPath (Join-Path (Join-Path $temp $case) 'manifest.json')) "Failure/complete manifest retained for $case."
}
}finally{Remove-Item -LiteralPath $temp -Recurse -Force}
Write-Host "WefQuery.Tests: $script:count focused assertions passed."
$global:LASTEXITCODE=0
+2
View File
@@ -7,6 +7,8 @@
**改善:**
- 読み取り専用の `wef-query` を追加しました。選択したソースのQueryListをそのままネイティブAPIで実行し、Select/Suppressの動作、チャネル別の失敗診断、上限付きの一致イベントXML、実際の操作者・ホスト・ソースの整合性を確認します。空の結果、アクセス拒否、未存在、不正クエリ、上限到達、状態変化を区別し、破棄可能なWindows環境で実イベントの選択・抑制と標準ユーザーの拒否、完全な後片付けを検証します。転送サービスのアクセス権、配送、Sigmaの準備完了は推定しません。 (Related #368) (@Shirofune-Security)
- 明示的な `registry-sacl-recovery` を追加しました。整合する4つの元記録、レビュー済み計画のハッシュ、過去・現在ともに空の子キー観測、監査縮小と継承への個別同意を必須とし、追加が証明されたレジストリルートの明示的な監査ACEを1つだけ削除します。SACLのみのネイティブ書き込みで他の記述子フィールドとACEの順序を保持し、部分的な書き込みの証跡と元の記述子バイトとの一致を別々に報告します。過去のキー・操作者の同一性認証、ツリー全体の原子性、イベント生成、Sigmaの準備完了は保証しません。 (Related #373) (@Shirofune-Security)
- Server 2022/2025とPowerShell 5.1/7でSMBポリシー設定の公開CLIを検証します。対応ホストで6項目の適用・再読取・再実行、非対応ホストのスキップ、元の型付き記録、無関係な設定の維持と完全な復元を確認します。イベント生成と実行時の有効化は別途検証します。(関連 #377) (@Shirofune-Security)
+2
View File
@@ -7,6 +7,8 @@
**Improvements:**
- Added read-only `wef-query` preflight for one exact selected source QueryList, with strict native Select/Suppress execution, separate per-channel failure diagnostics, bounded matching XML and actual caller/host/source guards. Empty, denied, missing, invalid, capped and drifted results remain distinct; disposable native tests cover real record selection/suppression and standard-user denial with exact cleanup. No forwarding-service access, delivery or Sigma credit is inferred. (Related #368) (@Shirofune-Security)
- Added opt-in `registry-sacl-recovery` for one proven explicit registry-root audit ACE, requiring four matching original records, a reviewed plan hash, empty historical/current descendants and separate audit-reduction/inheritance consent. Native SACL-only removal preserves unrelated descriptor fields and ACE order, retains partial-write evidence and reports original-byte equality separately; no authenticated historical key/operator identity, atomic-tree, event or Sigma claim. (Related #373) (@Shirofune-Security)
- Add native public SMB policy configuration acceptance on Server 2022/2025 and PowerShell 5.1/7: six-policy apply/readback and idempotence on supported hosts, unsupported-host skips, typed original journals, unrelated-state preservation and exact cleanup. Event generation and runtime activation remain separate. (Related #377) (@Shirofune-Security)