关于 investigating-m365-entra
面向事件响应人员的 M365 和 Entra ID 调查指南,适用于邮箱失陷、账户入侵及 OAuth 授权滥用等事件。它结合审计与登录日志分析、持久化检查和时间线构建,并强调日志留存与许可造成的可见性限制。
主要功能
- 01梳理审计、登录及身份日志
- 02分析异常登录与 MFA 活动
- 03调查 OAuth 授权和应用凭据
- 04检查邮箱规则及转发设置
- 05关联事件并构建时间线
适用场景
- 01调查商业邮件失陷和未授权邮箱访问
- 02排查可疑 OAuth 授权及持久化
- 03分析 Entra ID 登录异常与 MFA 篡改
- 04在遏制前保全邮箱证据
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ trilwu/ secskills --skill investigating-m365-entra安装后在 Claude Code 中输入/investigating-m365-entra确认已加载。
详细介绍
调查 M365 和 Entra ID
M365/Entra 调查与本地 DFIR 不同——没有磁盘映像、内存转储,也无法自行收集事件日志。所有数据都来自对 Microsoft 日志存储的 API 查询,其中有些日志需要 E5 许可证或高级审核才能保留所需数据。了解有哪些日志、缺少哪些日志,以及日志保留时长,是调查工作的一半。
适用场景
- 商务电子邮件泄露(BEC)——未经授权访问邮箱、设置转发或冒充他人
- Entra ID 帐户遭入侵——可疑登录、令牌重放、凭据填充
- 可疑的 OAuth 同意授权——权限过大的第三方应用
- 邮箱规则遭篡改——收件箱规则隐藏攻击者通信或转发邮件
- Azure AD 登录异常——不可能的旅行、旧式身份验证、匿名网络
- 条件访问或 MFA 遭篡改——策略变更、MFA 疲劳攻击
不适用场景
- 更广泛的事件响应方法——使用
responding-to-incidents - 对 Entra ID 进行攻击测试——使用
attacking-entra-id - Azure 资源/订阅遭入侵——使用
investigating-azure-incidents - AWS 遭入侵——使用
investigating-aws-incidents - 其他云基础设施(GCP、攻击测试)——使用
exploiting-cloud-platforms - 根据调查发现构建检测规则——使用
engineering-detections
日志概况与保留期限
查询任何数据之前,先确认你有哪些日志,以及日志可追溯到多久以前。 缺少日志本身就是一项调查发现,而不是跳过问题的理由。
| 日志源 | 保留期限(默认) | 许可证要求 | 关键操作 |
|---|---|---|---|
| 统一审核日志(UAL) | 默认 180 天;E5 许可用户为 1 年 | MailItemsAccessed 需要 E5 | MailItemsAccessed、New-InboxRule、Set-Mailbox、同意授权 |
| Entra ID 登录日志 | 30 天 | 导出到 Log Analytics 可延长保留期限 | 登录事件、CA 评估、MFA 结果 |
| Entra ID 审核日志 | 30 天 | 无 | 角色分配、应用注册、凭据变更 |
| Identity Protection | 30 天 | 需要 P2 | 风险登录、风险检测 |
| Defender for Cloud Apps | 180 天 | 需要 MDCA 许可证 | 活动日志、OAuth 应用清单 |
| 邮箱审核日志 | 90 天(默认启用) | MailItemsAccessed 需要 E5 | 邮件访问、代表发送、委派操作 |
在根据日志缺口得出任何结论前,先确认保留期限。 自
2023 年 10 月 17 日起,Audit (Standard) 的默认期限为 180 天,而不是许多较旧资料仍提到的 90 天——在该日期之前生成的记录仍按旧的 90 天期限保留。只有持有 E5(或 Purview Audit 附加许可证)的用户默认可保留一年,即便如此,也仅适用于 Exchange、SharePoint、OneDrive 和 Entra ID。因此,E3 租户的 UAL 保留期限为 180 天,且没有
MailItemsAccessed,也无法在产品内延长保留期限。
保留期限按用户许可证确定,而非按租户确定:在混合许可证的租户中,同一查询可能返回 E5 调查对象一整年的历史记录,以及其相邻 E3 帐户 180 天的历史记录。在将空结果解读为“没有活动”之前,请确认受调查帐户的许可证。 明确说明这一缺口。检查 SIEM 或 Log Analytics 中是否有延长保留的数据。
统一审核日志(UAL)
UAL 是数据最丰富的单一来源。每项调查都从这里开始。
Connect-ExchangeOnline -UserPrincipalName [email protected]
# Basic search -- always constrain by date and user
Search-UnifiedAuditLog -StartDate "2026-07-01" -EndDate "2026-07-20" `
-UserIds [email protected] -ResultSize 5000
# Search specific operations
Search-UnifiedAuditLog -StartDate "2026-07-01" -EndDate "2026-07-20" `
-Operations "New-InboxRule","Set-InboxRule","Set-Mailbox","Add-MailboxPermission" `
-ResultSize 5000
# MailItemsAccessed (E5 only)
Search-UnifiedAuditLog -StartDate "2026-07-01" -EndDate "2026-07-20" `
-Operations MailItemsAccessed -UserIds [email protected] -ResultSize 5000
# Export -- AuditData field is JSON, expand it
Search-UnifiedAuditLog -StartDate "2026-07-01" -EndDate "2026-07-20" `
-UserIds [email protected] -ResultSize 5000 |
Select-Object CreationDate, UserIds, Operations,
@{N='AuditData';E={$_.AuditData | ConvertFrom-Json | ConvertTo-Json -Depth 10}} |
Export-Csv -Path .\ual_export.csv -NoTypeInformation
关键 UAL 操作
| 操作 | 重要性 |
|---|---|
| MailItemsAccessed | Bind = 读取单个项目,Sync = 批量下载。批量同步是 BEC 数据外传的指标。 |
| New-InboxRule / Set-InboxRule | 隐藏回复或转发邮件的规则。检查关键词目标:“invoice”“payment”“security”。 |
| Set-Mailbox | ForwardingSMTPAddress 或 ForwardingAddress 已更改——静默外部转发。 |
| Add-MailboxPermission | FullAccess 或 SendAs 委派——持久化。 |
| Consent to application | OAuth 授权。AuditData 包含权限信息。 |
| Add service principal credentials | 在应用注册中添加新的密钥/证书。 |
| HardDelete / SoftDelete | 销毁证据——攻击者删除已发送邮件。 |
UAL 每次查询最多返回 50,000 条结果。如果达到上限,请缩小日期范围。
Entra ID 登录分析
查询登录日志并查找:
- 不可能的旅行——在不可能的时间范围内出现在相距遥远的位置
- 匿名 IP——Tor 出口节点、VPN 服务、已知匿名代理
- 旧式身份验证——IMAP、POP3、SMTP AUTH 可绕过 MFA,除非 CA 阻止
- 令牌重放——同一关联 ID 来自不同源 IP
- 异常用户代理——Python requests、PowerShell 访问 OWA 或 Graph
// Sign-ins from the compromised account
SigninLogs
| where UserPrincipalName == "[email protected]"
| where TimeGenerated > ago(30d)
| project TimeGenerated, AppDisplayName, IPAddress, Location,
ClientAppUsed, ResultType, AuthenticationRequirement, MfaDetail, RiskState
| order by TimeGenerated asc
// Legacy auth sign-ins that bypass MFA
SigninLogs
| where ClientAppUsed in ("IMAP4", "POP3", "SMTP", "Exchange ActiveSync",
"MAPI Over HTTP", "Outlook Anywhere", "Exchange Web Services")
| where ResultType == 0
| summarize count() by UserPrincipalName, ClientAppUsed, IPAddress
MFA 分析
- ResultType 50074——需要 MFA,但未完成
- ResultType 50076——已完成 MFA(攻击者拥有验证因子或使用了 MFA 疲劳攻击)
- AuthenticationRequirement = singleFactorAuthentication——不需要 MFA(CA 配置缺口)
- 检查
MfaDetail——在反复提示后接受推送通知,说明可能存在 MFA 疲劳攻击
OAuth 和授权授予调查
非法授权授予是 M365 入侵中最容易被漏掉的持久化手段。
Connect-MgGraph -Scopes "Application.Read.All","Directory.Read.All"
# Delegated permission grants -- look for Mail.Read, Files.ReadWrite, etc.
Get-MgOauth2PermissionGrant -All | Where-Object {
$_.Scope -match "Mail.Read|Mail.ReadWrite|Files.ReadWrite|User.Read.All"
} | Format-Table ClientId, ConsentType, Scope, PrincipalId
# Application permission assignments
Get-MgServicePrincipal -All | ForEach-Object {
$sp = $_
Get-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $sp.Id -ErrorAction SilentlyContinue |
Select-Object @{N='AppName';E={$sp.DisplayName}}, @{N='AppId';E={$sp.AppId}},
PrincipalDisplayName, @{N='Created';E={$_.CreatedDateTime}}
}
| 权限 | 风险 |
|---|---|
| Mail.Read / Mail.ReadWrite | 邮件数据外传。对未知应用而言很可疑。 |
| Files.ReadWrite.All | 完全访问 SharePoint/OneDrive。 |
| Directory.ReadWrite.All | 可修改用户、组和角色。 |
| full_access_as_app | Exchange 应用级邮箱访问——第三方几乎从不会正当使用。 |
区分委派授权(单个用户的数据)和管理员授权(整个租户)。 向恶意应用授予管理员授权会暴露所有用户的数据。
邮箱规则取证
密码重置后,收件箱规则仍会保留。务必检查。
# Inbox rules
Get-InboxRule -Mailbox [email protected] |
Select-Object Name, Enabled, MoveToFolder, DeleteMessage, ForwardTo,
RedirectTo, MarkAsRead | Format-List
# Mailbox-level forwarding
Get-Mailbox -Identity [email protected] |
Select-Object ForwardingSMTPAddress, ForwardingAddress, DeliverToMailboxAndForward
# All mailboxes with external forwarding
Get-Mailbox -ResultSize Unlimited |
Where-Object { $_.ForwardingSMTPAddress -ne $null } |
Select-Object UserPrincipalName, ForwardingSMTPAddress
# Transport rules
Get-TransportRule | Where-Object { $_.RedirectMessageTo -or $_.BlindCopyTo } |
Select-Object Name, State, RedirectMessageTo, BlindCopyTo
# Delegate access
Get-MailboxPermission -Identity [email protected] |
Where-Object { $_.User -ne "NT AUTHORITY\SELF" -and -not $_.IsInherited }
危险信号:针对关键词(“security”“password”“MFA”)的规则、删除邮件或将邮件移至 RSS Feeds / Conversation History 的规则、名称为空的规则、转发至免费电子邮件服务提供商的规则,以及在首次可疑登录后创建的规则。
eDiscovery 和内容搜索
Connect-IPPSSession -UserPrincipalName [email protected]
# Preserve mailbox content -- do this early
Set-Mailbox -Identity [email protected] -LitigationHoldEnabled $true
# Search outbound mail from compromised account
New-ComplianceSearch -Name "IR-2026-042 Outbound" `
-ExchangeLocation [email protected] `
-ContentMatchQuery "sent>=2026-07-01 AND sent<=2026-07-20"
Start-ComplianceSearch -Identity "IR-2026-042 Outbound"
请在保留策略生效前设置诉讼保全,否则攻击者可能清除证据。
Azure AD 审计日志分析
// Role assignments
AuditLogs
| where OperationName == "Add member to role"
| extend TargetUser = tostring(TargetResources[0].userPrincipalName),
RoleName = tostring(TargetResources[0].modifiedProperties[1].newValue)
| project TimeGenerated, InitiatedBy, TargetUser, RoleName
// Service principal credential changes (persistence)
AuditLogs
| where OperationName in ("Add service principal credentials",
"Update application - Certificates and secrets management")
| project TimeGenerated, InitiatedBy, TargetResources
// Conditional Access policy changes
AuditLogs
| where OperationName has "conditional access"
| project TimeGenerated, OperationName, InitiatedBy, Result
// MFA method changes (attacker registering their own factor)
AuditLogs
| where OperationName in ("User registered security info",
"Admin registered security info", "User deleted security info")
| project TimeGenerated, OperationName, InitiatedBy, TargetResources
拥有 Application Admin 或 Global Admin 权限的攻击者可以向现有应用注册添加凭据,以实现持久化且不受 MFA 影响的访问:
Get-MgApplication -All | ForEach-Object {
$app = $_
$app.PasswordCredentials + $app.KeyCredentials | Where-Object {
$_.StartDateTime -gt (Get-Date).AddDays(-30)
} | Select-Object @{N='App';E={$app.DisplayName}}, @{N='AppId';E={$app.AppId}},
StartDateTime, EndDateTime
}
构建时间线
关联三种主要日志来源:
Sign-in logs --> When and where the attacker authenticated
Audit logs --> Configuration changes they made
UAL --> Data they accessed or modified
- 以最早的可疑登录为锚点
- 提取该用户前后 7 天的登录、UAL 和审计事件
- 合并为单一 UTC 时间线
- 查找以下模式:登录、侦察、持久化(规则/转发/OAuth)、目标行动
UTC Timestamp | Source | Event | Detail
2026-07-12 08:41:22 | SignIn | Sign-in from 198.51.x.x | Nigeria, no MFA
2026-07-12 08:42:05 | UAL | MailItemsAccessed (Sync) | 847 items via Graph
2026-07-12 08:43:18 | UAL | New-InboxRule "." | Delete "security alert"
2026-07-12 08:44:01 | UAL | Set-Mailbox | ForwardingSMTPAddress set
2026-07-12 08:45:33 | UAL | Consent to application | Mail.Read, Mail.Send
2026-07-12 09:12:44 | UAL | Send (SendAs) | Invoice redirect to vendor
遏制
范围界定完成后同时执行。部分遏制会向攻击者发出警报。
# Revoke sessions and reset credentials
Revoke-MgUserSignInSession -UserId [email protected]
Update-MgUser -UserId [email protected] -PasswordProfile @{
Password = (New-Guid).Guid + "!Aa1"; ForceChangePasswordNextSignIn = $true }
# Disable account if active compromise is ongoing
Update-MgUser -UserId [email protected] -AccountEnabled:$false
# Remove attacker inbox rules
Get-InboxRule -Mailbox [email protected] |
Where-Object { $_.Name -match "^\.$|^$" -or $_.DeleteMessage -eq $true } |
Remove-InboxRule -Confirm:$false
# Remove forwarding
Set-Mailbox -Identity [email protected] `
-ForwardingSMTPAddress $null -ForwardingAddress $null `
-DeliverToMailboxAndForward $false
# Remove unauthorized delegate access
Get-MailboxPermission -Identity [email protected] |
Where-Object { $_.User -ne "NT AUTHORITY\SELF" -and -not $_.IsInherited } |
ForEach-Object { Remove-MailboxPermission -Identity [email protected] `
-User $_.User -AccessRights $_.AccessRights -Confirm:$false }
# Block malicious OAuth app
$sp = Get-MgServicePrincipal -Filter "appId eq '<malicious-app-id>'"
Update-MgServicePrincipal -ServicePrincipalId $sp.Id -AccountEnabled:$false
Get-MgOauth2PermissionGrant -Filter "clientId eq '$($sp.Id)'" |
Remove-MgOauth2PermissionGrant
仅撤销会话并不足够——令牌可能仍然有效长达一小时。请禁用账户以立即锁定。遏制后,确认不存在转发、未知委派、未知 OAuth 授权、攻击者注册的 MFA 方法,以及在入侵时间段内创建的服务主体凭据。
需要纠正的错误认知
- “我们重置了密码,所以账户安全了。” 刷新令牌、OAuth 授权、收件箱规则、邮件转发和委托访问权限都不会因密码重置而失效。请撤销会话,并审查所有持久化访问机制。
- “我们只有 E3,所以无法调查邮件访问情况。” 虽然无法使用 MailItemsAccessed,但登录日志、UAL 操作、收件箱规则和邮件转发仍然可查。请说明这一限制,并利用现有信息开展调查。
- “这次登录来自 VPN,所以可能是用户本人。” 请结合出口 IP、用户代理和时间,与已知模式进行比对。攻击者也会使用 VPN。
- “Defender 没有触发任何警报,所以没有遭到入侵。” Defender 需要相应的许可证等级和策略配置。没有警报并不能证明没有入侵。
- “这个 OAuth 应用只有委托权限。” 只要刷新令牌有效,委托权限就能提供持久访问,无需再次输入密码。
- “我们封锁了该 IP,所以攻击者无法再登录。” 攻击者会更换 IP。请撤销令牌和凭据,而不只是封锁网络路径。
- “日志只保留 30 天,所以入侵一定是在这段时间内开始的。” 这是你的可见范围限制,并不代表攻击者的活动时间线。请记录这一限制,并检查 SIEM 是否有更长的保留期限。
参考资料
responding-to-incidents-- 更全面的 IR 方法和证据处理attacking-entra-id-- Entra ID 攻击技术,有助于了解攻击者的手段exploiting-cloud-platforms-- M365 之外的云基础设施攻击engineering-detections-- 根据调查结果构建检测规则hunting-threats-- 主动搜寻 M365 和 Entra ID 遥测数据中的威胁