Modyfikowalność nagłówka LUKS2 i nadużycie null-cipher w Confidential VMs
Tip
Ucz się & ćwicz AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Ucz się & ćwicz GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Ucz się & ćwicz Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Wspieraj HackTricks
- Sprawdź subscription plans!
- Dołącz do 💬 Discord group lub telegram group lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Podziel się hacking tricks, zgłaszając PRy do HackTricks i HackTricks Cloud github repos.
W skrócie
- Wiele opartych na Linux Confidential VMs (CVMs) działających na AMD SEV-SNP lub Intel TDX używa LUKS2 do przechowywania trwałego. Nagłówek LUKS2 znajdujący się na dysku jest modyfikowalny i nie jest chroniony integralnością względem atakujących mających dostęp do warstwy pamięci.
- Jeśli szyfrowanie segmentu danych w nagłówku ustawione jest na null cipher (np. “cipher_null-ecb”), cryptsetup to zaakceptuje i gość przezroczysto będzie czytał/zapisywał plaintext, wierząc, że dysk jest zaszyfrowany.
- Do i włącznie z cryptsetup 2.8.0 null ciphers mogły być używane dla keyslots; od 2.8.1 są odrzucane dla keyslots z niepustymi hasłami, ale null ciphers nadal są dozwolone dla segmentów wolumenu.
- Remote attestation zwykle mierzy kod/konfigurację VM, a nie zewnętrzne, modyfikowalne nagłówki LUKS; bez jawnej walidacji/pomiaru atakujący z możliwością zapisu na dysku może wymusić I/O w postaci plaintextu.
Tło: format LUKS2 na dysku (co ma znaczenie dla atakujących)
- Urządzenie LUKS2 zaczyna się od nagłówka, po którym następują zaszyfrowane dane.
- Nagłówek zawiera dwie identyczne kopie sekcji binarnej i sekcję metadanych JSON, oraz jeden lub więcej keyslots.
- Metadane JSON definiują:
- włączone keyslots oraz ich wrapping KDF/cipher
- segmenty opisujące obszar danych (cipher/mode)
- digests (np. hash klucza wolumenu do weryfikacji haseł)
- Typowe bezpieczne wartości: keyslot KDF argon2id; szyfrowanie keyslot i segmentu danych aes-xts-plain64.
Szybko sprawdź szyfr segmentu bezpośrednio w 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'
Przyczyna źródłowa
- LUKS2 headers nie są uwierzytelniane pod kątem manipulacji na storage. Atakujący z poziomu hosta/storage może przepisać JSON metadata akceptowany przez cryptsetup.
- Od cryptsetup 2.8.0 akceptowane są nagłówki, które ustawiają szyfrowanie segmentu na cipher_null-ecb. Null cipher ignoruje klucze i zwraca plaintext.
- Do wersji 2.8.0 null ciphers mogły być też używane dla keyslots (keyslot otwiera się przy dowolnym passphrase). Od 2.8.1 null ciphers są odrzucane dla keyslots z niepustymi hasłami, ale pozostają dozwolone dla segments. Zmiana tylko ciphera segmentu nadal skutkuje plaintext I/O po 2.8.1.
Model zagrożeń: dlaczego attestation domyślnie cię nie uratowało
- CVMs mają na celu zapewnienie confidentiality, integrity i authenticity w nieufnym hoście.
- Remote attestation zwykle mierzy obraz VM i konfigurację uruchomienia, a nie mutowalny LUKS header znajdujący się na nieufnym storage.
- Jeśli twój CVM ufa nagłówkowi na dysku bez solidnej walidacji/measurement, atakujący na storage może go zmodyfikować na null cipher, a twój gość zamontuje wolumin w plaintext bez błędu.
Eksploatacja (wymagany dostęp zapisu do storage)
Warunki wstępne:
- Dostęp zapisu do LUKS2-szyfrowanego urządzenia blokowego CVM.
- Gość używa on-disk LUKS header bez solidnej walidacji/attestation.
Kroki (ogólnie):
- Odczytaj header JSON i zidentyfikuj definicję segmentu danych. Przykładowe pole docelowe: segments[“0”].encryption.
- Ustaw szyfrowanie segmentu danych na null cipher, np. cipher_null-ecb. Zachowaj parametry keyslot i strukturę digest tak, aby zwykły passphrase gościa nadal „działał.”
- Zaktualizuj obie kopie headera i powiązane header digesty, aby header był samospójny.
- Przy następnym uruchomieniu gość uruchomi cryptsetup, pomyślnie odblokuje istniejący keyslot swoim passphrase i zamontuje wolumin. Ponieważ cipher segmentu to null cipher, wszystkie odczyty/zapisy będą plaintext.
Wariant (nadużycie keyslot przed 2.8.1): jeśli area.encryption keyslota jest null cipher, otwiera się on przy dowolnym passphrase. Połącz to z null segment cipher, aby uzyskać bezproblemowy dostęp w plaintext bez znajomości sekretu gościa.
Skuteczne środki zaradcze (unikaj TOCTOU przy detached headers)
Zawsze traktuj nagłówki LUKS zapisane na dysku jako nieufne dane wejściowe. Użyj trybu detached-header, aby walidacja i otwarcie korzystały z tych samych zaufanych bajtów z chronionej pamięci 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
Wymuś jedno (lub więcej) z poniższych:
- MAC całego nagłówka
- Oblicz/zweryfikuj MAC dla całego nagłówka przed użyciem.
- Otwieraj wolumin tylko wtedy, gdy MAC zostanie zweryfikowany.
- Przykłady w praktyce: Flashbots tdx-init i Fortanix Salmiac zastosowały weryfikację opartą na MAC.
- Ścisła walidacja JSON (wstecznie kompatybilna)
- Zrzucaj metadane JSON i waliduj ścisłą listę dozwolonych parametrów (KDF, ciphers, liczba/typ segmentów, flagi).
#!/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
Przykładowy walidator (wymusza bezpieczne pola)
```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") ```- Zmierz/atestuj nagłówek
- Usuń losowe salts/digests i zmierz oczyszczony nagłówek do TPM/TDX/SEV PCRs lub stanu polityki KMS.
- Wydawaj klucze odszyfrowania tylko wtedy, gdy zmierzony nagłówek pasuje do zatwierdzonego, bezpiecznego profilu.
Wytyczne operacyjne:
- Wymuszaj detached header + MAC lub ścisłą walidację; nigdy nie ufaj bezpośrednio nagłówkom na dysku.
- Konsumenci atestacji powinni odrzucać pre-patch wersje frameworków w allow-lists.
Notatki o wersjach i stanowisku maintainerów
- maintainerzy cryptsetup wyjaśnili, że LUKS2 nie został zaprojektowany, aby zapewniać integralność przeciwko manipulacji pamięcią masową w tym kontekście; null ciphers są zachowane dla kompatybilności wstecznej.
- cryptsetup 2.8.1 (Oct 19, 2025) odrzuca null ciphers dla keyslots z niepustymi hasłami, ale nadal pozwala null ciphers dla segments.
Szybkie kontrole i triage
- Sprawdź, czy segment encryption jest ustawione na null cipher:
cryptsetup luksDump --type luks2 --dump-json-metadata /dev/VDISK \
| jq -r '.segments | to_entries[] | "segment=" + .key + ", enc=" + .value.encryption'
- Zweryfikuj algorytmy keyslot i segment przed otwarciem wolumenu. Jeśli nie możesz zweryfikować MAC, wymuś ścisłą walidację JSON i otwórz, używając detached header znajdującego się w protected memory.
Źródła
- 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
Ucz się & ćwicz AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Ucz się & ćwicz GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Ucz się & ćwicz Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Wspieraj HackTricks
- Sprawdź subscription plans!
- Dołącz do 💬 Discord group lub telegram group lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Podziel się hacking tricks, zgłaszając PRy do HackTricks i HackTricks Cloud github repos.
HackTricks Cloud

