LUKS2 Header Malleability and Null-Cipher Abuse in Confidential VMs
Tip
Lernen & üben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
TL;DR
- Viele Linux-basierte Confidential VMs (CVMs), die auf AMD SEV-SNP oder Intel TDX laufen, verwenden LUKS2 für persistenten Speicher. Der on-disk LUKS2-Header ist malleable und nicht gegen storage-adjacent Angreifer integritätsgeschützt.
- Wenn die Verschlüsselung des Header-Datensegments auf einen null cipher gesetzt ist (z. B. “cipher_null-ecb”), akzeptiert cryptsetup das und der Guest liest/schreibt transparent Klartext, während er glaubt, die Festplatte sei verschlüsselt.
- Bis einschließlich cryptsetup 2.8.0 konnten null ciphers für keyslots verwendet werden; seit 2.8.1 werden sie für keyslots mit nicht-leerem Passwort abgelehnt, aber null ciphers sind weiterhin für volume segments erlaubt.
- Remote attestation misst üblicherweise VM-Code/Config, nicht veränderliche externe LUKS-Header; ohne explizite Validierung/Measurement kann ein Angreifer mit Schreibzugriff auf die Disk Klartext-I/O erzwingen.
Background: LUKS2 on-disk format (what matters for attackers)
- Ein LUKS2-Device beginnt mit einem Header, gefolgt von verschlüsselten Daten.
- Der Header enthält zwei identische Kopien eines binären Abschnitts und einen JSON-Metadatenabschnitt sowie einen oder mehrere keyslots.
- Die JSON-Metadaten definieren:
- welche keyslots aktiviert sind und deren wrapping KDF/cipher
- segments, die den Datenbereich beschreiben (cipher/mode)
- digests (z. B. Hash des volume key zur Verifikation von Passphrasen)
- Typische sichere Werte: keyslot KDF argon2id; keyslot- und data segment-Verschlüsselung aes-xts-plain64.
Quickly inspect the segment cipher directly from JSON:
# Read JSON metadata and print the configured data segment cipher
cryptsetup luksDump --type luks2 --dump-json-metadata /dev/VDISK \
| jq -r '.segments["0"].encryption'
Root cause
- LUKS2-Header sind nicht gegen Manipulationen des Speichers authentifiziert. Ein Host-/Storage-Angreifer kann die von cryptsetup akzeptierten JSON-Metadaten umschreiben.
- Seit cryptsetup 2.8.0 werden Header akzeptiert, die die Verschlüsselung eines Segments auf cipher_null-ecb setzen. Der null cipher ignoriert Schlüssel und liefert Klartext zurück.
- Bis einschließlich 2.8.0 konnten null ciphers auch für keyslots verwendet werden (ein keyslot öffnet sich mit jeder Passphrase). Seit 2.8.1 werden null ciphers für keyslots mit nicht-leeren Passwörtern abgelehnt, bleiben aber für Segmente erlaubt. Allein das Ändern des Segment-Ciphers führt auch nach 2.8.1 weiterhin zu Klartext-I/O.
Threat model: why attestation didn’t save you by default
- CVMs sollen Vertraulichkeit, Integrität und Authentizität in einem nicht vertrauenswürdigen Host sicherstellen.
- Remote attestation misst üblicherweise das VM-Image und die Launch-Konfiguration, nicht den veränderlichen LUKS-Header, der auf nicht vertrauenswürdigem Speicher liegt.
- Wenn deine CVM einem on-disk Header ohne robuste Validierung/attestation vertraut, kann ein Storage-Angreifer ihn auf einen null cipher ändern und dein Guest wird ein Klartext-Volume ohne Fehler mounten.
Exploitation (storage write access required)
Preconditions:
- Schreibzugriff auf das LUKS2-verschlüsselte Blockgerät der CVM.
- Der Guest verwendet den on-disk LUKS2-Header ohne robuste Validierung/attestation.
Steps (high level):
- Lese das Header-JSON und identifiziere die Definition des Datensegments. Beispielziel-Feld: segments[“0”].encryption.
- Setze die Verschlüsselung des Datensegments auf einen null cipher, z.B. cipher_null-ecb. Belasse keyslot-Parameter und Digest-Struktur unverändert, sodass die übliche Passphrase des Guests weiterhin „funktioniert“.
- Aktualisiere beide Header-Kopien und die zugehörigen Header-Digests, sodass der Header selbstkonsistent ist.
- Beim nächsten Boot führt der Guest cryptsetup aus, entsperrt erfolgreich den vorhandenen keyslot mit seiner Passphrase und mountet das Volume. Da der Segment-Cipher ein null cipher ist, sind alle Lese-/Schreibvorgänge Klartext.
Variant (pre-2.8.1 keyslot abuse): wenn area.encryption eines keyslots ein null cipher ist, öffnet er sich mit jeder Passphrase. Kombiniere das mit einem null segment cipher für nahtlosen Klartext-Zugriff, ohne das Guest-Secret zu kennen.
Robust mitigations (avoid TOCTOU with detached headers)
Behandle on-disk LUKS-Header stets als nicht vertrauenswürdige Eingabe. Verwende detached-header mode, damit Validierung und Öffnen dieselben vertrauenswürdigen Bytes aus geschütztem RAM verwenden:
# Copy header into protected memory (e.g., tmpfs) and open from there
cryptsetup luksHeaderBackup --header-backup-file /tmp/luks_header /dev/VDISK
cryptsetup open --type luks2 --header /tmp/luks_header /dev/VDISK --key-file=key.txt
Dann erzwinge eine (oder mehrere) der folgenden Maßnahmen:
- Den gesamten Header mit einem MAC sichern
- Berechne/verifiziere vor der Verwendung einen MAC über den gesamten Header.
- Öffne das Volume nur, wenn der MAC verifiziert ist.
- Beispiele in der Praxis: Flashbots tdx-init und Fortanix Salmiac nutzen MAC-basierte Verifikation.
- Strikte JSON-Validierung (abwärtskompatibel)
- Dump JSON-Metadaten und validiere eine strikte allowlist von Parametern (KDF, ciphers, segment count/type, flags).
#!/bin/bash
set -e
# Store header in confidential RAM fs
cryptsetup luksHeaderBackup --header-backup-file /tmp/luks_header $BLOCK_DEVICE
# Dump JSON metadata header to a file
cryptsetup luksDump --type luks2 --dump-json-metadata /tmp/luks_header > header.json
# Validate the header
python validate.py header.json
# Open the cryptfs using key.txt
cryptsetup open --type luks2 --header /tmp/luks_header $BLOCK_DEVICE --key-file=key.txt
Beispiel-Validator (sichere Felder erzwingen)
```python from json import load import sys with open(sys.argv[1], "r") as f: header = load(f) if len(header["keyslots"]) != 1: raise ValueError("Expected 1 keyslot") if header["keyslots"]["0"]["type"] != "luks2": raise ValueError("Expected luks2 keyslot") if header["keyslots"]["0"]["area"]["encryption"] != "aes-xts-plain64": raise ValueError("Expected aes-xts-plain64 encryption") if header["keyslots"]["0"]["kdf"]["type"] != "argon2id": raise ValueError("Expected argon2id kdf") if len(header["tokens"]) != 0: raise ValueError("Expected 0 tokens") if len(header["segments"]) != 1: raise ValueError("Expected 1 segment") if header["segments"]["0"]["type"] != "crypt": raise ValueError("Expected crypt segment") if header["segments"]["0"]["encryption"] != "aes-xts-plain64": raise ValueError("Expected aes-xts-plain64 encryption") if "flags" in header["segments"]["0"] and header["segments"]["0"]["flags"]: raise ValueError("Segment contains unexpected flags") ```- Header messen/attestieren
- Entferne zufällige Salts/Digests und messe den bereinigten Header in TPM/TDX/SEV PCRs oder KMS policy state.
- Gib Entschlüsselungskeys nur frei, wenn der gemessene Header einem genehmigten, sicheren Profil entspricht.
Operational guidance:
- Enforce detached header + MAC oder strenge Validierung; vertraue niemals direkt auf on-disk Header.
- Empfänger von Attestierungen sollten pre-patch Framework-Versionen in allow-lists ablehnen.
Hinweise zu Versionen und Position der Maintainer
- Die Maintainer von cryptsetup haben klargestellt, dass LUKS2 nicht dafür ausgelegt ist, Integrität gegen Manipulationen des Speichers in diesem Kontext bereitzustellen; null ciphers werden zur Abwärtskompatibilität beibehalten.
- cryptsetup 2.8.1 (Oct 19, 2025) lehnt null ciphers für keyslots mit nicht-leeren Passwörtern ab, erlaubt aber weiterhin null ciphers für segments.
Schnelle Checks und Triage
- Prüfe, ob die Segmentverschlüsselung auf einen null cipher gesetzt ist:
cryptsetup luksDump --type luks2 --dump-json-metadata /dev/VDISK \
| jq -r '.segments | to_entries[] | "segment=" + .key + ", enc=" + .value.encryption'
- Überprüfen Sie keyslot- und Segment-Algorithmen, bevor Sie das Volume öffnen. Wenn Sie MAC nicht durchführen können, erzwingen Sie eine strikte JSON-Validierung und öffnen Sie das Volume mit dem getrennten Header aus dem geschützten Speicher.
Referenzen
- Vulnerabilities in LUKS2 disk encryption for confidential VMs (Trail of Bits)
- cryptsetup issue #954 (null cipher acceptance and integrity considerations)
- CVE-2025-59054
- CVE-2025-58356
- Related context: CVE-2021-4122 (auto-recovery path silently decrypting disks)
Tip
Lernen & üben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
HackTricks Cloud

