[BRLY-2021-004]
SMM callout vulnerability in SMM driver on multiple HP devices (SMM arbitrary code execution).
BINARLY efiXplorer team

Summary

BINARLY efiXplorer team identified a SMM callout in multiple HP devices, which allows an attacker to access the System Management Mode and execute arbitrary code.

Vulnerability Information

  • BINARLY internal vulnerability identifier: BRLY-2021-004
  • HP PSIRT assigned CVE identifier: CVE-2021-39298
  • CERT/CC assigned case number: VU#917518
  • 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

Fimware Driver name Driver MD5 File GUID
S05_02020000.bin 0701 d6fbd0215eae1935679c19766ce2195d 62C38AE7-4BF4-4112-B2C8-88B50F317BC9

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 evironment 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 the BIOS. Such a malicious firmware code in the BIOS could persist across operating system re-installs. Additionally, this vulnerability potentially could be used by threat actors to bypass security mechanisms provided by the UEFI firmware (for example, Secure Boot and some types of memory isolation for hypervisors).

Vulnerability description

Vulnerability exists in the software System Management Interrupt (SWSMI) handler located at offset 0x1574 in the module 0701.efi (code example given from S05_02020000.bin firmware).

The SWSMI handler with number 0xAE dereferences gRT (EFI_RUNTIME_SERVICES) pointer to call a GetVariable service, which is located outside of SMRAM. Hence, this can result in a code execution in SMM (escalating privilege from ring 0 to ring -2).

Below is the decompiled code of the vulnerable handler:

EFI_STATUS __fastcall SwSmiHandler_1574(EFI_HANDLE DispatchHandle)
{
  EFI_STATUS result;
  UINT32 Attributes;
  UINTN DataSize;
  EFI_SMM_SW_DISPATCH2_PROTOCOL *EfiSmmSwDispatch2;
  __int64 Data[6];

  Attributes = 6;
  DataSize = 32i64;
  if ( (gRT_20F8->GetVariable(L"AmdMemContextData", &VendorGuid, &Attributes, &DataSize, Data) & 0x8000000000000000ui64) == 0i64 )
    x_AmdMemContextHandler(Data);
  result = gSmst_20F0->SmmLocateProtocol(&EFI_SMM_SW_DISPATCH_PROTOCOL_GUID_2050, 0i64, &EfiSmmSwDispatch2);
  if ( (result & 0x8000000000000000ui64) == 0i64 )
    return (EfiSmmSwDispatch2->UnRegister)(EfiSmmSwDispatch2, DispatchHandle);
  return result;
}

Due to the fact this handler unregisters itself by calling EfiSmmSwDispatch2->UnRegister, the vulnerability cannot be exploited from the operating system. However, using EFI_BOOT_SERVICES and EFI_RUNTIME_SERVICES is unsafe inside a code intended to run in SMM (from SMRAM) because an attacker capable of executing code in DXE phase could exploit this vulnerability to escalate privileges to SMM (ring -2). This can be achieved even after EfiSmmReadyToLock event since no gSmst->InSmram() check is applied.

To exploit this vulnerability from DXE evironment it is enough to:

  • overwrite the GetVariable service address in the EFI_RUNTIME_SERVICES table with the shellcode address

  • trigger the handler in the same way as in the DXE driver with the name 0701 from the firmware S05_02020000.bin:

    EFI_STATUS __fastcall EfiEventReadyToBootNotifier(EFI_EVENT Event)
    {
      EFI_STATUS status;
      EFI_SMM_CONTROL2_PROTOCOL *EfiSmmControl2Protocol;
      char DataPort;
      char CommandPort;
    
      status = gBS_2098->LocateProtocol(&EFI_SMM_CONTROL2_PROTOCOL_GUID_2030, 0i64, &EfiSmmControl2Protocol);
      if ( (status & 0x8000000000000000ui64) == 0i64 )
      {
        CommandPort = 0xAE;
        DataPort = 1;
        (EfiSmmControl2Protocol->Trigger)(EfiSmmControl2Protocol, &CommandPort, &DataPort, 0i64, 0i64);
        return gBS_2098->CloseEvent(Event);
      }
      return status;
    }
    

To fix this vulnerability, it is essential to replace the GetVariable service from EFI_RUNTIME_SERVICES with EfiSmmVariableProtocol->SmmSetVariable.

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-02-04
BINARLY public disclosure date 2022-02-04

Acknowledgements

BINARLY efiXplorer team

References