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 the 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).
Binarly REsearch Team identified an SMM memory contents leak / information disclosure vulnerability, which allows an attacker to read portions of SMRAM memory. This in turn could help building a successful attack vector exploiting SMM memory corruption vulnerability.
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).
The vulnerability exists in the function located at offset 0x1D28
.This function located inside SW SMI handler and the SMI handler registered the following way:
...
result = gSmst_0->SmmLocateProtocol(&EFI_SMM_SW_DISPATCH2_PROTOCOL_GUID, 0, &EfiSmmSwDispatch2Protocol);
if ( result >= 0 )
{
RegisterContext.SwSmiInputValue = 0x50;
result = EfiSmmSwDispatch2Protocol->Register(
EfiSmmSwDispatch2Protocol,
SwSmiHandler,
&RegisterContext,
&DispatchHandle);
if ( result >= 0 )
{
RegisterContext.SwSmiInputValue = 0x51;
result = EfiSmmSwDispatch2Protocol->Register(
EfiSmmSwDispatch2Protocol,
SwSmiHandler,
&RegisterContext,
&DispatchHandle);
if ( result >= 0 )
{
RegisterContext.SwSmiInputValue = 0x52;
result = EfiSmmSwDispatch2Protocol->Register(
EfiSmmSwDispatch2Protocol,
SwSmiHandler,
&RegisterContext,
&DispatchHandle);
if ( result >= 0 )
{
RegisterContext.SwSmiInputValue = 0x53;
Status = (EfiSmmSwDispatch2Protocol->Register)(
EfiSmmSwDispatch2Protocol,
SwSmiHandler,
&RegisterContext,
&DispatchHandle);
if ( Status < 0 )
return Status;
return Result;
}
}
}
}
}
return result;
}
The pseudocode for the vulnerable function is shown below:
char __fastcall WriteOnceStatusSetVar(char value1, char value2, __int16 value3)
{
char Result;
unsigned __int8 Index;
_BYTE *table_ptr;
__int64 Counter;
__int64 Status;
EFI_RUNTIME_SERVICES *RuntimeServices;
UINTN Size;
char WriteOnceStatusData[64];
UINTN DataSize;
DataSize = 64;
Result = 0;
Index = 0;
table_ptr = &gTable;
Counter = 2;
Status = gRT->GetVariable(L"WriteOnceStatus", &EFI_SMBIOS_NVRAM_DATA_GUID, 0, &DataSize, WriteOnceStatusData);
do
{
if ( *(table_ptr - 1) == value1 && *table_ptr == value2 && table_ptr[1] )
{
if... // will not be executed is Status != EFI_SUCCESS
if ( Index < 0x10 && !Result )
{
RuntimeServices = gRT;
Size = DataSize;
WriteOnceStatusData[4 * Index] = value1;
WriteOnceStatusData[4 * Index + 1] = value2;
*&WriteOnceStatusData[4 * Index + 2] = value3;
Status = (RuntimeServices->SetVariable)(
L"WriteOnceStatus",
&EFI_SMBIOS_NVRAM_DATA_GUID,
7,
Size,
WriteOnceStatusData);
}
}
_Next:
table_ptr += 3;
--Counter;
}
while ( Counter );
return Result;
}
As we can see from the pseudocode, for the WriteOnceStatus
variable gRT->SetVariable()
service is called with the DataSize
value, which can be overwritten inside the gRT->GetVariable()
service.
Thus, a potential attacker can write X - 64
bytes from the SMRAM stack region to NVRAM if writes any buffer of length X > 64
to the WriteOnceStatus
NVRAM variable before triggering the SW SMI handler.
In order to fix this vulnerability, the DataSize
variable must be initialized before gRT->SetVariable()
.
This vulnerability is subject to a 90 day disclosure deadline. After 90 days elapsed or a patch has been made broadly available (whichever is earlier), the vulnerability report will become visible to the public.
Binarly REsearch Team