[BRLY-2022-011]
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-011
  • HP PSIRT assigned CVE identifier: CVE-2022-31644
  • CVSS v3.1: 7.5 High AV:L/AC:H/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 FFFF 398CB8FDD61555A40FFCCFAFF225F70084EB078667347275990A7C0AA31DE19C 86930B1D-F85D-4275-AC97-10A7A57F3E2E

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 993129e8-ec85-4df4-8a2c-9c84fdad175b, which contains the actual vulnerability:

Status = gSmst->SmiHandlerRegister(SmiHandler, &SmiHandlerGuid, &gSmiHandlerDispatchHandle);

The SMI handler itself is located at offset 0x2720 in the driver:

EFI_STATUS __fastcall SmiHandler(EFI_HANDLE DispatchHandle, const void *Context, void *CommBuffer, UINTN *CommBufferSize)
{
	...
	
  if ( CommBuffer && CommBufferSize && *CommBufferSize == 0x18 )
  {
    if ( !*(_QWORD *)CommBuffer )
      goto LABEL_18;
    size_ptr = (unsigned int *)((char *)CommBuffer + 8);
    
    if ( !*((_DWORD *)CommBuffer + 2) )
      goto LABEL_18;
    
    // Buffer is validated here, but the size is not used further
    v6 = CheckSmramMap_0(*(_QWORD *)CommBuffer, *size_ptr);
    v7 = -(__int64)(v6 == 0) & EFI_SECURITY_VIOLATION;
    if ( v6 )
    {
      v8 = 0;
      if ( size_ptr )
        v8 = CheckSmramMap_0(size_ptr, 4);
      v7 = -(__int64)(v8 == 0) & EFI_SECURITY_VIOLATION;
    }
    
    if ( !v7 )
    {
LABEL_18:
      if ( CommBuffer_1[3] )
        v9 = EFI_UNSUPPORTED;
      else
	      // Buffer size is not passed inside
        v9 = sub_800024D0(*(_BYTE **)CommBuffer);
      *((_QWORD *)CommBuffer + 2) = v9;
    }
  }
  
  return 0;
}

As we can see there are two nested pointers in a Communication Buffer passed into this SMI handler: a pointer to a buffer and a pointer to a size of this buffer. Both pointers are validated against pointing into SMRAM. However, the size of the buffer (which is used for the validation) is not used further and 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 the *(QWORD *)CommBuffer = SMRAM_BASE - 1 and *size_ptr = 1 byte.

In case the execution flow goes into routine sub_800024D0(), the following code will be executed:

__int64 __fastcall sub_800024D0(_BYTE *ptr)
{
  ...
  
  ZeroMemory(buffer, 0x20);
  
  v2 = UnknownProtocol53986f2e(buffer, v10);
  if ( !v2 )
  {
    ...
        memcpy(ptr + 2, buffer, 0x20); // OOB write
        
  ...
}

In the above mentioned case of partial bypassing input buffer validation, SMM memory corruption is possible with a predictable data retrieved using SMM protocol 53986f2e-4f54-4d40-8166-0e020fbabfbc.

This leads to corrupting memory in SMRAM at a controllable address with a predictable data and size. It could be used for example to change SMI handler's code 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 *size_ptr = 1.
  2. Call SW SMI (SwSmi number is specified in the UEFI ACPI table) via 0xB2 IO port, prior to it SMI handler GUID 993129e8-ec85-4df4-8a2c-9c84fdad175b and Communication Buffer size should be specified in Communication Buffer.

It should be noted that this SMI handler will be unregistered in a callback-notifier for SMM protocol EDKII_SMM_READY_TO_BOOT_PROTOCOL:

gSmst->SmmRegisterProtocolNotify(&EDKII_SMM_READY_TO_BOOT_PROTOCOL_GUID, EdkIISmmReadyToBootProtocolNotifier, &Registration);

EFI_STATUS __fastcall EdkIISmmReadyToBootProtocolNotifier(const EFI_GUID *Protocol, void *Interface, EFI_HANDLE Handle)
{
  if ( gSmiHandlerDispatchHandle )
  {
    gSmst->SmiHandlerUnRegister(gSmiHandlerDispatchHandle);
    gSmiHandlerDispatchHandle = 0;
  }
  return 0;
}

Due to this fact the vulnerability cannot be exploited from the operating system. However, there is a time window before the above mentioned event will occur and the handler will be unregistered. A possible attacker capable of executing code in DXE phase could exploit this vulnerability to escalate privileges to SMM (ring -2).

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