Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion powershell/Maester.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,8 @@
'Test-MtEntraIDConnectSyncSoftHardMatching', 'Test-MtKrbtgtAzureADNotSynced', 'Test-MtExoDelicensingResiliency',
'Test-MtExoMailTip', 'Test-MtExoModernAuth', 'Test-MtExoMoeraMailActivity', 'Test-MtExoOutlookAddin',
'Test-MtExoRejectDirectSend', 'Test-MtExoSetScl', 'Test-MtFeatureUpdatePolicy', 'Test-MtGroupCreationRestricted',
'Test-MtHighRiskAppPermissions', 'Test-MtIntuneDiagnosticSettings', 'Test-MtIntuneRbacGroupsProtected',
'Test-MtHighRiskAppPermissions', 'Test-MtIntuneAppControl', 'Test-MtIntuneASRRules', 'Test-MtIntuneDiagnosticSettings',
'Test-MtIntuneLAPSConfiguration', 'Test-MtIntuneManagedInstallerRules', 'Test-MtIntuneRbacGroupsProtected',
'Test-MtLimitOnMicrosoftDomainUsage', 'Test-MtManagedDeviceCleanupSettings', 'Test-MtManagementGroupWriteRequirement',
'Test-MtMdmAuthority', 'Test-MtMobileThreatDefenseConnectors', 'Test-MtMdeArchiveScanning',
'Test-MtMdeBehaviorMonitoring', 'Test-MtMdeCatchupFullScan', 'Test-MtMdeCatchupQuickScan',
Expand Down
65 changes: 65 additions & 0 deletions powershell/public/maester/intune/Test-MtIntuneASRRules.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
Ensure at least one Intune Attack Surface Reduction (ASR) policy has rules configured in **Block** or **Audit** mode.

ASR rules reduce the attack surface of applications by preventing behaviors commonly abused by malware and threat actors. These rules target specific techniques such as:

- **Office macros** spawning child processes or injecting code into other processes
- **Credential theft** from LSASS (Local Security Authority Subsystem Service)
- **Script-based attacks** using obfuscated JavaScript, VBScript, or PowerShell
- **Email-borne threats** executing content from Outlook or webmail
- **Ransomware** advanced protection heuristics
- **USB-based attacks** running untrusted unsigned processes
- **Persistence** through WMI event subscriptions

Each ASR rule can operate in one of four modes:

- **Block**: Actively prevents the behavior (recommended for production after testing)
- **Audit**: Logs the event without blocking (recommended for initial rollout)
- **Warn**: Warns the user before allowing the behavior to proceed
- **Disabled**: Rule is not active

The test passes if **every rule in the Microsoft Defender ASR Standard Protection baseline** is configured in **Block** or **Audit** mode across the union of all ASR policies in the tenant. The Standard Protection baseline is the minimum recommended set Microsoft publishes for initial ASR deployment:

1. Block abuse of exploited vulnerable signed drivers
2. Block credential stealing from LSASS
3. Block persistence through WMI event subscription

See the [Microsoft Defender ASR rules deployment guide](https://learn.microsoft.com/microsoft-365/security/defender-endpoint/attack-surface-reduction-rules-deployment-implement) for the canonical baseline definition.

Additional ASR rules detected in tenant policies are reported for visibility but do not affect the pass/fail result. **Warn** is a supported ASR rule state but does not satisfy the baseline. Baseline rules in **Audit** mode will trigger an informational note recommending a transition to **Block** mode.

#### Remediation action:

1. Navigate to [Microsoft Intune admin center](https://intune.microsoft.com).
2. Go to **Endpoint security** > **Attack surface reduction**.
3. Click **+ Create policy**.
4. Set **Platform** to **Windows 10 and later** and **Profile** to **Attack Surface Reduction Rules**.
5. Enter a policy name (e.g., "ASR Rules - Audit Mode").
6. Configure individual ASR rules — start with **Audit** mode for all rules:
- Block abuse of exploited vulnerable signed drivers
- Block Adobe Reader from creating child processes
- Block all Office applications from creating child processes
- Block credential stealing from Windows LSASS
- Block executable content from email client and webmail
- Block executable files unless they meet prevalence, age, or trusted list criteria
- Block execution of potentially obfuscated scripts
- Block JavaScript or VBScript from launching downloaded executable content
- Block Office applications from creating executable content
- Block Office applications from injecting code into other processes
- Block Office communication app from creating child processes
- Block persistence through WMI event subscription
- Block process creations originating from PSExec and WMI commands
- Block untrusted and unsigned processes that run from USB
- Block Win32 API calls from Office macros
- Use advanced protection against ransomware
7. Assign the policy to your device groups and click **Create**.
8. Monitor audit events in **Microsoft Defender for Endpoint** > **Reports** > **Attack surface reduction rules** for 2–4 weeks before transitioning rules to **Block** mode.

#### Related links

- [Microsoft Intune - Attack Surface Reduction](https://intune.microsoft.com/#view/Microsoft_Intune_Workflows/SecurityManagementMenu/~/asr)
- [Microsoft Learn - ASR rules reference](https://learn.microsoft.com/en-us/microsoft-365/security/defender-endpoint/attack-surface-reduction-rules-reference)
- [Microsoft Learn - Enable ASR rules in Intune](https://learn.microsoft.com/en-us/microsoft-365/security/defender-endpoint/enable-attack-surface-reduction)
- [Microsoft Learn - ASR rules deployment guide](https://learn.microsoft.com/en-us/microsoft-365/security/defender-endpoint/attack-surface-reduction-rules-deployment)

<!--- Results --->
%TestResult%
228 changes: 228 additions & 0 deletions powershell/public/maester/intune/Test-MtIntuneASRRules.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
function Test-MtIntuneASRRules {
<#
.SYNOPSIS
Ensure the Microsoft Defender ASR Standard Protection baseline rules are configured in Block or Audit mode.

.DESCRIPTION
Checks Intune Endpoint Security Attack Surface Reduction policies (configurationPolicies API) for
ASR rule configurations.

ASR rules reduce the attack surface of applications by preventing behaviors commonly abused by malware,
such as Office macros spawning child processes, credential theft from LSASS, or execution of obfuscated scripts.

Each ASR rule can be set to one of four modes:
- Block: Actively prevents the behavior (recommended for production)
- Audit: Logs the event without blocking (recommended for testing)
- Warn: Warns the user before allowing the behavior
- Disabled/Not configured: Rule is inactive

Pass criteria:
The test passes if every rule in the Microsoft Defender for Endpoint ASR Standard Protection baseline is
configured in Block or Audit mode in at least one ASR policy. The Standard Protection baseline is the
minimum recommended set Microsoft publishes for initial ASR deployment:

1. Block abuse of exploited vulnerable signed drivers
2. Block credential stealing from LSASS
3. Block persistence through WMI event subscription

See https://learn.microsoft.com/microsoft-365/security/defender-endpoint/attack-surface-reduction-rules-deployment-implement

Additional ASR rules detected in tenant policies are reported for visibility but do not affect the pass/fail result.

.EXAMPLE
Test-MtIntuneASRRules

Returns true if every Standard Protection baseline rule is configured in Block or Audit mode across the union of all ASR policies in the tenant.

.LINK
https://maester.dev/docs/commands/Test-MtIntuneASRRules
#>
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '', Justification = 'ASR Rules is the official Microsoft product name')]
[CmdletBinding()]
[OutputType([bool])]
param()

if (!(Test-MtConnection Graph)) {
Add-MtTestResultDetail -SkippedBecause NotConnectedGraph
return $null
}

if (-not (Get-MtLicenseInformation -Product Intune)) {
Add-MtTestResultDetail -SkippedBecause NotLicensedIntune
return $null
}

try {
Write-Verbose "Querying Intune ASR policies..."
$asrPolicies = @(Invoke-MtGraphRequest -RelativeUri "deviceManagement/configurationPolicies?`$filter=templateReference/templateFamily eq 'endpointSecurityAttackSurfaceReduction'&`$select=id,name,description,templateReference" -ApiVersion beta)

Write-Verbose "Found $($asrPolicies.Count) ASR policies."

if ($asrPolicies.Count -eq 0) {
$testResultMarkdown = "No Endpoint Security Attack Surface Reduction policies found in Intune.`n`n"
$testResultMarkdown += "Create an ASR policy under **Endpoint Security > Attack Surface Reduction** with "
$testResultMarkdown += "ASR rules enabled in **Audit** or **Block** mode to protect against common attack techniques."
Add-MtTestResultDetail -Result $testResultMarkdown
return $false
}

# Friendly names for ASR rules (extracted from setting definition IDs)
$asrRuleNames = @{
'blockexecutionofpotentiallyobfuscatedscripts' = 'Block execution of potentially obfuscated scripts'
'blockwin32apicallsfromofficemacros' = 'Block Win32 API calls from Office macros'
'blockexecutablefilesrunningunlesstheymeetprevalenceagetrustedlistcriterion' = 'Block executable files unless they meet prevalence/age/trusted list criteria'
'blockofficecommunicationappfromcreatingchildprocesses' = 'Block Office communication app from creating child processes'
'blockallofficeapplicationsfromcreatingchildprocesses' = 'Block all Office applications from creating child processes'
'blockadobereaderfromcreatingchildprocesses' = 'Block Adobe Reader from creating child processes'
'blockcredentialstealingfromwindowslocalsecurityauthoritysubsystem' = 'Block credential stealing from LSASS'
'blockjavascriptorvbscriptfromlaunchingdownloadedexecutablecontent' = 'Block JavaScript/VBScript from launching downloaded executable content'
'blockuntrustedunsignedprocessesthatrunfromusb' = 'Block untrusted/unsigned processes from USB'
'blockpersistencethroughwmieventsubscription' = 'Block persistence through WMI event subscription'
'blockuseofcopiedorimpersonatedsystemtools' = 'Block use of copied or impersonated system tools'
'blockabuseofexploitedvulnerablesigneddrivers' = 'Block abuse of exploited vulnerable signed drivers'
'blockprocesscreationsfrompsexecandwmicommands' = 'Block process creations from PSExec and WMI commands'
'blockofficeapplicationsfromcreatingexecutablecontent' = 'Block Office applications from creating executable content'
'blockofficeapplicationsfrominjectingcodeintootherprocesses' = 'Block Office applications from injecting code into other processes'
'blockrebootingmachineinsafemode' = 'Block rebooting machine in Safe Mode'
'useadvancedprotectionagainstransomware' = 'Use advanced protection against ransomware'
'blockexecutablecontentfromemailclientandwebmail' = 'Block executable content from email client and webmail'
'blockwebshellcreationforservers' = 'Block webshell creation for servers'
}

# Microsoft Standard Protection baseline (minimum recommended ASR rules per Defender deployment guide).
# Pass requires every rule in this set to be Block or Audit across the union of all ASR policies.
$standardProtectionRuleSuffixes = @{
'blockabuseofexploitedvulnerablesigneddrivers' = 'Block abuse of exploited vulnerable signed drivers'
'blockcredentialstealingfromwindowslocalsecurityauthoritysubsystem' = 'Block credential stealing from LSASS'
'blockpersistencethroughwmieventsubscription' = 'Block persistence through WMI event subscription'
}

$policyResults = [System.Collections.Generic.List[hashtable]]::new()
# Track best mode seen across the union of all policies for each baseline rule.
# Priority: Block > Audit > Warn > Disabled > Not configured.
$baselineRuleStatus = @{}
foreach ($k in $standardProtectionRuleSuffixes.Keys) { $baselineRuleStatus[$k] = 'Not configured' }

$modeRank = @{ 'Block' = 4; 'Audit' = 3; 'Warn' = 2; 'Disabled' = 1; 'Not configured' = 0 }

foreach ($policy in $asrPolicies) {
Write-Verbose "Checking ASR policy: $($policy.name) ($($policy.id))"
$settingsUri = "deviceManagement/configurationPolicies('$($policy.id)')/settings?`$expand=settingDefinitions&`$top=1000"
$settingsResponse = @(Invoke-MtGraphRequest -RelativeUri $settingsUri -ApiVersion beta)

$blockCount = 0
$auditCount = 0
$warnCount = 0
$disabledCount = 0
$notConfiguredCount = 0
$ruleDetails = [System.Collections.Generic.List[hashtable]]::new()

foreach ($setting in $settingsResponse) {
$defId = $setting.settingInstance.settingDefinitionId
if ($defId -ne 'device_vendor_msft_policy_config_defender_attacksurfacereductionrules') { continue }

# ASR rules are stored in a groupSettingCollectionValue
foreach ($group in $setting.settingInstance.groupSettingCollectionValue) {
foreach ($child in $group.children) {
$childDefId = $child.settingDefinitionId
$val = $child.choiceSettingValue.value

# Extract rule name from definition ID
$ruleSuffix = $childDefId -replace '^device_vendor_msft_policy_config_defender_attacksurfacereductionrules_', ''
$friendlyName = if ($asrRuleNames.ContainsKey($ruleSuffix)) { $asrRuleNames[$ruleSuffix] } else { $ruleSuffix }

# Determine enforcement mode from value suffix
$mode = 'Not configured'
if ($val -like '*_block') { $mode = 'Block'; $blockCount++ }
elseif ($val -like '*_audit') { $mode = 'Audit'; $auditCount++ }
elseif ($val -like '*_warn') { $mode = 'Warn'; $warnCount++ }
elseif ($val -like '*_off') { $mode = 'Disabled'; $disabledCount++ }
else { $notConfiguredCount++ }

Write-Verbose " Rule: $friendlyName = $mode"
$ruleDetails.Add(@{ Name = $friendlyName; Mode = $mode; IsBaseline = $standardProtectionRuleSuffixes.ContainsKey($ruleSuffix) })

# Track best mode for baseline rules across all policies
if ($standardProtectionRuleSuffixes.ContainsKey($ruleSuffix)) {
$current = $baselineRuleStatus[$ruleSuffix]
if ($modeRank[$mode] -gt $modeRank[$current]) {
$baselineRuleStatus[$ruleSuffix] = $mode
}
}
}
}
}

$policyResults.Add(@{
Name = $policy.name
BlockCount = $blockCount
AuditCount = $auditCount
WarnCount = $warnCount
DisabledCount = $disabledCount
NotConfiguredCount = $notConfiguredCount
TotalRules = $ruleDetails.Count
Rules = $ruleDetails
})
}

# Evaluate baseline coverage across the union of all policies
$baselineMissing = @()
foreach ($k in $standardProtectionRuleSuffixes.Keys) {
$mode = $baselineRuleStatus[$k]
if ($mode -ne 'Block' -and $mode -ne 'Audit') {
$baselineMissing += [pscustomobject]@{ Name = $standardProtectionRuleSuffixes[$k]; Mode = $mode }
}
}
$baselinePassed = ($baselineMissing.Count -eq 0)

# Build result markdown
$testResultMarkdown = "Found $($asrPolicies.Count) Attack Surface Reduction policy/policies in Intune.`n`n"
$testResultMarkdown += "**Pass criteria:** Every rule in the Microsoft Defender ASR Standard Protection baseline must be configured in **Block** or **Audit** mode in at least one ASR policy.`n`n"

$testResultMarkdown += "### Standard Protection baseline coverage (across all policies)`n"
$testResultMarkdown += "| Baseline rule | Best mode found |`n| --- | --- |`n"
foreach ($k in $standardProtectionRuleSuffixes.Keys) {
$testResultMarkdown += "| $($standardProtectionRuleSuffixes[$k]) | $($baselineRuleStatus[$k]) |`n"
}
$testResultMarkdown += "`n"

foreach ($p in $policyResults) {
$testResultMarkdown += "### $($p.Name)`n"
$testResultMarkdown += "**$($p.TotalRules) rules:** $($p.BlockCount) Block, $($p.AuditCount) Audit, $($p.WarnCount) Warn, $($p.DisabledCount) Disabled, $($p.NotConfiguredCount) Not configured`n`n"
$testResultMarkdown += "| Rule | Mode | Baseline |`n| --- | --- | --- |`n"
foreach ($r in $p.Rules) {
$baselineMark = if ($r.IsBaseline) { 'Yes' } else { '' }
$testResultMarkdown += "| $($r.Name) | $($r.Mode) | $baselineMark |`n"
}
$testResultMarkdown += "`n"
}

if ($baselinePassed) {
$testResultMarkdown += "**Result:** Well done. Every rule in the Microsoft Defender ASR Standard Protection baseline is configured in **Block** or **Audit** mode."

# Warn about baseline rules that are still in Audit only across the tenant
$auditOnly = @($baselineRuleStatus.Keys | Where-Object { $baselineRuleStatus[$_] -eq 'Audit' })
if ($auditOnly.Count -gt 0) {
$testResultMarkdown += "`n`n> **Note:** $($auditOnly.Count) baseline rule(s) are only in **Audit** mode. "
$testResultMarkdown += "Once you have validated impact, transition them to **Block** mode for active protection."
}

Add-MtTestResultDetail -Result $testResultMarkdown
return $true
} else {
$missingTable = ($baselineMissing | ForEach-Object { "- $($_.Name) (current: $($_.Mode))" }) -join "`n"
$testResultMarkdown += "**Result:** The following Standard Protection baseline rules are not in Block or Audit mode:`n`n$missingTable`n`n"
$testResultMarkdown += "> **Risk:** The Microsoft Defender ASR Standard Protection baseline is the published minimum set of rules required to mitigate "
$testResultMarkdown += "common credential theft, driver abuse, and persistence techniques. Missing rules leave endpoints exposed to these well-known attack patterns."
Add-MtTestResultDetail -Result $testResultMarkdown
return $false
}
} catch {
if ($_.Exception.Response -and $_.Exception.Response.StatusCode -in @(401, 403)) {
Add-MtTestResultDetail -SkippedBecause NotAuthorized
} else {
Add-MtTestResultDetail -SkippedBecause Error -SkippedError $_
}
return $null
}
}
Loading
Loading