prodfail/M365IR
GitHub: prodfail/M365IR
一个经过测试的 M365 安全事件响应 PowerShell 模块,提供只读调查、Playbook 编排和 token 门控的封禁隔离机制。
Stars: 0 | Forks: 0
# M365IR:Microsoft 365 事件响应 PowerShell 模块
一个用于调查 Microsoft 365 安全事件的只读 PowerShell 模块:网络钓鱼、BEC、账户接管、AiTM/MFA 绕过、OAuth 滥用和数据外发。专为在凌晨 2 点处理事件的分析师而构建:每个查询都会完整分页,每个日期限制都会在造成影响前进行验证,并且每个发现都会作为带哈希值的证据保存在磁盘上。
**安全姿态:** `M365IR` 模块对租户是只读的。写入/封禁操作特意放在一个独立的 `M365IR.Containment` 模块中,该模块受到随机 token 确认机制的限制。这种隔离是由测试强制执行的,而非依靠约定。
## 为什么选择 v2
v1 是一个复制粘贴的操作手册(保留在 [docs/RUNBOOK.md](docs/RUNBOOK.md) 中)。v2 将其转换为一个经过测试的模块,并增加了操作手册无法做到的功能:
- **Playbook 编排:** `Invoke-IRPlaybook -Type AiTM` 运行整个调查序列并将每一步导出为证据。
- **仅应用证书认证**,用于自动化,以及应对管理员账户就是那个被盗用账户的情况。
- **每日安全扫描**(`Invoke-IRDailySweep`):高风险用户、新的收件箱规则、同意授权、设备注册、传统认证命中、审计健康状态,全部快照到磁盘。集轻量级检测层和持续监控证据于一体。
- **MailItemsAccessed 违规范围界定**,内置对 bind/sync/throttling 的解析。
- **自动处理 Microsoft 限制的邮件跟踪:** 自动将时间窗口切分为 10 天的查询,自动对 5000 行上限进行分页,在 5 分钟 100 次的限流下休眠,拒绝超过 90 天上限的窗口。
- **默认提供监管链:** 案件文件夹、会话记录、SHA256 哈希的 CSV+JSON 导出,以及一份清单。
- **离线测试套件** (Pester),涵盖窗口切分、输入验证、确认门控以及只读/写入模块分离。
## 仓库结构
```
src/M365IR/
M365IR.psd1 Module manifest
M365IR.psm1 Read-only investigation module (24 functions)
M365IR.Containment.psm1 Write operations, token-gated (import deliberately)
tests/M365IR.Tests.ps1 Pester tests (offline, no tenant needed)
docs/RUNBOOK.md v1 copy-paste runbook (still valid for ad hoc work)
docs/CONTAINMENT-RUNBOOK.md v1 containment runbook
```
## 要求
- macOS、Windows 或 Linux 上的 PowerShell 7.0+ (`pwsh`)
- `ExchangeOnlineManagement` **3.7.0+** (Get-MessageTraceV2 基线)
- `Microsoft.Graph` 2.0+
- 可选:用于 `Get-IRFlowPersistence` 的 `Microsoft.PowerApps.Administration.PowerShell`
`Test-IRPreflight` 会检查所有这些条件并提供门控安装。
## 快速开始(交互式)
```
git clone https://github.com/prodfail/m365-ir-toolkit.git
cd m365-ir-toolkit
Import-Module ./src/M365IR/M365IR.psd1
Test-IRPreflight
Connect-IRTenant -AdminUPN admin@example.com
# Scope 设置一次;每个 function 都会继承它
Set-IRScope -TargetUser user@example.com -StartDate (Get-Date).AddDays(-3)
# 运行完整 playbook:打开 case,运行每个 step,导出 hashed evidence
Invoke-IRPlaybook -Type AiTM
# 或者逐个 function 执行
New-IRCase
Get-IRSignInActivity -Kind NonInteractive | Export-IREvidence -Name SignIns_NonInt
Get-IRMailItemsAccessed | ForEach-Object { $_.Sessions } | Export-IREvidence -Name MIA_Sessions
Get-IRMailboxForensics | Export-IREvidence -Name MailboxForensics
# 包含预填充 evidence inventory 的报告骨架
New-IRReportDraft -IncidentTitle "AiTM compromise of user@example.com"
Close-IRCase
```
## 仅应用(证书)认证
用于自动化,并且因为交互式认证往往会在你最需要它的时候失败。一次性设置:
1. **创建证书**(自签名证书即可用于此目的):
$cert = New-SelfSignedCertificate -Subject "CN=M365IR" -CertStoreLocation Cert:\CurrentUser\My `
-KeyExportPolicy NonExportable -KeySpec Signature -KeyLength 2048
Export-Certificate -Cert $cert -FilePath ./m365ir.cer
(macOS/Linux:使用 `openssl` 生成并导入到证书存储,或者对导入的 PEM 证书使用 `-CertificateThumbprint`。)
2. **在 Entra ID 中注册应用**:App registrations > New。在 Certificates & secrets 下上传 `m365ir.cer`。
3. **Graph 应用权限**(只读集),然后授予管理员同意:
`AuditLog.Read.All`, `Directory.Read.All`, `User.Read.All`, `Policy.Read.All`, `SecurityEvents.Read.All`, `IdentityRiskyUser.Read.All`, `MailboxSettings.Read`
4. **Exchange Online 应用访问:** 添加 `Office 365 Exchange Online > Exchange.ManageAsApp` 应用程序权限,然后为应用分配最小特权的 Exchange 角色。首选:Exchange RBAC for Applications,将应用的服务主体放在 **View-Only Organization Management** 中。备选方案(权限比需要的宽):为服务主体分配 Entra **Global Reader** 角色;除非你也打算通过它运行封禁操作,否则请避免使用 Exchange Administrator。
5. **连接:**
Connect-IRTenant -TenantId -AppId `
-CertificateThumbprint -Organization example.com
## 每日扫描(主动模式)
```
Connect-IRTenant -TenantId $tid -AppId $app -CertificateThumbprint $thumb -Organization example.com
Invoke-IRDailySweep
```
检查过去 24 小时内的:审计健康状态下降、活跃的高风险用户、收件箱规则更改、新的 OAuth 授权、设备注册和传统认证登录。每次运行写入一个 JSON 快照并打印调查结果摘要。安排它的执行:
```
# cron (Linux/macOS),工作日 07:00
0 7 * * 1-5 /usr/local/bin/pwsh -NoProfile -File /path/to/sweep.ps1
```
其中 `sweep.ps1` 导入模块,以仅应用方式连接,并调用 `Invoke-IRDailySweep`。在 macOS 上首选 launchd plist;在 Windows 上首选 Task Scheduler。
## 功能参考
| 功能 | 用途 |
|---|---|
| `Test-IRPreflight` | 版本/模块检查,带门控安装 |
| `Connect-IRTenant` | EXO + Graph,交互式或仅应用证书 |
| `Set-IRScope` | 默认目标用户 + 调查窗口 |
| `New-IRCase` / `Export-IREvidence` / `Close-IRCase` | 案件文件夹、记录、带哈希的证据清单 |
| `Search-IRAuditLog` | 完全分页的 UAL 搜索 (ReturnLargeSet) |
| `Test-IRAuditHealth` | UAL 摄取 + 每个邮箱的审计验证 |
| `Get-IRAccountBaseline` | 账户状态、MFA 方法、角色、最近登录 |
| `Get-IRSignInActivity` | `-Kind Interactive` / `NonInteractive` / `Risky` / `ServicePrincipal` / `ManagedIdentity` / `LegacyAuth` |
| `Get-IRDirectoryAudit` | 密码重置、MFA 注册、设备注册、角色/CA 更改、同意授权 |
| `Get-IRMailItemsAccessed` | 违规范围界定:bind/sync 解析、会话汇总、限流警告 |
| `Get-IRMailboxForensics` | 规则、转发、代理,带有可疑标记 |
| `Get-IRMessageTrace` | V2 跟踪,带自动切分、分页、限流处理 |
| `Get-IROAuthGrants` | 用户授权、最近的应用注册、凭据化的 SP |
| `Get-IRSecurityAlerts` | 高风险用户 + alerts_v2,通过证据匹配进行目标范围界定 |
| `Get-IRSharePointActivity` / `Get-IRTeamsActivity` | 工作负载 UAL 取证 |
| `Get-IRFlowPersistence` | Power Automate 持久化排查 |
| `Get-IRCAGapAnalysis` | CA 状态、排除清单、传统认证覆盖范围 |
| `Get-IRThreatIntel` | ThreatFox + OTX + OpenPhish 富化(缓存的 feed) |
| `Invoke-IRPlaybook` | `-Type AccountTakeover` / `AiTM` / `BEC` / `Phishing` / `DataExfil` |
| `Invoke-IRDailySweep` | 带快照的主动每日检测扫描 |
| `New-IRReportDraft` | 从案件清单生成报告骨架 |
## 封禁(独立模块,特意设计)
```
Import-Module ./src/M365IR/M365IR.Containment.psm1 # deliberate act
Connect-MgGraph -Scopes "User.ReadWrite.All","User.RevokeSessions.All","Application.ReadWrite.All"
Invoke-IRPasswordReset -TargetUser user@example.com
Invoke-IRSessionRevocation -TargetUser user@example.com
Disable-IRInboxRule -TargetUser user@example.com -RuleName "Sync" # disable first
Disable-IRInboxRule -TargetUser user@example.com -RuleName "Sync" -Remove # remove after evidence
Clear-IRMailForwarding -TargetUser user@example.com
Disable-IROAuthApp -ServicePrincipalId -GrantId
Block-IRSender -Entry attacker@evil.example
Invoke-IRMailPurge -Subject "Invoice overdue" -SenderAddress attacker@evil.example # stage 1: search
Invoke-IRMailPurge -Subject "Invoice overdue" -SenderAddress attacker@evil.example -SearchName -ExecutePurge
```
每个功能:支持 `-WhatIf`,需要输入一个随机的 4 字母 token(区分大小写,不依赖肌肉记忆输入 Y),并遵循模块头部中的行动规则:先授权,封禁前先获取证据,遵循重置后撤销的顺序。邮件清除分为两个阶段,在搜索和 SoftDelete 之间强制要求进行审查;HardDelete 被特意未实现。
## 数据保留限制
| 来源 | 保留期 |
|---|---|
| Entra 登录 / 目录审计 (Graph) | 30 天 (P1/P2);免费层 7 天 |
| 统一审计日志 | 180 天 (Audit Standard);1 年 (Premium) |
| 邮件跟踪 V2 | 总共 90 天;每次查询 10 天(自动处理) |
| 隔离区 | 30 天 |
在保留窗口之外的空结果意味着“没有可用数据”,而不是“什么也没发生”。`Get-IRMessageTrace` 会强制执行其上限;在界定范围时请注意其他限制。
## 测试
```
Install-Module Pester -MinimumVersion 5.0 -Scope CurrentUser
Invoke-Pester ./tests
```
所有测试均离线运行(不需要租户)。它们涵盖:导出的功能接口、只读保证、日期窗口切分计算、邮件跟踪输入验证、证据导出行为、封禁确认门控(错误的 token、区分大小写),以及每个封禁功能上的 `-WhatIf` 支持。CI 会在每次推送时运行它们。
## 许可证
MIT。详见 [LICENSE](LICENSE)。按“原样”提供用于防御性安全用途,不提供任何形式的保证。
标签:AI合规, IPv6, Libemu, Microsoft 365, PowerShell, 取证, 安全运营, 扫描框架, 数据泄露, 网络调试, 自动化