[BRLY-2021-053]
The stack buffer overflow vulnerability leads to arbitrary code execution in DXE driver on Intel platform
BINARLY efiXplorer team

Reported as a part of Intel Camping with Tigers bug bounty program

Summary

BINARLY efiXplorer team has discovered a stack overflow vulnerability that allows a local root user to access UEFI DXE driver and execute arbitrary code.

Vulnerability Information

  • BINARLY internal vulnerability identifier: BRLY-2021-053
  • HP PSIRT assigned CVE identifier: CVE-2021-39299, CVE-2021-39300
  • CVSS v3.1: 7.5 High AV:L/AC:H/PR:H/UI:N/S:C/C:H/I:H/A:H

Affected Intel firmwares with confirmed impact by Binarly team

Device/Firmware File Name SHA256 (File PE32 section) File GUID
HP EliteBook x360 1040 G8 0614 eeeacc5cb2fad20df51283460831816aed4f67e769e4f57186180adf7d20da3d 03E0A38B-3FBE-49CB-B311-726611213182

Potential impact

An attacker with local privileged access can exploit this vulnerability to elevate privileges from ring 3 or ring 0 (depends on the operating system) to DXE driver and execute arbitrary code. A malicious code installed as a result of vulnerability exploitation in DXE driver could survive across an operating system (OS) boot process and runtime or modify NVRAM area on SPI flash storage (to gain persistence on target platform). Additionally, this vulnerability potentially could be used by malicious actors to bypass OS security mechanisms (modify privileged memory or runtime variables), influence on OS boot process, and in some cases would allow an attacker to hook or modify EFI Runtime services.

Vulnerability description

The vulnerability exists in notifier for SA_POLICY_PROTOCOL located at offset 0x1538. The pseudocode for this notifier is shown below:

__int64 SaPolisyProtocolNotifier()
{
  EFI_STATUS Status; // rax
  __int64 result; // rax
  void *Interface; // [rsp+30h] [rbp-50h] BYREF
  EFI_GUID VendorGuid; // [rsp+48h] [rbp-38h] BYREF
  char IntelTechnologiesOptionsBuffer[40]; // [rsp+58h] [rbp-28h] BYREF
  char Buffer; // [rsp+A0h] [rbp+20h] BYREF
  UINTN DataSize; // [rsp+A8h] [rbp+28h] BYREF
  ...

  VendorGuid.Data1 = 0xFB3B9ECE;
  *&VendorGuid.Data2 = 0x49334ABA;
  *VendorGuid.Data4 = 0xD6B49DB4;
  *&VendorGuid.Data4[4] = 0x5123897D;
  gBS->LocateProtocol(&SA_POLICY_PROTOCOL_GUID, 0, &Interface);
  ...
  ZeroMem(&Buffer, 1);
  DataSize = 0;
  Status = gRT->GetVariable(L"PciePwrMgmt", &VendorGuid, 0, &DataSize, &Buffer);
  if ( Status == EFI_BUFFER_TOO_SMALL )
    Status = gRT->GetVariable(L"PciePwrMgmt", &VendorGuid, 0, &DataSize, &Buffer);
  if ( Status || Buffer )
  {
    ...
  }
  ...
  DataSize = 30;
  gRT->GetVariable(L"IntelTechnologiesOptions", &VendorGuid, 0, &DataSize, IntelTechnologiesOptionsBuffer);
  ...
  return result;
}

Consider following code snippet:

DataSize = 0;
Status = gRT->GetVariable(L"PciePwrMgmt", &VendorGuid, 0, &DataSize, &Buffer);
if ( Status == EFI_BUFFER_TOO_SMALL )
  Status = gRT->GetVariable(L"PciePwrMgmt", &VendorGuid, 0, &DataSize, &Buffer);

The first call to GetVariable is occurs with DataSize = 0. Thus, after this call, the DataSize variable will contain the real size of the PciePwrMgmt NVRAM variable buffer and GetVariable will return EFI_BUFFER_TOO_SMALL.

During the second call, the data from the PciePwrMgmt NVRAM variable will be written to the Buffer stack variable.

The size of the Buffer on the stack is 1 byte, but a potential attacker could make the buffer size of the PciePwrMgmt NVRAM variable much larger than 1 which will lead to a stack overflow and arbitrary code execution.

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
Intel PSIRT is notified 2022-01-05
HP PSIRT provide patch release 2022-01-27
BINARLY public disclosure date 2022-05-23

Acknowledgements

BINARLY efiXplorer team