Skip to content

Commit dc0465a

Browse files
authored
SecOps - 41050 - Attack surface reduction (ASR) rules are enabled in block mode (#1489)
2 parents 54a7759 + 9cb522e commit dc0465a

2 files changed

Lines changed: 280 additions & 0 deletions

File tree

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
Attack surface reduction rules block the specific behaviors that commodity malware, fileless threats, and human-operated intrusion sets reuse across campaigns. Each rule targets a narrow, well-documented execution pattern such as document applications creating child processes, script interpreters launching downloaded content, unsigned binaries performing bulk file operations, or processes attempting to read credential stores. When the rules are not set to block mode, an adversary who delivers a payload to an endpoint can exercise these patterns freely because no preventive control intervenes at the behavior layer. Audit mode records the activity but does not stop it, which means the security operations team sees the evidence only after the damage is done. The risk compounds because ASR rules operate as a set: leaving even a small number of rules in audit or disabled state creates predictable gaps that an attacker can target, knowing that the specific behavior will not be blocked. If you are new to ASR, Microsoft recommends starting in audit mode to understand the impact in your environment before switching rules to block - audit mode is a starting point, not the end state.
2+
3+
**Remediation action**
4+
5+
- [Attack surface reduction rules deployment](https://learn.microsoft.com/en-us/defender-endpoint/attack-surface-reduction-rules-deployment?wt.mc_id=zerotrustrecommendations_automation_content_cnl_csasci)
6+
- [Plan attack surface reduction rules deployment](https://learn.microsoft.com/en-us/defender-endpoint/attack-surface-reduction-rules-deployment-plan?wt.mc_id=zerotrustrecommendations_automation_content_cnl_csasci)
7+
- [Test attack surface reduction rules](https://learn.microsoft.com/en-us/defender-endpoint/attack-surface-reduction-rules-deployment-test?wt.mc_id=zerotrustrecommendations_automation_content_cnl_csasci)
8+
- [Enable attack surface reduction rules](https://learn.microsoft.com/en-us/defender-endpoint/enable-attack-surface-reduction?wt.mc_id=zerotrustrecommendations_automation_content_cnl_csasci)
9+
- [Attack surface reduction rules reference](https://learn.microsoft.com/en-us/defender-endpoint/attack-surface-reduction-rules-reference?wt.mc_id=zerotrustrecommendations_automation_content_cnl_csasci)
10+
11+
<!--- Results --->
12+
%TestResult%
Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
<#
2+
.SYNOPSIS
3+
Attack surface reduction (ASR) rules are enabled in block mode.
4+
5+
.DESCRIPTION
6+
Attack surface reduction rules block high-risk behaviors commonly reused by malware and
7+
human-operated attacks. This check evaluates the pinned ASR Secure Score control set
8+
(scid_2500 through scid_2518) by joining control profiles to the latest Microsoft Secure Score
9+
snapshot and comparing each available score with its maximum score.
10+
11+
.NOTES
12+
Test ID: 41050
13+
Workshop Task ID: SECOPS-050
14+
Category: Endpoint threat protection
15+
Pillar: SecOps
16+
Required Module: Microsoft.Graph.Authentication
17+
Required Connection: Microsoft Graph
18+
#>
19+
20+
function Test-Assessment-41050 {
21+
[ZtTest(
22+
Category = 'Endpoint threat protection',
23+
CompatibleLicense = ('WINDEFATP'),
24+
ImplementationCost = 'Medium',
25+
Pillar = 'SecOps',
26+
RiskLevel = 'High',
27+
Service = ('Graph'),
28+
SfiPillar = 'Monitor and detect cyberthreats',
29+
TenantType = ('Workforce'),
30+
TestId = 41050,
31+
Title = 'Attack surface reduction (ASR) rules are enabled in block mode',
32+
UserImpact = 'Medium'
33+
)]
34+
[CmdletBinding()]
35+
param()
36+
37+
#region Data Collection
38+
Write-PSFMessage '🟦 Start' -Tag Test -Level VeryVerbose
39+
40+
$activity = 'Checking ASR block-mode controls in Microsoft Secure Score'
41+
42+
$asrControlIds = @(
43+
'scid_2500', 'scid_2501', 'scid_2502', 'scid_2503', 'scid_2504',
44+
'scid_2505', 'scid_2506', 'scid_2507', 'scid_2508', 'scid_2509',
45+
'scid_2510', 'scid_2511', 'scid_2512', 'scid_2513', 'scid_2514',
46+
'scid_2515', 'scid_2516', 'scid_2517', 'scid_2518'
47+
)
48+
49+
$controlProfileError = $null
50+
$secureScoreError = $null
51+
52+
# Q1: Read all MDATP Secure Score control profiles, then intersect client-side with pinned IDs.
53+
Write-ZtProgress -Activity $activity -Status 'Getting MDATP Secure Score control profiles'
54+
55+
$mdatpControlProfiles = @()
56+
try {
57+
$mdatpControlProfiles = @(Invoke-ZtGraphRequest -RelativeUri 'security/secureScoreControlProfiles' -Filter "service eq 'MDATP'" -ApiVersion beta -ErrorAction Stop)
58+
}
59+
catch {
60+
$controlProfileError = $_
61+
Write-PSFMessage "Failed to retrieve MDATP Secure Score control profiles: $_" -Tag Test -Level Warning
62+
}
63+
64+
# Q2: Read the latest Secure Score snapshot; -DisablePaging returns the wrapper object.
65+
Write-ZtProgress -Activity $activity -Status 'Getting latest Secure Score snapshot'
66+
67+
$latestSecureScore = $null
68+
try {
69+
$secureScoresResponse = Invoke-ZtGraphRequest -RelativeUri 'security/secureScores' -Top 1 -ApiVersion beta -DisablePaging -ErrorAction Stop
70+
$secureScores = @($secureScoresResponse.value)
71+
if ($secureScores.Count -gt 0) {
72+
$latestSecureScore = $secureScores[0]
73+
}
74+
}
75+
catch {
76+
$secureScoreError = $_
77+
Write-PSFMessage "Failed to retrieve latest Secure Score snapshot: $_" -Tag Test -Level Warning
78+
}
79+
#endregion Data Collection
80+
81+
#region Assessment Logic
82+
$passed = $false
83+
$customStatus = $null
84+
85+
foreach ($queryError in @($controlProfileError, $secureScoreError) | Where-Object { $null -ne $_ }) {
86+
if ((Get-ZtHttpStatusCode -ErrorRecord $queryError) -in (401, 403)) {
87+
$params = @{
88+
TestId = '41050'
89+
Title = 'Attack surface reduction (ASR) rules are enabled in block mode'
90+
Status = $false
91+
Result = '⚠️ Microsoft Graph returned HTTP 401 or 403. Verify SecurityEvents.Read.All is granted, Secure Score data is flowing, and at least one MDE device is onboarded.'
92+
CustomStatus = 'Investigate'
93+
}
94+
Add-ZtTestResultDetail @params
95+
return
96+
}
97+
}
98+
99+
$controlProfileById = @{}
100+
foreach ($controlProfile in @($mdatpControlProfiles | Where-Object { $asrControlIds -contains $_.id })) {
101+
if ($null -ne $controlProfile.id -and -not $controlProfileById.ContainsKey($controlProfile.id)) {
102+
$controlProfileById[$controlProfile.id] = $controlProfile
103+
}
104+
}
105+
106+
if ($controlProfileError -or $secureScoreError -or $null -eq $latestSecureScore -or $controlProfileById.Count -eq 0) {
107+
$params = @{
108+
TestId = '41050'
109+
Title = 'Attack surface reduction (ASR) rules are enabled in block mode'
110+
Status = $false
111+
Result = '⚠️ ASR Secure Score data was not found; verify SecurityEvents.Read.All is granted, Secure Score data is flowing, and at least one MDE device is onboarded.'
112+
CustomStatus = 'Investigate'
113+
}
114+
Add-ZtTestResultDetail @params
115+
return
116+
}
117+
118+
$controlScoreByName = @{}
119+
foreach ($controlScore in @($latestSecureScore.controlScores)) {
120+
if ($null -ne $controlScore.controlName -and -not $controlScoreByName.ContainsKey($controlScore.controlName)) {
121+
$controlScoreByName[$controlScore.controlName] = $controlScore
122+
}
123+
}
124+
125+
$evaluationResults = @()
126+
foreach ($controlId in $asrControlIds) {
127+
$controlProfile = if ($controlProfileById.ContainsKey($controlId)) { $controlProfileById[$controlId] } else { $null }
128+
$matchingScore = if ($controlScoreByName.ContainsKey($controlId)) { $controlScoreByName[$controlId] } else { $null }
129+
130+
$score = if ($null -ne $matchingScore -and $null -ne $matchingScore.score) { $matchingScore.score } else { $null }
131+
$maxScore = if ($null -ne $controlProfile -and $null -ne $controlProfile.maxScore) { $controlProfile.maxScore } else { $null }
132+
133+
$latestStateUpdate = @()
134+
if ($null -ne $controlProfile) {
135+
$latestStateUpdate = @($controlProfile.controlStateUpdates | Sort-Object { if ($_.updatedDateTime) { [datetime]$_.updatedDateTime } else { [datetime]::MinValue } } -Descending | Select-Object -First 1)
136+
}
137+
$isIgnored = $latestStateUpdate.Count -gt 0 -and $latestStateUpdate[0].state -eq 'ignored'
138+
139+
$scoreValue = $null
140+
$scoreIsNumeric = $false
141+
if ($null -ne $score) {
142+
try {
143+
$scoreValue = [double]$score
144+
$scoreIsNumeric = $true
145+
}
146+
catch { }
147+
}
148+
149+
$maxScoreValue = $null
150+
$maxScoreIsNumeric = $false
151+
if ($null -ne $maxScore) {
152+
try {
153+
$maxScoreValue = [double]$maxScore
154+
$maxScoreIsNumeric = $true
155+
}
156+
catch { }
157+
}
158+
159+
$status = if ($null -eq $controlProfile) {
160+
'Investigate'
161+
}
162+
elseif ($null -eq $matchingScore) {
163+
'N/A'
164+
}
165+
elseif ($isIgnored) {
166+
'Skipped'
167+
}
168+
elseif (-not $scoreIsNumeric -or -not $maxScoreIsNumeric) {
169+
'Investigate'
170+
}
171+
elseif ($scoreValue -ge $maxScoreValue) {
172+
'Pass'
173+
}
174+
else {
175+
'Fail'
176+
}
177+
178+
$ruleName = if ($null -ne $controlProfile -and -not [string]::IsNullOrWhiteSpace($controlProfile.title)) {
179+
$controlProfile.title
180+
}
181+
else {
182+
$controlId
183+
}
184+
185+
$evaluationResults += [PSCustomObject]@{
186+
AsrRuleId = $controlId
187+
AsrRuleName = $ruleName
188+
ActionUrl = if ($null -ne $controlProfile) { $controlProfile.actionUrl } else { $null }
189+
Score = if ($null -ne $score) { $score } else { 'N/A' }
190+
MaxScore = if ($null -ne $maxScore) { $maxScore } else { 'N/A' }
191+
ImplementationStatus = if ($null -ne $matchingScore -and -not [string]::IsNullOrWhiteSpace($matchingScore.implementationStatus)) { $matchingScore.implementationStatus } else { 'N/A' }
192+
LastModifiedDateTime = if ($null -ne $controlProfile) { $controlProfile.lastModifiedDateTime } else { $null }
193+
Status = $status
194+
}
195+
}
196+
197+
$failedItems = @($evaluationResults | Where-Object Status -eq 'Fail')
198+
$passedItems = @($evaluationResults | Where-Object Status -eq 'Pass')
199+
200+
if ($failedItems.Count -gt 0) {
201+
$testResultMarkdown = "❌ One or more attack surface reduction rules are in audit / disabled mode (below their target score).`n`n%TestResult%"
202+
}
203+
elseif ($passedItems.Count -gt 0) {
204+
$passed = $true
205+
$testResultMarkdown = "✅ All applicable attack surface reduction rules are deployed in block mode.`n`n%TestResult%"
206+
}
207+
else {
208+
$customStatus = 'Investigate'
209+
$testResultMarkdown = "⚠️ ASR Secure Score data was not found; verify SecurityEvents.Read.All is granted, Secure Score data is flowing, and at least one MDE device is onboarded.`n`n%TestResult%"
210+
}
211+
#endregion Assessment Logic
212+
213+
#region Report Generation
214+
$totalCount = $evaluationResults.Count
215+
$countLine = "Total ASR controls evaluated: $totalCount"
216+
$asrPoliciesLink = 'https://intune.microsoft.com/#view/Microsoft_Intune_Workflows/SecurityManagementMenu/~/asr'
217+
$asrDefenderLink = 'https://security.microsoft.com/asr'
218+
219+
$portalLinks = "[Microsoft Intune ASR Policies]($asrPoliciesLink) | [Defender XDR > Endpoints > Attack surface reduction]($asrDefenderLink)"
220+
221+
$tableRows = ''
222+
foreach ($result in $evaluationResults) {
223+
$statusDisplay = switch ($result.Status) {
224+
'Pass' { '✅ Pass' }
225+
'Fail' { '❌ Fail' }
226+
'Investigate' { '⚠️ Investigate' }
227+
'N/A' { 'N/A (no applicable devices)' }
228+
default { 'Skipped' }
229+
}
230+
$lastModified = if ($result.LastModifiedDateTime) { Get-FormattedDate -DateString $result.LastModifiedDateTime } else { 'N/A' }
231+
$safeRuleName = Get-SafeMarkdown -Text $result.AsrRuleName
232+
$ruleDisplay = if (-not [string]::IsNullOrWhiteSpace($result.ActionUrl)) {
233+
"[$safeRuleName]($($result.ActionUrl)) ($($result.AsrRuleId))"
234+
}
235+
elseif ($result.AsrRuleName -ne $result.AsrRuleId) {
236+
"$safeRuleName ($($result.AsrRuleId))"
237+
}
238+
else {
239+
$safeRuleName
240+
}
241+
$tableRows += "| $ruleDisplay | $($result.Score) | $($result.MaxScore) | $($result.ImplementationStatus) | $lastModified | $statusDisplay |`n"
242+
}
243+
244+
$mdInfo = @"
245+
$countLine
246+
247+
$portalLinks
248+
249+
| ASR rule (id) | Score | Max score | Implementation status | Last modified | Status |
250+
| :------------ | ----: | --------: | :-------------------- | :------------ | :----- |
251+
$tableRows
252+
"@
253+
254+
$testResultMarkdown = $testResultMarkdown -replace '%TestResult%', $mdInfo
255+
#endregion Report Generation
256+
257+
$params = @{
258+
TestId = '41050'
259+
Title = 'Attack surface reduction (ASR) rules are enabled in block mode'
260+
Status = $passed
261+
Result = $testResultMarkdown
262+
}
263+
if ($customStatus) {
264+
$params.CustomStatus = $customStatus
265+
}
266+
267+
Add-ZtTestResultDetail @params
268+
}

0 commit comments

Comments
 (0)