← 返回博客

备用数据流:人人都会忘记的第二个 $DATA 属性

· 阅读 2 分钟

ADS 是不断让初级分析师感到意外的 NTFS 特性。一个文件可以拥有多个 $DATA 属性。无名的那个对应 dir 显示的文件大小。其它的,即标识符中带冒号的属性,对大多数人惯用的工具都是不可见的。攻击者知道这一点。Microsoft 知道这一点。审阅你 IR 报告的审计人员也应该知道。

机制简述

在 MFT 记录中,属性类型 0x80$DATA。属性头携带一个可选名称。一条记录可以承载多个 $DATA 属性:一个无名的(主数据流)以及任意数量的命名属性。在用户态使用 filename:streamname 格式访问它们。

echo payload > readme.txt:nope
type readme.txt:nope

按资源管理器显示的任何度量,readme.txt 的大小都是 0 字节。命名为 nope 的数据流保存了真正的载荷。同一条 MFT 记录、同一个父目录索引项、两个独立的数据属性。

这不是 bug。这是 1993 年的设计决策,NTFS 从 HPFS 继承而来,用于让 Services for Macintosh 附加 resource forks。今天几乎没有人为此使用 ADS。包括 Microsoft 在内的其他人,将其用作临时元数据的载体。

Windows 自身在哪里放 ADS

Zone.Identifier 是最著名的例子。Edge、Chrome、Firefox 和 Outlook 都会在任何跨越安全边界的文件上添加它。内容是一段 INI 片段,包含来源 URL、引荐来源以及触发 Office 与 SmartScreen 的 Mark-of-the-Web 防护的 ZoneId=3 行。如果你在读 MFT,发现 Downloads\ 下的某个二进制文件没有 Zone.Identifier,那就要问为什么。可能有人运行了 Unblock-File,或者文件经过一个会丢弃数据流的归档工具被复制。

其他 Microsoft 认可、你会遇到的数据流:

  • 亚洲语言键盘布局文件上的 $KSP
  • 保存到磁盘上的 Outlook 附件上的 OECustomProperty 等。
  • WIMBoot 和 CompactOS 下压缩文件上的 Wof 重解析数据。
  • Defender 已经指纹化的可执行文件上的 SmartScreen
  • ConfigMgr 缓存目录上的 encryptable

这些非常常见。在把数据流标记为可疑之前,先了解你的基线长什么样。

攻击者实际上拿 ADS 做什么

反复出现三种模式:

  1. 载荷藏匿、独立加载。 可见文件是无害的(Word 文档、PDF、许可证文件)。命名数据流承载真正的 PE。WMI、wmic process call createrundll32 直接启动 legit.docx:payload.exe。如今 Defender 会扫描命名数据流,但许多 EDR 在数据流由受信任进程创建时仍然不会扫描。
  2. Living-off-the-land 藏匿点。 把 PowerShell 载荷写入 ads:script.ps1,然后用 Get-Content -Stream 执行。在红队驻场服务里出奇地常见,因为它能躲过仅基于路径的 IOC 搜索。
  3. 借助系统文件的备用数据流持久化。 C:\Windows\System32\drivers\etc\hosts:backdoor 是教科书例子。hosts 文件看起来未被触动,时间戳甚至可能保持原样,而大多数文件完整性监控工具都不会看无名数据流之外的东西。

共同特征:用 dir 看不到,在资源管理器中看不到,对可见文件做哈希也看不到,但读 MFT 记录就能看到。

在在线主机上检测

dir /R 在 cmd 中枚举数据流。PowerShell 的 Get-Item -Stream * 也能做到,输出更整洁。Sysinternals 的 streams.exe 可以递归遍历整棵树。三者在所处卷上都能正常工作。但当卷处于离线状态,或者你不知道该检查哪些文件时,它们都帮不上忙。

dir /R C:\Users\bob\Documents\
Get-ChildItem -Recurse | ForEach-Object { Get-Item $_.FullName -Stream * } |
  Where-Object Stream -ne ':$DATA'

第二条 one-liner 枚举一棵树上所有非默认数据流。在全新 Windows 安装上运行,你就已经能得到数百条命中,绝大多数是 Zone.Identifier。把范围缩到大于几百字节的数据流,噪声会迅速减少。

为什么 MFT 是更好的视角

主机上的命令按文件枚举。它们会漏掉你没想到要检查的东西。MFT 不会。每一个 $DATA 属性,无论是否命名,都以属性类型 0x80 写入记录。遍历表,把每条记录的所有 $DATA 属性连同名称和大小一并列出,你就用一次扫描得到了卷上所有数据流的详尽清单。

按文件枚举无法给你的几件事:

  • 位于你根本不会去查的目录下的文件上的数据流,包括 C:\Windows\Temp\C:\$Recycle.Bin\
  • 已删除文件上的数据流。MFT 记录在删除后仍然存在;ADS 依旧列在属性流中。Sleuth Kit 的 flsistat 会显示它们,MFTECmd 与 omerbenamram/mft CLI 也会。
  • 内容直接驻留在 MFT 记录中的常驻数据流。小载荷(PowerShell loader、base64 块、编码后的配置)常常能塞进 1,024 字节记录的空闲处。无需触碰数据区,即可直接从 MFT 提取读到它们。大小阈值见 resident data
  • 数据流名称。MFT 保留攻击者选择的名称。在文件大小列表里 :payload.exe 看起来很无辜;当你对属性转储 grep exe 时它就会跳出来。

我实际使用的取证过滤器

用 MFTECmd 或 mft_dump 解析完 MFT 之后,我导出所有拥有多于一个 $DATA 属性的记录。然后剔除:

  • 额外数据流名称为 Zone.Identifier 且小于 1 KB 的项。
  • 位于 \Windows\WinSxS\ 下的项(清单存储,里面全是合法数据流)。
  • 位于厂商签名应用目录下、数据流为已知缩略图或元数据键的项。

剩下的就是工作集。在一台干净工作站上通常少于一百条记录。在发生过有趣事件的主机上,差异会立刻浮现。

把剩余项与 USN journal 交叉比对,查看每个数据流何时被创建或最后修改。一个在 02:14 出现、之后未被触动的命名 $DATA 属性值得仔细看看。如果有的话,再配合 Sysmon 与 Security 事件日志:Sysmon Event ID 15(FileCreateStreamHash)是唯一一个在记录 ADS 创建的同时捕获数据流内容哈希的事件 ID。

关于 Defender 的提醒

现代 Defender 默认会扫描 ADS。对于"把已知恶意 PE 丢进数据流"这种简单粗暴的模式,它确实很擅长。对藏在数据流里的小段混淆 PowerShell,它表现较弱,而且并不总是触碰排除路径下的数据流。不要把 Defender 的沉默视作不存在的证据。

延伸阅读

  • Microsoft,File Streams。官方机制说明,包括复制所有数据流的 BackupRead/BackupWrite API。
  • Sleuth Kit 的 istatfls,离线枚举可显出 ADS。
  • Microsoft 的 Mark of the Web 文档,说明 Zone.Identifier 的实际作用以及 Office 如何使用它。

外部资源