mirror of
https://github.com/Yamato-Security/WELA.git
synced 2026-10-08 15:25:24 +02:00
Report configuration-only audit states without rule coverage inference
This commit is contained in:
1 parent
571f9ff51f
commit
bf69494bd9
5 files changed
+98
-1
No files matched your search
@@ -17,3 +17,9 @@ jobs:
|
||||
- name: Test domain NTLM policy in PowerShell 7
|
||||
shell: pwsh
|
||||
run: ./tests/DomainNtlm.Tests.ps1
|
||||
- name: Test domain NTLM audit output in Windows PowerShell 5.1
|
||||
shell: powershell
|
||||
run: ./tests/DomainNtlmAuditOutput.Tests.ps1
|
||||
- name: Test domain NTLM audit output in PowerShell 7
|
||||
shell: pwsh
|
||||
run: ./tests/DomainNtlmAuditOutput.Tests.ps1
|
||||
@@ -485,7 +485,14 @@ function AuditLogSetting {
|
||||
$disabledCount = ($_.Group | Where-Object { $notEnabled -contains $_.CurrentSetting } | ForEach-Object { $_.Rules.Count } | Measure-Object -Sum).Sum
|
||||
$out = ""
|
||||
$color = ""
|
||||
if (@($_.Group | Where-Object { $_.CurrentSetting -ne "Unknown" }).Count -eq 0) {
|
||||
if (@($_.Group | Where-Object { $_.Rules.Count -gt 0 }).Count -eq 0) {
|
||||
# Configuration-only rows have no rule coverage to aggregate.
|
||||
# Preserve their observed state, including applicability and errors.
|
||||
$out = ($_.Group | Select-Object -ExpandProperty CurrentSetting -Unique) -join '; '
|
||||
if (-not $out) { $out = 'Unknown' }
|
||||
$color = 'DarkYellow'
|
||||
}
|
||||
elseif (@($_.Group | Where-Object { $_.CurrentSetting -ne "Unknown" }).Count -eq 0) {
|
||||
# 設定を確認できないカテゴリ。無効と断定はできない
|
||||
$out = "Unknown"
|
||||
$color = "DarkYellow"
|
||||
|
||||
@@ -102,6 +102,17 @@ Assert-Equal $script:writes 0 'Declining preserves policy'
|
||||
$script:response = ''
|
||||
Set-WelaDomainNtlmAudit
|
||||
Assert-Equal $script:value 7 'Confirming applies policy'
|
||||
foreach ($confirmation in @('y', 'Y')) {
|
||||
Reset-Policy 2
|
||||
$script:response = $confirmation
|
||||
Set-WelaDomainNtlmAudit
|
||||
Assert-Equal $script:value 7 "Confirmation '$confirmation' applies policy"
|
||||
Assert-Equal $script:writes 1 "Confirmation '$confirmation' writes once"
|
||||
}
|
||||
Reset-Policy 2
|
||||
$script:response = 'N'
|
||||
Set-WelaDomainNtlmAudit
|
||||
Assert-Equal $script:writes 0 'Uppercase refusal preserves policy'
|
||||
Reset-Policy 2
|
||||
$script:writeFails = $true
|
||||
Assert-Throws { Set-WelaDomainNtlmAudit -Auto } 'Write failure propagates'
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
# Exercise the real audit renderer/CSV exports with injected observations and rules.
|
||||
# Only a temporary directory is written; no Windows policy is read or changed.
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$tokens = $null; $parseErrors = $null
|
||||
$ast = [System.Management.Automation.Language.Parser]::ParseFile((Join-Path $PSScriptRoot '../WELA.ps1'), [ref]$tokens, [ref]$parseErrors)
|
||||
if ($parseErrors.Count) { throw ($parseErrors | Out-String) }
|
||||
$class = $ast.Find({ param($node) $node -is [System.Management.Automation.Language.TypeDefinitionAst] -and $node.Name -eq 'WELA' }, $true)
|
||||
. ([scriptblock]::Create($class.Extent.Text))
|
||||
$definition = $ast.Find({ param($node) $node -is [System.Management.Automation.Language.FunctionDefinitionAst] -and $node.Name -eq 'AuditLogSetting' }, $true)
|
||||
. ([scriptblock]::Create($definition.Extent.Text))
|
||||
|
||||
$script:assertions = 0
|
||||
function Assert-Equal($Actual, $Expected, [string]$Message) {
|
||||
if ($Actual -cne $Expected) { throw "$Message. Expected '$Expected', got '$Actual'." }
|
||||
$script:assertions++
|
||||
}
|
||||
function TestAdministrator { return $true }
|
||||
function CollectAuditpol { param([switch]$UseCached) return $true }
|
||||
function GetAuditpol { return @{} }
|
||||
function Get-WelaDomainNtlmState { return [pscustomobject]@{ Description = $script:description } }
|
||||
function Export-MitreHeatmap { param($sigmaRules, $OutputPath, $UseIdealCount) }
|
||||
function BuildAuditResult {
|
||||
param($all_rules, $Baseline, $enabledguid)
|
||||
$all_rules[0].applicable = $true
|
||||
@(
|
||||
[WELA]::new('Fixture rules', 'Available', 'Success', @($all_rules[0]))
|
||||
[WELA]::new('Fixture rules', 'Unavailable', 'No Auditing', @($all_rules[1]))
|
||||
)
|
||||
}
|
||||
|
||||
$script:ScriptRoot = Join-Path ([IO.Path]::GetTempPath()) ('wela-domain-output-' + [guid]::NewGuid().ToString('N'))
|
||||
$null = New-Item -ItemType Directory -Path $script:ScriptRoot
|
||||
$script:SecurityRulesPath = Join-Path $script:ScriptRoot 'rules.json'
|
||||
try {
|
||||
@(
|
||||
@{ id = 'available-rule'; title = 'Available fixture'; level = 'high'; subcategory_guids = @() }
|
||||
@{ id = 'unavailable-rule'; title = 'Unavailable fixture'; level = 'medium'; subcategory_guids = @() }
|
||||
) | ConvertTo-Json -Depth 4 | Set-Content -LiteralPath $script:SecurityRulesPath -Encoding UTF8
|
||||
foreach ($observed in @(
|
||||
'Enable all (7)',
|
||||
'Disabled (0)',
|
||||
'Not configured',
|
||||
'Value 2 (not interpreted as Enable all)',
|
||||
'Not applicable (Windows client)',
|
||||
'Not applicable (member or standalone server, including non-DC AD CS)',
|
||||
'Unknown (computer role could not be determined)',
|
||||
'Unknown (domain NTLM registry read failed: Access denied)'
|
||||
)) {
|
||||
$script:description = $observed
|
||||
$output = (AuditLogSetting -outType std -Baseline YamatoSecurity 6>&1 | Out-String)
|
||||
$expectedHeading = 'NTLM Authentication: ' + $observed
|
||||
Assert-Equal ($output -match ('(?m)^' + [regex]::Escape($expectedHeading) + '\r?$')) $true "Console heading retains '$observed'"
|
||||
Assert-Equal ($output -match 'NTLM Authentication: Partially Enabled') $false 'An empty rule array does not imply partial enablement'
|
||||
Assert-Equal ($output -match 'Fixture rules: Partially Enabled') $true 'Ordinary rule coverage aggregation is preserved'
|
||||
$row = @(Import-Csv -LiteralPath (Join-Path $script:ScriptRoot 'WELA-Audit-Result.csv') | Where-Object SubCategory -eq 'Domain NTLM auditing')
|
||||
Assert-Equal $row.Count 1 'CSV contains one domain NTLM setting row'
|
||||
Assert-Equal $row[0].CurrentSetting $observed 'CSV retains the observed configuration state'
|
||||
Assert-Equal $row[0].RuleCount '0' 'Configuration row claims no detection rules'
|
||||
Assert-Equal @(Import-Csv -LiteralPath (Join-Path $script:ScriptRoot 'UsableRules.csv')).Count 1 'Configuration row does not change usable rule counts'
|
||||
Assert-Equal @(Import-Csv -LiteralPath (Join-Path $script:ScriptRoot 'UnusableRules.csv')).Count 1 'Configuration row does not change unusable rule counts'
|
||||
}
|
||||
Write-Host "PASS: $script:assertions domain NTLM output assertions (mocked observations; temporary CSV files only)."
|
||||
} finally {
|
||||
Remove-Item -LiteralPath $script:ScriptRoot -Recurse -Force
|
||||
}
|
||||
@@ -55,6 +55,14 @@ an isolated DC before deployment. `tests/DomainNtlm.Tests.ps1` uses mocked OS an
|
||||
registry access; the associated Windows workflow runs Windows PowerShell 5.1 and
|
||||
PowerShell 7 without changing host policy.
|
||||
|
||||
Live-DC validation for [issue #363](https://github.com/Yamato-Security/WELA/issues/363)
|
||||
remains pending. Before closing that issue, record the Windows build and confirmed
|
||||
DC role, the previous registry value/type, the verified `AuditNTLMInDomain=7`
|
||||
DWORD, and representative NTLM event XML from benign test authentication. Also
|
||||
check that a second run is idempotent and that clients, member servers and non-DC CAs leave
|
||||
this domain-only setting unchanged. Mocked policy tests and console/CSV regression
|
||||
tests do not provide this event-generation evidence.
|
||||
|
||||
#### `configure` command examples
|
||||
Apply Yamato Security's recommended settings (with confirmation prompt before changing settings):
|
||||
```
|
||||
|
||||
Reference in new issue
Block a user