From 31aeeda768b76c12263b2e0df251af9167f144de Mon Sep 17 00:00:00 2001 From: Shirofune-Security <43838376+Shirofune-Security@users.noreply.github.com> Date: Thu, 17 Sep 2026 22:03:24 +0900 Subject: [PATCH] configure-sacl: cover per-user objects across all profiles + Default Enumerate every user profile from ProfileList (plus C:\Users\Default so future users inherit the SACL) and apply per-user SACLs: - user_files: file SACL under each profile dir (Startup folder, Signal AppData). - user_registry: registry SACL on each user hive - loaded hives via HKEY_USERS\ directly, offline/Default hives by reg-load/unload of NTUSER.DAT (HKCU Run/RunOnce, User Shell Folders, StartupApproved, Load/Run, Command Processor AutoRun, Control Panel\Desktop screensaver, Environment logon script, LangBarAddin, Outlook Addins). Handles are released ([gc]) before reg unload; objects/hives absent on the host are skipped. Not covered: folder-redirected AppData on network shares, mandatory profiles. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01MVUmXZBkr5FnZ2hwFkDhx7 --- WELA.ps1 | 100 ++++++++++++++++++++++++++++++++- config/audit_sacl_targets.json | 19 ++++++- 2 files changed, 117 insertions(+), 2 deletions(-) diff --git a/WELA.ps1 b/WELA.ps1 index 2abb4c85..82d1634b 100644 --- a/WELA.ps1 +++ b/WELA.ps1 @@ -1388,8 +1388,106 @@ function Set-AuditSacl { } catch { Write-Host "[ERROR] $($t.path) : $_" -ForegroundColor Red } } Write-Host "" + + # 4) Per-user objects: enumerate every profile (+ Default, for future users) and apply SACLs. + $hasUserTargets = ($targets.PSObject.Properties.Name -contains 'user_files' -and $targets.user_files) -or ` + ($targets.PSObject.Properties.Name -contains 'user_registry' -and $targets.user_registry) + if ($hasUserTargets) { + Write-Host "Enumerating user profiles for per-user SACLs..." + $profiles = Get-WelaUserProfiles + Write-Host "Found $($profiles.Count) profile(s) (incl. Default template)." + Write-Host "" + + # 4a) Per-user FILE SACLs (each existing profile + Default) + if ($targets.user_files) { + foreach ($prof in $profiles) { + foreach ($t in $targets.user_files) { + $path = Join-Path $prof.Path $t.relpath + try { + if (-not (Test-Path -LiteralPath $path)) { continue } # not installed for this user + $isDir = (Get-Item -LiteralPath $path -Force).PSIsContainer + $rights = [System.Security.AccessControl.FileSystemRights]($t.rights -join ",") + $inh = if ($isDir -and $t.inherit) { [System.Security.AccessControl.InheritanceFlags]"ContainerInherit,ObjectInherit" } else { [System.Security.AccessControl.InheritanceFlags]"None" } + $acl = Get-Acl -LiteralPath $path -Audit + $already = $acl.Audit | Where-Object { $_.IdentityReference.Value -eq $everyone.Value -and (($_.FileSystemRights -band $rights) -eq $rights) -and ($_.AuditFlags -eq $auditFlags) } + if ($already) { continue } + if ($Auto -or $PSCmdlet.ShouldProcess("$path [$($prof.Sid)]", "add audit SACL")) { + $rule = New-Object System.Security.AccessControl.FileSystemAuditRule($everyone, $rights, $inh, "None", $auditFlags) + $acl.AddAuditRule($rule); Set-Acl -LiteralPath $path -AclObject $acl + Write-Host "[OK] $path ($($t.note))" -ForegroundColor Green + } + } catch { Write-Host "[ERROR] $path : $_" -ForegroundColor Red } + } + } + } + + # 4b) Per-user REGISTRY SACLs. Loaded hives -> HKEY_USERS\ directly; + # offline / Default hives -> reg load NTUSER.DAT, apply, reg unload. + if ($targets.user_registry) { + foreach ($prof in $profiles) { + $loadedHere = $false + if ($prof.Loaded) { + $base = "Microsoft.PowerShell.Core\Registry::HKEY_USERS\$($prof.Sid)" + } else { + $hive = Join-Path $prof.Path "NTUSER.DAT" + if (-not (Test-Path -LiteralPath $hive)) { continue } + $mount = "WELA_$($prof.Sid)" + $out = reg load "HKU\$mount" "$hive" 2>&1 + if ($LASTEXITCODE -ne 0) { Write-Host "[SKIPPED] hive $($prof.Sid) : cannot load ($out)" -ForegroundColor DarkYellow; continue } + $loadedHere = $true + $base = "Microsoft.PowerShell.Core\Registry::HKEY_USERS\$mount" + } + try { + foreach ($t in $targets.user_registry) { + $key = "$base\$($t.key)" + try { + if (-not (Test-Path -LiteralPath $key)) { continue } + $rights = [System.Security.AccessControl.RegistryRights]($t.rights -join ",") + $inh = if ($t.inherit) { [System.Security.AccessControl.InheritanceFlags]"ContainerInherit" } else { [System.Security.AccessControl.InheritanceFlags]"None" } + $acl = Get-Acl -LiteralPath $key -Audit + $already = $acl.Audit | Where-Object { $_.IdentityReference.Value -eq $everyone.Value -and (($_.RegistryRights -band $rights) -eq $rights) -and ($_.AuditFlags -eq $auditFlags) } + if ($already) { continue } + if ($Auto -or $PSCmdlet.ShouldProcess("$($t.key) [$($prof.Sid)]", "add audit SACL")) { + $rule = New-Object System.Security.AccessControl.RegistryAuditRule($everyone, $rights, $inh, "None", $auditFlags) + $acl.AddAuditRule($rule); Set-Acl -LiteralPath $key -AclObject $acl + Write-Host "[OK] HKU\$($prof.Sid)\$($t.key) ($($t.note))" -ForegroundColor Green + } + } catch { Write-Host "[ERROR] $($t.key) [$($prof.Sid)] : $_" -ForegroundColor Red } + } + } + finally { + if ($loadedHere) { + # release handles before unloading, or 'reg unload' fails + [gc]::Collect(); [gc]::WaitForPendingFinalizers() + reg unload "HKU\$mount" 2>&1 | Out-Null + } + } + } + } + Write-Host "" + } + Write-Host "Done. Targeted object-access auditing is enabled without global file/registry auditing." -ForegroundColor Cyan - Write-Host "Note: per-user (HKCU / profile AppData) objects are out of scope for a machine-wide SACL policy." -ForegroundColor DarkCyan + Write-Host "Per-user objects were applied to existing profiles and the Default profile (future users)." -ForegroundColor DarkCyan + Write-Host "Not covered: folder-redirected AppData on network shares, and mandatory profiles." -ForegroundColor DarkCyan +} + +function Get-WelaUserProfiles { + # Enumerate real user profiles from ProfileList (SID + path + whether the hive is loaded), + # plus the Default profile template so SACLs propagate to future users. + $result = @() + $pl = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList" + foreach ($k in (Get-ChildItem -LiteralPath $pl -ErrorAction SilentlyContinue)) { + $sid = $k.PSChildName + if ($sid -notmatch '^S-1-5-21-') { continue } # skip system/service SIDs (S-1-5-18/19/20) + $p = (Get-ItemProperty -LiteralPath $k.PSPath -Name ProfileImagePath -ErrorAction SilentlyContinue).ProfileImagePath + if (-not $p -or -not (Test-Path -LiteralPath $p)) { continue } + $loaded = Test-Path -LiteralPath "Microsoft.PowerShell.Core\Registry::HKEY_USERS\$sid" + $result += [pscustomobject]@{ Sid = $sid; Path = $p; Loaded = $loaded } + } + $def = Join-Path $env:SystemDrive "Users\Default" + if (Test-Path -LiteralPath $def) { $result += [pscustomobject]@{ Sid = "DEFAULT"; Path = $def; Loaded = $false } } + return $result } $usage = @" diff --git a/config/audit_sacl_targets.json b/config/audit_sacl_targets.json index f5547509..96555a24 100644 --- a/config/audit_sacl_targets.json +++ b/config/audit_sacl_targets.json @@ -1,5 +1,5 @@ { - "description": "Targeted System Access Control Lists (SACLs) that make Object Access File System (4663), Registry (4657) and Handle Manipulation (4656/4658) auditing produce the events the Hayabusa/Sigma Security-channel rules rely on - WITHOUT enabling global file/registry auditing (which would flood). Only the specific autostart/persistence registry keys (ASEPs) and sensitive files referenced by the ruleset are audited. Principal is 'Everyone'. Registry keys use ContainerInherit so subkeys are covered. Objects that are absent on a given host (e.g. Wow6432Node on 32-bit, NTDS on non-DCs) are skipped. Per-user objects (HKCU / user-profile AppData) cannot be set machine-wide here and are intentionally out of scope - apply those via logon script / GPP.", + "description": "Targeted System Access Control Lists (SACLs) that make Object Access File System (4663), Registry (4657) and Handle Manipulation (4656/4658) auditing produce the events the Hayabusa/Sigma Security-channel rules rely on - WITHOUT enabling global file/registry auditing (which would flood). Only the specific autostart/persistence registry keys (ASEPs) and sensitive files referenced by the ruleset are audited. Principal is 'Everyone'. Registry keys use ContainerInherit so subkeys are covered. Objects that are absent on a given host (e.g. Wow6432Node on 32-bit, NTDS on non-DCs) are skipped. Per-user objects are handled via 'user_registry' and 'user_files': WELA enumerates every profile from ProfileList (plus C:\\Users\\Default so future users inherit the SACL), sets file SACLs under each profile, and sets registry SACLs on each user hive (loaded hives directly via HKU:\\, offline/Default hives by reg-load/unload of NTUSER.DAT). 'user_registry' keys are relative to the user hive root; 'user_files' paths are relative to the profile directory. Remaining edge cases (folder-redirected AppData on network shares, mandatory profiles) are not covered.", "registry": [ {"path": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", "inherit": true, "rights": ["SetValue","CreateSubKey","Delete"], "note": "ASEP Run (T1547.001)"}, {"path": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnce", "inherit": true, "rights": ["SetValue","CreateSubKey","Delete"], "note": "ASEP RunOnce"}, @@ -32,6 +32,23 @@ {"path": "HKLM:\\SOFTWARE\\Microsoft\\Windows Defender\\Exclusions", "inherit": true, "rights": ["SetValue","CreateSubKey"], "note": "Defender exclusion tampering (T1562.001)"}, {"path": "HKLM:\\SYSTEM\\CurrentControlSet\\Services", "inherit": false, "rights": ["CreateSubKey","Delete"], "note": "Service create/delete (T1543.003). Subkey add/remove only, to limit noise - service value edits are captured by 4697/7045."} ], + "user_registry": [ + {"key": "Software\\Microsoft\\Windows\\CurrentVersion\\Run", "inherit": true, "rights": ["SetValue","CreateSubKey","Delete"], "note": "HKCU ASEP Run (T1547.001)"}, + {"key": "Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce", "inherit": true, "rights": ["SetValue","CreateSubKey","Delete"], "note": "HKCU ASEP RunOnce"}, + {"key": "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer\\Run", "inherit": true, "rights": ["SetValue","CreateSubKey","Delete"], "note": "HKCU Policies Explorer Run"}, + {"key": "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders", "inherit": false, "rights": ["SetValue"], "note": "Startup folder redirection (T1547.001)"}, + {"key": "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\StartupApproved\\Run", "inherit": false, "rights": ["SetValue","Delete"], "note": "StartupApproved (enable/disable autorun)"}, + {"key": "Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows", "inherit": false, "rights": ["SetValue"], "note": "HKCU Load/Run (T1546.010)"}, + {"key": "Software\\Microsoft\\Command Processor", "inherit": false, "rights": ["SetValue"], "note": "HKCU cmd AutoRun (T1546.011)"}, + {"key": "Control Panel\\Desktop", "inherit": false, "rights": ["SetValue"], "note": "Scrnsave.exe screensaver hijack (T1546.002)"}, + {"key": "Environment", "inherit": false, "rights": ["SetValue"], "note": "UserInitMprLogonScript logon-script persistence (T1037.001)"}, + {"key": "Software\\Microsoft\\Ctf\\LangBarAddin", "inherit": true, "rights": ["SetValue","CreateSubKey","Delete"], "note": "HKCU LangBarAddin"}, + {"key": "Software\\Microsoft\\Office\\Outlook\\Addins", "inherit": true, "rights": ["CreateSubKey","Delete","SetValue"], "note": "Outlook add-in persistence (T1137.006)"} + ], + "user_files": [ + {"relpath": "AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Startup", "inherit": true, "rights": ["WriteData","CreateFiles","Delete"], "note": "Startup folder persistence (T1547.001)"}, + {"relpath": "AppData\\Roaming\\Signal", "inherit": true, "rights": ["ReadData"], "note": "Signal Desktop sensitive data access (T1005)"} + ], "files": [ {"path": "C:\\Windows\\NTDS", "inherit": true, "rights": ["ReadData","WriteData","Delete","ChangePermissions","TakeOwnership"], "note": "AD database dir - ntds.dit theft (T1003.003)"}, {"path": "C:\\Windows\\System32\\config\\SAM", "inherit": false, "rights": ["ReadData","WriteData","Delete","TakeOwnership"], "note": "SAM hive theft (T1003.002)"},