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.
Binarly REsearch Team has discovered a stack overflow vulnerability that allows a local root user to access UEFI DXE driver and execute arbitrary code.
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.
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.
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.
Binarly REsearch Team