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 a DXE Runtime UEFI application and execute arbitrary code. A malicious code installed as a result of the vulnerability exploitation in DXE driver could survive across an operating system (OS) boot process and runtime or modify NVRAM area on the SPI flash storage (to gain persistence on target platform). Additionally, this vulnerability potentially could be used by threat 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 priviledged 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 a DXE Runtime UEFI application and execute arbitrary code.A malicious code installed as a result of the vulnerability exploitation in DXE driver could survive across an operating system (OS) boot process and runtime or modify NVRAM area on the SPI flash storage (to gain persistence on target platform).Additionally, this vulnerability potentially could be used by threat 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 following piece of code contains a stack overflow vulnerability (firmware name: Q92_011500.bin
, driver name: 0D24
, code offset: 0x171F
):
...
_GetCoolControlData:
DataSize = 8i64;
vStatus = gRT_23B0->GetVariable(
(CHAR16 *)L"CoolControlData",
&gVendorGuid,
(UINT32 *)&Attributes,
&DataSize,
vCoolControlDataValue);
// If the length of the CoolControlData variable is greater than 8, then at the moment vStatus = EFI_BUFFER_TOO_SMALL
// (this means that the GetVariable call will occur a second time)
if ( !vStatus
|| (vStatus = gRT_23B0->GetVariable(
(CHAR16 *)L"CoolControlData",
&gVendorGuid,
(UINT32 *)&Attributes,
&DataSize,
vCoolControlDataValue)) == 0 )
{
LOBYTE(v19) = vCoolControlDataValue[1];
LOBYTE(v20) = 1;
sub_1A78(v20, v19);
}
return vStatus;
}
The value of the DataSize
is initialized only once (before the first call to GetVariable
service).If the length of NVRAM CoolControlData
variable is greater than 8, then after the second call to GetVariable
service, a stack overflow may occur, followed by execution of arbitrary code.
Below is a section of the stack for the function under consideration:
-0000000000000038 vCoolControlDataValue db ?
-0000000000000037 var_37 db ?
-0000000000000036 db ? ; undefined
-0000000000000035 db ? ; undefined
-0000000000000034 db ? ; undefined
-0000000000000033 db ? ; undefined
-0000000000000032 db ? ; undefined
-0000000000000031 db ? ; undefined
-0000000000000030 Buffer dq ?
-0000000000000028 var_28 dd ?
-0000000000000024 db ? ; undefined
-0000000000000023 db ? ; undefined
-0000000000000022 db ? ; undefined
-0000000000000021 db ? ; undefined
-0000000000000020 db ? ; undefined
-000000000000001F db ? ; undefined
-000000000000001E db ? ; undefined
-000000000000001D db ? ; undefined
-000000000000001C db ? ; undefined
-000000000000001B db ? ; undefined
-000000000000001A db ? ; undefined
-0000000000000019 db ? ; undefined
-0000000000000018 var_18 dq ?
-0000000000000010 var_10 dd ?
-000000000000000C db ? ; undefined
-000000000000000B db ? ; undefined
-000000000000000A db ? ; undefined
-0000000000000009 db ? ; undefined
-0000000000000008 db ? ; undefined
-0000000000000007 db ? ; undefined
-0000000000000006 db ? ; undefined
-0000000000000005 db ? ; undefined
-0000000000000004 db ? ; undefined
-0000000000000003 db ? ; undefined
-0000000000000002 db ? ; undefined
-0000000000000001 db ? ; undefined
+0000000000000000 s db 16 dup(?)
+0000000000000010 r db 8 dup(?)
+0000000000000018 Interface dq ? ; offset
+0000000000000020 Attributes dq ?
+0000000000000028 DataSize dq ?
+0000000000000030 arg_18 dq ? ; offset
+0000000000000038
+0000000000000038 ; end of stack variables
Thus, by assigning a 72-byte value to CoolControlData
variable, an attacker can completely overwrite the return address from the current function and execute arbitrary code.
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