[BRLY-2022-012]
SMM memory corruption vulnerability in SMM driver on HP device (SMRAM write).
BINARLY efiXplorer team

Summary

BINARLY efiXplorer 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.

Vulnerability Information

  • BINARLY internal vulnerability identifier: BRLY-2022-012
  • HP PSIRT assigned CVE identifier: CVE-2022-31645
  • 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 name Driver name Driver SHA256 File GUID
HP EliteBook x360 1040 G8 0185 C75AF834D8BA590D596E791599F58FEA5B538F221F15876E254D3ED8392286E5 B7CD60D6-4627-4411-8B6D-C60BA7FAB120

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 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).

Vulnerability description

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.

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 2022-04-12
HP PSIRT is confirmed issue 2022-06-15
HP PSIRT assigned CVE number 2022-06-15
HP PSIRT provide patch release 2022-08-09
BINARLY public disclosure date 2022-08-10

Acknowledgements

BINARLY efiXplorer team