The vulnerability for today’s CVE Wednesday is CVE-2022-34400
. I became aware of this vulnerability by monitoring the feed of all new CVEs for UEFI-related vulnerabilities.
NVD is currently unpublished.
Since the NVD analysis isn’t public yet, let’s refer to the Dell Vendor Advisory.
From Vendor Advisory:
Dell BIOS contains a heap buffer overflow vulnerability. A local attacker with admin privileges may potentially exploit this vulnerability to perform an arbitrary write to SMRAM during SMM.
Credit for discovering this vulnerability goes entirely to Cederic Laumen. Check out his blog. This CVE was a set of several that @ling_sec discovered recently in Dell firmware images, and if you’re interested, you should check out the others:
Additionally, @ling_sec was kind enough to answer a few questions I had about his research in preparation for this blog post. Thank you, @ling_sec!
CVE-2022-34400
exists in multiple different vendor products. I chose to look at the Dell Inspiron 3585 model as it was listed as impacted. I downloaded the following firmware versions:
1.9.0
is the vulnerable firmware version, whereas 1.10.0
is the next “fixed” version.
Version 1.11.0
is the latest as of this writing, but was not evaluated for this research.
After downloading the firmware image file and extracting the UEFI image, I used UEFIExtract to dump out all of the individual modules from the UEFI image to the local filesystem. After doing this for both versions, I ran GNU diff recursively over the output directories and discovered the following modified Dxe and Smm drivers:
ODMServiceSmm
DiagnosticTestBIOSInterfaceSmm
SMBIOSTypeDAhCallingInterfaceSmm
BootManagerDxe
BootMaintDxe
DeviceManagerDxe
SecureBootMgrDxe
FrontPageDxe
ODMServiceDxe
InstallHookDxe
BdsDxe
Once I had identified the modules that had changed between 1.9.0
and 1.10.0
, I went through each of them and looked at the differences. I started with the SMM Modules and was able to quickly identify several potential modifications in 1.10.0
that fixed problems in 1.9.0
.
In ODMServiceSmm
from 1.9.0
:
EFI_STATUS FUN_80000858((char *)_variable_data)
{
EFI_STATUS _efi_status;
long _variable_length;
_variable_length = 0;
// Check if running in SMM
if ((((gEFI_SMM_VARIABLE_PROTOCOL != 0x0) ||
// Retrieve the SmmVariable Protocol.
(_efi_status = (*gSmst->SmmLocateProtocol)(&EfiSmmVariableProtocolGuid, 0x0, &gEFI_SMM_VARIABLE_PROTOCOL),
-1 < _efi_status)) &&
// Check length of "EfiD01AssetTag" SMM variable
(_efi_status = SmmGetVariable("EfiD01AssetTag", &.data, 0, _variable_length, _variable_data), _efi_status == EFI_BUFFER_TOO_SMALL)) &&
// Check length of "EfiD01AssetTag" SMM variable to ensure it is not longer than 10 bytes.
((_efi_status = SmmGetVariable("EfiD01AssetTag",&.data, 0 , _variable_length, _variable_data),
-1 < _efi_status && (10 < _variable_length)))) {
_efi_status = EFI_UNSUPPORTED;
}
return _efi_status;
This function has been removed from the ODMServiceSmm
module in 1.10.0
.
Additionally, the other CVE in the advisory (CVE-2022-34403
) cannot be this vulnerability because CVE-2022-34403
specifies that the vulnerability is triggerable via SMI.
gEFI_SMM_VARIABLE_PROTOCOL_55 is an implementation of EFI_GET_VARIABLE
and functions like RuntimeServices->GetVariable
, except for the variable and it’s data are only accessible during SMM.
We know this because code is executed from the first pointer in the EFI_SMM_VARIABLE_PROTOCOL_55 struct, which is SmmGetVariable
. (* (code *)(EFI_SMM_VARIABLE_PROTOCOL[2]))
would refer to SmmSetVariable
, because the third pointer in the struct points to SmmSetVariable
.
Let’s look at the arguments to EFI_GET_VARIABLE
:
typedef
EFI_STATUS
(EFIAPI *EFI_GET_VARIABLE)(
IN CHAR16 *VariableName,
IN EFI_GUID *VendorGuid,
OUT UINT32 *Attributes OPTIONAL,
IN OUT UINTN *DataSize,
OUT VOID *Data OPTIONAL
);
The important argument is DataSize
. IN OUT
means that the value of DataSize will be set to whatever the length of Data
is after writing the variable. From https://github.com/tianocore/edk2/blob/e0200cc47a691291ce1ad0207678a2db12d6503f/MdePkg/Include/Uefi/UefiSpec.h#L653:
@param[in, out] DataSize On input, the size in bytes of the return Data buffer. On output the size of data in Data.
The team at Binarly released an advisory in 2021 (https://github.com/binarly-io/Vulnerability-REsearch/blob/80a82a11dc9b94e707790e97e86ee34cd33b5ebd/HP/BRLY-2021-053.md) that describes the pattern well.
From the Binarly Team:
The first call to GetVariable is occurs with DataSize = 0. Thus, after this call, the DataSize variable will contain the real size of the EfiD01AssetTag NVRAM variable buffer and >GetVariable will return EFI_BUFFER_TOO_SMALL.
During the second call, the data from the EfiD01AssetTag 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 EfiD01AssetTag NVRAM variable much larger than 1 which will lead to a stack overflow and arbitrary code execution.
Modifications of the NVRAM variable name from “PciePwrMgmt” to “EfiD01AssetTag” are mine
NVRAM Variables both in RuntimeServices and SMM are prone to vulnerable patterns such as the one outlined by @ling_sec independently and @matrosov at Binarly. Often times when EFI Modules make multiple (G|S)etVariable
calls in the same function, there is a vulnerability. The DataSize
variable must be reinitialized to 0 before subsequent Variable calls in order to avoid this vulnerability.
A side note, the Ghidra Tooling around EFI analysis is severely lacking when compared with the IDA Pro tooling. Tools such as efiXplorer, which are IDA Pro only, are the gold standard for this type of analysis. I use Ghidra mostly for personal purposes (Can’t afford a Pro License for this Blog LOL) because it forces me to really understand what is going on in the disassembly/decompliation output.
Lastly, as I mentioned above there were several CVEs discovered here and I am not 100% positive my CVE IDs match up precisely with my research and analysis here. I am confident however that at least ONE of the CVEs in question matches up with my analysis here. Have feedback? Drop me a line on twitter (or comment below!).