Intel TDX MMIO 暗门

摘要 Intel Trust Domain Extensions 通过内存加密和 MRTD 测量为信任域提供硬件级隔离,使 VM 免受即使已被攻陷的 VMM 的侵害。然而,TD 与 VMM 之间共享内存的设计引入了一个根本性的信任悖论:TD 依赖 VMM 维护的 EPT 映射来访问共享页,而 EPT 由不可信的 VMM 完全控制。攻击者(即恶意 VMM)可在 TD 向共享页写入数据后、读取响应前的极短时间内,将 EPT 中的 GPA→HPA 映射切换到包含恶意数据的物理页,实现 L2 地址劫持。由于 TDX 的运行时 EPT 变更不会被证明报告捕获,该攻击可完全绕过远程验证。 TDX 的信任边界 信任域与不可信 VMM Intel TDX 将虚拟机封装为信任域,其内存由 MKTME(多密钥全内存加密)引擎使用 TD 私钥加密,VMM 无法解密读取。TD 的 CPU 状态、寄存器和缓存也被隔离。远程验证方通过 MRTD(TD 内容的 SHA-384 测量)确认…

AMD SEV-SNP测量欺骗

摘要 AMD SEV-SNP 通过启动测量生成 VM 初始状态的 SHA-384 哈希,并由平台安全处理器签名为远程证明报告,为机密计算提供信任根基。然而,测量的累积过程包含多个可变但可控的输入——OVMF 固件版本、内核命令行、initrd 内容——且测量日志在 VM 启动后可被恶意 VMM 篡改。攻击者可在合法 VM 完成测量后,利用迁移接口替换测量日志中的条目,将恶意启动配置伪装成预期值;更危险的是,若利用 SHA-384 的碰撞攻击在 OVMF 固件页中注入后门,测量值可保持不变,使得从密码学验证到真实安全之间存在一道无法闭合的鸿沟。 SEV-SNP 远程证明与启动测量的信任模型 SEV-SNP 的测量累积机制 SEV-SNP 的启动测量(Launch Measurement)并非一次性计算,而是在 VM 启动过程中逐步累积的。平台安全处理器(PSP)维护一个测量寄存器,每次向 VM 加载新的内存页(通过 sev_launch_update 调用)时,PSP 都会根据预设的顺序将页面内容或元数据哈希到累积测量中。测量内容包括: 初始 VMSA 页面(VM 状态) 客户页表 OVMF 固件代码 内核命令行参数 initrd 镜像内容 每个组件的测量顺序由启动协议决定,任何顺序错乱或内容变化都会导致最终测量值不同。启动完成后,PSP 生成一个签名的证明报告(Attestation Report),其中包含最终测量值、VM 配置(策略、ASID 等)和平台证书链,远程验证方据此判断 VM 的启动状态是否可信。 证明报告中的信任链 证明报告的签名由 PSP 内置的 SEV 签名密钥(VLEK…

iOS 的 FUSE 盲区

摘要 iOS 的 Live Photos 将一段 HEIC 静止帧与 MOV 视频封装在同一资产中,其视频轨道由 CoreMedia 框架解析。MOV 文件基于原子结构,其中 tkhd 原子包含一个 3×3 变换矩阵,CoreMedia 在读取该矩阵的旋转与缩放参数时,存在一个整数溢出漏洞:当矩阵的 a 或 d 字段被刻意设置为极大的 16.16 定点数时,随后进行的乘法运算可导致宽或高变为负值,进而触发越界堆写入。攻击者可将恶意制作的 MOV 嵌入 Live Photos 资产中,通过 QuickLook 预览或 iMessage 自动下载触发 quicklookd 解析,利用此漏洞打破相册沙箱的边界,读取其他照片、视频文件内容。 Live Photos 与 MOV 原子结构 Live Photos 的双轨资产 苹果的 Live Photos 在拍摄时同时记录一张 HEIC 格式的静止帧和一段约 3 秒的 MOV 视频(通常 1440×1080,15fps)。这两个文件被存储在一个名为 IMG_XXXX.photolibrary 或直接配对(IMG_XXXX.HEIC 与 IMG_XXXX.MOV)的包结构中。当用户通过 QuickLook 预览 Live Photos 或接收…

WebRTC 插入流音频劫持

摘要 WebRTC 通过 RTCRtpSender.setParameters() 允许动态调整编码参数,其 encodings 数组用于描述 simulcast 各层的 rid 和 active 状态。然而,Chromium 实现中,对该数组与底层 RTP 流同步源的映射更新并非原子操作——攻击者可在重协商信令阶段插入一个携带伪造 rid 的高优先级编码条目,调用 setParameters() 后,内部编码器可能为这个新条目分配独立的 SSRC,而该 SSRC 并未出现在远端 SDP 中。此时音频数据会被同时发送到合法接收者和攻击者控制的 SSRC,形成无声监听。更隐蔽的是,利用 RTCRtpContributingSource 统计信息无法及时反映这一变化,使得劫持长期隐匿。 Simulcast与RTCRtpEncodingParameters的映射关系 Simulcast 的 RID 与 SSRC WebRTC 的 Simulcast 允许一个发送器(RTCRtpSender)同时生成多个不同码率或分辨率的视频/音频流,每个流由一个独立的 SSRC 标识。 在 SDP 协商中,a=simulcast:send 属性声明了这些流的 rid(Restriction Identifier),接收方根据 rid 识别流。例如: a=simulcast:send low;medium;high a=rid:low send pt=96;max-br=100000 a=rid:medium send pt=96;max-br=500000 a=rid:high send pt=96;max-br=1000000 在发送方,RTCRtpSender.getParameters().encodings 返回一个数组,每个元素对应一个 simulcast 层,包含 rid、active、maxBitrate 等属性。底层媒体引擎根据这些参数创建独立的 RTP 编码流,每个流对应唯一的 SSRC,并且该 SSRC 会通过 a=ssrc: 属性在 SDP 中声明。正常情况下,rid 与 SSRC 的映射在 setParameters() 调用后保持不变,除非明确移除或禁用某层。 setParameters的非原子性 setParameters() 允许修改 encodings 数组的某些字段(在…

XFRM隐藏隧道

摘要 Linux 内核的 XFRM 框架负责 IPsec 变换,其中 ESP 的 BEET(Bound End-to-End Tunnel)模式在解密 IPsec 包后,会重构内部 IP 头。然而,在某些内核路径中,用于构造新 IP 头的 skb 区域未被完全初始化为零,导致内核堆中残留的指针或数据碎片被嵌入数据包并返回给远端用户。攻击者可从互联网发送特制的空载荷 ESP 包,在解密后的响应中泄露堆上的内核基址、堆地址甚至密钥材料,从而彻底击溃 KASLR 并为后续内核利用铺路。 BEET 模式 IPsec ESP 隧道 IPsec ESP 支持两种经典模式:传输模式仅加密传输层以上内容,保留原始 IP 头;隧道模式则加密整个原始 IP 数据包,并添加新的外部 IP 头。BEET 模式是两者的混合:它使用外部 IP 头进行路由,但内部 IP 头在解密后被重新计算,并以最小开销嵌入外部 IP 头之后。这种模式常用于移动 IPv6 和端到端加密场景。 其核心特性对比可以参考以下表: 维度 传输模式 隧道模式 BEET 模式 IP 标头数量 1 个(原始…

Swift 中的不可见角色

摘要 Swift 5.10 引入了严格并发检查,通过 @Sendable 闭包和 Actor 隔离在编译期防止数据竞争。然而,这些安全保证几乎完全依赖于编译器的静态分析,运行时缺乏强制机制。攻击者可利用 UnsafeMutablePointer 将非 Sendable 类型强制转换为 @Sendable 闭包,并将其跨 Actor 传递;在另一个 Actor 上通过 withUnsafeCurrentTask 执行任意代码,破坏原 Actor 的状态,实现数据竞争和类型混淆。更隐蔽的是,利用 TaskLocal 传递裸指针,或通过 GCD 直接调度绕过 @MainActor 隔离,可在服务器端 Swift 应用(如 Vapor)中实现持久化的隐蔽后门。 Sendable与 Actor 隔离 Sendable协议的类型安全承诺 Sendable 是 Swift 并发模型的核心协议之一,用于标记可以安全地跨并发域传递的类型。值类型(如 Int、String)、无内部共享状态的 final class 以及显式标记为 @Sendable 的闭包均符合 Sendable。编译器会检查所有跨 Actor 或 Task 传递的值的类型,如果非 Sendable 类型被错误传递,则发出严格并发检查的编译错误或警告。 在底层,@Sendable 闭包会被编译器转换为捕获不可变副本或同步原语保护的上下文,但这一转换完全发生在 SIL(Swift Intermediate Language)层,最终生成的 LLVM IR 中并没有额外的运行时检查。也就是说,一旦绕过编译器的静态检查,运行时将不加区别地执行任何闭包。 Actor 隔离的执行语义 Actor 是一种引用类型,通过串行执行队列保护其内部状态。所有对 Actor 可变状态的访问都必须通过 await 异步调用或在 Actor 内部的同步代码中进行。编译器负责保证这一约束:在 Actor 外部,无法直接访问其存储属性或调用未标记 nonisolated 的方法。 运行时实现上,Actor 携带一个内部的 DistributedActor 标识和串行执行器。当任务需要在 Actor 上执行时,会被调度到该执行器上排队。但 Actor 的执行器本身是可替换的,且 GCD 等旧并发 API 可以绕过这一调度机制,直接将任务提交到任意队列执行。这构成了 Actor…