mirror of
https://github.com/Yamato-Security/WELA.git
synced 2026-10-14 02:05:25 +02:00
Reject LDAP options before profile command dispatch
This commit is contained in:
1 parent
9e2b4b5b43
commit
c7cfb0d112
7 files changed
+55
-11
No files matched your search
@@ -4,7 +4,7 @@
|
||||
|
||||
**改善:**
|
||||
|
||||
- 通常の設定でDCのField Engineeringを自動的にレベル5へ変更せず、既存のLDAP 1644診断設定を保持するようにしました。明示的な`ldap-diagnostics`の監査・計画・設定を追加し、保持、しきい値を指定した診断、MDIの旧設定削除を選択できます。役割・ビルド確認、型付き復旧記録、競合検出、順序付きの読み戻しと最終状態確認に対応します。イベント生成・量・転送は隔離DCでの検証が必要です。 (#383) (@Shirofune-Security)
|
||||
- 通常の設定でDCのField Engineeringを自動的にレベル5へ変更せず、既存のLDAP 1644診断設定を保持するようにしました。明示的な`ldap-diagnostics`の監査・計画・設定を追加し、保持、しきい値を指定した診断、MDIの旧設定削除を選択できます。役割・ビルド確認、型付き復旧記録、競合検出、順序付きの読み戻しと最終状態確認に対応します。LDAP専用オプションを他のプロファイルコマンドへ指定すると、実行前に拒否します。イベント生成・量・転送は隔離DCでの検証が必要です。 (#383) (@Shirofune-Security)
|
||||
|
||||
- MDIのドメイン/Exchange Configuration監査と、明示的に選択した証明書テンプレート/登録サービスオブジェクト向けに、任意実行の`ad-object-sacl`監査・計画・設定・保守的なロールバックを追加しました。接続先DCとスキーマGUIDを検証し、既存のセキュリティ設定を保持したまま不足する監査ACEだけをSACLに追加します。変更前のSDDLと追加ACEを保存し、書き込み後と最終状態を確認します。任意のdMSA前提条件が不明な場合は未確認のスキップ項目として報告し、独立した他の5種類のドメインクラスの監査ACEは引き続き設定します。実効監査ポリシー、継承・レプリケーション、4662/5136イベントの証拠は隔離DCで別途検証が必要です。Sigma検知範囲の向上は未検証です。 (#402) (@Shirofune-Security)
|
||||
- Microsoft WEF Appendix Cのチャネルを監査・計画・設定する任意実行の`channel-settings`を追加しました。CAPI2の有効化、原典の正確なバイト数、明示的に指定したEvent Log Readersの読み取りACEに対応します。既存のセキュリティ記述子・ACEと大きいバッファを保持し、安全に扱えないACLは変更しません。共通の復旧記録、書き込み直前の状態確認と読み戻しで失敗を報告します。Appendix E/Fの標準チャネル一覧からSysmonとEMETを除外し、実際のIDによるアクセス・イベント生成・収集は未検証と表示します。Windowsラボでの検証は別途必要です。 (#401) (@Shirofune-Security)
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
|
||||
**Improvements:**
|
||||
|
||||
- Preserved LDAP 1644 diagnostics during normal configuration instead of automatically enabling Field Engineering level 5 on DCs. Added explicit `ldap-diagnostics` audit/plan/configure modes for preservation, tunable diagnostics and MDI legacy cleanup, with role/build checks, typed recovery snapshots, race guards, ordered readback and final drift checks. Generated events, volume and forwarding remain isolated-DC validation. (#383) (@Shirofune-Security)
|
||||
- Preserved LDAP 1644 diagnostics during normal configuration instead of automatically enabling Field Engineering level 5 on DCs. Added explicit `ldap-diagnostics` audit/plan/configure modes for preservation, tunable diagnostics and MDI legacy cleanup, with role/build checks, typed recovery snapshots, race guards, ordered readback and final drift checks. LDAP-only options are rejected before unrelated profile commands can run. Generated events, volume and forwarding remain isolated-DC validation. (#383) (@Shirofune-Security)
|
||||
|
||||
- Added opt-in `ad-object-sacl` audit, plan, configure and conservative rollback actions for MDI domain/Exchange Configuration auditing and explicitly selected certificate template/enrollment service objects. Exact DC binding, schema GUID checks, additive SACL-only changes, pre-write SDDL/ACE receipts and read-back preserve existing security entries. Unknown optional dMSA prerequisites are reported as a separate skipped gap while the five independent domain class ACEs continue. Effective audit policy, inheritance/replication and 4662/5136 event evidence remain separate isolated-DC checks; no Sigma uplift is claimed. (#402) (@Shirofune-Security)
|
||||
- Added opt-in `channel-settings` audit, plan and configure actions for Microsoft WEF Appendix C, including CAPI2 enablement, exact source byte sizes and an explicitly requested Event Log Readers read ACE. Existing descriptor components/ACEs and larger buffers are preserved or unsafe ACL edits are refused; shared journaling, fresh-state guards and readback report failures. Native Appendix E/F channel inventories exclude Sysmon/EMET and retain unverified identity access, generation and ingestion prerequisites. Windows lab evidence remains pending. (#401) (@Shirofune-Security)
|
||||
|
||||
@@ -1794,15 +1794,15 @@ if (($PSBoundParameters.ContainsKey('ChannelAction') -or $PSBoundParameters.Cont
|
||||
throw 'Channel options require channel-settings. No command was run.'
|
||||
}
|
||||
|
||||
if ($Cmd -ne 'ldap-diagnostics' -and @($PSBoundParameters.Keys | Where-Object { $_ -in @('LdapAction','LdapMode','LdapSearchTimeMs','LdapExpensiveThreshold','LdapInefficientThreshold') }).Count) {
|
||||
throw 'LDAP options require the dedicated ldap-diagnostics command. No command was run.'
|
||||
}
|
||||
|
||||
if ($Profile -and $Cmd.ToLower() -in @('plan', 'audit', 'audit-settings', 'configure') -and -not $Help) {
|
||||
Invoke-WelaProfileCommand -Command $Cmd.ToLower()
|
||||
return
|
||||
}
|
||||
|
||||
if ($Cmd -ne 'ldap-diagnostics' -and @($PSBoundParameters.Keys | Where-Object { $_ -in @('LdapAction','LdapMode','LdapSearchTimeMs','LdapExpensiveThreshold','LdapInefficientThreshold') }).Count) {
|
||||
throw 'LDAP options require the dedicated ldap-diagnostics command. No command was run.'
|
||||
}
|
||||
|
||||
switch ($Cmd.ToLower()) {
|
||||
'ldap-diagnostics' {
|
||||
if ($Help) { Write-Host 'Usage: ./WELA.ps1 ldap-diagnostics [-LdapAction Audit|Plan|Configure] [-LdapMode Preserve|Diagnostic|MdiCleanup] [-LdapSearchTimeMs positive-ms] [-LdapExpensiveThreshold positive-count] [-LdapInefficientThreshold positive-count] [-Auto] [-DryRun] [-BackupPath new-directory] [-ResultsPath report.json]. See docs/ldap-diagnostics.md.'; return }
|
||||
|
||||
@@ -4,6 +4,8 @@ Normal `configure` preserves existing LDAP diagnostics and explains that 1644 is
|
||||
|
||||
The dedicated local workflow supports Server 2022/2025 DC builds 20348/26100 in 64-bit Windows PowerShell 5.1 or PowerShell 7. Client, member server and member-server CA hosts are not applicable. Unknown or conflicting role/build evidence blocks writes; no NTDS settings are created on a non-DC.
|
||||
|
||||
LDAP options require the dedicated `ldap-diagnostics` command. Supplying them to another command, including `configure -Profile`, stops before that command runs.
|
||||
|
||||
```powershell
|
||||
./WELA.ps1 ldap-diagnostics -LdapAction Audit -ResultsPath ldap-before.json
|
||||
./WELA.ps1 ldap-diagnostics -LdapAction Plan -LdapMode Diagnostic -LdapSearchTimeMs 100
|
||||
|
||||
@@ -11,7 +11,7 @@ function Reject([scriptblock]$Action,[string]$Pattern) {
|
||||
function Reset-Fixture {
|
||||
$script:values=@{}; $script:writes=@(); $script:role='Applicable'; $script:readError=$false
|
||||
$script:writeError=$false; $script:ignoreWrite=$false; $script:race=$false; $script:reads=0
|
||||
$script:types=@{}; $script:journal=$null
|
||||
$script:types=@{}; $script:journal=$null; $script:failName=$null
|
||||
}
|
||||
function Get-WelaLdapHost { [pscustomobject]@{Status=$script:role;Diagnostic='fixture';ComputerName='dc1';Build=26100} }
|
||||
function Get-WelaRegistryState {
|
||||
@@ -25,14 +25,14 @@ function New-WelaRegistryKey { param($Path) }
|
||||
function Set-ItemProperty {
|
||||
param($LiteralPath,$Name,$Value,$Type,$ErrorAction)
|
||||
Assert ($script:journal -and (Test-Path $script:journal)) 'Every native write must follow the complete pre-change journal.'
|
||||
if ($script:writeError) { throw 'write denied' }
|
||||
if ($script:writeError -or $Name -eq $script:failName) { throw 'write denied' }
|
||||
$script:writes += $Name
|
||||
if (-not $script:ignoreWrite) { $script:values[$Name]=$Value; $script:types[$Name]=$Type }
|
||||
}
|
||||
function Remove-ItemProperty {
|
||||
param($LiteralPath,$Name,$ErrorAction)
|
||||
Assert ($script:journal -and (Test-Path $script:journal)) 'Every removal must follow a recovery journal.'
|
||||
if ($script:writeError) { throw 'remove denied' }
|
||||
if ($script:writeError -or $Name -eq $script:failName) { throw 'remove denied' }
|
||||
$script:writes += $Name
|
||||
if (-not $script:ignoreWrite) { $script:values.Remove($Name); $script:types.Remove($Name) }
|
||||
}
|
||||
@@ -95,6 +95,31 @@ try {
|
||||
default { Assert ($result.ExitCode -eq 1 -and $script:writes.Count -eq 0) "Scenario $scenario must block before native writes." }
|
||||
}
|
||||
}
|
||||
# Exercise actual partial mutation boundaries: recovery is journal-based and
|
||||
# does not automatically overwrite the successfully changed subset.
|
||||
foreach ($mode in @('Diagnostic','MdiCleanup')) {
|
||||
Reset-Fixture
|
||||
$thresholds=@{SearchTime=100;Expensive=10000;Inefficient=1000}
|
||||
if ($mode -eq 'MdiCleanup') {
|
||||
$thresholds=@{}
|
||||
foreach ($definition in Get-WelaLdapDefinitions) { $script:values[$definition.Name]=1; $script:types[$definition.Name]='DWord' }
|
||||
$script:values['15 Field Engineering']=5
|
||||
$script:failName='Search Time Threshold (msecs)'
|
||||
} else { $script:failName='15 Field Engineering' }
|
||||
$script:values['Unrelated diagnostic']=7; $script:types['Unrelated diagnostic']='DWord'
|
||||
$plan=Get-WelaLdapPlan (Get-WelaLdapSnapshot) $mode $thresholds
|
||||
$context=New-FixtureContext
|
||||
Set-WelaLdapDiagnostics $context $plan
|
||||
$result=Complete-WelaConfiguration $context
|
||||
$journal=Get-Content $script:journal -Raw | ConvertFrom-Json
|
||||
Assert ($result.ExitCode -eq 1 -and $journal.Before.Values.Count -eq 4) 'A failure after earlier writes retains the complete recovery snapshot.'
|
||||
Assert ($script:values['Unrelated diagnostic'] -eq 7) 'Partial failures preserve unrelated registry values.'
|
||||
if ($mode -eq 'Diagnostic') {
|
||||
Assert ($script:writes.Count -eq 3 -and -not $script:values.ContainsKey('15 Field Engineering')) 'Failed verbosity write leaves verified thresholds and does not claim success.'
|
||||
} else {
|
||||
Assert ($script:writes.Count -eq 1 -and -not $script:values.ContainsKey('15 Field Engineering') -and $script:values['Search Time Threshold (msecs)'] -eq 1 -and $script:values['Expensive Search Results Threshold'] -eq 1 -and $script:values['Inefficient Search Results Threshold'] -eq 1) 'Cleanup stops after the first failed threshold removal without restoring verbosity or removing later values.'
|
||||
}
|
||||
}
|
||||
Reset-Fixture; $script:role='NotApplicable'
|
||||
$report=Invoke-WelaLdapCommand -Action Audit
|
||||
Assert ($report.Snapshot.Values.Count -eq 0 -and $script:reads -eq 0) 'Member/client/non-DC CA never queries or creates NTDS settings.'
|
||||
@@ -104,6 +129,23 @@ try {
|
||||
|
||||
# Execute the real general configure body with all native boundaries replaced.
|
||||
$ast=[Management.Automation.Language.Parser]::ParseFile((Join-Path $script:ScriptRoot 'WELA.ps1'),[ref]$null,[ref]$null)
|
||||
# Preserve the real ordering of the LDAP guard and early profile dispatch, while
|
||||
# replacing the profile handler so configure can never change this test host.
|
||||
$dispatchNodes=@($ast.EndBlock.Statements | Where-Object {
|
||||
$_ -is [Management.Automation.Language.IfStatementAst] -and
|
||||
($_.Extent.Text -match 'LDAP options require' -or $_.Extent.Text -match 'Invoke-WelaProfileCommand -Command')
|
||||
})
|
||||
Assert ($dispatchNodes.Count -eq 2) 'Exercise both real CLI boundaries in source order.'
|
||||
$dispatch=[scriptblock]::Create('param($Cmd,$Profile,$LdapAction,$LdapMode,$LdapSearchTimeMs,$LdapExpensiveThreshold,$LdapInefficientThreshold)' + [Environment]::NewLine + (($dispatchNodes | ForEach-Object {$_.Extent.Text}) -join [Environment]::NewLine))
|
||||
function Invoke-WelaProfileCommand { param($Command) $script:profileDispatched=$true }
|
||||
foreach ($command in @('plan','audit','audit-settings','configure')) {
|
||||
foreach ($option in @('LdapAction','LdapMode','LdapSearchTimeMs','LdapExpensiveThreshold','LdapInefficientThreshold')) {
|
||||
$script:profileDispatched=$false
|
||||
$arguments=@{Cmd=$command;Profile='fixture'}; $arguments[$option]='fixture'
|
||||
Reject { & $dispatch @arguments } 'LDAP options require'
|
||||
Assert (-not $script:profileDispatched) "LDAP option $option must block $command before unrelated profile dispatch."
|
||||
}
|
||||
}
|
||||
$node=$ast.Find({param($n) $n -is [Management.Automation.Language.FunctionDefinitionAst] -and $n.Name -eq 'ConfigureAuditSettings'},$false)
|
||||
. ([scriptblock]::Create($node.Extent.Text))
|
||||
function TestWindows {$true}; function TestAdministrator {$true}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
**改善:**
|
||||
|
||||
- 通常の設定でDCのField Engineeringを自動的にレベル5へ変更せず、既存のLDAP 1644診断設定を保持するようにしました。明示的な`ldap-diagnostics`の監査・計画・設定を追加し、保持、しきい値を指定した診断、MDIの旧設定削除を選択できます。役割・ビルド確認、型付き復旧記録、競合検出、順序付きの読み戻しと最終状態確認に対応します。イベント生成・量・転送は隔離DCでの検証が必要です。 (#383) (@Shirofune-Security)
|
||||
- 通常の設定でDCのField Engineeringを自動的にレベル5へ変更せず、既存のLDAP 1644診断設定を保持するようにしました。明示的な`ldap-diagnostics`の監査・計画・設定を追加し、保持、しきい値を指定した診断、MDIの旧設定削除を選択できます。役割・ビルド確認、型付き復旧記録、競合検出、順序付きの読み戻しと最終状態確認に対応します。LDAP専用オプションを他のプロファイルコマンドへ指定すると、実行前に拒否します。イベント生成・量・転送は隔離DCでの検証が必要です。 (#383) (@Shirofune-Security)
|
||||
|
||||
- MDIのドメイン/Exchange Configuration監査と、明示的に選択した証明書テンプレート/登録サービスオブジェクト向けに、任意実行の`ad-object-sacl`監査・計画・設定・保守的なロールバックを追加しました。接続先DCとスキーマGUIDを検証し、既存のセキュリティ設定を保持したまま不足する監査ACEだけをSACLに追加します。変更前のSDDLと追加ACEを保存し、書き込み後と最終状態を確認します。任意のdMSA前提条件が不明な場合は未確認のスキップ項目として報告し、独立した他の5種類のドメインクラスの監査ACEは引き続き設定します。実効監査ポリシー、継承・レプリケーション、4662/5136イベントの証拠は隔離DCで別途検証が必要です。Sigma検知範囲の向上は未検証です。 (#402) (@Shirofune-Security)
|
||||
- Microsoft WEF Appendix Cのチャネルを監査・計画・設定する任意実行の`channel-settings`を追加しました。CAPI2の有効化、原典の正確なバイト数、明示的に指定したEvent Log Readersの読み取りACEに対応します。既存のセキュリティ記述子・ACEと大きいバッファを保持し、安全に扱えないACLは変更しません。共通の復旧記録、書き込み直前の状態確認と読み戻しで失敗を報告します。Appendix E/Fの標準チャネル一覧からSysmonとEMETを除外し、実際のIDによるアクセス・イベント生成・収集は未検証と表示します。Windowsラボでの検証は別途必要です。 (#401) (@Shirofune-Security)
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
**Improvements:**
|
||||
|
||||
- Preserved LDAP 1644 diagnostics during normal configuration instead of automatically enabling Field Engineering level 5 on DCs. Added explicit `ldap-diagnostics` audit/plan/configure modes for preservation, tunable diagnostics and MDI legacy cleanup, with role/build checks, typed recovery snapshots, race guards, ordered readback and final drift checks. Generated events, volume and forwarding remain isolated-DC validation. (#383) (@Shirofune-Security)
|
||||
- Preserved LDAP 1644 diagnostics during normal configuration instead of automatically enabling Field Engineering level 5 on DCs. Added explicit `ldap-diagnostics` audit/plan/configure modes for preservation, tunable diagnostics and MDI legacy cleanup, with role/build checks, typed recovery snapshots, race guards, ordered readback and final drift checks. LDAP-only options are rejected before unrelated profile commands can run. Generated events, volume and forwarding remain isolated-DC validation. (#383) (@Shirofune-Security)
|
||||
|
||||
- Added opt-in `ad-object-sacl` audit, plan, configure and conservative rollback actions for MDI domain/Exchange Configuration auditing and explicitly selected certificate template/enrollment service objects. Exact DC binding, schema GUID checks, additive SACL-only changes, pre-write SDDL/ACE receipts and read-back preserve existing security entries. Unknown optional dMSA prerequisites are reported as a separate skipped gap while the five independent domain class ACEs continue. Effective audit policy, inheritance/replication and 4662/5136 event evidence remain separate isolated-DC checks; no Sigma uplift is claimed. (#402) (@Shirofune-Security)
|
||||
- Added opt-in `channel-settings` audit, plan and configure actions for Microsoft WEF Appendix C, including CAPI2 enablement, exact source byte sizes and an explicitly requested Event Log Readers read ACE. Existing descriptor components/ACEs and larger buffers are preserved or unsafe ACL edits are refused; shared journaling, fresh-state guards and readback report failures. Native Appendix E/F channel inventories exclude Sysmon/EMET and retain unverified identity access, generation and ingestion prerequisites. Windows lab evidence remains pending. (#401) (@Shirofune-Security)
|
||||
|
||||
Reference in new issue
Block a user