Эксплойт для уязвимости прошивки AMD SEV-SNP (CVE-2023-31355), который расшифровывает произвольную память выведенных из эксплуатации гостей, повреждая ключевое семя UMC через запись неинициализированной записи RMP по нулевому адресу.
В этом репозитории содержится эксплойт для уязвимости в прошивке SEV. Эксплойт позволяет расшифровывать произвольную память гостевой системы SEV-SNP после её вывода из эксплуатации.
Проверено на версии 1.55.16 (последней на момент написания).
snp_reclaim_buffer безусловно пытается записать изменения RMP обратно, даже когда адрес не покрыт RMP. Если address не покрыт RMP, адрес элемента RMP page_rmp_paddr никогда не инициализируется должным образом и остаётся в своём начальном значении 0. В результате прошивка пытается записать изменения элемента RMP обратно по адресу 0. Это плохо, потому что адрес 0 покрыт RMP и его не следует записывать без дополнительных проверок. Если address находится вне области, покрытой RMP, page_rmp_entry никогда не инициализируется должным образом и содержит мусорные данные из стека. На практике эти мусорные данные постоянны.
В коде есть комментарий, предупреждающий именно об этом паттерне, поэтому я не удивлюсь, если я не первый, кто сообщает об этой проблеме.
snp_reclaim_buffer вызывается с адресом страницы состояния кольцевых буферов SEV, когда гипервизор запрашивает выход из режима кольцевого буфера. Этот адрес контролируется атакующим. Для этого адреса есть некоторые проверки, но страницы по умолчанию (т.е. страницы вне области, покрытой RMP) явно разрешены.
Мы можем использовать эту запись по адресу 0, разместив там страницу контекста гостя. Удачно, что первым полем страницы контекста гостя является зерно ключа UMC, размер которого в точности совпадает с размером элемента RMP (обе — 16 байт). Обманув прошивку, заставив её записать изменения обратно по адресу 0, мы можем повредить зерно ключа UMC. Неинициализированный элемент RMP, который записывается, всегда одинаков, поэтому повреждённое зерно ключа UMC тоже всегда будет почти одинаковым: счётчик подстраниц (9 бит) в элементе RMP не записывается, а все остальные поля записываются. Многократно создавая новые страницы контекста гостя, которые каждый раз будут иметь разные случайные начальные значения счётчика подстраниц, мы в итоге можем создать несколько гостей с одинаковым зерном ключа UMC.
Чтобы использовать уязвимость, можно выполнить следующие шаги:
0 для гостевой системы-жертвы.0 для гостевой системы атакующего.SNP_DBG_ENCRYPT, чтобы расшифровать память гостевой системы-жертвы с помощью страницы контекста гостя атакующего. Это удастся, потому что гостевая система-жертва и гостевая система атакующего используют общее зерно ключа UMC.Из-за того, что мы можем расшифровать память только после вывода гостя из эксплуатации, невозможно создать поддельные отчёты аттестации, даже если у нас есть доступ к секретам гостя. Мы можем создать поддельные отчёты аттестации, только если гость был мигрирован на другой хост до вывода из эксплуатации: в этом случае секреты (т.е. VMPCK) выведенного из эксплуатации гостя также будут работать на новой мигрированной системе.
Однако на практике многие приложения хранят другую чувствительную информацию (т.е. закрытые ключи, ключи шифрования диска), которая может быть раскрыта с помощью этого эксплойта.
Элемент RMP следует записывать обратно только в том случае, если страница не находилась в состоянии по умолчанию.