Detection rules › Kusto
NIST SP 800-53 Posture Changed
'This alert is desinged to monitor Azure policies aligned with the NIST SP 800-53 Regulatory Compliance initative. The alert triggers when policy compliance falls below 70% within a 1 week timeframe.'
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Discovery | T1082 System Information Discovery |
Rule body kusto
id: dd834c97-4638-4bb3-a4e3-807e8b0580dc
name: NIST SP 800-53 Posture Changed
description: |
'This alert is desinged to monitor Azure policies aligned with the NIST SP 800-53 Regulatory Compliance initative. The alert triggers when policy compliance falls below 70% within a 1 week timeframe.'
severity: Medium
status: Available
requiredDataConnectors: []
queryFrequency: 7d
queryPeriod: 7d
triggerOperator: gt
triggerThreshold: 0
tactics:
- Discovery
relevantTechniques:
- T1082
query:
let Last_Evaluated=SecurityRecommendation
| join kind=fullouter(SecurityRegulatoryCompliance| where ComplianceStandard == "NIST-SP-800-53-R4") on RecommendationName
| summarize arg_max(TimeGenerated, *) by AssessedResourceId, RecommendationName
| extend ComplianceDomain=iff(ComplianceControl contains "AC.", "Access Control", iff(ComplianceControl contains "AT.", "Security Awareness & Training", iff(ComplianceControl contains "AU.", "Audit & Accountability", iff(ComplianceControl contains "CA.", "Security Assessment", iff(ComplianceControl contains "CM.", "Configuration Management", iff(ComplianceControl contains "CP.", "Contingency Planning", iff(ComplianceControl contains "IA.", "Identification & Authentication", iff(ComplianceControl contains "IR.", "Incident Response", iff(ComplianceControl contains "MA.", "System Maintenance", iff(ComplianceControl contains "MP.", "Media Protection", iff(ComplianceControl contains "PE.", "Physical Protection", iff(ComplianceControl contains "PL.", "Security Planning", iff(ComplianceControl contains "PS.", "Personnel Security",iff(ComplianceControl contains "RA.", "Risk Assessment",iff(ComplianceControl contains "SA.", "System & Services Acquisition",iff(ComplianceControl contains "SC.", "System & Communications Protection",iff(ComplianceControl contains "SI.", "System & Information Integrity","Other")))))))))))))))))
| summarize Failed = countif(RecommendationState == "Unhealthy"), Passed = countif(RecommendationState == "Healthy"), Total = countif(RecommendationState == "Healthy" or RecommendationState == "Unhealthy") by ComplianceDomain, TimeGenerated;
SecurityRecommendation
| join kind=fullouter(SecurityRegulatoryCompliance| where ComplianceStandard == "NIST-SP-800-53-R4") on RecommendationName
| summarize arg_max(TimeGenerated, *) by AssessedResourceId, RecommendationName
| extend ComplianceDomain=iff(ComplianceControl contains "AC.", "Access Control", iff(ComplianceControl contains "AT.", "Security Awareness & Training", iff(ComplianceControl contains "AU.", "Audit & Accountability", iff(ComplianceControl contains "CA.", "Security Assessment", iff(ComplianceControl contains "CM.", "Configuration Management", iff(ComplianceControl contains "CP.", "Contingency Planning", iff(ComplianceControl contains "IA.", "Identification & Authentication", iff(ComplianceControl contains "IR.", "Incident Response", iff(ComplianceControl contains "MA.", "System Maintenance", iff(ComplianceControl contains "MP.", "Media Protection", iff(ComplianceControl contains "PE.", "Physical Protection", iff(ComplianceControl contains "PL.", "Security Planning", iff(ComplianceControl contains "PS.", "Personnel Security",iff(ComplianceControl contains "RA.", "Risk Assessment",iff(ComplianceControl contains "SA.", "System & Services Acquisition",iff(ComplianceControl contains "SC.", "System & Communications Protection",iff(ComplianceControl contains "SI.", "System & Information Integrity","Other")))))))))))))))))
| summarize Failed = countif(RecommendationState == "Unhealthy"), Passed = countif(RecommendationState == "Healthy"), Total = countif(RecommendationState == "Healthy" or RecommendationState == "Unhealthy") by ComplianceDomain
| extend PassedControlsPercentage = (Passed/todouble(Total))*100
| join (Last_Evaluated) on ComplianceDomain
| project ComplianceDomain, Total, PassedControlsPercentage, Passed, Failed, LastEvaluated=TimeGenerated
| summarize arg_max(LastEvaluated, *) by ComplianceDomain, Total, PassedControlsPercentage, Passed, Failed
| where PassedControlsPercentage < 70
| sort by PassedControlsPercentage, Passed desc
| extend RemediationLink = strcat('https://portal.azure.com/#blade/Microsoft_Azure_Security/SecurityMenuBlade/22')
| extend URLCustomEntity = RemediationLink
entityMappings:
- entityType: URL
fieldMappings:
- identifier: Url
columnName: URLCustomEntity
version: 1.0.0
kind: Scheduled
Stages and Predicates
Let binding: Last_Evaluated
let Last_Evaluated = SecurityRecommendation | join kind=fullouter(SecurityRegulatoryCompliance| where ComplianceStandard == "NIST-SP-800-53-R4") on RecommendationName | summarize arg_max(TimeGenerated, *) by AssessedResourceId, RecommendationName | extend ComplianceDomain=iff(ComplianceControl contains "AC.", "Access Control", iff(ComplianceControl contains "AT.", "Security Awareness & Training", iff(ComplianceControl contains "AU.", "Audit & Accountability", iff(ComplianceControl contains "CA.", "Security Assessment", iff(ComplianceControl contains "CM.", "Configuration Management", iff(ComplianceControl contains "CP.", "Contingency Planning", iff(ComplianceControl contains "IA.", "Identification & Authentication", iff(ComplianceControl contains "IR.", "Incident Response", iff(ComplianceControl contains "MA.", "System Maintenance", iff(ComplianceControl contains "MP.", "Media Protection", iff(ComplianceControl contains "PE.", "Physical Protection", iff(ComplianceControl contains "PL.", "Security Planning", iff(ComplianceControl contains "PS.", "Personnel Security",iff(ComplianceControl contains "RA.", "Risk Assessment",iff(ComplianceControl contains "SA.", "System & Services Acquisition",iff(ComplianceControl contains "SC.", "System & Communications Protection",iff(ComplianceControl contains "SI.", "System & Information Integrity","Other"))))))))))))))))) | summarize Failed = countif(RecommendationState == "Unhealthy"), Passed = countif(RecommendationState == "Healthy"), Total = countif(RecommendationState == "Healthy" or RecommendationState == "Unhealthy") by ComplianceDomain, TimeGenerated;
Stage 1: source
SecurityRecommendation
Stage 2: join
join kind=fullouter (...)
Stage 3: summarize
summarize by AssessedResourceId, RecommendationName
Stage 4: extend
extend ComplianceDomain
ComplianceDomain =ComplianceControl contains "AC.""Access Control"iff((ComplianceControl contains "AT."), "Security Awareness & Training", iff((ComplianceControl contains "AU."), "Audit & Accountability", iff((ComplianceControl contains "CA."), "Security Assessment", iff((ComplianceControl contains "CM."), "Configuration Management", iff((ComplianceControl contains "CP."), "Contingency Planning", iff((ComplianceControl contains "IA."), "Identification & Authentication", iff((ComplianceControl contains "IR."), "Incident Response", iff((ComplianceControl contains "MA."), "System Maintenance", iff((ComplianceControl contains "MP."), "Media Protection", iff((ComplianceControl contains "PE."), "Physical Protection", iff((ComplianceControl contains "PL."), "Security Planning", iff((ComplianceControl contains "PS."), "Personnel Security", iff((ComplianceControl contains "RA."), "Risk Assessment", iff((ComplianceControl contains "SA."), "System & Services Acquisition", iff((ComplianceControl contains "SC."), "System & Communications Protection", iff((ComplianceControl contains "SI."), "System & Information Integrity", "Other"))))))))))))))))Stage 5: summarize
summarize Failed, Passed, Total by ComplianceDomain
Stage 6: extend
extend PassedControlsPercentage
Stage 7: join
join (...)
Stage 8: project
project ComplianceDomain, Failed, LastEvaluated, Passed, PassedControlsPercentage, Total
Stage 9: summarize
summarize by ComplianceDomain, Total, PassedControlsPercentage, Passed, Failed
Stage 10: where
where PassedControlsPercentage < 70
Stage 11: sort
sort by Passed, PassedControlsPercentage
Stage 12: extend
extend RemediationLink
Stage 13: extend
extend URLCustomEntity
Indicators
Each row is a field, operator, and value that the rule matches. The corpus column counts how many other rules in the catalog look for the same combination: high numbers point to widely-used, community-vetted indicators. Blank or 1 shows that the indicator is specific to this rule.
| Field | Kind | Values |
|---|---|---|
ComplianceStandard | eq |
|
PassedControlsPercentage | lt |
|
Output fields
Fields the rule emits when it matches. Chronicle authors list these in the outcome block; they appear on the detection and $risk_score drives alerting. Sentinel / Defender XDR rules build them up through project / summarize / extend stages. Sentinel maps these into alert fields via entityMappings and customDetails; Defender XDR custom detections surface them as alert fields directly.
| Field | Source |
|---|---|
ComplianceDomain | summarize |
Failed | summarize |
Passed | summarize |
PassedControlsPercentage | summarize |
Total | summarize |
RemediationLink | extend |
URLCustomEntity | extend |