LUKS2 Header Malleability and Null-Cipher Abuse in Confidential VMs
Tip
学习和实践 AWS 黑客技术:
HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
TL;DR
- 许多基于 Linux 的 Confidential VMs (CVMs) 在 AMD SEV-SNP 或 Intel TDX 上运行,使用 LUKS2 作为持久存储。磁盘上的 LUKS2 header 是可篡改的,对于与存储相邻的攻击者没有完整性保护。
- 如果 header 的 data segment encryption 被设置为 null cipher(例如 “cipher_null-ecb”),cryptsetup 会接受它,guest 会在认为磁盘已加密的情况下透明地读/写明文。
- 在 cryptsetup 2.8.0 及以前,null ciphers 可用于 keyslots;从 2.8.1 起,对于带非空密码的 keyslots 会被拒绝,但 null ciphers 仍然允许用于 volume segments。
- Remote attestation 通常只度量 VM 的代码/配置,而不是可变的外部 LUKS headers;如果没有显式的验证/度量,拥有磁盘写入权限的攻击者可以强制明文 I/O。
Background: LUKS2 on-disk format (what matters for attackers)
- A LUKS2 device starts with a header followed by encrypted data.
- The header contains two identical copies of a binary section and a JSON metadata section, plus one or more keyslots.
- JSON metadata defines:
- keyslots enabled and their wrapping KDF/cipher
- segments that describe the data area (cipher/mode)
- digests (e.g., hash of the volume key to verify passphrases)
- Typical secure values: keyslot KDF argon2id; keyslot and data segment encryption 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 headers are not authenticated against storage tampering. A host/storage attacker can rewrite the JSON metadata accepted by cryptsetup.
- As of cryptsetup 2.8.0, headers that set a segment’s encryption to cipher_null-ecb are accepted. The null cipher ignores keys and returns plaintext.
- Up to 2.8.0, null ciphers could also be used for keyslots (keyslot opens with any passphrase). Since 2.8.1, null ciphers are rejected for keyslots with non-empty passwords, but remain allowed for segments. Switching only the segment cipher still yields plaintext I/O post-2.8.1.
Threat model: why attestation didn’t save you by default
- CVMs aim to ensure confidentiality, integrity, and authenticity in an untrusted host.
- Remote attestation usually measures the VM image and launch configuration, not the mutable LUKS header living on untrusted storage.
- If your CVM trusts an on-disk header without robust validation/attestation, a storage attacker can alter it to a null cipher and your guest will mount a plaintext volume without error.
Exploitation (storage write access required)
Preconditions:
- 对 CVM 的 LUKS2 加密块设备具有写入权限。
- 客户机使用磁盘上的 LUKS2 header 而没有进行健壮的验证/attestation。
Steps (high level):
- 读取 header JSON 并识别 data segment 定义。示例目标字段:segments[“0”].encryption。
- 将 data segment 的 encryption 设置为 null cipher,例如 cipher_null-ecb。保持 keyslot 参数和 digest 结构不变,以便 guest 的常用 passphrase 仍然“有效”。
- 更新两个 header 副本及相关的 header digests,使 header 自洽。
- 在下一次启动时,guest 运行 cryptsetup,使用其 passphrase 成功解锁现有的 keyslot 并挂载卷。因为 segment cipher 是 null cipher,所有读/写都是明文。
Variant (pre-2.8.1 keyslot abuse): 如果某个 keyslot 的 area.encryption 使用 null cipher,则它可以被任意 passphrase 打开。将其与 null segment cipher 结合即可在不知晓 guest 密钥的情况下无缝获得明文访问。
Robust mitigations (avoid TOCTOU with detached headers)
始终将磁盘上的 LUKS headers 视为不受信任的输入。使用 detached-header 模式,以便验证和打开使用来自受保护 RAM 的相同受信任字节:
# 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
然后执行以下一项(或多项):
- 对整个 header 进行 MAC
- 在使用前对整个 header 计算/验证 MAC。
- 只有在 MAC 验证通过时才打开 volume。
- 实际例子:Flashbots tdx-init 和 Fortanix Salmiac 采用了基于 MAC 的验证。
- 严格的 JSON 验证(向后兼容)
- 导出 JSON 元数据并验证一份严格的参数 allowlist(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
示例验证器(强制安全字段)
```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") ```- Measure/attest the header
- Remove random salts/digests and measure the sanitized header into TPM/TDX/SEV PCRs or KMS policy state.
- Release decryption keys only when the measured header matches an approved, safe profile.
Operational guidance:
- Enforce detached header + MAC or strict validation; never trust on-disk headers directly.
- Consumers of attestation should deny pre-patch framework versions in allow-lists.
关于版本和维护者立场的说明
- cryptsetup 维护者澄清,LUKS2 并非为在此场景下提供针对存储篡改的完整性保护而设计;null ciphers 为向后兼容而保留。
- cryptsetup 2.8.1 (Oct 19, 2025) 在 keyslots 中带有非空密码时拒绝 null ciphers,但仍然允许 segments 使用 null ciphers。
快速检查与分流
- 检查是否有任何 segment encryption 被设置为 a null cipher:
cryptsetup luksDump --type luks2 --dump-json-metadata /dev/VDISK \
| jq -r '.segments | to_entries[] | "segment=" + .key + ", enc=" + .value.encryption'
- 在打开 volume 之前,验证 keyslot 和 segment 的算法。如果无法进行 MAC,请强制执行严格的 JSON 验证,并使用来自 protected memory 的 detached header 打开。
参考资料
- 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
学习和实践 AWS 黑客技术:
HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
HackTricks Cloud

