CVE-2025-3052
An attacker can exploit this vulnerability to bypass Secure Boot, allowing them to execute untrusted code during the boot process. This enables an attacker to run malicious UEFI bootkits before the operating system is fully initialized. Once deployed, these malicious components can compromise the integrity of the operating system, gain elevated privileges, or facilitate further attacks, undermining system security and potentially evading detection by traditional security mechanisms.
The vulnerability exists in a UEFI application which has been found on VirusTotal:
$ sha256sum Dtbios-efi64-71.22.efi
a11996aaf7f32aa09f78db608106e25a47970bfeeec76d49af743eee71b55f06 Dtbios-efi64-71.22.efi
$ authenticode-tool info Dtbios-efi64-71.22.efi
SHA-1: 7ec65bb912b1fdce514a1a5ff8cf2ed187eb8fa3
SHA-256: 6b4328ebcbe46ed9118ff2d4472de329d70ba83016df7a6f50f8af923883bc54
Signature 0:
Digest: 6b4328ebcbe46ed9118ff2d4472de329d70ba83016df7a6f50f8af923883bc54
Signer:
Issuer: CN=Microsoft Corporation UEFI CA 2011,O=Microsoft Corporation,L=Redmond,ST=Washington,C=US
Serial number: 33:00:00:00:4F:53:61:25:A6:D6:64:88:67:00:01:00:00:00:4F
Certificate 0:
Issuer: CN=Microsoft Corporation UEFI CA 2011,O=Microsoft Corporation,L=Redmond,ST=Washington,C=US
Subject: CN=Microsoft Windows UEFI Driver Publisher,O=Microsoft Corporation,L=Redmond,ST=Washington,C=US
Serial number: 33:00:00:00:4F:53:61:25:A6:D6:64:88:67:00:01:00:00:00:4F
Certificate 1:
Issuer: CN=Microsoft Corporation Third Party Marketplace Root,O=Microsoft Corporation,L=Redmond,ST=Washington,C=US
Subject: CN=Microsoft Corporation UEFI CA 2011,O=Microsoft Corporation,L=Redmond,ST=Washington,C=US
Serial number: 61:08:D3:C4:00:00:00:00:00:04
As shown above, this module is signed with the 'Microsoft Corporation UEFI CA 2011' key. This key is widely trusted by many devices, since it's also used to sign shim, the UEFI application that effectively allows Linux-based systems to work when Secure Boot is enabled.
The vulnerability is present in the function at address 0x6914 in the module, which is called from the module's entrypoint. The pseudocode of vulnerable function is shown below:
__int16 **VulnerableFunction()
{
EFI_RUNTIME_SERVICES *RuntimeServices; // r10
__int16 **v1; // rsi
char v2; // al
char v3; // al
__int64 param3_low; // rdx
char param1; // r11
H2oIhisiParams *v6; // rbx
H2oIhisiParams *v7; // rcx
__int64 v8; // rbx
__int64 (__fastcall **i)(); // rdi
__int64 v11; // [rsp+40h] [rbp+8h] BYREF
RuntimeServices = gST->RuntimeServices;
v1 = 0LL;
v11 = 8LL;
if ( (RuntimeServices->GetVariable)(L"IhisiParamBuffer", &H2O_IHIS_PARAM_BUFFER_GUID, 0LL, &v11, &ParamBuffAddr) < 0 )
{
v2 = byte_F795;
}
else
{
if ( dword_70C >= 7 )
sub_DB0C(L"mIsParamsBufferSupported: 0x%x\n", byte_F795);
v2 = 1;
byte_F795 = 1;
}
if ( !v2 )
{
v3 = sub_F6D2(&dword_F790, &qword_F798);
param3_low = dword_F790;
param1 = v3;
goto LABEL_10;
}
v6 = ParamBuffAddr;
v7 = ParamBuffAddr;
// MULTIPLE ARBITRARY WRITE
ParamBuffAddr->param3 = 0LL;
v7->param5 = 0LL;
v7->param6 = 0LL;
v7->param1 = 0x83EFLL;
v7->param2 = '$H2O';
v7->param4 = 0xB2LL;
sub_F6FB(v7);
param1 = v6->param1;
if ( !param1 )
{
param3_low = LODWORD(v6->param3);
dword_F790 = v6->param3;
qword_F798 = v6->param4;
LABEL_10:
if ( !param1 )
{
if ( dword_70C >= 7 )
{
sub_DB0C(L"CmdBufAddress: 0x%x\n", param3_low);
if ( dword_70C >= 7 )
sub_DB0C(L"CmdBufSize: 0x%x\n", qword_F798);
}
byte_F794 = 1;
}
}
v8 = 0LL;
for ( i = off_6C8; !*i || (*i)() != 1; i += 5 )
{
v8 = (v8 + 1);
if ( v8 )
return v1;
}
v1 = &(&off_6C0)[5 * v8];
if ( v1 && dword_70C >= 7 )
sub_DB0C(L"Platform = %s\n", *v1);
return v1;
}
As seen in the pseudocode, the function retrieves the NVRAM variable "IhisiParamBuffer" (GUID: 92E59835-5F42-4E0B-9A84-47C7810EA806) and stores its content in the global variable "ParamBuffAddr". A few lines later, "ParamBuffAddr" is used a pointer for multiple memory writes. This allows an attacker to store an arbitrary memory address in the "IhisiParamBuffer" NVRAM variable, and when the module will run, the folllowing attacker-controlled writes will be performed:
[ADDR + 0x08] = 0x00000000000083EF
[ADDR + 0x10] = 0x000000002448324F
[ADDR + 0x18] = 0x0000000000000000
[ADDR + 0x20] = 0x00000000000000B2
[ADDR + 0x28] = 0x0000000000000000
[ADDR + 0x30] = 0x0000000000000000
The attacker-controlled memory writes described in the previous section provide a powerful primitive that can be exploited in multiple ways. In this advisory, we demonstrate how this vulnerability can be used to bypass Secure Boot and execute untrusted code, which is arguably the most impactful way to leverage it.
The core idea behind our proof-of-concept is to leverage the attacker-controlled memory write to zero "gSecurity2". This global variable holds a pointer to the Security2 Architectural Protocol, which is used by the LoadImage function to verify files and thus to enforcing Secure Boot. As shown here, when gSecurity2 is set to zero, Secure Boot is effectively disabled, allowing the execution of untrusted UEFI modules.
We developed and tested a PoC based on the previous idea. The PoC follows these steps:
This PoC demonstrates how an attacker can bypass Secure Boot and load untrusted code without any user interaction or physical access to the device, requiring only privileged OS access (e.g., through a root shell).
The module's entrypoint checks for the presence of the EFI_TSC_FREQUENCY_GUID in the EFI Configuration Table, and when this table is not found, the module calls the InternalCalculateTscFrequency function:
UINT64
InternalCalculateTscFrequency (
VOID
)
{
...
//
// ACPI I/O space should be enabled now, locate the ACPI Timer.
// ACPI I/O base address maybe have be initialized by other driver with different value,
// So get it from PCI space directly.
//
TimerAddr = ((PciRead16 (PCI_ICH_LPC_ADDRESS (R_ICH_LPC_ACPI_BASE))) & B_ICH_LPC_ACPI_BASE_BAR) + R_ACPI_PM1_TMR;
Ticks = IoRead32 (TimerAddr) + (3579); // Set Ticks to 1ms in the future
StartTSC = AsmReadTsc(); // Get base value for the TSC
//
// Wait until the ACPI timer has counted 1ms.
// Timer wrap-arounds are handled correctly by this function.
// When the current ACPI timer value is greater than 'Ticks', the while loop will exit.
//
while (((Ticks - IoRead32 (TimerAddr)) & BIT23) == 0) {
CpuPause();
}
EndTSC = AsmReadTsc(); // TSC value 1ms later
...
}
This function determines the TSC frequency by using the ACPI timer. However, on platforms where the ACPI timer isn’t implemented, calling IoRead32(TimerAddr) returns -1 (0xFFFFFFFF). As a result, the condition in the while loop always evaluates to true, causing the module to hang indefinitely there. In most cases, the only way to determine what value IoRead32(TimerAddr) returns on platforms without an ACPI timer is to test it directly on the physical hardware itself.
This advisory affects all devices where the previous loop condition eventually evaluates to false and all devices that trust the 'Microsoft Corporation UEFI CA 2011' certificate, which is extremely common on both consumer and enterprise-grade devices. Moreover, based on our previous experience, some Insyde-based devices might lock the variable "IhisiParamBuffer", preventing its content to be modified from the OS. As a result, these devices are not vulnerable to this specific issue unless a second vulnerability is exploited to allow modification of the "IhisiParamBuffer".
To remediate this vulnerability, the execution of Dtbios-efi64-71.22.efi must be prevented. This can be achieved by adding its Authenticode hash to the dbx database. It's important to note that while we identified a single instance of the vulnerable module, it’s possible that other variations and versions exists in the wild, so each of these should be added to the dbx database to ensure comprehensive protection. Additionally, since NVRAM variables can have arbitrary values, the module developer should remove the vulnerable code. This is the only reliable way to prevent exploitation of the vulnerability described in this advisory.
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