本仓库包含一个针对 SEV 固件中漏洞的利用利用方法。该漏洞允许在 SEV-SNP 客户机被解除授权后,解密其任意内存。
已在版本 1.55.16(撰写本文时的最新版本)上进行测试。
SEV 固件包含一个名为 master_handler_table 的表,其中包含所有命令的函数指针以及一些与命令相关的其他属性。其中两个附加属性是 cmd_buf_type 和 snp_cmd_buf_enforcement。cmd_buf_type 决定命令缓冲区是否应从主机内存复制或复制到主机内存。snp_cmd_buf_enforcement 决定这些复制操作是否应受到检查,以验证支持命令缓冲区的内存是否处于 FIRMWARE 或 DEFAULT 状态。对于 cmd_buf_type 为 CMD_BUF_OUTPUT_ONLY、CMD_BUF_INPUT_AND_OUTPUT 或 CMD_BUF_INPUT_AND_OUTPUT_ERROR 的命令,其 snp_cmd_buf_enforcement 均应设置为 true。否则,写回命令输出可能会导致 RMP 覆盖区域内的内存损坏。snp_cmd_buf_enforcement 对于所有此类命令均为 true,但有一个例外—— SEV_MCMD_ID_ATTESTATION:此命令的 cmd_buf_type 设置为 CMD_BUF_INPUT_AND_OUTPUT_ERROR,但 snp_cmd_buf_enforcement 却设置为 false。因此,可以使用指向 RMP 覆盖内存的命令缓冲区执行 SEV_MCMD_ID_ATTESTATION,并在输出写回时导致该内存损坏。
我不明白为什么 SEV_MCMD_ID_ATTESTATION 需要成为例外,在我看来这很可能是打字/复制粘贴错误。
SEV_MCMD_ID_ATTESTATION 仅向命令缓冲区中的单个字段 length(4 字节)写入数据,因此我们只能利用这些字节来损坏内存。SEV_MCMD_ID_ATTESTATION 总是写入相同的值——0x000000d0。幸运的是,命令缓冲区没有对齐要求,因此我们可以重复移位命令缓冲区来损坏更大范围的连续内存。我们将利用这一点,用静态模式损坏客户机上下文页面的前 16 个字节。这前 16 个字节包含 UMC 密钥种子,因此通过将其强制为静态值,我们可以迫使客户机的加密密钥成为静态值。
这里提供的利用方法很大程度上基于我为 SWPSIRT-2684/CVE-2023-31355 提供的利用方法。
要利用该漏洞,我们可以执行以下步骤:
SEV_MCMD_ID_ATTESTATION 所必需的。保持此客户机运行。0x2000 处为受害者客户机创建一个客户机上下文页面。RMP 覆盖区域内的任何其他地址也可以,不过固定地址有助于调试。0x2000 处为攻击者客户机创建一个客户机上下文页面。这必须与步骤 1 中使用的地址相同。SNP_DBG_ENCRYPT 命令,利用攻击者客户机的上下文页面解密受害者客户机的内存。这会成功,因为受害者客户机和攻击者客户机共享同一个 UMC 密钥种子。这里的影响至少应与 SWPSIRT-2684 相同。目前尚不清楚此漏洞是否可用于解密正在运行的客户机在解除授权之前的内存。
snp_cmd_buf_enforcement 应为 SEV_MCMD_ID_ATTESTATION 设置为 true。
有趣的是,Linux KVM 主机支持补丁不需要更新,因为它们已经将 SEV_CMD_ATTESTATION_REPORT 列为 sev_cmd_buf_writable 中需要其命令缓冲区处于 FIRMWARE 状态的命令。其他虚拟机监控程序可能需要进行更改,也可能不需要。