diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e43b0f9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.DS_Store diff --git a/E8-CAT.ps1 b/E8-CAT.ps1 new file mode 100644 index 0000000..264de12 --- /dev/null +++ b/E8-CAT.ps1 @@ -0,0 +1,198 @@ +[CmdletBinding()] +param( + [ValidateSet('ML1','ML2','ML3','All')] [string]$Profile = 'ML1', + [string]$RulesPath = ".\rules", + [string]$ProfilesPath = ".\profiles", + [string]$OutDir = ".\out" +) + +function New-Result($rule,$status,$evidence){ + [pscustomobject]@{ + RuleId = $rule.id + Title = $rule.title + Strategy = $rule.strategy + Level = $Profile + Status = $status # PASS / FAIL / SKIPPED / N/A / ERROR + Evidence = $evidence + Timestamp = (Get-Date).ToString("s") + } +} + +function Test-Registry { + param($r) + $root = if ($r.scope -eq 'HKCU') { 'HKCU:' } else { 'HKLM:' } + $path = if ($r.path.StartsWith('\')) { Join-Path $root $r.path.Substring(1) } else { Join-Path $root $r.path } + try { + if (-not (Test-Path $path)) { return @{ok=$false; ev="Path missing: $path"} } + $prop = Get-ItemProperty -Path $path -ErrorAction Stop + if (-not $r.name -or $r.name -eq '') { return @{ ok=$true; ev="Key exists: $path" } } + if ($null -eq $prop.$($r.name)) { return @{ok=$false; ev="Value missing: $path\$($r.name)"} } + $val = $prop.$($r.name) + $op = if ($r.op) { $r.op } else { 'eq' } + $ok = $false + switch ($op) { + 'eq' { $ok = ([string]$val -eq [string]$r.expected) } + 'ne' { $ok = ([string]$val -ne [string]$r.expected) } + 'in' { $ok = ($r.expected -contains ([string]$val)) } + 'ge' { $ok = ([double]$val -ge [double]$r.expected) } + 'le' { $ok = ([double]$val -le [double]$r.expected) } + default { $ok = ([string]$val -eq [string]$r.expected) } + } + @{ ok=$ok; ev="[$path] $($r.name)=$val (expect $op $($r.expected))" } + } catch { @{ ok=$false; ev=("Error: {0}" -f $_.Exception.Message) } } +} + +function Test-File { + param($r) + $exists = Test-Path $r.path + $ok = if ($r.op -eq 'absent') { -not $exists } else { $exists } + @{ ok=$ok; ev="$($r.path) Exists=$exists (expect $($r.op))" } +} + +function Test-Command { + param($r) + try { + $expected = if ($null -ne $r.expectedExitCode) { [int]$r.expectedExitCode } else { 0 } + $p = Start-Process -FilePath "powershell.exe" -ArgumentList "-NoProfile -NonInteractive -Command `$ErrorActionPreference='Stop'; $($r.command)" -NoNewWindow -PassThru -Wait + $ok = ($p.ExitCode -eq $expected) + @{ ok=$ok; ev=("ExitCode={0} (expect {1})" -f $p.ExitCode, $expected) } + } catch { @{ ok=$false; ev=("Error: {0}" -f $_.Exception.Message) } } +} + +function Test-ScriptBlock { + param($r) + try { + $sb = [ScriptBlock]::Create($r.script) + $res = & $sb + if ($null -eq $res) { return @{ ok=$false; ev="Script returned `$null (treat as SKIPPED)"; skipped=$true } } + $ok = [bool]$res + @{ ok=$ok; ev=("Script returned: {0}. Expected $true; return $null to SKIP." -f $res) } + } catch { @{ ok=$false; ev=("Error: {0}" -f $_.Exception.Message) } } +} + +function Test-ADOptional { + param($r) + if (-not (Get-Module -ListAvailable ActiveDirectory)) { + return @{ ok=$false; ev="Skipped (ActiveDirectory module not found)"; skipped=$true } + } + try { + $sb = [ScriptBlock]::Create($r.script) + $res = & $sb + if ($null -eq $res) { return @{ ok=$false; ev="Script returned `$null (treat as SKIPPED)"; skipped=$true } } + $ok = [bool]$res + @{ ok=$ok; ev=("Script returned: {0}. Expected $true; return $null to SKIP." -f $res) } + } catch { @{ ok=$false; ev=("Error: {0}" -f $_.Exception.Message) } } +} + +# Load rules +$ruleFiles = Get-ChildItem -Path $RulesPath -Filter *.json -File +$allRules = @() +foreach ($f in $ruleFiles) { + $data = Get-Content $f.FullName -Raw | ConvertFrom-Json + if ($data -is [System.Array]) { $allRules += $data } else { $allRules += ,$data } +} + +# Load profile object unless All +$ProfileObj = $null +if ($Profile -ne 'All') { + $profileFile = Join-Path $ProfilesPath ("{0}.json" -f $Profile.ToLower()) + if (-not (Test-Path $profileFile)) { throw "Profile not found: $profileFile" } + $ProfileObj = Get-Content $profileFile -Raw | ConvertFrom-Json +} + +# Evaluate (single level or all levels) +$results = New-Object System.Collections.Generic.List[object] + +# Determine rule set +$rules = $allRules +if ($Profile -ne 'All' -and $ProfileObj -and ($ProfileObj.PSObject.Properties.Name -contains 'includeRuleIds') -and $ProfileObj.includeRuleIds) { + $rules = @() + foreach ($r in $allRules) { if ($ProfileObj.includeRuleIds -contains $r.id) { $rules += ,$r } } +} + +$levelsToRun = if ($Profile -eq 'All') { @('ML1','ML2','ML3') } else { @($Profile) } +$levelOrder = @{ ML1=1; ML2=2; ML3=3 } + +foreach ($runLevel in $levelsToRun) { + foreach ($rule in $rules) { + switch ($rule.type) { + 'registry' { $r = Test-Registry $rule } + 'file' { $r = Test-File $rule } + 'command' { $r = Test-Command $rule } + 'scriptblock' { $r = Test-ScriptBlock $rule } + 'ad-optional' { $r = Test-ADOptional $rule } + default { $r = @{ ok=$false; ev=("Unknown type {0}" -f $rule.type) } } + } + + $applies = $true + if ($rule.minLevel) { $applies = ($levelOrder[$runLevel] -ge $levelOrder[$rule.minLevel]) } + + if ($r.skipped) { $status = 'SKIPPED' } + else { + if (-not $applies) { $status = 'N/A' } + else { if ($r.ok) { $status = 'PASS' } else { $status = 'FAIL' } } + } + + $results.Add([pscustomobject]@{ + RuleId = $rule.id + Title = $rule.title + Strategy = $rule.strategy + Level = $runLevel + Status = $status + Evidence = $r.ev + Timestamp= (Get-Date).ToString("s") + }) + } +} + +# Score per level (avoid $pass name to prevent any oddities) +$levelScores = @{} +foreach ($lvl in $levelsToRun) { + $scored = $results | Where-Object { $_.Level -eq $lvl -and $_.Status -in 'PASS','FAIL' } + $passCount = ($scored | Where-Object { $_.Status -eq 'PASS' }).Count + $failCount = ($scored | Where-Object { $_.Status -eq 'FAIL' }).Count + $totalCount = [math]::Max(1, $scored.Count) + $pct = [math]::Round(100 * $passCount / $totalCount, 1) + $levelScores[$lvl] = @{ Pass=$passCount; Fail=$failCount; Total=$totalCount; Pct=$pct } + Write-Host ("E8-CAT {0} score: {1}% (PASS={2} / FAIL={3} / Total={4})" -f $lvl,$pct,$passCount,$failCount,$totalCount) +} + +New-Item -ItemType Directory -Force -Path $OutDir | Out-Null +$ts = (Get-Date).ToString("yyyyMMdd-HHmmss") +$jsonPath = Join-Path $OutDir ("E8CAT-{0}-{1}.json" -f $Profile,$ts) +$csvPath = Join-Path $OutDir ("E8CAT-{0}-{1}.csv" -f $Profile,$ts) +$htmlPath = Join-Path $OutDir ("E8CAT-{0}-{1}.html" -f $Profile,$ts) + +$results | ConvertTo-Json -Depth 6 | Set-Content -Path $jsonPath -Encoding UTF8 +$results | Export-Csv -NoTypeInformation -Path $csvPath -Encoding UTF8 + +$summary = '' +foreach ($k in ('ML1','ML2','ML3')) { + if ($levelScores.ContainsKey($k)) { + $s = $levelScores[$k] + $summary += ("
  • {0}: {1}% (PASS {2} / FAIL {3} / Total {4})
  • " -f $k,$s.Pct,$s.Pass,$s.Fail,$s.Total) + } +} +$summary = "" + +$rows = $results | ForEach-Object { + "$($_.RuleId)$($_.Strategy)$($_.Title)$($_.Level)$($_.Status)
    $($_.Evidence -replace '<','<')
    " +} | Out-String + +@" +E8-CAT $Profile + + +

    E8-CAT - Profile $Profile

    +

    Scores

    +$summary + + +$rows +
    RuleIdStrategyTitleLevelStatusEvidence
    + +"@ | Set-Content -Path $htmlPath -Encoding UTF8 + +Write-Host "Saved: $jsonPath" +Write-Host "Saved: $csvPath" +Write-Host "Saved: $htmlPath" diff --git a/README.md b/README.md index d17e6e2..14d2397 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,110 @@ -# E8-CAT +# E8-CAT – Essential Eight Compliance Assessment Tool -Essential Eight compliance assessment tool \ No newline at end of file +`E8-CAT` is a lightweight PowerShell-based compliance scanner, similar in spirit to CIS-CAT, designed to check Windows workstations and servers against the [ACSC Essential Eight](https://www.cyber.gov.au/acsc/view-all-content/essential-eight) hardening strategies. + +This build includes rules for **Maturity Levels 1–3** and can report on all levels in a single run. + +--- + +## Features +- **Profiles:** Run checks for a specific level (`ML1`, `ML2`, `ML3`) or all at once (`All`). +- **All-level mode:** With `-Profile All`, the scanner evaluates ML1–3 in one pass and reports per-level results and scores. +- **Per-rule applicability:** Rules know their minimum level. If they don’t apply to a level, they’re marked **N/A**. +- **Evidence-based:** Each rule outputs evidence showing registry values, feature state, or script results. +- **Skip logic:** If a product isn’t installed (e.g., Chrome, Edge, Firefox, IE on Win11), the rule reports **SKIPPED**. +- **Cross-scope checks:** Registry policies are checked under both **HKLM** and **HKCU**. +- **Output formats:** JSON, CSV, and HTML reports saved under `.\out\`. +- **PowerShell 5.1 compatible:** Works on standard Windows builds (no modern operators like `??`). + +--- + +## Usage +```powershell +Set-ExecutionPolicy Bypass -Scope Process -Force + +# Navigate into the E8-CAT folder +Set-Location .\E8-CAT + +# Run all levels in one pass +.\E8-CAT.ps1 -Profile All + +# Run a specific maturity level +.\E8-CAT.ps1 -Profile ML1 +.\E8-CAT.ps1 -Profile ML2 +.\E8-CAT.ps1 -Profile ML3 +``` + +--- + +## Outputs +Results are written to `.\out` with timestamped filenames: +- **CSV** – Easy import into Excel or SIEM tools +- **JSON** – Machine-readable for pipelines and dashboards +- **HTML** – Human-friendly report with tables and score summaries + +Example output files: +``` +.\out\E8CAT-ML1-20250902-153936.csv +.\out\E8CAT-ML1-20250902-153936.json +.\out\E8CAT-ML1-20250902-153936.html +``` + +--- + +## Rule Coverage +Rules are organised by strategy: + +- **RM – Restrict Macros:** + - Office macro settings (Word/Excel/PowerPoint/Outlook, Office 15.0 & 16.0) + - Block macros from the Internet + - Macro runtime AV scanning + - Trusted Publisher enforcement (ML3) + +- **AH – Application Hardening:** + - Internet Explorer 11 feature disabled (skips on Win11) + - Java browser plugin absent + - Microsoft Edge SmartScreen + download restrictions + - Chrome SafeBrowsing, download restrictions, extension blocklist + - Firefox enterprise policy presence + - Windows SmartScreen (multiple policy keys) + +- **AC – Application Control:** + - AppLocker policy present and enforced (not AuditOnly) + - Windows Defender Application Control (WDAC) policy present + - Software Restriction Policies present + +- **RA – Restrict Admin Privileges:** + - Built-in Administrator account disabled + - UAC (EnableLUA) enabled + - Local Administrator Password Solution (LAPS) policy present (Windows or legacy) + +--- + +## Rule Semantics +Rules are defined in `.\rules\*.json`. Each rule specifies: +- `id`, `title`, `strategy`, `type`, `script` (or registry/command parameters) +- `minLevel` (ML1, ML2, ML3) + +**Return values in rules:** +- `$true` → **PASS** +- `$false` → **FAIL** +- `$null` → **SKIPPED** + +--- + +## Profiles +Profiles are stored under `.\profiles\ml1.json`, `ml2.json`, `ml3.json`. They contain the rule IDs included at each level. +When running `-Profile All`, these profiles are ignored and all rules are checked, with results shown for each level. + +--- + +## Example Run +```powershell +PS C:\E8-CAT> .\E8-CAT.ps1 -Profile All +E8-CAT ML1 score: 78.9% (PASS=15 / FAIL=4 / Total=19) +E8-CAT ML2 score: 65.0% (PASS=13 / FAIL=7 / Total=20) +E8-CAT ML3 score: 42.9% (PASS=9 / FAIL=12 / Total=21) +Saved: .\out\E8CAT-All-20250902-161413.json +Saved: .\out\E8CAT-All-20250902-161413.csv +Saved: .\out\E8CAT-All-20250902-161413.html +``` diff --git a/profiles/ml1.json b/profiles/ml1.json new file mode 100644 index 0000000..9dbc670 --- /dev/null +++ b/profiles/ml1.json @@ -0,0 +1,41 @@ +{ + "name": "ML1", + "includeRuleIds": [ + "RM-01-VBAWarnings-Word-160", + "RM-02-BlockInternet-Word-160", + "RM-01-VBAWarnings-Excel-160", + "RM-02-BlockInternet-Excel-160", + "RM-01-VBAWarnings-PowerPoint-160", + "RM-02-BlockInternet-PowerPoint-160", + "RM-01-VBAWarnings-Outlook-160", + "RM-02-BlockInternet-Outlook-160", + "RM-01-VBAWarnings-Word-150", + "RM-02-BlockInternet-Word-150", + "RM-01-VBAWarnings-Excel-150", + "RM-02-BlockInternet-Excel-150", + "RM-01-VBAWarnings-PowerPoint-150", + "RM-02-BlockInternet-PowerPoint-150", + "RM-01-VBAWarnings-Outlook-150", + "RM-02-BlockInternet-Outlook-150", + "RM-03-MacroRuntimeScan-160", + "RM-03-MacroRuntimeScan-150", + "RM-TRUSTED-PUBLISHERS-160", + "RM-TRUSTED-PUBLISHERS-150", + "AH-IE11-Feature-Disabled", + "AH-Java-Plugin-Absent", + "AH-Edge-SmartScreen", + "AH-Edge-DownloadRestrictions", + "AH-Chrome-SafeBrowsing", + "AH-Chrome-DownloadRestrictions", + "AH-Chrome-Ext-Blocklist", + "AH-Firefox-PolicyKey", + "AH-Windows-SmartScreen", + "AC-01-AppLocker", + "AC-AppLocker-Enforced", + "AC-02-WDAC", + "AC-03-SRP", + "RA-Local-Administrator-Disabled", + "RA-UAC-Enabled", + "RA-LAPS-PolicyPresent" + ] +} \ No newline at end of file diff --git a/profiles/ml2.json b/profiles/ml2.json new file mode 100644 index 0000000..22ec9b7 --- /dev/null +++ b/profiles/ml2.json @@ -0,0 +1,41 @@ +{ + "name": "ML2", + "includeRuleIds": [ + "RM-01-VBAWarnings-Word-160", + "RM-02-BlockInternet-Word-160", + "RM-01-VBAWarnings-Excel-160", + "RM-02-BlockInternet-Excel-160", + "RM-01-VBAWarnings-PowerPoint-160", + "RM-02-BlockInternet-PowerPoint-160", + "RM-01-VBAWarnings-Outlook-160", + "RM-02-BlockInternet-Outlook-160", + "RM-01-VBAWarnings-Word-150", + "RM-02-BlockInternet-Word-150", + "RM-01-VBAWarnings-Excel-150", + "RM-02-BlockInternet-Excel-150", + "RM-01-VBAWarnings-PowerPoint-150", + "RM-02-BlockInternet-PowerPoint-150", + "RM-01-VBAWarnings-Outlook-150", + "RM-02-BlockInternet-Outlook-150", + "RM-03-MacroRuntimeScan-160", + "RM-03-MacroRuntimeScan-150", + "RM-TRUSTED-PUBLISHERS-160", + "RM-TRUSTED-PUBLISHERS-150", + "AH-IE11-Feature-Disabled", + "AH-Java-Plugin-Absent", + "AH-Edge-SmartScreen", + "AH-Edge-DownloadRestrictions", + "AH-Chrome-SafeBrowsing", + "AH-Chrome-DownloadRestrictions", + "AH-Chrome-Ext-Blocklist", + "AH-Firefox-PolicyKey", + "AH-Windows-SmartScreen", + "AC-01-AppLocker", + "AC-AppLocker-Enforced", + "AC-02-WDAC", + "AC-03-SRP", + "RA-Local-Administrator-Disabled", + "RA-UAC-Enabled", + "RA-LAPS-PolicyPresent" + ] +} \ No newline at end of file diff --git a/profiles/ml3.json b/profiles/ml3.json new file mode 100644 index 0000000..dc03c28 --- /dev/null +++ b/profiles/ml3.json @@ -0,0 +1,41 @@ +{ + "name": "ML3", + "includeRuleIds": [ + "RM-01-VBAWarnings-Word-160", + "RM-02-BlockInternet-Word-160", + "RM-01-VBAWarnings-Excel-160", + "RM-02-BlockInternet-Excel-160", + "RM-01-VBAWarnings-PowerPoint-160", + "RM-02-BlockInternet-PowerPoint-160", + "RM-01-VBAWarnings-Outlook-160", + "RM-02-BlockInternet-Outlook-160", + "RM-01-VBAWarnings-Word-150", + "RM-02-BlockInternet-Word-150", + "RM-01-VBAWarnings-Excel-150", + "RM-02-BlockInternet-Excel-150", + "RM-01-VBAWarnings-PowerPoint-150", + "RM-02-BlockInternet-PowerPoint-150", + "RM-01-VBAWarnings-Outlook-150", + "RM-02-BlockInternet-Outlook-150", + "RM-03-MacroRuntimeScan-160", + "RM-03-MacroRuntimeScan-150", + "RM-TRUSTED-PUBLISHERS-160", + "RM-TRUSTED-PUBLISHERS-150", + "AH-IE11-Feature-Disabled", + "AH-Java-Plugin-Absent", + "AH-Edge-SmartScreen", + "AH-Edge-DownloadRestrictions", + "AH-Chrome-SafeBrowsing", + "AH-Chrome-DownloadRestrictions", + "AH-Chrome-Ext-Blocklist", + "AH-Firefox-PolicyKey", + "AH-Windows-SmartScreen", + "AC-01-AppLocker", + "AC-AppLocker-Enforced", + "AC-02-WDAC", + "AC-03-SRP", + "RA-Local-Administrator-Disabled", + "RA-UAC-Enabled", + "RA-LAPS-PolicyPresent" + ] +} \ No newline at end of file diff --git a/rules/ac.json b/rules/ac.json new file mode 100644 index 0000000..e1481f9 --- /dev/null +++ b/rules/ac.json @@ -0,0 +1,34 @@ +[ + { + "id": "AC-01-AppLocker", + "title": "AppLocker policy present", + "strategy": "AC", + "type": "scriptblock", + "script": "try { (Get-AppLockerPolicy -Effective).RuleCollections.Count -gt 0 } catch { $false }", + "minLevel": "ML1" + }, + { + "id": "AC-AppLocker-Enforced", + "title": "AppLocker enforcement not AuditOnly for at least one collection", + "strategy": "AC", + "type": "scriptblock", + "script": "(Get-AppLockerPolicy -Effective -ErrorAction SilentlyContinue).RuleCollections | Where-Object { $_.EnforcementMode -and $_.EnforcementMode -ne 'AuditOnly' } | Measure-Object | ForEach-Object { $_.Count -gt 0 }", + "minLevel": "ML1" + }, + { + "id": "AC-02-WDAC", + "title": "WDAC policy key present", + "strategy": "AC", + "type": "scriptblock", + "script": "Test-Path 'HKLM:\\SYSTEM\\CurrentControlSet\\Control\\CI\\Policy'", + "minLevel": "ML1" + }, + { + "id": "AC-03-SRP", + "title": "Software Restriction Policies present", + "strategy": "AC", + "type": "scriptblock", + "script": "Test-Path 'HKLM:\\SOFTWARE\\Policies\\Microsoft\\Windows\\Safer\\CodeIdentifiers'", + "minLevel": "ML1" + } +] \ No newline at end of file diff --git a/rules/ah.json b/rules/ah.json new file mode 100644 index 0000000..7fa6693 --- /dev/null +++ b/rules/ah.json @@ -0,0 +1,74 @@ +[ + { + "id": "AH-IE11-Feature-Disabled", + "title": "Internet Explorer 11 feature is disabled/removed (skip on Win11)", + "strategy": "AH", + "type": "scriptblock", + "script": "$f=Get-WindowsOptionalFeature -Online -FeatureName Internet-Explorer-Optional-amd64 -ErrorAction SilentlyContinue; if($null -eq $f){ return $null }; $f.State -in @('Disabled','Removed')", + "minLevel": "ML1" + }, + { + "id": "AH-Java-Plugin-Absent", + "title": "Legacy Java browser plugin not present", + "strategy": "AH", + "type": "scriptblock", + "script": "if( (Test-Path 'HKLM:\\SOFTWARE\\JavaSoft\\Java Plug-in') -or (Test-Path 'HKLM:\\SOFTWARE\\Oracle\\JavaDeploy\\WebDeployJava') ){ return $false } else { return $true }", + "minLevel": "ML1" + }, + { + "id": "AH-Edge-SmartScreen", + "title": "Microsoft Edge SmartScreen enabled via policy", + "strategy": "AH", + "type": "scriptblock", + "script": "$edge=@('C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe','C:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe') | Where-Object {Test-Path $_}; if(-not $edge){ return $null }; $keys=@('HKLM:\\SOFTWARE\\Policies\\Microsoft\\Edge','HKCU:\\SOFTWARE\\Policies\\Microsoft\\Edge','HKLM:\\SOFTWARE\\Microsoft\\PolicyManager\\current\\device\\Browser'); foreach($k in $keys){ if(Test-Path $k){ try{ $val=(Get-ItemProperty -Path $k -ErrorAction Stop).SmartScreenEnabled; if($null -ne $val -and [int]$val -ge 1){ return $true } } catch{} } } $false", + "minLevel": "ML1" + }, + { + "id": "AH-Edge-DownloadRestrictions", + "title": "Edge download restrictions present", + "strategy": "AH", + "type": "scriptblock", + "script": "$edge=@('C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe','C:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe') | Where-Object {Test-Path $_}; if(-not $edge){ return $null }; foreach($k in @('HKLM:\\SOFTWARE\\Policies\\Microsoft\\Edge','HKCU:\\SOFTWARE\\Policies\\Microsoft\\Edge')){ if(Test-Path $k){ $v=(Get-ItemProperty -Path $k -ErrorAction SilentlyContinue).DownloadRestrictions; if($null -ne $v -and [int]$v -ge 1){ return $true } } } $false", + "minLevel": "ML1" + }, + { + "id": "AH-Chrome-SafeBrowsing", + "title": "Chrome SafeBrowsing policy configured", + "strategy": "AH", + "type": "scriptblock", + "script": "$chrome=@('C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe','C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe') | Where-Object {Test-Path $_}; if(-not $chrome){ return $null }; foreach($k in @('HKLM:\\SOFTWARE\\Policies\\Google\\Chrome','HKCU:\\SOFTWARE\\Policies\\Google\\Chrome')){ if(Test-Path $k){ $v=(Get-ItemProperty -Path $k -ErrorAction SilentlyContinue).SafeBrowsingProtectionLevel; if($null -ne $v -and [int]$v -ge 1){ return $true } } } $false", + "minLevel": "ML1" + }, + { + "id": "AH-Chrome-DownloadRestrictions", + "title": "Chrome download restrictions present", + "strategy": "AH", + "type": "scriptblock", + "script": "$chrome=@('C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe','C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe') | Where-Object {Test-Path $_}; if(-not $chrome){ return $null }; foreach($k in @('HKLM:\\SOFTWARE\\Policies\\Google\\Chrome','HKCU:\\SOFTWARE\\Policies\\Google\\Chrome')){ if(Test-Path $k){ $v=(Get-ItemProperty -Path $k -ErrorAction SilentlyContinue).DownloadRestrictions; if($null -ne $v -and [int]$v -ge 1){ return $true } } } $false", + "minLevel": "ML1" + }, + { + "id": "AH-Chrome-Ext-Blocklist", + "title": "Chrome extension install blocklist configured", + "strategy": "AH", + "type": "scriptblock", + "script": "if(-not (Test-Path 'HKLM:\\SOFTWARE\\Policies\\Google\\Chrome') -and -not (Test-Path 'HKCU:\\SOFTWARE\\Policies\\Google\\Chrome')){ return $null } $k='HKLM:\\SOFTWARE\\Policies\\Google\\Chrome\\ExtensionInstallBlocklist'; $k2='HKCU:\\SOFTWARE\\Policies\\Google\\Chrome\\ExtensionInstallBlocklist'; if(Test-Path $k -or Test-Path $k2){ return $true } $false", + "minLevel": "ML1" + }, + { + "id": "AH-Firefox-PolicyKey", + "title": "Firefox enterprise policies present", + "strategy": "AH", + "type": "scriptblock", + "script": "$ff=@('C:\\Program Files\\Mozilla Firefox\\firefox.exe','C:\\Program Files (x86)\\Mozilla Firefox\\firefox.exe') | Where-Object {Test-Path $_}; if(-not $ff){ return $null }; if( (Test-Path 'HKLM:\\SOFTWARE\\Policies\\Mozilla\\Firefox') -or (Test-Path 'HKCU:\\SOFTWARE\\Policies\\Mozilla\\Firefox') ){ return $true } else { return $false }", + "minLevel": "ML1" + }, + { + "id": "AH-Windows-SmartScreen", + "title": "Windows SmartScreen enabled by policy", + "strategy": "AH", + "type": "scriptblock", + "script": "$paths=@('HKLM:\\SOFTWARE\\Policies\\Microsoft\\Windows\\System','HKCU:\\SOFTWARE\\Policies\\Microsoft\\Windows\\System','HKLM:\\SOFTWARE\\Policies\\Microsoft\\Windows\\Explorer','HKCU:\\SOFTWARE\\Policies\\Microsoft\\Windows\\Explorer'); foreach($p in $paths){ if(Test-Path $p){ $prop=Get-ItemProperty -Path $p -ErrorAction SilentlyContinue; if($null -ne $prop.EnableSmartScreen -and [int]$prop.EnableSmartScreen -eq 1){ return $true }; if($null -ne $prop.SmartScreenEnabled -and [int]$prop.SmartScreenEnabled -ge 1){ return $true } } } $false", + "minLevel": "ML1" + } +] \ No newline at end of file diff --git a/rules/ra.json b/rules/ra.json new file mode 100644 index 0000000..f4edc72 --- /dev/null +++ b/rules/ra.json @@ -0,0 +1,26 @@ +[ + { + "id": "RA-Local-Administrator-Disabled", + "title": "Built-in Administrator account is disabled", + "strategy": "RA", + "type": "scriptblock", + "script": "$u=Get-LocalUser -Name 'Administrator' -ErrorAction SilentlyContinue; if($null -eq $u){ return $true }; return (-not $u.Enabled)", + "minLevel": "ML1" + }, + { + "id": "RA-UAC-Enabled", + "title": "User Account Control (EnableLUA) enabled", + "strategy": "RA", + "type": "scriptblock", + "script": "try { $v=(Get-ItemProperty -Path 'HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System' -ErrorAction Stop).EnableLUA; if($null -ne $v -and [int]$v -eq 1){ return $true } else { return $false } } catch { return $false }", + "minLevel": "ML1" + }, + { + "id": "RA-LAPS-PolicyPresent", + "title": "Windows LAPS (or legacy LAPS) policy present", + "strategy": "RA", + "type": "scriptblock", + "script": "if( (Test-Path 'HKLM:\\SOFTWARE\\Policies\\Microsoft\\Windows\\LAPS') -or (Test-Path 'HKLM:\\SOFTWARE\\Policies\\Microsoft Services\\AdmPwd') ){ return $true } else { return $false }", + "minLevel": "ML1" + } +] \ No newline at end of file diff --git a/rules/rm.json b/rules/rm.json new file mode 100644 index 0000000..42e39d6 --- /dev/null +++ b/rules/rm.json @@ -0,0 +1,162 @@ +[ + { + "id": "RM-01-VBAWarnings-Word-160", + "title": "Word macros disabled by policy (VBAWarnings=4) Office 16.0", + "strategy": "RM", + "type": "scriptblock", + "script": "$paths=@('HKLM:\\SOFTWARE\\Policies\\Microsoft\\Office\\16.0\\Word\\Security','HKCU:\\SOFTWARE\\Policies\\Microsoft\\Office\\16.0\\Word\\Security'); foreach($p in $paths){} foreach($p in $paths){ if(Test-Path $p){ $v=(Get-ItemProperty -Path $p -ErrorAction SilentlyContinue).VBAWarnings; if($null -ne $v -and [int]$v -eq 4){ return $true } } } $false", + "minLevel": "ML1" + }, + { + "id": "RM-02-BlockInternet-Word-160", + "title": "Word: block macros from Internet (blockcontentexecutionfrominternet=1) Office 16.0", + "strategy": "RM", + "type": "scriptblock", + "script": "$paths=@('HKLM:\\SOFTWARE\\Policies\\Microsoft\\Office\\16.0\\Word\\Security','HKCU:\\SOFTWARE\\Policies\\Microsoft\\Office\\16.0\\Word\\Security'); foreach($p in $paths){ if(Test-Path $p){ $v=(Get-ItemProperty -Path $p -ErrorAction SilentlyContinue).blockcontentexecutionfrominternet; if($null -ne $v -and [int]$v -eq 1){ return $true } } } $false", + "minLevel": "ML1" + }, + { + "id": "RM-01-VBAWarnings-Excel-160", + "title": "Excel macros disabled by policy (VBAWarnings=4) Office 16.0", + "strategy": "RM", + "type": "scriptblock", + "script": "$paths=@('HKLM:\\SOFTWARE\\Policies\\Microsoft\\Office\\16.0\\Excel\\Security','HKCU:\\SOFTWARE\\Policies\\Microsoft\\Office\\16.0\\Excel\\Security'); foreach($p in $paths){} foreach($p in $paths){ if(Test-Path $p){ $v=(Get-ItemProperty -Path $p -ErrorAction SilentlyContinue).VBAWarnings; if($null -ne $v -and [int]$v -eq 4){ return $true } } } $false", + "minLevel": "ML1" + }, + { + "id": "RM-02-BlockInternet-Excel-160", + "title": "Excel: block macros from Internet (blockcontentexecutionfrominternet=1) Office 16.0", + "strategy": "RM", + "type": "scriptblock", + "script": "$paths=@('HKLM:\\SOFTWARE\\Policies\\Microsoft\\Office\\16.0\\Excel\\Security','HKCU:\\SOFTWARE\\Policies\\Microsoft\\Office\\16.0\\Excel\\Security'); foreach($p in $paths){ if(Test-Path $p){ $v=(Get-ItemProperty -Path $p -ErrorAction SilentlyContinue).blockcontentexecutionfrominternet; if($null -ne $v -and [int]$v -eq 1){ return $true } } } $false", + "minLevel": "ML1" + }, + { + "id": "RM-01-VBAWarnings-PowerPoint-160", + "title": "PowerPoint macros disabled by policy (VBAWarnings=4) Office 16.0", + "strategy": "RM", + "type": "scriptblock", + "script": "$paths=@('HKLM:\\SOFTWARE\\Policies\\Microsoft\\Office\\16.0\\PowerPoint\\Security','HKCU:\\SOFTWARE\\Policies\\Microsoft\\Office\\16.0\\PowerPoint\\Security'); foreach($p in $paths){} foreach($p in $paths){ if(Test-Path $p){ $v=(Get-ItemProperty -Path $p -ErrorAction SilentlyContinue).VBAWarnings; if($null -ne $v -and [int]$v -eq 4){ return $true } } } $false", + "minLevel": "ML1" + }, + { + "id": "RM-02-BlockInternet-PowerPoint-160", + "title": "PowerPoint: block macros from Internet (blockcontentexecutionfrominternet=1) Office 16.0", + "strategy": "RM", + "type": "scriptblock", + "script": "$paths=@('HKLM:\\SOFTWARE\\Policies\\Microsoft\\Office\\16.0\\PowerPoint\\Security','HKCU:\\SOFTWARE\\Policies\\Microsoft\\Office\\16.0\\PowerPoint\\Security'); foreach($p in $paths){ if(Test-Path $p){ $v=(Get-ItemProperty -Path $p -ErrorAction SilentlyContinue).blockcontentexecutionfrominternet; if($null -ne $v -and [int]$v -eq 1){ return $true } } } $false", + "minLevel": "ML1" + }, + { + "id": "RM-01-VBAWarnings-Outlook-160", + "title": "Outlook macros disabled by policy (VBAWarnings=4) Office 16.0", + "strategy": "RM", + "type": "scriptblock", + "script": "$paths=@('HKLM:\\SOFTWARE\\Policies\\Microsoft\\Office\\16.0\\Outlook\\Security','HKCU:\\SOFTWARE\\Policies\\Microsoft\\Office\\16.0\\Outlook\\Security'); foreach($p in $paths){} foreach($p in $paths){ if(Test-Path $p){ $v=(Get-ItemProperty -Path $p -ErrorAction SilentlyContinue).VBAWarnings; if($null -ne $v -and [int]$v -eq 4){ return $true } } } $false", + "minLevel": "ML1" + }, + { + "id": "RM-02-BlockInternet-Outlook-160", + "title": "Outlook: block macros from Internet (blockcontentexecutionfrominternet=1) Office 16.0", + "strategy": "RM", + "type": "scriptblock", + "script": "$paths=@('HKLM:\\SOFTWARE\\Policies\\Microsoft\\Office\\16.0\\Outlook\\Security','HKCU:\\SOFTWARE\\Policies\\Microsoft\\Office\\16.0\\Outlook\\Security'); foreach($p in $paths){ if(Test-Path $p){ $v=(Get-ItemProperty -Path $p -ErrorAction SilentlyContinue).blockcontentexecutionfrominternet; if($null -ne $v -and [int]$v -eq 1){ return $true } } } $false", + "minLevel": "ML1" + }, + { + "id": "RM-01-VBAWarnings-Word-150", + "title": "Word macros disabled by policy (VBAWarnings=4) Office 15.0", + "strategy": "RM", + "type": "scriptblock", + "script": "$paths=@('HKLM:\\SOFTWARE\\Policies\\Microsoft\\Office\\15.0\\Word\\Security','HKCU:\\SOFTWARE\\Policies\\Microsoft\\Office\\15.0\\Word\\Security'); foreach($p in $paths){} foreach($p in $paths){ if(Test-Path $p){ $v=(Get-ItemProperty -Path $p -ErrorAction SilentlyContinue).VBAWarnings; if($null -ne $v -and [int]$v -eq 4){ return $true } } } $false", + "minLevel": "ML1" + }, + { + "id": "RM-02-BlockInternet-Word-150", + "title": "Word: block macros from Internet (blockcontentexecutionfrominternet=1) Office 15.0", + "strategy": "RM", + "type": "scriptblock", + "script": "$paths=@('HKLM:\\SOFTWARE\\Policies\\Microsoft\\Office\\15.0\\Word\\Security','HKCU:\\SOFTWARE\\Policies\\Microsoft\\Office\\15.0\\Word\\Security'); foreach($p in $paths){ if(Test-Path $p){ $v=(Get-ItemProperty -Path $p -ErrorAction SilentlyContinue).blockcontentexecutionfrominternet; if($null -ne $v -and [int]$v -eq 1){ return $true } } } $false", + "minLevel": "ML1" + }, + { + "id": "RM-01-VBAWarnings-Excel-150", + "title": "Excel macros disabled by policy (VBAWarnings=4) Office 15.0", + "strategy": "RM", + "type": "scriptblock", + "script": "$paths=@('HKLM:\\SOFTWARE\\Policies\\Microsoft\\Office\\15.0\\Excel\\Security','HKCU:\\SOFTWARE\\Policies\\Microsoft\\Office\\15.0\\Excel\\Security'); foreach($p in $paths){} foreach($p in $paths){ if(Test-Path $p){ $v=(Get-ItemProperty -Path $p -ErrorAction SilentlyContinue).VBAWarnings; if($null -ne $v -and [int]$v -eq 4){ return $true } } } $false", + "minLevel": "ML1" + }, + { + "id": "RM-02-BlockInternet-Excel-150", + "title": "Excel: block macros from Internet (blockcontentexecutionfrominternet=1) Office 15.0", + "strategy": "RM", + "type": "scriptblock", + "script": "$paths=@('HKLM:\\SOFTWARE\\Policies\\Microsoft\\Office\\15.0\\Excel\\Security','HKCU:\\SOFTWARE\\Policies\\Microsoft\\Office\\15.0\\Excel\\Security'); foreach($p in $paths){ if(Test-Path $p){ $v=(Get-ItemProperty -Path $p -ErrorAction SilentlyContinue).blockcontentexecutionfrominternet; if($null -ne $v -and [int]$v -eq 1){ return $true } } } $false", + "minLevel": "ML1" + }, + { + "id": "RM-01-VBAWarnings-PowerPoint-150", + "title": "PowerPoint macros disabled by policy (VBAWarnings=4) Office 15.0", + "strategy": "RM", + "type": "scriptblock", + "script": "$paths=@('HKLM:\\SOFTWARE\\Policies\\Microsoft\\Office\\15.0\\PowerPoint\\Security','HKCU:\\SOFTWARE\\Policies\\Microsoft\\Office\\15.0\\PowerPoint\\Security'); foreach($p in $paths){} foreach($p in $paths){ if(Test-Path $p){ $v=(Get-ItemProperty -Path $p -ErrorAction SilentlyContinue).VBAWarnings; if($null -ne $v -and [int]$v -eq 4){ return $true } } } $false", + "minLevel": "ML1" + }, + { + "id": "RM-02-BlockInternet-PowerPoint-150", + "title": "PowerPoint: block macros from Internet (blockcontentexecutionfrominternet=1) Office 15.0", + "strategy": "RM", + "type": "scriptblock", + "script": "$paths=@('HKLM:\\SOFTWARE\\Policies\\Microsoft\\Office\\15.0\\PowerPoint\\Security','HKCU:\\SOFTWARE\\Policies\\Microsoft\\Office\\15.0\\PowerPoint\\Security'); foreach($p in $paths){ if(Test-Path $p){ $v=(Get-ItemProperty -Path $p -ErrorAction SilentlyContinue).blockcontentexecutionfrominternet; if($null -ne $v -and [int]$v -eq 1){ return $true } } } $false", + "minLevel": "ML1" + }, + { + "id": "RM-01-VBAWarnings-Outlook-150", + "title": "Outlook macros disabled by policy (VBAWarnings=4) Office 15.0", + "strategy": "RM", + "type": "scriptblock", + "script": "$paths=@('HKLM:\\SOFTWARE\\Policies\\Microsoft\\Office\\15.0\\Outlook\\Security','HKCU:\\SOFTWARE\\Policies\\Microsoft\\Office\\15.0\\Outlook\\Security'); foreach($p in $paths){} foreach($p in $paths){ if(Test-Path $p){ $v=(Get-ItemProperty -Path $p -ErrorAction SilentlyContinue).VBAWarnings; if($null -ne $v -and [int]$v -eq 4){ return $true } } } $false", + "minLevel": "ML1" + }, + { + "id": "RM-02-BlockInternet-Outlook-150", + "title": "Outlook: block macros from Internet (blockcontentexecutionfrominternet=1) Office 15.0", + "strategy": "RM", + "type": "scriptblock", + "script": "$paths=@('HKLM:\\SOFTWARE\\Policies\\Microsoft\\Office\\15.0\\Outlook\\Security','HKCU:\\SOFTWARE\\Policies\\Microsoft\\Office\\15.0\\Outlook\\Security'); foreach($p in $paths){ if(Test-Path $p){ $v=(Get-ItemProperty -Path $p -ErrorAction SilentlyContinue).blockcontentexecutionfrominternet; if($null -ne $v -and [int]$v -eq 1){ return $true } } } $false", + "minLevel": "ML1" + }, + { + "id": "RM-03-MacroRuntimeScan-160", + "title": "Macro runtime AV scanning configured (Office 16.0 common security)", + "strategy": "RM", + "type": "scriptblock", + "script": "$paths=@('HKLM:\\SOFTWARE\\Policies\\Microsoft\\Office\\16.0\\Common\\Security','HKCU:\\SOFTWARE\\Policies\\Microsoft\\Office\\16.0\\Common\\Security'); foreach($p in $paths){ if(Test-Path $p){ $v=(Get-ItemProperty -Path $p -ErrorAction SilentlyContinue).MacroRuntimeScanScope; if($null -ne $v -and @('1','2') -contains ([string]$v)){ return $true } } } $false", + "minLevel": "ML1" + }, + { + "id": "RM-03-MacroRuntimeScan-150", + "title": "Macro runtime AV scanning configured (Office 15.0 common security)", + "strategy": "RM", + "type": "scriptblock", + "script": "$paths=@('HKLM:\\SOFTWARE\\Policies\\Microsoft\\Office\\15.0\\Common\\Security','HKCU:\\SOFTWARE\\Policies\\Microsoft\\Office\\15.0\\Common\\Security'); foreach($p in $paths){ if(Test-Path $p){ $v=(Get-ItemProperty -Path $p -ErrorAction SilentlyContinue).MacroRuntimeScanScope; if($null -ne $v -and @('1','2') -contains ([string]$v)){ return $true } } } $false", + "minLevel": "ML1" + }, + { + "id": "RM-TRUSTED-PUBLISHERS-160", + "title": "Trusted Publishers enforcement present (Office 16.0)", + "strategy": "RM", + "type": "scriptblock", + "script": "$p='HKLM:\\SOFTWARE\\Policies\\Microsoft\\Office\\16.0\\Common\\Security'; if(Test-Path $p){ $v=(Get-ItemProperty -Path $p -ErrorAction SilentlyContinue).TrustedPublisher; if($null -ne $v -and [int]$v -eq 1){ return $true } } $false", + "minLevel": "ML3" + }, + { + "id": "RM-TRUSTED-PUBLISHERS-150", + "title": "Trusted Publishers enforcement present (Office 15.0)", + "strategy": "RM", + "type": "scriptblock", + "script": "$p='HKLM:\\SOFTWARE\\Policies\\Microsoft\\Office\\15.0\\Common\\Security'; if(Test-Path $p){ $v=(Get-ItemProperty -Path $p -ErrorAction SilentlyContinue).TrustedPublisher; if($null -ne $v -and [int]$v -eq 1){ return $true } } $false", + "minLevel": "ML3" + } +] \ No newline at end of file