Summary
BINARLY efiXplorer team has discovered a heap buffer overflow vulnerability in a child SW SMI handler on multiple HP devices that allows corruption of heap metadata.
Vulnerability Information
- BINARLY internal vulnerability identifier: BRLY-2021-032
- HP PSIRT assigned CVE identifier: CVE-2022-23924
- CERT/CC assigned case number: VU#683814
- CVSS v3.1 8.2 High AV:L/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H
Affected HP firmwares with confirmed impact by Binarly team
Device/Firmware | File Name | SHA256 (File PE32 section) | File GUID |
---|---|---|---|
Device / firmware version: 02.05.01 Rev.A |
0135 | b4bafc81429259891b9b9fd60bc06eedf2e61cbee3fbdd1963579d00c7b025a5 | 3F626A59-87D2-4FCF-B5DE-9D12A8B2AF88 |
Potential impact
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 malicious firmware code in BIOS could persist across operating system re-installs. Additionally, this vulnerability potentially could be used by threat actors to bypass security mechanisms provided by UEFI firmware (for example, Secure Boot and some types of memory isolation for hypervisors).
Vulnerability description
The vulnerability was found in the child SW SMI handler registered with GUID 3b46cda7-0bd6-4323-a03b-bdf94a023f0a
and located at offset 0x2158
in the driver.
The pseudocode for this handler is shown below:
EFI_STATUS __fastcall SmiHandler_2158(
EFI_HANDLE DispatchHandle,
const void *Context,
_QWORD *CommBuffer,
UINTN *CommBufferSize)
{
// [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]
Num = 4;
if ( CommBuffer && CommBufferSize && (-(__int64)(*CommBufferSize != 24) & EFI_INVALID_PARAMETER) == 0 )
{
Size = GetStrSize((_WORD *)CommBuffer[1]);
CommBuffer1 = CommBuffer[1];
Size1 = Size;
Res = 0;
if ( CommBuffer1 && Size1 )
Res = SmmIsBufferOutsideSmmValid(CommBuffer1, Size1);
if ( (-(__int64)(Res == 0) & EFI_INVALID_PARAMETER) == 0 )
{
if ( *(_BYTE *)CommBuffer )
{
if ( *(_BYTE *)CommBuffer == 1 )
{
if ( GetWideStrSize((_WORD *)CommBuffer[1]) )
{
Res1 = FactoryConfigHandler((_WORD *)CommBuffer[1], (__int64)&Num, 1);// possible heap overflow
goto _Exit;
}
}
else if ( *(_BYTE *)CommBuffer == 2 )
{
Res1 = BuildIdHandler((_WORD *)CommBuffer[1], (__int64)&Num, 1);// possible heap overflow
_Exit:
CommBuffer[2] = Res1;
return 0;
}
}
else if ( GetWideStrSize((_WORD *)CommBuffer[1]) )
{
CommBuffer[2] = Validate((_WORD *)CommBuffer[1]) ? 0 : EFI_CRC_ERROR;
return 0;
}
CommBuffer[2] = EFI_INVALID_PARAMETER;
}
}
return 0;
}
If the initial checks pass, the following happens in this handler:
- if the first byte from
CommBuffer
is1
and a pointer to a wide string is located at offsetCommBuffer + 8
, then functionFactoryConfigHandler
(offset:0x1A60
) will be called - if the first byte from
CommBuffer
is2
and a pointer to a wide string is located at offsetCommBuffer + 8
, then functionBuildIdHandler
(offset:0x1C88
) will be called
BuildIdHandler
Consider the FactoryConfigHandler
function.
Status = SmmGetVariable(L"FactoryConfig", &VariableValue);
if ( Stautus )
goto _Exit;
if ( GetWideStrSize(StringFromCommBufferPtr) )
{
StrSize = GetStrSize(StringFromCommBufferPtr);
Value = VariableValue;
if ( VariableValue && StrSize )
{
if ( StrSize > 500 )
StrSize = 500;
if ( VariableValue != StringFromCommBufferPtr )
CopyMem(VariableValue, StringFromCommBufferPtr, StrSize);
}
...
}
SmmGetVariable
function will do the following:
- gets the size of the
FactoryConfig
NVRAM variable - allocates a buffer with
gSmst->SmmAllocatePool(EfiRuntimeServicesData, Size, &Buffer)
(insideSmmAllocatePool
, offset:0x2F98
) - сopies the value of the
FactoryConfig
NVRAM variable to the allocated buffer - as a result, the
VariableValue
variable will contain the address of the buffer in the heap containing the value of theFactoryConfig
variable- at the same time, we control the size of this buffer, because we can change the
FactoryConfig
NVRAM variable
- at the same time, we control the size of this buffer, because we can change the
CopyMem
will copy the data at the address that an attacker can control into VariableValue
. In this case, the size of the data copied is equal to the size of the string located at the controlled address in CommBuffer (but not more than 500
).
In other words, attacker control both buffers:
- the size of the destination buffer
- the size and data of the source buffer
This will lead to a heap buffer overflow.
To exploit this vulnerability it is enough to:
- If the size of the
FactoryConfig
NVRAM variable >= 500, set the value of this variable so that its size is less than 500 - Setup Communication Buffer:
02 00 00 00 00 00 00 00
- pointer to wide string with size >= 500
00 00 00 00 00 00 00 00
- Trigger the SW SMI Handler (SW SMI number and pointer to Communication Buffer are specified in UEFI ACPI table) via
0xB2
IO port.
BuildIdHandler
This function has the same vulnerability.
But the allocated buffer will contain the value of the BuildId
variable, and the maximum data size that can be written in the allocated buffer is 112
.
To exploit this vulnerability it is enough to:
- If the size of the
BuildId
NVRAM variable >= 112, set the value of this variable so that its size is less than 112 - Setup Communication Buffer:
01 00 00 00 00 00 00 00
- pointer to wide string with size >= 112
00 00 00 00 00 00 00 00
- Trigger the SW SMI Handler (SW SMI number and pointer to Communication Buffer are specified in UEFI ACPI table) via
0xB2
IO port
Disclosure timeline
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.
Disclosure Activity | Date |
---|---|
HP PSIRT is notified | 2021-07-12 |
HP PSIRT confirmed reported issue | 2021-08-09 |
HP PSIRT assigned CVE number | 2021-08-19 |
CERT/CC created a case | 2021-11-16 |
HP PSIRT provide patch release | 2022-03-08 |
BINARLY public disclosure date | 2022-03-08 |
Acknowledgements
BINARLY efiXplorer team