AttackingAndDefendingBIOS RECon2015
AttackingAndDefendingBIOS RECon2015
AttackingAndDefendingBIOS RECon2015
BIOS in 2015
Dell BIOS in some Latitude laptops and Precision Mobile Workstations VU#912156 Dell
vulnerable to buffer overflow (Ruy Lopez)
LegbaCore
SMI Suppression if SMM BIOS protection is not used (Charizard) VU#291102 Multiple
Intel BIOS locking mechanism contains race condition that enables VU#766164 AMI,
write protection bypass (Speed Racer) Phoenix
Exploding Rainbows (2014)
Vulnerability Ref Affected Discoverer
UEFI EDK2 Capsule Update vulnerabilities a.k.a. King and Queens VU#552286 Multiple, LegbaCore
Gambit (2 issues) Tianocore EDK2
UEFI Variable Reinstallation (bypassing Boot-Service only variables) Tianocore Multiple,
Intel ATR
EDK2
Insecure Default Secure Boot Policy for Option ROMs
Loading unsigned Option ROMs (Thunderstrike) based on trmm.net Apple Trammell Hudson
earlier work by @snare
SMI input pointer validation vulnerabilities (multiple issues) CSW2015 Multiple Intel ATR
SMI handler call-out vulnerabilities (multiple issues) LegbaCore Multiple LegbaCore
Earlier by Filip Wecherowski & ITL (bugtraq, ITL)
SPI flash configuration lock (FLOCKDN) is lost after resume reverse.put.as Apple Pedro Vilaa
from S3 sleep (Update: Apple advisory) Update: Trammell
Hudson, LegbaCore
http://sovietart.me/
Calm silence ends the history of
mankind...
So lets talk what needs to be done
But, first, why we need any changes
Image source
VU# 976132 (CVE-2014-8274)
typedef struct {
//
// Acpi Related variables
//
EFI_PHYSICAL_ADDRESS AcpiReservedMemoryBase;
UINT32 AcpiReservedMemorySize;
EFI_PHYSICAL_ADDRESS S3ReservedLowMemoryBase;
EFI_PHYSICAL_ADDRESS AcpiBootScriptTable;
..
} ACPI_VARIABLE_SET_COMPATIBILITY;
S3 Boot Script table in memory
Why S3 Resume Boot Script?
00 00 00 00 21 00 00 00 02 00 0f 01 00 00 00 00
00 00 c0 fe 00 00 00 00 01 00 00 00 00 00 00 00
00 01 00 00 00 24 00 00 00 02 02 0f 01 00 00 00
00 04 00 c0 fe 00 00 00 00 01 00 00 00 00 00 00
00 00 00 00 08 02 00 00 00 21 00 00 00 02 00 0f
01 00 00 00 00 00 00 c0 fe 00 00 00 00 01 00 00
00 00 00 00 00 10 03 00 00 00 24 00 00 00 02 02
..
01 00 00 00 00 00 00 00 f0 00 02 00 67 01 00 00
20 00 00 00 01 02 30 04 00 00 00 00 21 00 00 00
00 00 00 00 de ff ff ff 00 00 00 00 68 01 00 00
..
d3 d1 4b 4a 7e ff
Decoding Opcodes
[000] Entry at offset 0x0000 (length = 0x21):
Data:
02 00 0f 01 00 00 00 00 00 00 c0 fe 00 00 00 00
01 00 00 00 00 00 00 00 00
Decoded:
Opcode : S3_BOOTSCRIPT_MEM_WRITE (0x02)
Width : 0x00 (1 bytes)
Address: 0xFEC00000
Count : 0x1
Values : 0x00
..
Ok And?
Execute arbitrary firmware code during early resume
Disable hardware protections such as BIOS write
protection which are going to be restored by the script
Install persistent BIOS rootkit in the SPI flash memory
Read/write any memory or execute arbitrary code in the
context of system firmware during early boot (PEI)
Bypass secure boot of the OS and install UEFI Bootkit
Yes, It Can Your
Steal PGP keys!
Forbes
Changing it to OFF
Oh wait
[x][ ==========================================
[x][ Module: S3 Resume Boot-Script Protections
[x][ ==========================================
[!] Found 1 S3 boot-script(s) in EFI variables
[*] Checking S3 boot-script at 0x00000000DA88A018
[!] S3 boot-script is not in SMRAM
[*] Reading S3 boot-script from memory..
[*] Decoding S3 boot-script opcodes..
[*] Checking entry-points of Dispatch opcodes..
[-] Found Dispatch opcode (offset 0x014E) with Entry-Point:
0x00000000DA5C3260 : UNPROTECTED
LockBox: https://github.com/tianocore/edk2-MdeModulePkg/blob/master/Include/Protocol/LockBox.h
Saving S3 Boot Script to LockBox
SaveBootScriptDataToLockBox():
//
// mS3BootScriptTablePtr->TableLength does not include
EFI_BOOT_SCRIPT_TERMINATE, because we need add entry at runtime.
// Save all info here, just in case that no one will add boot
script entry in SMM.
//
Status = SaveLockBox (
&mBootScriptDataGuid,
(VOID *)mS3BootScriptTablePtr->TableBase,
mS3BootScriptTablePtr->TableLength +
sizeof(EFI_BOOT_SCRIPT_TERMINATE)
);
ASSERT_EFI_ERROR (Status);
Status = SetLockBoxAttributes (&mBootScriptDataGuid,
LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);
https://svn.code.sf.net/p/edk2/code/trunk/edk2/MdeModulePkg/Library/PiDxeS3BootScriptLib/BootScriptSave.c
Attacking EFI Firmware via
UEFI Variables
Where does firmware store its settings?
AcpiGlobalVariable
BootOrder
Secure Boot
certificates
(PK, KEK, db, dbx)
Setup
Things we found in unprotected runtime
(read user-mode) accessible variables
VU#758382
Storing Secure Boot settings in Setup
could be bad
Now user-mode malware can clobber
contents of Setup UEFI variable with
garbage or delete it
Malware may also clobber/delete
default configuration (StdDefaults)
The system may never boot again
VARIABLE_LOCK Exit
EndOfDxe BootServices
Protocol Loaded
Image source
Where there is no BIOS, there is
boredom. BIOS makes life interesting.
System Management Interrupt (SMI) Handlers
0xFFFFFFFF
Protected SMRAM
SMRAM
SMI code lives here SMBASE + FFFFh
SMM state
SMRAM Base
save area
SMBASE + FC00h
SMI handlers
SMBASE + 8000h
0x00000000 SMBASE
Pointer Arguments to SMI Handlers
Phys Memory
SMI Handlers in
RAX (code) SMI SMRAM
RBX (pointer)
RCX (function)
RDX OS Memory
RSI SMI handler specific structure
RDI
Phys Memory
SMI Handlers in
RAX (code) SMI SMRAM
RBX (pointer) Fake structure inside SMRAM
RCX (function)
RDX OS Memory
RSI
RDI
4GB
Low MMIO Range Access to GFx Aperture is
GTT MMIO redirected to SMRAM
Graphics Aperture
TOLUD
GTT PTEs
Phys Memory
RAX (code) SMI Saved SMBASE value SMM State Save Area
RBX (pointer)
RCX (function) SMI Entry Point
SMI Handler (SMBASE + 8000h)
SMBASE
OS Memory
SMI handler specific structure
CPU stores current value of SMBASE in SMM save state area on SMI
and restores it on RSM
How does the attack work?
Phys Memory
Saved SMBASE value SMM State Save Area
OS Memory
Fake SMI handler
Exploit prepares fake SMRAM with fake SMI handler outside of SMRAM
How does the attack work?
Phys Memory
RAX (code) SMI Saved SMBASE value SMM State Save Area
RBX (pointer)
RCX (function) SMI Entry Point
SMI Handler (SMBASE + 8000h)
SMBASE
OS Memory
Fake SMI handler
Phys Memory
Saved SMBASE value SMM State Save Area
SMI Handler
SMI OS Memory
Fake SMI handler New SMI Entry Point
SMBASE
Phys Memory
Original saved SMBASE SMM State Save Area
value
SMI Handler
(SMRAM is not protected)
OS Memory
Fake SMI handler New SMI Entry Point
SMBASE
Phys Memory
OS Memory
CommBuffer is a memory buffer used as a communication protocol between OS runtime and DXE
SMI handlers. Pointer to CommBuffer is stored in UEFI ACPI table in ACPI memory
Contents of CommBuffer are specific to SMI handler. Variable SMI handler read UEFI variable
GUID, Name and Data from CommBuffer
Example: VariableAuthenticated SMI Handler reads/writes UEFI variables from/to CommBuffer
Source: A Tour Beyond Implementing UEFI Auth Variables in SMM with EDKII (Jiewen Yao, Vincent Zimmer)
Attacking CommBuffer Pointer
SmmVariableHandler (
...
SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *)
CommBuffer;
switch (SmmVariableFunctionHeader->Function) {
case SMM_VARIABLE_FUNCTION_GET_VARIABLE:
SmmVariableHeader = (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *)
SmmVariableFunctionHeader->Data;
Status = VariableServiceGetVariable (
...
(UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize
);
VariableServiceGetVariable (
...
OUT VOID *Data
)
...
CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize);
CommBuffer SMRAM
CommBuffer TOCTOU Issues
SMI handler checks that it wont access outside of CommBuffer
What if SMI handler reads CommBuffer memory again after the check
DMA engine (for example GFx) can modify contents of CommBuffer
Time of Check
InfoSize = .. + SmmVariableHeader->DataSize + SmmVariableHeader->NameSize;
if (InfoSize > *CommBufferSize - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) {
Status = VariableServiceGetVariable (
...
(UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize
);
VariableServiceGetVariable (
...
OUT VOID *Data
)
...
Time of Use
if (*DataSize >= VarDataSize) {
CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize);
Detecting & Mitigating
Unvalidated SMI Input Pointers
Tools For Everybody, Free, And No One
Will Go Away Unsatisfied!
Discovering SMI Pointer Vulns with CHIPSEC
[x][ =======================================================================
[x][ Module: Testing SMI handlers for pointer validation vulnerabilities
[x][ =======================================================================
...
[*] Allocated memory buffer (to pass to SMI handlers) : 0x00000000DAAC3000
[*] >>> Testing SMI handlers defined in 'smm_config.ini'..
...
SmiHandler() {
// check InputBuffer is outside SMRAM
if (!SmmIsBufferOutsideSmmValid(InputBuffer, Size)) {
return EFI_SUCCESS;
}
switch(command)
case 1: do_command1(InputBuffer);
case 2: do_command2(InputBuffer);
One Missed CALL
Phys Memory
SMRAM
CALL F000:8070
1 MB
Far CALL in
SMM to BIOS
Legacy BIOS Shadow
service outside
(F/ E-segments)
of SMRAM
PA = 0xF0000
SMI Handlers Calling Out of SMRAM
Phys Memory
SMRAM
CALL F000:8070
1 MB
Far CALL in
SMM to BIOS
Legacy BIOS Shadow
service outside
(F/ E-segments)
of SMRAM
PA = 0xF0000
0F000:08070 = 0xF8070: payload
0xF8070 PA
UEFI SMI Call-Outs
DXE SMI drivers may call Runtime, Boot or DXE services API
Find Runtime, Boot and DXE service tables containing UEFI API
function pointers in memory (EFI System Table)
Patch each function with detour code chaining the original function
Enumerate and invoke all SMI handlers
If SMI handler calls-out to some UEFI API, patch will get invoked
Phys Memory
SMRAM
CALL F000:8070
1 MB
Code fetch
Legacy BIOS Shadow in SMM
(F/ E-segments) causes MC
PA = 0xF0000 exception
0F000:08070 =
0xF8070: payload
0xF8070 PA
It's like trying to fit an octopus into a pair
of tuxedo pants
Image source: speckyboy.com
Why are we investing in CHIPSEC?
Thank You!