Thursday, October 24, 2024

Tales from the Call-Gate: An SMM Supervisor Vulnerability

  by Joseph Tartaro and Enrique Nissim 

Introduction

A few years ago we started analyzing the platform security of AMD systems. This research led to a number of blog posts and presentations at several technical security conferences. The presentations covered issues from SMM modules, the AMD SMM Supervisor and even a decades old CPU bug. The theme of the research was dubbed "Back to the Future", this was tongue in cheek due to the types of vulnerabilities that we were finding for AMD systems that have not affected Intel platforms for many years, such as failures to lock down SPI flash. Another bug that inspired the concept was what we reported regarding the SMM Supervisor, which involved x86 Call-Gates, something that you would never see related to modern exploitation in today's world. Although the reported issue received a CVE, we realized we never made the details public, hence this blog post.

Overview

The SMM Supervisor is essentially a new operating system within SMM, with the purpose of deprivileging SMI handlers. This is a new security boundary to help mitigate constant SMM vulnerabilities in various vendor custom SMI handlers. If you're ever reverse engineering a modern SMM module you may see a pattern like the following, this is checking the CPL and if it is running under Ring-3 then it knows the SMM Supervisor is initialized and will call into the new interface, else it will operate normally for legacy purposes or if no supervisor is running.



The details in this blog post are specifically regarding the AMD SMM Supervisor implementation, if you have an interest in the Intel implementation detailed blog posts and presentations have been given by Satoshi Tanda which you can review.


The SMM Supervisor implementation lives in the SmmSupervisorBinRelease module.


During its initialization, the module does essentially four things:

  1. Retrieves the Trusted SMI Entry Code

  2. Installs an SMM Interface for PiSmmCpuDxeSmm

  3. It sends the DRTMInfo message to the PSP

  4. It reserves the required memory to hold information per core such as the Syscall Entry Point, SMM Base Address, GDT and GDTR


This post is only going to cover steps 1 and 2, if you're interested in a full overview of the flow please reference our presentation on it.

The Trusted SMI Entry Code is the code that is going to be executed upon the System Management Interrupt (SMI). This code is part of a Raw Freeform file that comes in the BIOS image and has a guid of 83E1F409-21A3-491D-A415-B163A153776D


The Supervisor has functions to parse this blob of data and extract the specific sections as required. The beginning of the file starts with a PSP header (0x10 bytes long), which at offset 0x08 indicates the number of sections that follow (5 in this case). 



Each section is represented with the following struct:


Struct policy_section {

   int type;

   unsigned int size;

   unsigned int offset;

   int unused;

};


The Trusted SMI Entry Code is type 0xC1, it has a size of 0x2A4 and starts at offset 0x600. The following image shows the beginning of the supervisor code.



The code puts the content the section 0xC1 and its size into global variables, followed by the installation of an SMM Protocol Interface with the GUID SmmSupervisorInterfaceProtocolGuid (1738B3B1-762F-454B-9779432877A062F6).


This interface exposes the size of the Trusted SMI Entry Code, and four functions:



Using UEFITool to search for the GUID across the entire BIOS image, there is a single module that consumes this interface, which is PiSmmCpuDxeSmm


In EDK-II, it is PiSmmCpuDxeSmm the module that prepares SMRAM and installs the first set of SMM Protocols that are used for SmmCore. In this case, the module invokes the first exported function in the Supervisor interface, which returns the Trusted SMI Entry Code that is going to be copied into SMM_BASE+0x8000, which is the SMI Handler Entry Point.



The purpose of the Supervisor SmmCpuFeaturesInstallSmiHandler function is to patch the Trusted SMI Entry Code with the arguments received from PiSmmCpuDxeSmm (e.g. IDTR, Cr3, SmiRandezvous function pointer) and return the modified version back so it gets copied into the proper SMRAM location.

Analysis of SmmCpuFeaturesInstallSmiHandler

This function starts by allocating memory for the GDT and initializing it with predefined values. The predefined values are the following:


These values translate to the following:


This new GDT is where the new call-gates are configured. An x86 call-gate is a mechanism in the x86 architecture used to facilitate controlled transitions between different privilege levels in the processor. It allows code running in a lower-privileged ring (ring-3) to call a into a higher-privileged ring (ring-0). If you need a refresher on x86 internals we recommend you review the OST2 Architecture 2001: x86-64 OS Internals course.


The function that initializes the GDT also receives an argument that is used to patch the entry 0x60 (the first call-gate), but SmmCpuFeaturesInstallSmiHandler sets this argument to NULL.


The predefined values have the two call-gates set with a DPL of 3 (Ring-3) and the selector points to 0x38, which is a 64-bit Code Segment with DPL 0 (Ring-0).


Following the initialization of the GDT, the code parses the memory content of the 0xC1 Section (the Trusted SMI Entry) and gets a pointer to the end of the section minus 4.


The code performs a calculation using this value to get a pointer to a table that is located right after the code ends:


pTable = pC1Section + C1SectionSize - 4 - 0x78

C1SectionSize = 0x2A4

pTable = pC1Section + 0x228


EDI holds the pointer to the table located at +0x228.


The code uses the table bytes to get offsets into locations that will be used to store the arguments passed to the function and function pointers like the high-level SmiEntry and SmiExit.


The table at the end looks like this:


The Trusted SMI Entry Code references these offsets taking into account the SmmBase and the SmiEntry Point (0x8000). Note the various comments regarding when GDTR, SmiEntry, SmiExit, Smi Randezvous, etc. are referenced.


; 16-bit - Real Mode
00 : 2E 66 8B 3E 88 82 mov edi, dword ptr cs:[0x8288] ; Load GDTR
06 : 3E 66 67 0F 01 17 lgdt ds:[edi]
0c : BB 47 80 mov bx, 0x8047
0f : B8 08 00 mov ax, 8
12 : 2E 89 47 FE mov word ptr cs:[bx - 2], ax
16 : 66 B9 11 01 01 C0 mov ecx, 0xc0010111
1c : 0F 32 rdmsr
1e : 66 89 C7 mov edi, eax
21 : 66 67 8D 87 47 80 00 00 lea eax, [edi + 0x8047]
29 : 2E 66 89 47 FA mov dword ptr cs:[bx - 6], eax
2e : 0F 20 C3 mov ebx, cr0
31 : 66 81 E3 F3 FF FA 9F and ebx, 0x9ffafff3
38 : 66 83 CB 23 or ebx, 0x23 ; Configuration bits for cr0
3c : 0F 22 C3 mov cr0, ebx ; Enter Protected Mode
; 32-bit - Protected Mode
45 : 00 00 add BYTE PTR [eax],al
47 : 66 b8 20 00 mov ax,0x20
4b : 66 8e d8 mov ds,ax
4e : 66 8e c0 mov es,ax
51 : 66 8e e0 mov fs,ax
54 : 66 8e e8 mov gs,ax
57 : 66 8e d0 mov ss,ax
; Load Stack Pointer
5a : 8b a7 90 82 00 00 mov esp,DWORD PTR [edi+0x8290]
60 : 8b 14 24 mov edx,DWORD PTR [esp]
63 : 8b a7 98 82 00 00 mov esp,DWORD PTR [edi+0x8298]
69 : eb 00 jmp 0x6b
6b : be 8c 82 00 00 mov esi,0x828c ; 0x8000 + 0x28C
70 : 48 dec eax
71 : 01 fe add esi,edi
73 : 8b 06 mov eax,DWORD PTR [esi]
75 : 0f 22 d8 mov cr3,eax
78 : b8 68 06 00 00 mov eax,0x668
7d : 0f 22 e0 mov cr4,eax
80 : 83 ec 08 sub esp,0x8
83 : 0f 01 04 24 sgdtd [esp]
87 : 8b 44 24 02 mov eax,DWORD PTR [esp+0x2]
8b : 83 c4 08 add esp,0x8
8e : b1 89 mov cl,0x89
90 : 38 88 85 00 00 00 cmp BYTE PTR [eax+0x85],cl
96 : 74 06 je 0x9e
98 : 88 88 85 00 00 00 mov BYTE PTR [eax+0x85],cl
9e : b8 80 00 00 00 mov eax,0x80
a3 : 0f 00 d8 ltr ax
a6 : b9 80 00 00 c0 mov ecx,0xc0000080
ab : 52 push edx
ac : 0f 32 rdmsr
ae : 66 0d 00 08 or ax,0x800
b2 : 0f 30 wrmsr
b4 : 5a pop edx
b5 : 6a 38 push 0x38
b7 : e8 00 00 00 00 call 0xbc
bc : 83 04 24 21 add DWORD PTR [esp],0x21
c0 : 52 push edx
c1 : b9 80 00 00 c0 mov ecx,0xc0000080
c6 : 0f 32 rdmsr
c8 : 80 cc 01 or ah,0x1
cb : 0c 01 or al,0x1
cd : 0f 30 wrmsr
cf : 5a pop edx
d0 : 0f 20 c3 mov ebx,cr0
; enables paging and more
d3 : 81 cb 23 00 01 80 or ebx,0x80010023
d9 : 0f 22 c3 mov cr0,ebx
dc : cb retf ; Transition into 64-bit mode
; 64-bit
; Load IdtSize
dd : 48 8B 87 74 82 00 00 mov rax,QWORD PTR [rdi+0x8274]
; Load IDT for 64-bit mode
e4 : 0F 01 18 lidt [rax]
e7 : 66 B8 20 00 mov ax,0x20
eb : 8E D8 mov ds,ax
ed : 8E C0 mov es,ax
ef : 8E E0 mov fs,ax
f1 : 8E E8 mov gs,ax
f3 : 8E D0 mov ss,ax
f5 : 48 83 EC 08 sub rsp,0x8
f9 : 48 81 EC 00 02 00 00 sub rsp,0x200
100: 48 0F AE 04 24 fxsave64 [rsp]
105: 52 push rdx
106: 48 81 EC 80 00 00 00 sub rsp,0x80
10d: 48 89 14 24 mov QWORD PTR [rsp],rdx
111: B8 00 00 00 00 mov eax,0x0
116: 8B 87 98 82 00 00 mov eax,DWORD PTR [rdi+0x8298]
11c: 48 89 44 24 08 mov QWORD PTR [rsp+0x8],rax
121: 8B 87 90 82 00 00 mov eax,DWORD PTR [rdi+0x8290]
127: 48 89 44 24 10 mov QWORD PTR [rsp+0x10],rax
12c: 8B 87 9C 82 00 00 mov eax,DWORD PTR [rdi+0x829c]
132: 48 89 44 24 18 mov QWORD PTR [rsp+0x18],rax
137: 48 8D 87 28 82 00 00 lea rax,[rdi+0x8228]
13e: 48 89 44 24 20 mov QWORD PTR [rsp+0x20],rax
143: 48 8D 87 CC 81 00 00 lea rax,[rdi+0x81cc]
14a: 48 89 44 24 28 mov QWORD PTR [rsp+0x28],rax
14f: 48 89 E0 mov rax,rsp
152: 48 05 88 00 00 00 add rax,0x88
158: 48 89 44 24 30 mov QWORD PTR [rsp+0x30],rax
; Load SmiEntry
15d: 48 8B 87 4C 82 00 00 mov rax,QWORD PTR [rdi+0x824c]
164: 48 89 E1 mov rcx,rsp
167: 48 83 EC 48 sub rsp,0x48
16b: FF D0 call rax
16d: 48 83 C4 48 add rsp,0x48
171: 48 81 C4 80 00 00 00 add rsp,0x80
178: 5A pop rdx
179: 48 25 FF FF FF 00 and rax,0xffffff
17e: 48 3D FF FF FF 00 cmp rax,0xffffff
183: 74 14 je 0x19a
185: 3C FF cmp al,0xff
187: 74 00 je 0x18a
189: 4C 8D 3D 4C 00 00 00 lea r15,[rip+0x4c]
; Load SmiRandezvous
190: 48 8B B7 5C 82 00 00 mov rsi,QWORD PTR [rdi+0x825c]
197: FF E6 jmp rsi
19a: 66 B8 53 00 mov ax,0x53
19e: 8E D8 mov ds,ax
1a0: 8E C0 mov es,ax
1a2: 8E E0 mov fs,ax
1a4: 8E E8 mov gs,ax
1a6: B8 00 00 00 00 mov eax,0x0
1ab: 67 8B 87 90 82 00 00 mov eax,DWORD PTR [edi+0x8290]
1b2: 48 8B B7 5C 82 00 00 mov rsi,QWORD PTR [rdi+0x825c]
1b9: 41 BF 63 00 00 00 mov r15d,0x63
1bf: 49 C1 E7 20 shl r15,0x20
1c3: 6A 53 push 0x53
1c5: 50 push rax
1c6: 6A 5B push 0x5b
1c8: 56 push rsi
1c9: 48 CB rex.W retf
; Call-Gate Code
1cc: 48 83 C4 20 add rsp, 0x20
1d0: 66 B8 20 00 mov ax, 0x20
1d4: 8E D8 mov ds, ax
1d6: 8E C0 mov es, ax
1d8: 8E E0 mov fs, ax
1da: 8E E8 mov gs, ax
1dc: 8E D0 mov ss, ax
1de: 48 89 D9 mov rcx, rbx
; RDI assumed to be SMM_BASE+0x8000 but is attacker controlled
1e1: 48 8B 87 54 82 00 00 mov rax, QWORD PTR [rdi+0x8254]
; Call the attacker controlled function
1e8: FF D0 call rax
1ea: 48 0F AE 0C 24 fxrstor64 [rsp]
1ef: 48 81 C4 00 02 00 00 add rsp, 0x200
1f6: B8 10 00 00 00 mov eax, 0x10
1fb: E8 07 00 00 00 call 0x202
200: F3 90 pause
202: 0F AE E8 lfence
204: EB F9 jmp 0x1ff
206: E8 07 00 00 00 call 0x20e
20b: F3 90 pause
20d: 0F AE E8 lfence
20f: EB F9 jmp 0x20b
211: 48 FF C8 dec rax
214: 75 E3 jne 0x1fa
216: 48 81 C4 00 01 00 00 add rsp, 0x100
21d: 0F AA rsm
21f: 21 02 and DWORD PTR [rdx], eax
221: 90 nop
222: 90 nop
223: 90 nop
224: 90 nop
225: 90 nop

At offset +0x15D the SmiEntry function pointer is retrieved from the table and then is invoked at +0x16B. The code builds a structure in the stack of 0x80 bytes in size and passes it through RCX


At offset 0x28, this structure holds a pointer to the Call-Gate offset. This offset is passed into the InitializeGDT function as part of the SmiEntry execution:


After the SmiEntry code finishes, the code follows and executes the SmiRandezvous, which will be executed with Ring-3 privileges (Usermode) and will invoke the proper OEM’s SMI Handlers.


The problem here is that the GDT set by the Supervisor contains a Call-Gate with DPL3 that can be abused by a malicious (or compromised) SMI Handler to elevate privileges.


Because the Call-Gate code is also part of the SMI Entry, it expects that RDI will always contain the value of SmmBase. Nevertheless, a malicious SMI Handler can control the value of RDI. This allows for the attacker to escalate to Ring-0 privileges.


; Call-Gate Code
1cc: 48 83 C4 20 add rsp, 0x20
1d0: 66 B8 20 00 mov ax, 0x20
1d4: 8E D8 mov ds, ax
1d6: 8E C0 mov es, ax
1d8: 8E E0 mov fs, ax
1da: 8E E8 mov gs, ax
1dc: 8E D0 mov ss, ax
1de: 48 89 D9 mov rcx, rbx
; RDI assumed to be SMM_BASE+0x8000 but is attacker controlled
1e1: 48 8B 87 54 82 00 00 mov rax, QWORD PTR [rdi+0x8254]
; Call the attacker controlled function
1e8: FF D0 call rax


In addition to the Call-Gate issue, you can see at offset +0x78, the code initializes CR0 to 0x668. This means SMEP is not enabled in this configuration, which means that an attacker can point RDI to a function in Ring-3 and take control of Ring-0 by abusing the Call-Gate. Also, UMIP is not enabled in this context. This translates into Supervisor pointer leakages from Ring-3 via the instructions Store IDT (sidt) and Store GDT (sgdt). These additional misconfigurations make it easier for an attacker to exploit the Call-Gate vulnerability.


Timeline

These issues were reported to the AMD PSIRT team on 5/9/2023. The AMD PSIRT team issued CVE-2023-20596 and released the following AMD-SB-7011 bulletin on 11/14/2023.

Tuesday, February 6, 2024

Exploring AMD Platform Secure Boot

by Krzysztof Okupski


Introduction

In our previous post on platform security (see here) we provided a brief introduction into platform security protections on AMD-based platforms and touched upon the topic of AMD Platform Secure Boot (PSB).

As a quick reminder, the purpose of PSB is to provide a hardware root-of-trust that will verify the integrity of the initial UEFI firmware phases, thereby preventing persistent firmware implants.

In this part of the blog series, we will dig deeper into the nitty gritty details of PSB, including a first glimpse of how it works under the hood, how it should be configured and, naturally, how various major vendors fail to do so.


Architecture

To begin, it is important to understand that the UEFI boot process is divided into various phases, referred to as SEC, PEI, DXE, BDS, TSL, RT and AL. For the sake of brevity, we won't go into detail on the purpose of each phase as it has already been widely covered already (e.g. here).

In short, the role of the PSB is to ensure that the initial UEFI phases, specifically the SEC and PEI phase, are properly verified and cannot be tampered with. In turn, the PEI phase will verify the DXE phase using a proprietary and vendor-specific method.   

The resulting scheme is summarized in the following image:


Upon reset, only the AMD Platform Security Processor (PSP), an ARM-based co-processor embedded within the AMD chip, is running. It functions as a hardware root-of-trust and verifies the SEC and PEI phase portions of the UEFI firmware. If verification succeeds, then it releases the main cores that then start executing the SEC and PEI phase.


Trust Hierarchy

In order to understand the trust hierarchy in more depth, we will first take a look at how the UEFI firmware, stored in the SPI flash, is structured. To do so, we will use the SPI flash dump we have obtained from an AMD-based Huawei Matebook 16 (BIOS v2.28).

When we open up a SPI flash dump with our trusty UEFI Tool, we will typically see, among others, the following structures:

  • Padding areas
  • Firmware volumes (containing DXE drivers and SMM modules)
  • NVRAM data (containing non-volatile configuration data, i.e. UEFI variables)

However, while UEFI Tool correctly identifies firmware volumes that contain code executed in the DXE phase of the UEFI boot process, the code running in the SEC and PEI phases seems to be missing altogether.

This is because it does not support parsing an AMD platform specific structure called the Embedded Firmware Structure (EFS). Once again, for the sake of brevity, as the structure is relatively complex, we will only focus on portions relevant to the chain-of-trust.

As described here, the EFS is located at one of the pre-defined locations in the SPI flash and contains pointers to:

  1. The PSP directory table that includes:
    • The BIOS signing key (entry type 0x05)
    • The BIOS PEI firmware volume (entry type 0x62)
    • The BIOS PEI firmware volume signature (entry type 0x07)

  2. The BIOS directory table that includes:
    • The AMD root signing key (entry type 0x00)

In visualized form, the resulting data structure looks as follows:

As a sidenote, we have also developed a simple parser (available here) that can be used to parse and extract the different portions of the PSP and BIOS directories.

Upon reset, the PSP will hold the main cores and verify the trust chain in the following order:

  • The AMD root signing key is verified against a SHA256 hash programmed into the PSP
  • The BIOS signing key is verified against the AMD root signing key
  • The BIOS PEI firmware volume is verified against the BIOS signing key

At this point the PSP releases the main cores and the SEC+PEI phase code, stored in the PEI firmware volume, will execute. Then, to complete the chain-of-trust, a vendor-specific PEI module will verify the DXE firmware volume(s).


PSB Configuration

The next step is to understand how we can interact with the PSP to determine whether the PSB is properly configured or not. This, in turn, could be used to implement a simple tool to detect potential misconfigurations. 

Here we found that the configuration can be checked by first determining the PSP MMIO base address and then, at a specific offset, reading out the value of two PSB-related registers.


PSP MMIO Base Address

First, the PSP MMIO base address is obtained by writing a specific value to a register of the AMD IOHUB Core (IOHC). More specifically:

  • 0x13E102E0 for families 17h, model 30h/70h or family 19h, model 20h or
  • 0x13B102E0 for all other models

is written to the register at offset 0xB8 of the IOHC device (on bus 00h, device 00h, function 00h) and the result is read from the register at offset 0xBC.

For example, on an Acer Swift 3 (fam 17h, model 60h) we write the value 0x13B102E0 at offset 0xB8 of the IOHC and read the base address 0xFDE00000 (after masking) at offset 0xBC.



PSB Configuration Registers

The PSB fuse register, located at offset 0x10994, reflects the actual fuse configuration and has the following structure:

It has various fields, such as:

  • the platform vendor ID and platform model ID to uniquely identify the platform
  • the BIOS key revision and anti-rollback to revoke BIOS signing keys
  • the AMD disable key to prevent booting a BIOS signed with the AMD root signing key
  • the PSB enable field to enable the feature
  • the customer key lock to permanently burn the fuses

We observed that on systems with the PSB enabled, typically the platform vendor ID, the platform model ID, the PSB enable bit and the customer key lock are configured accordingly. In fact, if the BIOS was compiled with the feature enabled, the fusing process occurs automatically when the system boots for the first time.

Interestingly, the PSB can also be permanently disabled by setting the PSB enable bit to 0 and the customer key lock to 1. This would enable an attacker to leave the system vulnerable indefinitely and is similar to what was discovered for Intel BootGuard by Alexander Ermolov (see Safeguarding Rootkits: Intel BootGuard at ZeroNights). 


The PSB status register, located at offset 0x10998, is used for obtaining PSB state information and has the following structure:

Here we only know that the PSB status field returns 0x00 if no errors occurred; otherwise returns a non-zero value likely corresponding to a specific error code.


Vulnerabilities

Now that we understand how the PSB should be configured, we would like to walk you through misconfiguration and implementation issues we discovered during our research.

For completeness, the list of systems we tested and whether they were found to be vulnerable or not can be found in a table at the end of this blog.


Configuration flaws

Based on our knowledge of the PSB fuse and status registers, we implemented the logic into our in-house developed platform testing tool Platbox (see here) and discovered that almost none of the tested systems had the feature enabled. 

As can be seen below, the Lenovo IdeaPad 1 Gen7 (BIOS JTCN44WW) did not have the PSB fuse register burned and the PSB status field returned a non-zero value. In fact, the same pattern was observed on all other vulnerable systems.


When trying to determine the root cause, we found that various data structures that are essential to the correct functioning of the PSB were missing, such as the BIOS signing key and the BIOS PEI firmware volume signature. This may indicate that already during the build process of the firmware image the feature was simply disabled.


Implementation flaws

Beyond configuration flaws, we also wanted to find out whether there were any potential implementation issues. While AMD implements the first portion of the chain-of-trust, verifying the SEC and PEI phase, we decided to focus on the vendor-specific portion that verifies the DXE phase.

To begin, we picked the Lenovo Thinkpad P16s Gen1 (BIOS v1.32) as our target, as it was one of the few systems that had the PSB enabled, and inspected the firmware with UEFI Tool. As it turns out, it uses a Phoenix-based BIOS and a well-known data structure, called the Phoenix hash file, to verify the DXE phase:

The Phoenix hash file format is straightforward - it is a list of protected ranges of the SPI flash encoded using triples that consist of base address, size and a hash. These protected ranges should, at least in theory, cover the DXE phase code, stored in DXE firmware volumes, that will be loaded.

However, we found that that multiple firmware volumes were used and that one of them (GUID 8FC151AE-C96F-4BC9-8C33-107992C7735B) was not covered by the protected ranges. Thereby, code contained within said volume could be tampered with and it would be automatically loaded during the boot process.

To make matters worse, we noticed that while the BIOS PEI firmware volume, verified by the PSP, was located in the beginning of the firmware in the padding section, whereas the Phoenix hash file was located at the end of it and thereby could be tampered with.

To confirm that the issue was indeed exploitable, we replaced the PersistenceConfigDxe DXE driver (GUID 27A95D13-15FB-4A2E-91E2-C784BF0D20D3) with a malicious DXE driver that configures the SMM_KEY MSR and allows us, at runtime, to disable the TSEG protections and thereby trivially escalate privileges to SMM (see previous blog post for more details).

Note that an advisory was published by Lenovo (see here) for this vulnerability (assigned CVE-2023-5078) that details which systems it affected and when different BIOS updates were released.


Vendor response

As part of our responsible disclosure process, we have reached out to various vendors in order to address the issues and get an understanding of the underlying problem. The responses were, to say the least, quite surprising:


Acer

"We appreciated your information about a possible vulnerability in Acer product. After thoroughly investigation, AMD PSB is an Optional Design during develop on consumption product, it’s not a mandatory requirement in Swift 3 SF314-42;

even though AMD PSB status is not enabled by default, platform with Secure Boot and Secure Flash are in position to protect system if malicious code injecting to flash ROM, so we don’t consider this as a vulnerability."


Lenovo

"Platform Secure Boot was introduced as a standard feature on all consumer Lenovo laptops in 2022, and laptops manufactured prior to this date were not designed with this feature in mind. Enabling it on devices now in the field would be likely to frustrate consumers if any unexpected issues arise."


Huawei

The PSB function was not enabled on our early AMD platform product, the PSB-like function(also known as "Intel Boot Guard") was enabled on our later Intel platform product (such as MateBook 16s 2022).

We confirmed with the BIOS supplier (Wingtech Technology) of the AMD platform product, there is no modification plan for this issue. To avoid confusing users, we kindly ask you not to disclose this issue. […]”


Conclusions

The results of our research demonstrate how vendors systematically failed to either properly configure the platform or correctly implement the chain-of-trust. Although it is clear how this issue needs to be addressed, based on vendor responses, it appears that they are reluctant to do so.

These issues would allow an attacker that has obtained a foothold on the OS, in combination with a SPI flash write primitive (e.g. CVE-2023-28468), to install firmware implants on the system. These, by design, bypass any OS- and Hypervisor-level protections that may be implemented and, if done properly, can also be made resistant to traditional firmware updates.

To determine whether you are vulnerable, we recommend running our in-house developed tool Platbox (see here) and, if that is the case, to reach out to the vendor in the hope that they will address these issues.


Appendix

The following table lists the systems we tested and what we discovered.

OEM Model PSB State
Acer Swift 3 (SF314-42) Not configured
Acer TravelMate P4 (P414-41) Not configured
ASUS Strix G15 (G513QR) Not configured
Lenovo Thinkpad P16s Gen1 Configured (but vulnerable)
Lenovo IdeaPad 1 Gen7 Not configured
Lenovo Thinkpad T495s Not configured
Huawei Matebook 16 Not configured
HP 15s (15s-eq2xxx) Not configured
Microsoft Surface 4 Configured
MSI Bravo 15 (B5DD) Not configured