Welcome back to CVE Wednesday! Today we are going to look at CVE-2021-39297. CVE-2021-39297 was originally discovered and reported by Binarly and impacts certain HP PCs. A full write up, including a demonstration of a proof of concept, is available on the Binarly Website as BRLY-2021-003.
Additionally, HP provides a support document here
A Discussion regarding reproducing the vulnerability inspired me to write up this blog post.
Full credit for the discovery of this vulnerability is due to the team at Binarly. I had nothing to do with the discovery of this vulnerability
I reproduced this vulnerability using WSL2 on a Windows 11 laptop. You will need qemu-system
and ovmf
installed, and potentially ovmf-ia32
.
First, I downloaded a firmware file from HP that the Binarly disclosure listed as vulnerable:
https://ftp.ext.hp.com/pub/pcbios/8521/Q95_011400.bin
Next I used a script I wrote to extract the DXE firmware volume from the Q95_011400.bin
file:
$ python3 hp-dxe-extract.py Q95_011400.bin
This left me with a directory volume-0
that contains a directory with the module GUID:
$ ls volume-0/file-c988bded-6977-464d-b714-e61debd2de97/
file.obj section0.pe section1.ui
c988bded-6977-464d-b714-e61debd2de97
is listed in the original binarly advisory as being the vulnerable DXE driver GUID.
Now lets do a checksum:
$ md5sum volume-0/file-c988bded-6977-464d-b714-e61debd2de97/section0.pe
f0f53a2f30f91feb32af7b6b8d73353d volume-0/file-c988bded-6977-464d-b714-e61debd2de97/section0.pe
The md5 hash f0f53a2f30f91feb32af7b6b8d73353d
matches the hash listed for this firmware version in the Binarly Advisory. We have the vulnerable 0138.efi
file at this point.
I then created a directory fs
to use as my FAT32 ESP.
$ mkdir -p fs/EFI/boot
$ cp volume-0/file-c988bded-6977-464d-b714-e61debd2de97/section0.pe fs/0138.efi
Next, we can use OVMF with QEMU to launch into an EFI shell:
$ qemu-system-x86_64 -bios /usr/share/ovmf/OVMF.fd -hda fat:rw:fs -nographic -serial mon:stdio
I ran the EFI shell with QEMU from the CLI using -nographic
because it made pasting in the EFI variable values easy.
From the EFI Shell we can then run 0138
and see the application launch:
The vulnerability stems from handling the EFI variables PlatformLang
and Lang
, so those need to be set to the values provided in the binarly advisory using the EFI command setvar
.
It is important to note that the binarly advisory contains a video demonstrating successful exploitation of the vulnerability. However, the video does not capture which firmware file the 0138.efi
file was extracted from. As such, the memory layout may differ between the various versions. This means when I attempted to exploit the vulnerability, I received a CPU exception:
!!!! X64 Exception Type - 0D(#GP - General Protection) CPU Apic ID - 00000000 !!!!
ExceptionData - 0000000000000000
RIP - 4C07E9E741BA079E, CS - 0000000000000038, RFLAGS - 0000000000000206
RAX - 0000000000000003, RCX - 0000000000000065, RDX - 0000000005F14A70
RBX - 0000000007F10588, RSP - 0000000007F10440, RBP - 0000000007F10578
RSI - 000000000614E018, RDI - E018B82850FF41C1
R8 - 0000000000000003, R9 - 000000000640531E, R10 - 00000000000005F2
R11 - 0000000000000001, R12 - 0000000000000000, R13 - 000000000614FA18
R14 - 000000000605DA00, R15 - 00000000060C2AE8
DS - 0000000000000030, ES - 0000000000000030, FS - 0000000000000030
GS - 0000000000000030, SS - 0000000000000030
CR0 - 0000000080010033, CR2 - 0000000000000000, CR3 - 0000000007C01000
CR4 - 0000000000000668, CR8 - 0000000000000000
DR0 - 0000000000000000, DR1 - 0000000000000000, DR2 - 0000000000000000
DR3 - 0000000000000000, DR6 - 00000000FFFF0FF0, DR7 - 0000000000000400
GDTR - 00000000079DE000 0000000000000047, LDTR - 0000000000000000
IDTR - 0000000007471018 0000000000000FFF, TR - 0000000000000000
FXSAVE_STATE - 0000000007F100A0
The next steps would be adjusting the exploit data to match up with the specific firmware version I am running against for this write up. If I have time and there is interest, I’ll write another blog post on how to do that later.