executing-plans
executing-plans
Use when executing an implementation plan in the current session as the implementer yourself — your human partner chose inline execution, or no subagent tool is available
detecting-azure-service-principal-abuse在 Microsoft Entra ID 环境中检测和调查 Azure 服务主体滥用,包括权限提升、凭据入侵、管理员同意绕过和未授权枚举。
Independent GitHub snapshot · Automated classification · Original documentation governs
Azure 服务主体是应用程序、服务和自动化工具用于访问 Azure 资源的身份对象。攻击者利用服务主体进行权限提升、横向移动和持久访问。关键滥用模式包括:向现有主体添加凭据、分配特权角色、绕过管理员同意以及枚举服务主体以寻找攻击路径。应用程序所有权授予管理凭据和配置权限的能力,从而产生隐藏的权限提升路径。
攻击者添加新的客户端密钥或证书以获得持久访问:
检测查询(KQL - Sentinel):
AuditLogs
| where OperationName has "Add service principal credentials"
or OperationName has "Update application - Certificates and secrets management"
| extend InitiatedBy = tostring(InitiatedBy.user.userPrincipalName)
| extend TargetSP = tostring(TargetResources[0].displayName)
| extend TargetSPId = tostring(TargetResources[0].id)
| project TimeGenerated, InitiatedBy, OperationName, TargetSP, TargetSPId
| sort by TimeGenerated desc
检测查询(SPL - Splunk):
index=azure sourcetype="azure:aad:audit"
operationName="Add service principal credentials"
OR operationName="Update application*Certificates and secrets*"
| stats count by initiatedBy.user.userPrincipalName, targetResources{}.displayName, _time
| sort -_time
AuditLogs
| where OperationName == "Add member to role"
| extend RoleName = tostring(TargetResources[0].modifiedProperties[1].newValue)
| where RoleName has_any ("Global Administrator", "Application Administrator",
"Privileged Role Administrator", "Cloud Application Administrator")
| extend TargetSP = tostring(TargetResources[0].displayName)
| extend InitiatedBy = tostring(InitiatedBy.user.userPrincipalName)
| project TimeGenerated, InitiatedBy, TargetSP, RoleName, OperationName
MicrosoftGraphActivityLogs
| where RequestMethod == "GET"
| where RequestUri has "/servicePrincipals"
| summarize RequestCount = count() by UserAgent, IPAddress, bin(TimeGenerated, 1h)
| where RequestCount > 10
| sort by RequestCount desc
AuditLogs
| where OperationName == "Consent to application"
| extend ConsentType = tostring(TargetResources[0].modifiedProperties[4].newValue)
| where ConsentType has "AllPrincipals"
| extend AppName = tostring(TargetResources[0].displayName)
| extend InitiatedBy = tostring(InitiatedBy.user.userPrincipalName)
| project TimeGenerated, InitiatedBy, AppName, ConsentType
AuditLogs
| where OperationName == "Add app role assignment to service principal"
| extend AppRoleValue = tostring(TargetResources[0].modifiedProperties[1].newValue)
| where AppRoleValue has_any ("RoleManagement.ReadWrite.Directory",
"Application.ReadWrite.All", "AppRoleAssignment.ReadWrite.All",
"Directory.ReadWrite.All", "Mail.ReadWrite")
| extend TargetApp = tostring(TargetResources[0].displayName)
| project TimeGenerated, TargetApp, AppRoleValue, CorrelationId
# 列出最近添加了凭据的服务主体
Connect-MgGraph -Scopes "Application.Read.All"
$suspiciousSPs = Get-MgServicePrincipal -All | ForEach-Object {
$sp = $_
$creds = Get-MgServicePrincipalPasswordCredential -ServicePrincipalId $sp.Id
$recentCreds = $creds | Where-Object { $_.StartDateTime -gt (Get-Date).AddDays(-7) }
if ($recentCreds) {
[PSCustomObject]@{
DisplayName = $sp.DisplayName
AppId = $sp.AppId
ObjectId = $sp.Id
NewCredsCount = $recentCreds.Count
LatestCredAdded = ($recentCreds | Sort-Object StartDateTime -Descending | Select-Object -First 1).StartDateTime
}
}
}
$suspiciousSPs | Sort-Object LatestCredAdded -Descending
# 检查特定服务主体的角色分配
$spId = "<service-principal-object-id>"
Get-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $spId | ForEach-Object {
$resource = Get-MgServicePrincipal -ServicePrincipalId $_.ResourceId
[PSCustomObject]@{
AppRoleId = $_.AppRoleId
ResourceDisplayName = $resource.DisplayName
CreatedDateTime = $_.CreatedDateTime
}
}
# 列出所有应用程序的所有者(所有权 = 凭据控制权)
Get-MgApplication -All | ForEach-Object {
$app = $_
$owners = Get-MgApplicationOwner -ApplicationId $app.Id
foreach ($owner in $owners) {
[PSCustomObject]@{
AppName = $app.DisplayName
AppId = $app.AppId
OwnerUPN = $owner.AdditionalProperties.userPrincipalName
OwnerType = $owner.AdditionalProperties.'@odata.type'
}
}
} | Where-Object { $_.OwnerUPN -ne $null }
AADServicePrincipalSignInLogs
| where ServicePrincipalId == "<target-sp-id>"
| project TimeGenerated, ServicePrincipalName, IPAddress, Location,
ResourceDisplayName, Status.errorCode
| sort by TimeGenerated desc
# 禁用用户注册应用程序的能力
Update-MgPolicyAuthorizationPolicy -DefaultUserRolePermissions @{
AllowedToCreateApps = $false
}
# 要求对所有应用同意请求进行管理员审批
New-MgPolicyPermissionGrantPolicy -Id "admin-only-consent" `
-DisplayName "Admin Only Consent" `
-Description "Only admins can consent to applications"
创建以下分析规则:
| 技术 | ID | 描述 |
|---|---|---|
| 账户操控:附加云凭据(Account Manipulation: Additional Cloud Credentials) | T1098.001 | 向服务主体添加凭据 |
| 有效账户:云账户(Valid Accounts: Cloud Accounts) | T1078.004 | 使用受损的服务主体 |
| 账户发现:云账户(Account Discovery: Cloud Account) | T1087.004 | 枚举服务主体 |
| 窃取应用程序访问令牌(Steal Application Access Token) | T1528 | 通过服务主体窃取 OAuth 令牌 |