jo-marcelo/sentinel-mde-dfir-domain-compromise
GitHub: jo-marcelo/sentinel-mde-dfir-domain-compromise
基于Microsoft Sentinel和Defender XDR遥测数据重建的一次模拟Azure控制平面域入侵事件的完整数字取证与事件响应案例研究,包含KQL查询、恶意软件静态分析和检测规则。
Stars: 0 | Forks: 0
# Hidden Directive — DFIR 案例研究
**针对一次模拟域入侵事件的完整应急响应调查,基于 Microsoft Sentinel 和 Defender XDR 遥测数据重建,并结合对五个恢复的恶意软件样本的静态分析。**
[](https://learn.microsoft.com/azure/sentinel/)
[](https://learn.microsoft.com/defender-xdr/)
[](https://learn.microsoft.com/kusto/query/)
[](https://attack.mitre.org/)
## 简述
一名拥有 **Azure 控制平面**访问权限的攻击者利用内置的虚拟机管理功能重置了本地管理员的密码,随后通过 RDP 登录——无需漏洞利用,初始访问也不需要恶意软件。在接下来的六个小时内,他们在目标范围内的所有三台主机中进行横向移动,到达了域控制器,准备了用于外发窃取的员工记录,并植入了一个 Active Directory 权限后门,该后门即使在密码重置和主机重装后依然存活。
第一次 SOC 警报在入侵开始 **20 分钟**后触发,且描述的是表象而非入侵行为本身。在 **5 小时 46 分钟**时,攻击者实现了完全的域沦陷。
**最重要的发现:** 攻击者授予了一个服务账户对 **AdminSDHolder** 对象的 `GenericAll` 权限。Active Directory 大约每小时将该权限重新传播到每个特权组。重置所有密码并重装所有受影响的主机也无法将其移除。
📄 **[阅读完整报告(PDF,20 页)](report/GF-INC-2026-0704-Incident-Report.pdf)**
## 攻击链
```
flowchart TD
A["09:58 UTC
RDP brute force fails
sancadmin @ GF-WS01"] --> B["10:01 UTC
Azure Run Command resets
password as SYSTEM
T1651"] B --> C["10:02 UTC
RDP logon succeeds
no MFA
T1078 / T1021.001"] C --> D["10:16 UTC
PowerShell download cradle
AMSI bypass, in-memory C#
T1059.001 / T1562.001"] D --> E["11:46 UTC
Scheduled task persistence
MicrosoftHealthUpdate
T1053.005"] D --> F["12:04 UTC
C2 beacon established
api.cloud-endpoint.net
T1071.001"] C --> G["10:22 UTC
Lateral move to GF-SRV01
t.harris
T1078"] G --> H["14:44 UTC
Reaches GF-DC01
d.williams
T1021"] H --> I["15:00 UTC
RemCom service execution
hOQjiirI.exe as SYSTEM
T1569.002"] I --> J["15:05 UTC
employee_records.csv staged
compressed to exfil.zip
T1005 / T1560.001"] I --> K["15:44 UTC
AdminSDHolder ACL backdoor
svc_backup granted GenericAll
T1222.001"] style B fill:#c62828,color:#fff style K fill:#c62828,color:#fff style J fill:#ef6c00,color:#fff ``` ## 调查涵盖范围 | | | |---|---| | **范围** | 3 台主机(工作站、文件服务器、域控制器),17 小时的事件窗口 | | **遥测数据** | Microsoft Sentinel(ASIM 表、Sysmon、Windows Event Log)+ Defender XDR(`Device*` 表) | | **查询语句** | 28 条 KQL 查询,已记录且可复现 | | **样本文件** | 在隔离虚拟机上静态分析了 5 个文件 — 哈希校验、`strings`、PE 解析、`binwalk`、XOR 解码 | | **账户** | 4 个被攻陷,其中 3 个已确认获取方式 | | **输出** | 20 页的事件报告,25 张证据截图,2 条经过验证的检测规则 | ## 部分调查发现 ### 云控制平面作为初始访问向量 这个案例中最有趣的地方在于没有利用任何漏洞。针对 `sancadmin` 的连续 RDP 登录失败后,93 秒后出现了一次 **Azure Run Command** 调用,以 `NT AUTHORITY\SYSTEM` 的身份运行了 `net user sancadmin` 和 `/active:yes` —— 随后立即出现了来自同一来源的成功 RDP 登录。
Run Command 在设计上就是以 SYSTEM 权限执行提交的脚本。攻击者在这起入侵中使用了它 **两次,横跨两台主机**,这意味着他们根本不需要进行操作系统级别的提权。这重新定义了根本原因:薄弱环节不在于端点,而在于云管理功能可以在不受监控的情况下写入操作系统,再加上仅凭密码即可通过验证的 RDP。
*诚实的局限性说明:* 遥测数据显示 Run Command **被调用了**以及**它做了什么**,但没有显示**谁调用了它** —— 该信息存在于 Azure Activity Log 中,而这不在本次调查的范围内。报告中如实进行了说明,而不是去推断行为主体。
### AdminSDHolder — 存续于修复措施之外的持久化
```
Add-ADPermission -Identity 'CN=AdminSDHolder,CN=System,DC=greenfield,DC=local' `
-User svc_backup -AccessRights GenericAll
```
AdminSDHolder 是 Active Directory 中的一个权限模板。SDProp 后台进程大约每 60 分钟将其 ACL 复制到每个受保护的账户和组 —— 包括 Domain Admins、Enterprise Admins 及其等效组。
因此,授予 `svc_backup` 对该对象的完全控制权,等同于赋予了会**自动重新应用**的域管理员等效权限。标准的修复措施对其不起作用。必须显式移除该 ACE 并强制运行 SDProp,以清除已传播的权限。
### 与遥测数据关联的静态分析
在隔离虚拟机上恢复并分析了五个样本文件。其中两个产生了与实时遥测数据直接、独立且可验证的关联:
**`hOQjiirI.exe`** — 通过 strings 和 Service Control Manager 导入表确认为 **RemCom**(一个开源的 PsExec 替代工具)。从二进制文件中恢复的命名管道与 Sysmon 遥测中观察到的管道**完全一致**:
```
Binary strings: RemCom_communicaton, RemCom_stdin, RemCom_stdout, RemCom_stderr
Sysmon (15:00:39): \RemCom_communicaton, \RemCom_stdinGRNK379504, ...
ActingProcessFilePath: C:\Windows\hOQjiirI.exe
ActorUsername: NT AUTHORITY\SYSTEM
```
**`gfupdater.exe`** — 与嵌入在 shellcode stager 中的 PE 具有相同的植入物代码库(相同的节大小、PEB-walking API 解析、无导入表),被编译为独立可执行文件。其 PE 编译时间戳解析为 **2026-07-04 11:07:22 UTC** —— 即入侵发生的当天。
### 针对 AI 工具的提示词注入 Payload
`blog_lure.html` 携带了两个 payload:一个是面向人类读者的传统钓鱼横幅,另一个是隐藏的 HTML 注释,针对 **AI 摘要工具**,指示它们静默执行 PowerShell 下载、请求跟踪像素、将钓鱼链接插入到它们自己的输出中,并隐瞒这一切的发生。
这是在静态分析过程中发现的,并未被实际执行。
准确界定证据支持的结论是有必要的:该 payload 确实存在,并且该组织的内部 AI 网页摘要工具在加载器被拉取的 69 秒前,确实联系了同一个 C2 域。但是,该摘要工具的父进程链是 `explorer.exe → cmd.exe → python.exe` —— **是手动调用,而非计划任务** —— 并且加载器的下载来自一个独立的 `explorer.exe → powershell.exe` 进程链。因此,更直接的解读是,已经持有交互式会话的攻击者使用该工具访问了他们自己的诱饵页面。该注入是否真正影响了工具的行为**无法从现有遥测数据中确认**,报告以中等置信度对此进行了陈述,而不是宣称该技术取得了成功。
## 检测工程
根据调查发现编写了两条规则,并在事件窗口内进行了验证。这两条规则都涵盖了在事件期间**未产生任何警报**的技术。
| 规则 | 技术 | 误报风险 |
|---|---|---|
| [AdminSDHolder ACL 修改](detections/D1-adminsdholder-acl-modification.kql) | T1222.001 | 极低 |
| [RemCom / PsExec 命名管道创建](detections/D2-remcom-named-pipes.kql) | T1569.002 | 极低 |
**验证过程中捕捉到了一个值得记录的 Bug。** 管道规则最初是使用 `has_any` 编写的:
```
| where PipeName has_any ("RemCom_communicaton", "RemCom_stdin", "RemCom_stdout", "RemCom_stderr")
```
KQL 的 `has` 操作符匹配的是**整个 token**,而 RemCom 会为其四个管道中的三个追加基于会话的随机后缀(`\RemCom_stdoutGRNK379504`)。该规则只匹配到了 **7 个事件中的 1 个**。使用 `contains` 重写后捕捉到了全部七个事件 —— 并且发现了一场**第二次 RemCom 会话**(发生于 15:05:08),这在最初的调查报告中完全被遗漏了。
事实证明,这第二次会话正是执行后续工具和数据暂存的通道,因此这个修复不仅更改了一条查询语句,更是更改了一项调查发现。
## 仓库内容
```
├── README.md you are here
├── report/
│ ├── GF-INC-2026-0704-Incident-Report.pdf full report, 20 pages
│ └── GF-INC-2026-0704-Incident-Report.md markdown source
├── queries/ 26 KQL queries, one file each, named by purpose
├── detections/ 2 validated detection rules + companions
├── analysis/
│ └── artefact-analysis.md static analysis of all five artefacts
└── evidence/ 25 annotated screenshots (EV-01 … EV-38)
```
**本仓库不包含任何恶意软件样本。** 仅提供哈希值、静态分析输出和威胁指标。案例处理指南禁止重新分发样本,而且无论如何,发布样本都是不良做法。
## 工具
**调查** — Microsoft Sentinel(Log Analytics / KQL),Microsoft Defender XDR Advanced Hunting,VirusTotal(仅用于被动查询)
**静态分析** — 在隔离 VM 上的 REMnux:`sha256sum`、`file`、`strings`、`binwalk`、`pefile`、`xxd`
**参考** — MITRE ATT&CK
## 方法论说明
我希望读者了解关于本报告是如何产出的几个要点:
**空白点被如实记录为空白点。** 有四个阶段无法从现有的遥测数据中完全确认 —— Run Command 调用背后的身份、四个被攻陷账户中其中两个的凭证来源、两个未生成子进程的 Run Command 脚本的操作,以及暂存的归档文件是否曾离开过网络。报告中对每一项都进行了点名说明,记录了已检查的内容以及可以解决该空白的方法。记录在案的盲区比自信的猜测更有价值。
**被排除的线索也一并记录。** 几个看似很有希望的线索最终被证明是良性的 —— 源自 Defender 自身取证收集的 Robocopy 活动、一个被怀疑但实际上是合法 Edge 自启动项的注册表 Run 键、完全来源于平台进程的 DPAPI 访问。这些都被写入了报告中,因为排除某些可能性也是工作的一部分。
**AI 辅助。** 演练范围的规则允许使用 AI 来协助查询和研究,我也确实这样使用了它 —— KQL 语法、ATT&CK 技术查询以及文本的编辑润色。而调查、分析和结论都是我自己完成的。
## 相关工作
- [azure-threat-hunting-kql](https://github.com/jo-marcelo/azure-threat-hunting-kql) — 针对配置错误的公开虚拟机的暴力破解检测
- [mde-threat-hunting-network-slowdown](https://github.com/jo-marcelo/mde-threat-hunting-network-slowdown) — living-off-the-land 的 PowerShell 端口扫描
Joao Marcelo Miranda · [LinkedIn](https://www.linkedin.com/in/joaomarcelo-miranda/) · [GitHub](https://github.com/jo-marcelo)
RDP brute force fails
sancadmin @ GF-WS01"] --> B["10:01 UTC
Azure Run Command resets
password as SYSTEM
T1651"] B --> C["10:02 UTC
RDP logon succeeds
no MFA
T1078 / T1021.001"] C --> D["10:16 UTC
PowerShell download cradle
AMSI bypass, in-memory C#
T1059.001 / T1562.001"] D --> E["11:46 UTC
Scheduled task persistence
MicrosoftHealthUpdate
T1053.005"] D --> F["12:04 UTC
C2 beacon established
api.cloud-endpoint.net
T1071.001"] C --> G["10:22 UTC
Lateral move to GF-SRV01
t.harris
T1078"] G --> H["14:44 UTC
Reaches GF-DC01
d.williams
T1021"] H --> I["15:00 UTC
RemCom service execution
hOQjiirI.exe as SYSTEM
T1569.002"] I --> J["15:05 UTC
employee_records.csv staged
compressed to exfil.zip
T1005 / T1560.001"] I --> K["15:44 UTC
AdminSDHolder ACL backdoor
svc_backup granted GenericAll
T1222.001"] style B fill:#c62828,color:#fff style K fill:#c62828,color:#fff style J fill:#ef6c00,color:#fff ``` ## 调查涵盖范围 | | | |---|---| | **范围** | 3 台主机(工作站、文件服务器、域控制器),17 小时的事件窗口 | | **遥测数据** | Microsoft Sentinel(ASIM 表、Sysmon、Windows Event Log)+ Defender XDR(`Device*` 表) | | **查询语句** | 28 条 KQL 查询,已记录且可复现 | | **样本文件** | 在隔离虚拟机上静态分析了 5 个文件 — 哈希校验、`strings`、PE 解析、`binwalk`、XOR 解码 | | **账户** | 4 个被攻陷,其中 3 个已确认获取方式 | | **输出** | 20 页的事件报告,25 张证据截图,2 条经过验证的检测规则 | ## 部分调查发现 ### 云控制平面作为初始访问向量 这个案例中最有趣的地方在于没有利用任何漏洞。针对 `sancadmin` 的连续 RDP 登录失败后,93 秒后出现了一次 **Azure Run Command** 调用,以 `NT AUTHORITY\SYSTEM` 的身份运行了 `net user sancadmin
标签:KQL, Microsoft Defender, PE 加载器, 云安全监控, 安全案例分析, 库, 应急响应, 静态分析