diff --git a/README.md b/README.md index 866a704e..2547b290 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ All documentation now lives on a dedicated, searchable, multi-language site: | Section | | | --- | --- | | 🚀 [Getting Started](https://yamato-security.github.io/WELA/getting-started/) | Prerequisites, downloads and running WELA | -| ⌨️ [Command Reference](https://yamato-security.github.io/WELA/commands/) | `audit-settings`, `audit-filesize`, `configure`, `update-rules` | +| ⌨️ [Command Reference](https://yamato-security.github.io/WELA/commands/) | `audit-settings`, `audit-filesize`, `configure`, `configure-sacl`, `update-rules` | | ✨ [Features](https://yamato-security.github.io/WELA/overview/features/) | What WELA can do | | 📦 [Resources](https://yamato-security.github.io/WELA/resources/companion-projects/) | Companion projects, changelog, contributing | diff --git a/WELA.ps1 b/WELA.ps1 index 1690b119..2abb4c85 100644 --- a/WELA.ps1 +++ b/WELA.ps1 @@ -16,6 +16,7 @@ $BaselineConfigPath = Join-Path $ScriptRoot "config/baselines.json" $SecurityRulesPath = Join-Path $ScriptRoot "config/security_rules.json" $EidMappingPath = Join-Path $ScriptRoot "config/eid_subcategory_mapping.csv" $AuditpolTxtPath = Join-Path $ScriptRoot "auditpol.txt" +$SaclTargetsPath = Join-Path $ScriptRoot "config/audit_sacl_targets.json" # 64bit の PowerShell と GPO が読むのは Wow6432Node の無いパス。32bit 用に両方を扱う。 $PowerShellPolicyRoots = @( @@ -1286,6 +1287,111 @@ $logo = @" by Yamato Security "@ +function Enable-WelaPrivilege { + # Enable SeSecurityPrivilege (required to read/write SACLs) + backup/restore, in the current token. + param([string[]] $Privileges = @("SeSecurityPrivilege","SeBackupPrivilege","SeRestorePrivilege")) + if (-not ("WELA.PrivHelper" -as [type])) { + Add-Type -Namespace WELA -Name PrivHelper -MemberDefinition @" +[DllImport("advapi32.dll", SetLastError=true)] public static extern bool OpenProcessToken(IntPtr h, uint acc, out IntPtr tok); +[DllImport("advapi32.dll", SetLastError=true)] public static extern bool LookupPrivilegeValue(string host, string name, out long luid); +[DllImport("advapi32.dll", SetLastError=true)] public static extern bool AdjustTokenPrivileges(IntPtr tok, bool dis, ref TOKEN_PRIVILEGES np, uint len, IntPtr prev, IntPtr rl); +[DllImport("kernel32.dll")] public static extern IntPtr GetCurrentProcess(); +[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)] +public struct TOKEN_PRIVILEGES { public uint Count; public long Luid; public uint Attr; } +public static bool Enable(string priv) { + IntPtr tok; if(!OpenProcessToken(GetCurrentProcess(), 0x20, out tok)) return false; + long luid; if(!LookupPrivilegeValue(null, priv, out luid)) return false; + TOKEN_PRIVILEGES tp = new TOKEN_PRIVILEGES(); tp.Count=1; tp.Luid=luid; tp.Attr=0x2; + return AdjustTokenPrivileges(tok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero); +} +"@ + } + foreach ($p in $Privileges) { [void][WELA.PrivHelper]::Enable($p) } +} + +function Set-AuditSacl { + # Apply TARGETED audit SACLs (from config/audit_sacl_targets.json) so that File System (4663), + # Registry (4657) and Handle Manipulation (4656) auditing fires only on the specific ASEP keys + # and sensitive files the detection rules watch - never globally. + [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')] + param([switch] $Auto) + + if (-not (TestWindows)) { + Write-Host "[ERROR] 'configure-sacl' changes Windows settings and can only run on Windows." -ForegroundColor Red; return + } + if (-not (TestAdministrator)) { Write-Error "This command requires Administrator privileges"; return } + if (-not (Test-Path $script:SaclTargetsPath)) { + Write-Host "[ERROR] Missing config: $script:SaclTargetsPath (run 'update-rules' or reinstall WELA)." -ForegroundColor Red; return + } + Enable-WelaPrivilege + $targets = Get-Content -Path $script:SaclTargetsPath -Raw | ConvertFrom-Json + + # 1) Enable ONLY the object-access subcategories these SACLs need (by GUID, locale-independent). + # With no SACLs beyond the targeted ones below, these subcategories stay effectively silent. + Write-Host "Enabling Object Access subcategories (File System, Registry, Handle Manipulation)..." + $subs = @( + @{Name="File System"; GUID="0CCE921D-69AE-11D9-BED3-505054503030"}, + @{Name="Registry"; GUID="0CCE921E-69AE-11D9-BED3-505054503030"}, + @{Name="Handle Manipulation"; GUID="0CCE9223-69AE-11D9-BED3-505054503030"} + ) + foreach ($s in $subs) { + if ($Auto -or $PSCmdlet.ShouldProcess($s.Name, "auditpol enable Success+Failure")) { + $p = Start-Process -FilePath "auditpol.exe" -ArgumentList "/set /subcategory:{$($s.GUID)} /success:enable /failure:enable" -Wait -PassThru -NoNewWindow -RedirectStandardOutput "NUL" + if ($p.ExitCode -eq 0) { Write-Host "[OK] subcategory: $($s.Name)" -ForegroundColor Green } + else { Write-Host "[ERROR] subcategory: $($s.Name) (ExitCode $($p.ExitCode))" -ForegroundColor Red } + } + } + Write-Host "" + + $everyone = New-Object System.Security.Principal.SecurityIdentifier("S-1-1-0") + $auditFlags = [System.Security.AccessControl.AuditFlags]"Success,Failure" + + # 2) Registry SACLs + Write-Host "Applying targeted REGISTRY audit SACLs..." + foreach ($t in $targets.registry) { + try { + if (-not (Test-Path -LiteralPath $t.path)) { + Write-Host "[SKIPPED] $($t.path) : key not present on this host" -ForegroundColor DarkYellow; 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 $t.path -Audit + $already = $acl.Audit | Where-Object { $_.IdentityReference.Value -eq $everyone.Value -and (($_.RegistryRights -band $rights) -eq $rights) -and ($_.AuditFlags -eq $auditFlags) } + if ($already) { Write-Host "[SKIPPED] $($t.path) : SACL already present ($($t.note))" -ForegroundColor Yellow; continue } + if ($Auto -or $PSCmdlet.ShouldProcess($t.path, "add audit SACL [$($t.rights -join ',')] Everyone Success+Failure")) { + $rule = New-Object System.Security.AccessControl.RegistryAuditRule($everyone, $rights, $inh, "None", $auditFlags) + $acl.AddAuditRule($rule); Set-Acl -LiteralPath $t.path -AclObject $acl + Write-Host "[OK] $($t.path) ($($t.note))" -ForegroundColor Green + } + } catch { Write-Host "[ERROR] $($t.path) : $_" -ForegroundColor Red } + } + Write-Host "" + + # 3) File / directory SACLs + Write-Host "Applying targeted FILE audit SACLs..." + foreach ($t in $targets.files) { + try { + if (-not (Test-Path -LiteralPath $t.path)) { + Write-Host "[SKIPPED] $($t.path) : path not present on this host" -ForegroundColor DarkYellow; continue + } + $isDir = (Get-Item -LiteralPath $t.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 $t.path -Audit + $already = $acl.Audit | Where-Object { $_.IdentityReference.Value -eq $everyone.Value -and (($_.FileSystemRights -band $rights) -eq $rights) -and ($_.AuditFlags -eq $auditFlags) } + if ($already) { Write-Host "[SKIPPED] $($t.path) : SACL already present ($($t.note))" -ForegroundColor Yellow; continue } + if ($Auto -or $PSCmdlet.ShouldProcess($t.path, "add audit SACL [$($t.rights -join ',')] Everyone Success+Failure")) { + $rule = New-Object System.Security.AccessControl.FileSystemAuditRule($everyone, $rights, $inh, "None", $auditFlags) + $acl.AddAuditRule($rule); Set-Acl -LiteralPath $t.path -AclObject $acl + Write-Host "[OK] $($t.path) ($($t.note))" -ForegroundColor Green + } + } catch { Write-Host "[ERROR] $($t.path) : $_" -ForegroundColor Red } + } + 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 +} + $usage = @" Usage: ./WELA.ps1 audit-settings -Baseline YamatoSecurity # Audit current setting and show in stdout, save to csv @@ -1293,6 +1399,8 @@ Usage: ./WELA.ps1 audit-filesize -Baseline YamatoSecurity # Audit current file size and show in stdout, save to csv ./WELA.ps1 configure -Baseline YamatoSecurity # Configure audit settings based on the specified baseline ./WELA.ps1 configure -Baseline YamatoSecurity -Auto # Configure audit settings automatically without prompts + ./WELA.ps1 configure-sacl # Add targeted File System/Registry audit SACLs (ASEP keys + sensitive files) needed by the rules, without global auditing + ./WELA.ps1 configure-sacl -Auto # ...automatically without prompts ./WELA.ps1 update-rules # Update rule config files from https://github.com/Yamato-Security/WELA ./WELA.ps1 version # Show the WELA version ./WELA.ps1 help # Show this help @@ -1363,6 +1471,25 @@ switch ($Cmd.ToLower()) { ConfigureAuditSettings -Auto:$Auto -Debug:$Debug } + "configure-sacl" { + if ($Help){ + Write-Host "Add TARGETED object-access audit SACLs so File System (4663) / Registry (4657) /" + Write-Host "Handle Manipulation (4656) auditing fires only on the specific autostart/persistence" + Write-Host "registry keys and sensitive files the Hayabusa/Sigma rules watch - never globally." + Write-Host "" + Write-Host "Usage: ./WELA.ps1 configure-sacl [-Auto]" + Write-Host "" + Write-Host "Options:" + Write-Host " -Auto Apply without per-object prompts" + Write-Host "" + Write-Host "Targets are defined in config/audit_sacl_targets.json (edit to customize)." + Write-Host "Objects absent on the host are skipped; per-user HKCU/AppData objects are out of scope." + Write-Host "" + return + } + Set-AuditSacl -Auto:$Auto + } + "update-rules" { if ($Help) { Write-Host "Update detection rule configuration files from GitHub repository" diff --git a/config/audit_sacl_targets.json b/config/audit_sacl_targets.json new file mode 100644 index 00000000..f5547509 --- /dev/null +++ b/config/audit_sacl_targets.json @@ -0,0 +1,44 @@ +{ + "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.", + "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"}, + {"path": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnceEx", "inherit": true, "rights": ["SetValue","CreateSubKey","Delete"], "note": "ASEP RunOnceEx"}, + {"path": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunServices", "inherit": true, "rights": ["SetValue","CreateSubKey","Delete"], "note": "ASEP RunServices"}, + {"path": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunServicesOnce", "inherit": true, "rights": ["SetValue","CreateSubKey","Delete"], "note": "ASEP RunServicesOnce"}, + {"path": "HKLM:\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Run", "inherit": true, "rights": ["SetValue","CreateSubKey","Delete"], "note": "ASEP Run (WOW64)"}, + {"path": "HKLM:\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\RunOnce", "inherit": true, "rights": ["SetValue","CreateSubKey","Delete"], "note": "ASEP RunOnce (WOW64)"}, + {"path": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer\\Run", "inherit": true, "rights": ["SetValue","CreateSubKey","Delete"], "note": "ASEP Policies Explorer Run"}, + {"path": "HKLM:\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon", "inherit": true, "rights": ["SetValue","CreateSubKey","Delete"], "note": "Winlogon Shell/Userinit/Notify (T1547.004)"}, + {"path": "HKLM:\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options", "inherit": true, "rights": ["SetValue","CreateSubKey","Delete"], "note": "IFEO debugger/GlobalFlag (T1546.012)"}, + {"path": "HKLM:\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options", "inherit": true, "rights": ["SetValue","CreateSubKey","Delete"], "note": "IFEO (WOW64)"}, + {"path": "HKLM:\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows", "inherit": false, "rights": ["SetValue"], "note": "AppInit_DLLs / Load / Run (T1546.010)"}, + {"path": "HKLM:\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows NT\\CurrentVersion\\Windows", "inherit": false, "rights": ["SetValue"], "note": "AppInit_DLLs (WOW64)"}, + {"path": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ShellServiceObjectDelayLoad", "inherit": true, "rights": ["SetValue","CreateSubKey","Delete"], "note": "SSODL (T1547.005)"}, + {"path": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\SharedTaskScheduler", "inherit": true, "rights": ["SetValue","CreateSubKey","Delete"], "note": "SharedTaskScheduler"}, + {"path": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ShellIconOverlayIdentifiers", "inherit": true, "rights": ["CreateSubKey","Delete"], "note": "ShellIconOverlayIdentifiers"}, + {"path": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Browser Helper Objects", "inherit": true, "rights": ["CreateSubKey","Delete"], "note": "BHO (T1176)"}, + {"path": "HKLM:\\SOFTWARE\\Microsoft\\Active Setup\\Installed Components", "inherit": true, "rights": ["SetValue","CreateSubKey","Delete"], "note": "Active Setup (T1547.014)"}, + {"path": "HKLM:\\SOFTWARE\\Wow6432Node\\Microsoft\\Active Setup\\Installed Components", "inherit": true, "rights": ["SetValue","CreateSubKey","Delete"], "note": "Active Setup (WOW64)"}, + {"path": "HKLM:\\SOFTWARE\\Microsoft\\Command Processor", "inherit": false, "rights": ["SetValue"], "note": "cmd AutoRun (T1546.011)"}, + {"path": "HKLM:\\SOFTWARE\\Wow6432Node\\Microsoft\\Command Processor", "inherit": false, "rights": ["SetValue"], "note": "cmd AutoRun (WOW64)"}, + {"path": "HKLM:\\SYSTEM\\CurrentControlSet\\Control\\Session Manager", "inherit": false, "rights": ["SetValue"], "note": "BootExecute/AppCertDlls/SubSystems (T1546.009)"}, + {"path": "HKLM:\\SYSTEM\\CurrentControlSet\\Control\\Lsa", "inherit": false, "rights": ["SetValue"], "note": "LSA Security/Authentication/Notification Packages - SSP (T1547.005/T1556)"}, + {"path": "HKLM:\\SYSTEM\\CurrentControlSet\\Services\\WinSock2\\Parameters", "inherit": true, "rights": ["SetValue","CreateSubKey"], "note": "Winsock LSP (T1546.015)"}, + {"path": "HKLM:\\SOFTWARE\\Microsoft\\Ctf\\LangBarAddin", "inherit": true, "rights": ["SetValue","CreateSubKey","Delete"], "note": "LangBarAddin"}, + {"path": "HKLM:\\SOFTWARE\\Classes\\Protocols\\Handler", "inherit": true, "rights": ["CreateSubKey","Delete"], "note": "Protocol handler hijack"}, + {"path": "HKLM:\\SOFTWARE\\Classes\\Protocols\\Filter", "inherit": true, "rights": ["CreateSubKey","Delete"], "note": "Protocol filter hijack"}, + {"path": "HKLM:\\SOFTWARE\\Policies\\Microsoft\\Windows\\System\\Scripts", "inherit": true, "rights": ["SetValue","CreateSubKey"], "note": "Logon/Logoff/Startup scripts (T1037)"}, + {"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."} + ], + "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)"}, + {"path": "C:\\Windows\\System32\\config\\SECURITY", "inherit": false, "rights": ["ReadData","WriteData","Delete","TakeOwnership"], "note": "SECURITY hive (T1003.004 LSA secrets)"}, + {"path": "C:\\Windows\\System32\\config\\SYSTEM", "inherit": false, "rights": ["ReadData","WriteData","Delete","TakeOwnership"], "note": "SYSTEM hive (boot key for offline SAM)"}, + {"path": "C:\\Windows\\System32\\lsass.exe", "inherit": false, "rights": ["ReadData","WriteData","TakeOwnership"], "note": "LSASS binary read/replace. NOTE: live LSASS memory/handle access (credential dumping) is better detected via Sysmon EID 10, not a file SACL."}, + {"path": "C:\\Windows\\System32\\ntdsutil.exe", "inherit": false, "rights": ["ExecuteFile"], "note": "ntdsutil execution (IFM/ntds.dit dump)"}, + {"path": "C:\\Windows\\System32\\vssadmin.exe", "inherit": false, "rights": ["ExecuteFile"], "note": "Shadow copy tooling"} + ] +}