norwytch/weeping-angel
GitHub: norwytch/weeping-angel
一个针对 Windows 时间戳篡改(timestomping)恶意软件的检测框架,通过多见证者分歧和防篡改账本实现带外取证。
Stars: 1 | Forks: 0
# 哭泣天使
[](https://github.com/norwytch/weeping-angel/actions/workflows/ci.yml)
[](https://www.python.org/)
[](LICENSE)
[](https://attack.mitre.org/techniques/T1070/006/)
检测仅在认为自己未被观察时才运作的 timestomping 恶意软件。
在经典的英国科幻剧集《神秘博士》中,哭泣天使是一种只有在未被观察时才能移动的实体。在直接观察下,它必须保持墓地雕像的形态,一动不动。脱离观察后,哭泣天使可以超越光速在空间中移动,以触及受害者并吸食他们的“时间能量”,包括通过数字信号网络进行移动。这意味着哭泣天使也有可能被用于恶意软件。
在这个 repo 中,我们设想了一款具有与剧中相似能力(仅在未被观察时进行横向移动)和目标(破坏目标的时间线)的恶意软件。当然,我们最终受限于天使被设想为“量子”实体这一事实,而我们受到经典计算系统的制约。尽管如此,我们将这款恶意软件设想为以下映射关系:
| 《神秘博士》 | 本系统 |
|---|---|
| 天使 | 进行 timestomp 的反取证恶意软件 |
| 移动 | 写入伪造的 `$STANDARD_INFORMATION` 时间戳 |
| 被观察 | 恶意软件的自查:带内检查 Procmon、EDR、打开的句柄、调试器 |
| 量子锁定 / 变成石头 | 每当其自查显示“被观察”时便进入休眠 |
| 两个天使互相锁定 | 必须达成共识的独立见证者;它们之间的分歧即为指纹 |
| 时间悖论 | 一条仅可追加、防篡改的记录,你无法在不产生矛盾的情况下重写它 |
| 从时间之外观察 | 带外观察(内核 minifilter、hypervisor/VMI),它无法感知 |
## 核心设计原则
1. 带外观察。恶意软件会检查带内观察者(用户态
进程、句柄、调试器)。从它之下或外部进行观察(内核
minifilter,或监视 guest 的 hypervisor),这样它行动的前提条件
在现实中永远为假,而它却无法察觉。
2. 多见证者分歧。保留多个独立的时间戳源,
如果没有人伪造任何东西,它们必须一致。没有单一的见证者能抓住天使;
它们的分歧可以。
3. 防篡改账本。一条前向哈希链、仅可追加的日志,其中每条
记录都与其前驱绑定。篡改过去会打破这条链。
有关更多详细信息,请参阅[威胁模型](docs/THREAT_MODEL.md)。
```
flowchart LR
subgraph guest["What the Angel can see (in-band)"]
A[Angel / malware] -->|checks| O[procmon? handle? debugger?]
A -->|stomp $SI| SI["DisplayWitness ($SI)"]
end
subgraph oob["Out-of-band, invisible to the Angel"]
REC[Recorder
minifilter / VMI] --> LED[(Hash-chained ledger)] FN["MFTWitness ($FN)"] LED --> JW["JournalWitness (USN)"] end REC -. observes every op .-> A SI --> DET{DivergenceDetector} FN --> DET JW --> DET DET --> F[Findings: the move, recorded] ``` ## 快速入门 ``` git clone && cd weeping_angel
python examples/demo.py # narrated walkthrough of the scenarios
python -m weeping_angel.adapters.mft examples/data/sample.mft # parse a raw $MFT and scan it
python -m weeping_angel.efficacy # precision/recall over a labeled corpus
python examples/arena_demo.py # adversarial arena: Angels vs the recorder
pip install -e . && weeping-angel scan examples/data/sample.mft # the unified CLI
pip install -e ".[test]" && pytest -q # 115 tests
```
有关完整的论证和设计说明,请参阅 [`docs/WRITEUP.md`](docs/WRITEUP.md)。
要在来自 Windows VM 的真实 timestomp 上运行检测器,请参阅
[`docs/LAB.md`](docs/LAB.md) 中的实验指南。
## 面对天使
天使是 Whoniverse 中最令人恐惧的实体之一。了解如何在你的系统中检测并击败它们非常重要!`python examples/demo.py` 会在模拟的天使上运行完整流程。
1. 移动。在没有带内观察者存在的情况下,`Angel.tick` (`weeping_angel/simulator.py`)
写入伪造的 `$SI` 时间戳并返回 `MOVING`。同样的操作
会在天使无法看到的账本中进行带外记录。
2. 检测。由于带外见证者保留了真实值,
`DivergenceDetector.scan` (`weeping_angel/detector.py`) 发现它们存在分歧,并
在场景 1 中触发 R1、R2、R4 和 R6。没有使用天使能够观察到的任何信息
来抓住它。
3. 击败。有两种方式。如果它认为自己被观察,它会变成 `STONE` 并且绝不行动
(场景 2)。当 `AdvancedAngel` 试图抹除记录时(场景 3),
哈希链账本在任何内部编辑时都会断裂,并且机外锚点
会捕获到被丢弃的尾部。最终证明 (`weeping_angel/paradox.py`) 表明,
只要带外观察持续存在,“移动但未被记录”的状态是无法达到的。
示例输出(已精简):
```
Scenario 1 -- the Angel moves while it believes no one is watching
Angel.tick -> MOVING (it sees no in-band observer)
Three independent witnesses disagree:
[HIGH] R1_si_fn_birth_divergence display($SI) vs mft($FN)
[HIGH] R2_si_journal_rollback display($SI) vs journal(USN)
[HIGH] R4_setinfo_captured journal(USN) the forgery caught in the act
Scenario 2 -- the Angel freezes because it believes it is watched
Angel.tick -> STONE no divergence, quantum-locked (harmless)
Scenario 3 -- the Angel also tries to rewrite history
ledger.verify().ok = False broken chain link, cannot rewrite the past
```
场景 1 中的伪造在内部逻辑上是一致的(创建时间早于修改时间,看起来
像是一个旧文件),因此单源启发式方法会漏掉它。它依然无法逃脱
它无法触及的见证者。

显示的 `$SI` 时间停留在 2019 年,而带外记录显示了真实的
2023 年活动;阴影间隙就是伪造的倒填日期。你可以使用
`weeping_angel.timeline.divergence_svg` 为任何文件生成它。
## 检测规则
| 规则 | 见证者 | 捕获内容 |
|---|---|---|
| `R1_si_fn_birth_divergence` | `$SI` vs `$FN` | 显示的创建时间早于内核设置的 MFT 创建时间 |
| `R2_si_journal_rollback` | `$SI` vs USN | 显示的修改时间早于日志中真实的最后写入时间 |
| `R3_internal_ordering` | `$SI` | 修改时间早于其自身的创建时间(不可能) |
| `R4_setinfo_captured` | USN | 写入与基准事实相矛盾的元数据设置操作:早于 `$FN` 创建时间、回滚到早于真实的最后写入时间,或处于未来 |
| `R5_future_timestamp` | `$SI` | 处于未来的时间戳 |
| `R6_subsecond_truncation` | `$SI` vs `$FN`/USN | `$SI` 被清零至整秒,而见证者保留了 100 纳秒的精度,这是基于 `SetFileTime` 的 stompers 将纳秒清零的特征 |
| `R7_si_fn_modified_divergence` | `$SI` vs `$FN` | 显示的修改时间早于内核设置的 `$FN` 修改时间,而经典的 stompers 不会触及后者 |
每个 `Finding` 都标记有 MITRE ATT&CK
[T1070.006](https://attack.mitre.org/techniques/T1070/006/)(Indicator Removal:
Timestomp)。Sigma 规则和基于 Sysmon Event ID 2
(FileCreateTime,该技术的实时遥测)键控的 Sysmon 配置位于
[`detections/`](detections/)。
## 已实现 vs 仅限设计
以下所有内容都是可运行、经过测试的代码(Python,以及用于记录器的 Go);
[布局](#layout) 是按文件映射的目录。亮点如下:
- **检测:** 在真实的 `$MFT` 和 USN-journal
二进制解析器(以及 MFTECmd-CSV 适配器)上应用了七条带有 ATT&CK 标签的规则,并配备了精度/召回率测试套件。
- **防篡改记录:** 一个带有 off-box HMAC
锚点的哈希链 JSONL 账本,由 Python 检测器和 Go `recorder/` 完全一致地写入:
字节一致的 SHA-256 链,经过跨语言验证。
- **响应与集成:** 一套试运行的交战规则响应层,
用于 SIEM 摄取的 ECS/OCSF 导出器,以及 Sigma/Sysmon 检测。
- **对手建模:** 悖论证明、确定性模拟器,以及配备了启发式、贝叶斯和进化策略训练的智能体的对抗性竞技场(也作为下方的 Kaggle 竞赛打包)。
- **靶场:** Terraform (Docker) 用于配置记录器机群并端到端地运行
timestomp 场景。
仅限设计(已记录文档,但在此处不可执行):内核 minifilter、
hypervisor/VMI 视角,以及实时 USN 收集。每个见证者
的真实数据源都在
[`weeping_angel/adapters/windows.py`](weeping_angel/adapters/windows.py) 和
[`docs/DESIGN.md`](docs/DESIGN.md) 中有详细说明。
## 备注/对现实情况的让步
- 复杂的样本不一定使用纯粹的“被观察/未被观察”二元状态。它可能会
按概率或定时器进行 timestomp,不会留下任何可供利用的瞬间破绽。
防御方假设它会行动,并依赖于不可磨灭的记录,而不是冻结它。
- 用虚假的观察者(诱饵 Procmon 进程、被保持的句柄)来
冻结它符合主题但很脆弱,因为这取决于能否准确枚举其检查项。应将其
视为绊线,而不是核心机制。
- 防篡改保护了已记录的过去。它无法恢复记录器
从未见过的值,因此记录器的覆盖范围才是真正的安全边界。
- 除非其头部被锚定在 off-box,否则最新的账本记录仍可能被丢弃。
`weeping_angel/anchor.py` 实现了该锚点,因此被丢弃的尾部
会表现为“锚定的头部领先于磁盘上的内容”。参见
[`docs/DESIGN.md`](docs/DESIGN.md)。
- 设置旧的时间戳本身并不具有恶意;归档程序、
restore/backup、`cp -p` 和 `rsync -t` 都会这样做。因此,`R4` 仅在
捕获到的 `setinfo` 与带外基准事实相矛盾时触发,并
豁免已知合法设置者(`trusted_setinfo_actors`)的白名单,其匹配
基于记录器提供的映像路径或签名者,而不是可伪造的名称。
## Kaggle
该竞技场还被封装为
[`kaggle/`](kaggle/) 中的
[kaggle-environments](https://github.com/Kaggle/kaggle-environments) 模拟,包含一个自包含的
notebook
([`kaggle/weeping_angel_arena.ipynb`](kaggle/weeping_angel_arena.ipynb)),该
notebook 内联定义了 env(无需附加数据集),运行一个 episode,并对
内置的智能体进行相互评分。竞赛环境是一场深度博弈:包含
staging-cost 机制(天使必须先发出活动才能进行 timestomp),因此
不存在统治性策略,外加贝叶斯(Thompson-sampling)和混合策略
基线智能体。
- 在 Kaggle 上运行:https://www.kaggle.com/code/jaq2347/weeping-angel-notebook
- 在本地运行:`pip install -e ".[arena]" && python examples/kaggle_arena.py`
- 对于官方举办的竞赛,[`kaggle/contrib/`](kaggle/contrib/) 包含了
可合并的 `kaggle-environments` 环境包,以及贡献 + 推介指南。
## 布局
```
weeping_angel/ # the package: detection logic and the simulation that exercises it
ledger.py # hash-chained, append-only, tamper-evident log
anchor.py # HMAC-authenticated off-box head anchor (closes tail-truncation)
witnesses.py # $SI / $FN / USN witnesses over a common interface
detector.py # seven divergence rules -> ATT&CK-tagged findings
paradox.py # observed/unobserved state machine + unreachability proof
simulator.py # filesystem sim, observation oracle, Angel agents
response.py # rules-of-engagement response layer (dry-run, ledger-audited)
export.py # render findings as ECS / OCSF for SIEM ingestion
timeline.py # forged-vs-true timeline as a standalone SVG
cli.py # unified `weeping-angel` command-line entry point
efficacy.py # precision/recall harness over a labeled corpus
arena.py # adversarial Angels-vs-recorder game (coverage budget)
learn.py # learned arena agent (Evolution Strategies, no deps)
adapters/windows.py # design-only real-artifact adapters
adapters/mft.py # executable: parse a raw NTFS $MFT and run the rules
adapters/mft_csv.py # executable: run the rules over an MFTECmd CSV export
adapters/usn.py # executable: parse the USN journal ($J) for the true timeline
recorder/ # out-of-band collector in Go (shared JSONL ledger, hash chain)
range/ # Terraform range: recorder fleet + timestomp scenario (Docker)
kaggle/ # the arena as a kaggle-environments sim (bot-vs-bot, optional dep)
detections/ # ATT&CK map, Sigma rules, Sysmon config (Event ID 2)
examples/ # demo, arena, and kaggle runners; data/ ($MFT + USN samples)
docs/ # DESIGN, THREAT_MODEL, WRITEUP, LAB, timeline.svg
tests/ # 115 tests, incl. Hypothesis property tests
```
## 许可证
MIT,请参阅 [LICENSE](LICENSE)。
minifilter / VMI] --> LED[(Hash-chained ledger)] FN["MFTWitness ($FN)"] LED --> JW["JournalWitness (USN)"] end REC -. observes every op .-> A SI --> DET{DivergenceDetector} FN --> DET JW --> DET DET --> F[Findings: the move, recorded] ``` ## 快速入门 ``` git clone
标签:Python, 反取证, 安全评估, 强化学习, 数字取证, 无后门, 日志审计, 自动化脚本, 请求拦截, 逆向工具