LUKS2 Header Malleability and Null-Cipher Abuse in Confidential VMs

Tip

Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Вивчайте та практикуйте Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Підтримка HackTricks

TL;DR

  • Багато Linux-based Confidential VMs (CVMs) на AMD SEV-SNP або Intel TDX використовують LUKS2 для постійного зберігання. LUKS2 header на диску є змінним і не має захисту цілісності проти атакуючих з доступом до сусіднього сховища.
  • Якщо шифрування сегмента даних у header встановлене як null cipher (наприклад, “cipher_null-ecb”), cryptsetup приймає його і гість прозоро читає/записує plaintext, вважаючи диск зашифрованим.
  • До та включно з cryptsetup 2.8.0 null ciphers могли використовуватися для keyslots; починаючи з 2.8.1 вони відхиляються для keyslots з непорожніми паролями, але null ciphers залишаються дозволеними для volume segments.
  • Remote attestation зазвичай вимірює код/конфігурацію VM, а не змінні зовнішні LUKS headers; без явної валідації/вимірювання атакуючий з правом запису на диск може примусити plaintext I/O.

Background: LUKS2 on-disk format (what matters for attackers)

  • Пристрій LUKS2 починається з header, за яким ідуть зашифровані дані.
  • Header містить дві ідентичні копії бінарної секції і секцію JSON metadata, плюс один або декілька keyslots.
  • JSON metadata визначає:
    • які keyslots увімкнені та їх wrapping KDF/cipher
    • segments, які описують область даних (cipher/mode)
    • digests (наприклад, хеш volume key для перевірки passphrases)
  • Типові безпечні значення: keyslot KDF argon2id; шифрування keyslot і data segment — 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'

Корінна причина

  • LUKS2 headers are not authenticated against storage tampering. Атакуючий на рівні хоста/сховища може переписати JSON-метадані, які приймає cryptsetup.
  • Починаючи з cryptsetup 2.8.0, заголовки, що встановлюють шифрування сегмента як cipher_null-ecb, приймаються. null cipher ігнорує ключі і повертає plaintext.
  • До 2.8.0 null ciphers також могли використовуватися для keyslots (keyslot відкривається з будь-якою passphrase). Починаючи з 2.8.1, null ciphers відхиляються для keyslots з непорожніми паролями, але залишаються дозволеними для сегментів. Заміна лише segment cipher все ще дає plaintext I/O після 2.8.1.

Модель загрози: чому атестація не врятувала вас за замовчуванням

  • CVMs прагнуть забезпечити конфіденційність, цілісність і автентичність на ненадійному хості.
  • Віддалена атестація зазвичай вимірює образ VM і конфігурацію запуску, а не змінний LUKS header, що знаходиться на ненадійному сховищі.
  • Якщо ваш CVM довіряє on-disk header без надійної валідації/вимірювання, атакуючий на сховище може змінити його на null cipher, і ваша гостьова система змонтує plaintext том без помилок.

Експлуатація (потрібен доступ на запис до сховища)

Передумови:

  • Доступ на запис до LUKS2-зашифрованого блочного пристрою CVM.
  • Гість використовує on-disk LUKS2 header без надійної валідації/атестації.

Кроки (на високому рівні):

  1. Зчитайте header JSON і визначте визначення data segment. Приклад цільового поля: segments[“0”].encryption.
  2. Встановіть шифрування data segment на null cipher, наприклад cipher_null-ecb. Залиште параметри keyslot і структуру digest незмінними, щоб звичайна passphrase гостя все ще “працювала.”
  3. Оновіть обидві копії header та пов’язані header digests так, щоб заголовок був узгодженим.
  4. При наступному завантаженні гість запускає cryptsetup, успішно розблоковує існуючий keyslot своєю passphrase і монтує том. Оскільки segment cipher — null cipher, усі операції читання/запису будуть plaintext.

Варіант (pre-2.8.1 keyslot abuse): якщо area.encryption keyslot встановлено як null cipher, він відкривається з будь-якою passphrase. Поєднайте це з null segment cipher для безперервного доступу до plaintext без знання секрету гостя.

Надійні пом’якшення (уникайте TOCTOU за допомогою detached headers)

Завжди розглядайте on-disk LUKS headers як недовірений вхід. Використовуйте detached-header mode, щоб валідація та відкриття використовували ті самі довірені байти з protected 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

Потім застосуйте одне (або декілька) з наступного:

  1. Накласти MAC на весь заголовок
  • Обчислювати/перевіряти MAC над усім заголовком перед використанням.
  • Відкривати том лише коли MAC підтверджено.
  • Приклади на практиці: Flashbots tdx-init та Fortanix Salmiac впровадили перевірку на основі MAC.
  1. Строга валідація 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") ```
  1. Виміряйте/атестуйте заголовок
  • Видаліть випадкові salts/digests і виміряйте очищений заголовок у PCRs TPM/TDX/SEV або у стан політики KMS.
  • Видавайте ключі розшифрування лише коли виміряний заголовок відповідає затвердженому, безпечному профілю.

Оперативні рекомендації:

  • Примусово використовуйте detached header + MAC або сувору валідацію; ніколи не довіряйте заголовкам на диску безпосередньо.
  • Споживачі атестації повинні відхиляти версії фреймворку до застосування патчів у allow-list’ах.

Примітки щодо версій та позиції мейнтейнера

  • Розробники cryptsetup уточнили, що LUKS2 не призначався для забезпечення цілісності проти підміни даних на носії в цьому сценарії; null ciphers збережено для зворотної сумісності.
  • cryptsetup 2.8.1 (Oct 19, 2025) відкидає null ciphers для keyslots з непустими паролями, але все ще дозволяє null ciphers для сегментів.

Швидкі перевірки та тріаж

  • Перевірте, чи для шифрування будь-якого сегмента встановлено null cipher:
cryptsetup luksDump --type luks2 --dump-json-metadata /dev/VDISK \
| jq -r '.segments | to_entries[] | "segment=" + .key + ", enc=" + .value.encryption'
  • Перевірте keyslot та segment algorithms перед відкриттям volume. Якщо ви не можете виконати MAC, застосуйте сувору валідацію JSON і відкривайте, використовуючи detached header із protected memory.

Посилання

Tip

Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Вивчайте та практикуйте Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Підтримка HackTricks