An attacker can exploit this vulnerability to elevate privileges from ring 0 to ring -2, execute arbitrary code in System Management Mode - an environment more privileged than operating system (OS) and completely isolated from it. Running arbitrary code in SMM additionally bypasses SMM-based SPI flash protections against modifications, which can help an attacker to install a firmware backdoor/implant into BIOS. Such a malicious firmware code in BIOS could persist across operating system re-installs. Additionally, this vulnerability potentially could be used by malicious actors to bypass security mechanisms provided by UEFI firmware (for example, Secure Boot and some types of memory isolation for hypervisors).
Binarly REsearch Team has discovered an SMM memory corruption vulnerability in an HP device allowing a possible attacker to write fixed or predictable data to SMRAM. Exploiting this issue could lead to escalating privileges to SMM.
An attacker can exploit this vulnerability to elevate privileges from ring 0 to ring -2, execute arbitrary code in System Management Mode - an environment more privileged than operating system (OS) and completely isolated from it. Running arbitrary code in SMM additionally bypasses SMM-based SPI flash protections against modifications, which can help an attacker to install a firmware backdoor/implant into BIOS. Such a malicious firmware code in BIOS could persist across operating system re-installs. Additionally, this vulnerability potentially could be used by malicious actors to bypass security mechanisms provided by UEFI firmware (for example, Secure Boot and some types of memory isolation for hypervisors).
The SMM driver registers a child software System Management Interrupt (SW SMI) handler with GUID 67511ba8-5a25-4bba-ac59-f00feb85dffa
, which contains the actual vulnerability:
Status = gSmst->SmiHandlerRegister(SmiHandler, &gSmiHandlerGuid, &SmiHandlerDispatchHandle);
The SMI handler itself is located at offset 0x2630
in the driver:
EFI_STATUS __fastcall SmiHandler(EFI_HANDLE DispatchHandle, const void *Context, void *CommBuffer, UINTN *CommBufferSize)
{
...
char *ptr;
if ( CommBuffer )
{
if ( CommBufferSize )
{
if ( *CommBufferSize == 0x18 )
{
ptr = *(char **)CommBuffer;
if ( *(_QWORD *)CommBuffer )
{
if ( *((_DWORD *)CommBuffer + 2) &&
CheckSmramMap_0(*(_QWORD *)CommBuffer, *((unsigned int *)CommBuffer + 2)) )
{
// buffer size pointed by ptr not validated, OOB write
ptr[0x25] = 0;
v7 = EFI_SECURITY_VIOLATION;
if ( *((_BYTE *)CommBuffer + 0xC) == 4 )
{
if ( gSmmReadyToLockFlag2 )
goto exit;
if ( ptr != gLocal20Buffer )
memcpy(ptr, gLocal20Buffer, 0x20); // OOB write
}
else if ( *((_BYTE *)CommBuffer + 0xC) == 5 )
{
if ( !sub_800025E0(ptr) )
goto exit;
if ( !sub_80002490(v10) )
sub_800022C8(ptr, v10); // OOB write
...
As we can see there is a nested pointer in a Communication Buffer passed into this SMI handler. The pointer is validated, however the size of a pointed buffer (which is used for the pointer validation) is not checked to be an expected value or range, which allows a possible attacker to partially bypass the applied validation for example by specifying *(QWORD *)CommBuffer = SMRAM_BASE - 1
and *((unsigned int *)CommBuffer + 2) = 1
byte.
This leads to corrupting memory in SMRAM in multiple ways. Firstly, at offset (25 bytes) relative to a controllable address with a fixed 1-byte value 0
. Secondly, an execution flow can reach a copy operation: memcpy()
to a controllable address of data (0x20 bytes) stored in gLocal20Buffer
. Additionally, in case the execution flow goes into routine sub_800022C8()
, the following code will be executed:
void __fastcall sub_800022C8(_BYTE *ptr, __int64 res)
{
...
ptr[0x25] = 1; // OOB write
...
}
It could be used for example to hijack SMM S3 Resume Entry Point stored at (QWORD *)SMRAM_BASE + 8
or modify SMRAM Map structures to break input pointers validation for other SMI handlers, hence to completely make this mitigation inefficient. This could lead to gaining arbitrary code execution in SMM.
To exploit this vulnerability it is enough to specify in a CommBuffer:1. Set CommBuffer to contain these values: *(QWORD *)CommBuffer = SMRAM_BASE - 1
and *((unsigned int *)CommBuffer + 2 = 1
.2. Call SW SMI (SwSmi number is specified in the UEFI ACPI table) via 0xB2 IO port, prior to it SMI handler GUID 67511ba8-5a25-4bba-ac59-f00feb85dffa
and Communication Buffer size should be specified in Communication Buffer.
To fix this vulnerability, it is essential to wrap all the input pointers (including the nested pointers) of the SMI handlers with sanity checks to make sure they are not pointing into SMRAM.
This bug is subject to a 90 day disclosure deadline. After 90 days elapsed or a patch has been made broadly available (whichever is earlier), the bug report will become visible to the public.
Binarly REsearch Team