Skip to content

Commit 6726a5e

Browse files
authored
Merge pull request #231 from HackTricks-wiki/update_Vulnerabilities_in_LUKS2_disk_encryption_for_confi_20251030_130547
Vulnerabilities in LUKS2 disk encryption for confidential VM...
2 parents a9a58a9 + 293ae05 commit 6726a5e

File tree

3 files changed

+157
-7
lines changed

3 files changed

+157
-7
lines changed

src/SUMMARY.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
# ⛈️ Pentesting Cloud
5858

5959
- [Pentesting Cloud Methodology](pentesting-cloud/pentesting-cloud-methodology.md)
60+
- [Luks2 Header Malleability Null Cipher Abuse](pentesting-cloud/confidential-computing/luks2-header-malleability-null-cipher-abuse.md)
6061
- [Kubernetes Pentesting](pentesting-cloud/kubernetes-security/README.md)
6162
- [Kubernetes Basics](pentesting-cloud/kubernetes-security/kubernetes-basics.md)
6263
- [Pentesting Kubernetes Services](pentesting-cloud/kubernetes-security/pentesting-kubernetes-services/README.md)
@@ -579,4 +580,3 @@
579580

580581
- [HackTricks Pentesting Network$$external:https://book.hacktricks.wiki/en/generic-methodologies-and-resources/pentesting-network/index.html$$]()
581582
- [HackTricks Pentesting Services$$external:https://book.hacktricks.wiki/en/network-services-pentesting/pentesting-ssh.html$$]()
582-
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
# LUKS2 Header Malleability and Null-Cipher Abuse in Confidential VMs
2+
3+
{{#include ../../banners/hacktricks-training.md}}
4+
5+
## TL;DR
6+
7+
- Many Linux-based Confidential VMs (CVMs) running on AMD SEV-SNP or Intel TDX use LUKS2 for persistent storage. The on-disk LUKS2 header is malleable and not integrity-protected against storage-adjacent attackers.
8+
- If the header’s data segment encryption is set to a null cipher (e.g., "cipher_null-ecb"), cryptsetup accepts it and the guest transparently reads/writes plaintext while believing the disk is encrypted.
9+
- Prior to and including cryptsetup 2.8.0, null ciphers could be used for keyslots; since 2.8.1 they are rejected for keyslots with non-empty passwords, but null ciphers remain allowed for volume segments.
10+
- Remote attestation usually measures VM code/config, not mutable external LUKS headers; without explicit validation/measurement, an attacker with disk write access can force plaintext I/O.
11+
12+
## Background: LUKS2 on-disk format (what matters for attackers)
13+
14+
- A LUKS2 device starts with a header followed by encrypted data.
15+
- The header contains two identical copies of a binary section and a JSON metadata section, plus one or more keyslots.
16+
- JSON metadata defines:
17+
- keyslots enabled and their wrapping KDF/cipher
18+
- segments that describe the data area (cipher/mode)
19+
- digests (e.g., hash of the volume key to verify passphrases)
20+
- Typical secure values: keyslot KDF argon2id; keyslot and data segment encryption aes-xts-plain64.
21+
22+
Quickly inspect the segment cipher directly from JSON:
23+
24+
```bash
25+
# Read JSON metadata and print the configured data segment cipher
26+
cryptsetup luksDump --type luks2 --dump-json-metadata /dev/VDISK \
27+
| jq -r '.segments["0"].encryption'
28+
```
29+
30+
## Root cause
31+
32+
- LUKS2 headers are not authenticated against storage tampering. A host/storage attacker can rewrite the JSON metadata accepted by cryptsetup.
33+
- 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.
34+
- 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.
35+
36+
## Threat model: why attestation didn’t save you by default
37+
38+
- CVMs aim to ensure confidentiality, integrity, and authenticity in an untrusted host.
39+
- Remote attestation usually measures the VM image and launch configuration, not the mutable LUKS header living on untrusted storage.
40+
- If your CVM trusts an on-disk header without robust validation/measurement, a storage attacker can alter it to a null cipher and your guest will mount a plaintext volume without error.
41+
42+
## Exploitation (storage write access required)
43+
44+
Preconditions:
45+
- Write access to the CVM’s LUKS2-encrypted block device.
46+
- The guest uses the on-disk LUKS2 header without robust validation/attestation.
47+
48+
Steps (high level):
49+
1) Read the header JSON and identify the data segment definition. Example target field: segments["0"].encryption.
50+
2) Set the data segment encryption to a null cipher, e.g., cipher_null-ecb. Keep keyslot parameters and digest structure intact so the guest’s usual passphrase still “works.”
51+
3) Update both header copies and associated header digests so the header is self-consistent.
52+
4) On next boot, the guest runs cryptsetup, successfully unlocks the existing keyslot with its passphrase, and mounts the volume. Because the segment cipher is a null cipher, all reads/writes are plaintext.
53+
54+
Variant (pre-2.8.1 keyslot abuse): if a keyslot’s area.encryption is a null cipher, it opens with any passphrase. Combine with a null segment cipher for seamless plaintext access without knowing the guest secret.
55+
56+
## Robust mitigations (avoid TOCTOU with detached headers)
57+
58+
Always treat on-disk LUKS headers as untrusted input. Use detached-header mode so validation and opening use the same trusted bytes from protected RAM:
59+
60+
```bash
61+
# Copy header into protected memory (e.g., tmpfs) and open from there
62+
cryptsetup luksHeaderBackup --header-backup-file /tmp/luks_header /dev/VDISK
63+
cryptsetup open --type luks2 --header /tmp/luks_header /dev/VDISK --key-file=key.txt
64+
```
65+
66+
Then enforce one (or more) of:
67+
68+
1) MAC the full header
69+
- Compute/verify a MAC over the entire header prior to use.
70+
- Only open the volume when the MAC verifies.
71+
- Examples in the wild: Flashbots tdx-init and Fortanix Salmiac adopted MAC-based verification.
72+
73+
2) Strict JSON validation (backward compatible)
74+
- Dump JSON metadata and validate a strict allowlist of parameters (KDF, ciphers, segment count/type, flags).
75+
76+
```bash
77+
#!/bin/bash
78+
set -e
79+
# Store header in confidential RAM fs
80+
cryptsetup luksHeaderBackup --header-backup-file /tmp/luks_header $BLOCK_DEVICE
81+
# Dump JSON metadata header to a file
82+
cryptsetup luksDump --type luks2 --dump-json-metadata /tmp/luks_header > header.json
83+
# Validate the header
84+
python validate.py header.json
85+
# Open the cryptfs using key.txt
86+
cryptsetup open --type luks2 --header /tmp/luks_header $BLOCK_DEVICE --key-file=key.txt
87+
```
88+
89+
<details>
90+
<summary>Example validator (enforce safe fields)</summary>
91+
92+
```python
93+
from json import load
94+
import sys
95+
with open(sys.argv[1], "r") as f:
96+
header = load(f)
97+
if len(header["keyslots"]) != 1:
98+
raise ValueError("Expected 1 keyslot")
99+
if header["keyslots"]["0"]["type"] != "luks2":
100+
raise ValueError("Expected luks2 keyslot")
101+
if header["keyslots"]["0"]["area"]["encryption"] != "aes-xts-plain64":
102+
raise ValueError("Expected aes-xts-plain64 encryption")
103+
if header["keyslots"]["0"]["kdf"]["type"] != "argon2id":
104+
raise ValueError("Expected argon2id kdf")
105+
if len(header["tokens"]) != 0:
106+
raise ValueError("Expected 0 tokens")
107+
if len(header["segments"]) != 1:
108+
raise ValueError("Expected 1 segment")
109+
if header["segments"]["0"]["type"] != "crypt":
110+
raise ValueError("Expected crypt segment")
111+
if header["segments"]["0"]["encryption"] != "aes-xts-plain64":
112+
raise ValueError("Expected aes-xts-plain64 encryption")
113+
if "flags" in header["segments"]["0"] and header["segments"]["0"]["flags"]:
114+
raise ValueError("Segment contains unexpected flags")
115+
```
116+
117+
</details>
118+
119+
3) Measure/attest the header
120+
- Remove random salts/digests and measure the sanitized header into TPM/TDX/SEV PCRs or KMS policy state.
121+
- Release decryption keys only when the measured header matches an approved, safe profile.
122+
123+
Operational guidance:
124+
- Enforce detached header + MAC or strict validation; never trust on-disk headers directly.
125+
- Consumers of attestation should deny pre-patch framework versions in allow-lists.
126+
127+
## Notes on versions and maintainer position
128+
129+
- cryptsetup maintainers clarified that LUKS2 was not designed to provide integrity against storage tampering in this setting; null ciphers are retained for backward compatibility.
130+
- cryptsetup 2.8.1 (Oct 19, 2025) rejects null ciphers for keyslots with non-empty passwords but still allows null ciphers for segments.
131+
132+
## Quick checks and triage
133+
134+
- Inspect whether any segment encryption is set to a null cipher:
135+
136+
```bash
137+
cryptsetup luksDump --type luks2 --dump-json-metadata /dev/VDISK \
138+
| jq -r '.segments | to_entries[] | "segment=" + .key + ", enc=" + .value.encryption'
139+
```
140+
141+
- Verify keyslot and segment algorithms before opening the volume. If you cannot MAC, enforce strict JSON validation and open using the detached header from protected memory.
142+
143+
## References
144+
145+
- [Vulnerabilities in LUKS2 disk encryption for confidential VMs (Trail of Bits)](https://blog.trailofbits.com/2025/10/30/vulnerabilities-in-luks2-disk-encryption-for-confidential-vms/)
146+
- [cryptsetup issue #954 (null cipher acceptance and integrity considerations)](https://gitlab.com/cryptsetup/cryptsetup/-/issues/954)
147+
- [CVE-2025-59054](https://nvd.nist.gov/vuln/detail/CVE-2025-59054)
148+
- [CVE-2025-58356](https://nvd.nist.gov/vuln/detail/CVE-2025-58356)
149+
- [Related context: CVE-2021-4122 (auto-recovery path silently decrypting disks)](https://www.cve.org/CVERecord?id=CVE-2021-4122)
150+
151+
{{#include ../../banners/hacktricks-training.md}}

src/pentesting-cloud/pentesting-cloud-methodology.md

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -446,14 +446,13 @@ aws-security/
446446
azure-security/
447447
{{#endref}}
448448

449-
### Attack Graph
449+
## Common Cloud Security Features
450450

451-
[**Stormspotter** ](https://github.com/Azure/Stormspotter)creates an “attack graph” of the resources in an Azure subscription. It enables red teams and pentesters to visualize the attack surface and pivot opportunities within a tenant, and supercharges your defenders to quickly orient and prioritize incident response work.
452-
453-
### Office365
454-
455-
You need **Global Admin** or at least **Global Admin Reader** (but note that Global Admin Reader is a little bit limited). However, those limitations appear in some PS modules and can be bypassed accessing the features **via the web application**.
451+
### Confidential Computing
456452

453+
{{#ref}}
454+
confidential-computing/luks2-header-malleability-null-cipher-abuse.md
455+
{{#endref}}
457456

458457
{{#include ../banners/hacktricks-training.md}}
459458

0 commit comments

Comments
 (0)