Insomnihack Presentation
Insomnihack Presentation
with SMM
[email protected] [email protected]
@assaf_carlsbad @liba2k
1
Agenda
https://medium.com/swlh/negative-rings-in-
intel-architecture-the-security-threats-youve-
probably-never-heard-of-d725a4b6f831
SMRAM
● System Management RAM
● Isolated address space
● Contains:
○ SMM binaries
https://edk2-docs.gitbook.io/a-tour-beyond-bios-memory-protection-in-uefi-bios/memory-protection-in-smm
SMRAM
● Can only be read and written from SMM
○ Chipset provides mechanism to close and lock SMRAM
○ Attempts to access SMRAM from outside of SMM will be discarded
SMIs
● System Management Interrupt
● Causes transition into SMM
○ One “master” SMI Handler
● In UEFI:
○ Handlers are installed by calling
SmiHandlerRegister
https://nixhacker.com/digging-into-smm/
Software SMIs
11
Software SMIs
12
02
SMM Vulnerabilities
And how to automatically
uncover them
Attacking SMM
● Main attack surface are software SMIs
○ Can be triggered in a controlled fashion
○ Contents of the Comm Buffer are attacker controlled
https://github.com/tianocore-
docs/Docs/raw/master/White_Papers/A_Tour_Beyond_BIOS_Secure_SMM_Communication.pdf
Unsanitized nested pointers
16
Phys Mem
Exploiting nested
pointer issues SMI SMRAM
Handler
Phys Mem
Exploiting nested
pointer issues SMI SMRAM
Handler
OpCode
Write Comm
Address Buffer
Phys Mem
Exploiting nested
pointer issues SMI SMRAM
Handler
OpCode
Comm
Address Buffer
Phys Mem
Exploiting nested
pointer issues SMI SMRAM
Handler
OpCode
Comm
Address Buffer
Phys Mem
Exploiting nested
pointer issues SMI SMRAM
Handler
An invalid opcode
values will force the
handler to fallback
into the default case
OpCode: 4
Comm
Address Buffer
Phys Mem
Exploiting nested
pointer issues SMI SMRAM
Handler
Handler inspects
Address field to
know where to
write the status
OpCode: 4
Comm
Address Buffer
Phys Mem
Exploiting nested
pointer issues SMI SMRAM
Handler
SMRAM corruption
at attacker
controlled address
OpCode: 4
Comm
Address Buffer
Handlers should call
BOOLEAN EFIAPI
❌
SmmIsBufferOutsideSmmValid(
IN EFI_PHYSICAL_ADDRESS Buffer,
IN UINT64 Length)
to make sure nested pointers do not
overlap with SMRAM
✅
24
Using Brick to automatically hunt
SMM bugs
● Brick is an automated, static
analysis tool for hunting SMM
vulnerabilities
● Based on IDA
● https://github.com/Sentinel-One/brick
Using Brick to automatically hunt
● SMM
Brick is an automated, static bugs
analysis tool for
hunting SMM vulnerabilities
● Based on IDA
26
Interpreting Results
27
Phase 0
Phase 1 - Preprocessor
github.com/tianocore/edk2
github.com/tianocore/edk2-platforms
UEFI Protocols
● Allow inter-module communication
● Producers publish protocols using SmmInstallProtocolInterface
● Each protocol is composed out of a:
○ GUID
○ Interface (usually a vtable)
UEFI Protocols
● Consumers utilize existing protocols via SmmLocateProtocol
○ Passes the GUID of the protocol
○ Receives the associated interface pointer in response
github.com/tianocore/edk2
github.com/tianocore/edk2-platforms
PCH_SPI_PROTOCOL
Phase 2 - efiXplorer
● https://github.com/binarly-io/efiXplorer
Phase 2 - efiXplorer
Discovering SMI
handlers
Phase 2 - efiXplorer
Identifying SMM
services
Phase 2 - efiXplorer
Assigning types to
interface pointers
Phase 2 - efiXplorer
Identifying SMI
handlers
EFI_SMM_ACCESS2_PROTOCOL
● Controls visibility of SMRAM
● Exposes methods to Open, Close, and Lock SMRAM
GetCapabilities()
● Let’s the caller know where SMRAM is located
● Returns an array of structures of type EFI_SMRAM_DESCRIPTOR
EFI_SMRAM_DESCRIPTOR
● Each descriptor holds information
about one SMRAM region
○ Address
○ Size
○ State
○ Attributes
● Used internally by
SmmIsBufferOutsideSmmValid
to determine if the buffer is safe
Phase 3 - Postprocessor
Phase 3 - Postprocessor
Marking global
EFI_SMRAM_DESCRIPTORs
Phase 4 - REconstructing the
Comm Buffer
● https://github.com/REhints/HexRaysCodeXplorer
Phase 4 - REconstructing the
Comm Buffer
Phase 4 - REconstructing the
Comm Buffer
Found nested
pointers
Phase 4 - REconstructing the
Comm Buffer
References
EFI_SMRAM_DESCRIPTOR
Phase 5 - Resolving
SmmIsBufferOutsideSmmValid
Returns BOOLEAN
Phase 5 - Resolving
SmmIsBufferOutsideSmmValid
Match found!
Phase 6 - Checking usage
Only xref to
SmmIsBufferOutsideSmmValid
Conclusion
● Likely to be a vulnerability
03
Exploiting SMM
Vulnerabilties
CVE-2021-0157 & CVE-2021-
0158
Exploitation Overview
Developing Breaking
03 arbitrary code 04 SecureBoot
execution
Vulnerable function
● Here we are looking at an SMI handler
of SpiSmmStub module from a Dell
UEFI BIOS.
● This SMI handler uses the
PCH_SPI_PROTOCOL to read, write
and erase the SPI flash.
● Parameters from all the operations
come from the Comm Buffer without
any validation.
● Writing directly to the flash is possible,
but we might break BootGuard.
Write primitive
● The FlashRead function is used
to read a buffer from the flash to
memory.
● We can supply any address in the
flash and a size and the data
from the flash will be written to
the Buffer pointer without
SMI Comm
validating the location. Handler Buffer
● It can be used to overwrite
SMRAM
SMRAM
Write primitive
● The FlashRead function is used
to read a buffer from the flash to
memory.
● We can supply any address in the
flash and a size and the data
from the flash will be written to
the Buffer pointer without
SMI Comm
validating the location. Handler Buffer
● It can be used to overwrite
SMRAM
SMRAM
Write primitive
We can read a block from the
flash to a buffer we have read
permission to.
SMI Flash
Handler Block
SMRAM
Write primitive
Byte value
● We can use the flash block
0x00 0x01 0x02 ......... 0xFF
to generate a dictionary
mapping byte value to
0x50 0x32 0xC1 ......... 0xB2
flash offsets.
● Now we can use the Flash Offset
dictionary to write any
value to any memory
location.
Flash Block
Read primitive - SMM_CORE_PRIVATE_DATA
PiSmmCore.efi
mSmiEntryList
SMI_HANDLER SMI_HANDLER SMI_HANDLER
Handler(
EFI_HANDLE
DispatchHandle,
void *Context,
void *CommBuffer,
UINTN
*CommBufferSize
SMRAM )
Manual creation of SMI entry
SMI_ENTRY SMI_ENTRY SMI_ENTRY
PiSmmCore.efi
NewHandler( Handler(
EFI_HANDLE EFI_HANDLE
DispatchHandle, DispatchHandle,
void *Context, void *Context,
void *CommBuffer, void *CommBuffer,
Normal UINTN UINTN
RAM *CommBufferSize
)SMRAM
*CommBufferSize
)
Manual creation of SMI entry
SMI_ENTRY SMI_ENTRY SMI_ENTRY
PiSmmCore.efi
NewHandler( Handler(
EFI_HANDLE EFI_HANDLE
DispatchHandle, DispatchHandle,
void *Context, void *Context,
void *CommBuffer, void *CommBuffer,
Normal UINTN UINTN
RAM *CommBufferSize
)SMRAM
*CommBufferSize
)
Read primitive - Adding an handler
● In modern systems SMM code must reside in SMRAM
due to the use of the SMM_CODE_CHECK mitigation.
That means that the handler we will add must point
to a function in SMRAM.
● We need to find a function or a ROP gadget we can
use for copying SMRAM to accessible memory.
● We are looking for a memcpy like function in
PiSmmCore that can use with our limited control
over the arguments.
Read primitive - finding a function to use
● We’ve found a function
that:
○ Only takes one
argument
○ Calls memcpy to copy
16 bytes
○ Source and destination
addresses are derived
from the argument
Read primitive - finding a function to use
SMI_ENTRY
SMI_HANDLER
Craft a structure
Extra
that will satisfy both
arguments for the SMI dispatcher
leakFunction
and this function.
Normal
SMRAM
RAM
Dumping SMRAM
● Now we can trigger the SMI repeatedly and read 16 bytes at a time.
● Every time updating the address in the struct to point to the next
16 byte chunk.
Execute primitive
● SMM code only run from SMRAM. Code segments and
non-writable and Data segments are non-executable.
● Do we need to find ROP chain to change page
permissions? No!
Execute primitive
● We can find a gadget to
disable the WP bit in
CR0.
● Then overwrite existing
SMM code with a
shellcode and jump
there.
Execute primitive - ROP
● We find ROP gadgets in the SMRAM dump we got.
● Performing the stack pivot is very complex and
documented in the GitHub repo containing the POC.
Disable Secure Boot - Why?
● Bootkits are trending now, but most of the recent
publications target old systems.
● On new systems BootGuard prevents SPI Flash
implants and Secure boot prevents unsigned “OS
loader” implants.
● Disabling Secure Boot allows installation of bootkits
to the UEFI partition and loading them before the OS
loader.
SecureBoot UEFI variables
● On this system there are two EFI variables for controlling secure boot.
○ SecureBootEnable let the user set SecureBoot On/Off in the BIOS
setup. It is not accessible during runtime.
SecureBoot UEFI variables
● SecureBootMode lets the user choose between DeployedMode and
AuditMode
○ DeployedMode enforces SecureBoot.
○ AuditMode verifies the signature but doesn’t prevent the module
from loading.
● SecureBootMode is accessible during runtime, but is write protected.
Disable Secure Boot - How?
● To bypass the SecureBootMode
write protection we can use the
SmmVariableSetVariable
function.
● The SmmVariableSetVariable
function disables the write
protection check before setting
the variable.
● Since SMM is considered
privileged, it’s allowed to change
write protected variables.
Disable Secure Boot - How?
● We can set it to AuditMode to enable loading of unsigned loaders.
● We can set it to an invalid value, that will have the added benefit of
preventing the user from changing the value in the BIOS setup back to
DeployedMode.
Demo time
Reporting the bug
● We’ve reported the bug to Dell.
● Dell informed us that the bug is in Intel’s BIOS Reference Code.
● We’ve reported the bug to Intel.
● Intel acknowledges with two CVEs: CVE-2021-0157 & CVE-2021-0158
Reporting the bug
● Intel asked for extra time before the disclosure, to allow all the vendors
time to update their BIOS.
● This bug affects many Intel products.
Exploitation tools and techniques
● Using Chipsec on Linux or Windows is great for UEFI exploration, but
when exploiting vulnerabilities it’s very limiting since you have to boot
into an OS every time.
● We can use EFI shell, it boots very quickly.
● EFI Shell supports executing a shell script at startup. This is very useful
for automation.
● However EFI Shell waits 5 second before executing the shell script.
● We’ve found it useful to recompile EFI shell with no delay.
● This allows for quicker execution of automation.
MicroPython in EFI shell
● We can use chipsec from EFI shell, but we’ve found it even quicker to
use MicroPython.
● There is a MicroPython implementation for EFI shell in the edk2-
staging repo. But it doesn't have a quick way to deal with large
memory buffers.
● We’ve added support for reading and writing using python’s bytes
data type . It can be found in my GitHub repo:
https://github.com/liba2k/edk2-
staging/tree/MicroPythonTestFramework
MicroPython code using a protocol
PeachPy - Assembly in MicroPython
● PeachPy is a small assembler for
python, that was easy enough to port
to MicroPython.
https://github.com/Maratyszcza/Peac
hPy
● Here we can see an example of
PeachPy assembling a small
shellcode.
● The shellcode variable is using the
added python bytes memory type ‘A’.
PCILeech
● While working on exploitation, before restoring
normal execution we need a way to return
information from SMM before the computer
hangs.
● We were writing information to an hardcoded
physical address and using a USB3380 board with
PCILeech from another computer to read it.
● https://github.com/ufrisk/pcileech
● https://mfactors.com/usb3380-evb-usb3380-
evaluation-board/
There are always problems
04
Mitigations
Intel Boot Guard
● Intel Boot Guard is a relatively new technology that complements
Secure Boot
● Works by moving the root of trust to the PCH
● Caused us to abandon the SPI flash implant approach
Intel Runtime BIOS Resilience
● New SMM mitigations on Intel vPro platforms:
○ The new mitigations Include CR0 lock, which would have
prevented us from writing on SMM code segment.
https://www.intel.com/content/dam/www/central-
libraries/us/en/documents/drtm-based-computing-
SMM Info Leaks
● Multiple SMRAM addresses
are exposed to the OS (ring0)
via the
SMM_CORE_PRIVATE_DATA
structure.
● While by design, they help
the exploitation of SMM
vulnerabilities.
● We think it can be avoided by
a small number of changes in
EDK2.
SMI_ENTRY Linked List verification
● In our exploit, we add an handler
by overwriting the first member
pointer in the SMI_ENTRY linked
list.
● The new SMI_ENTRY is stored in
normal RAM.
● The code assumes all entries are
in SMRAM, but does not validate
this assumption.
SMI_ENTRY Linked List verification
● To mitigate this, we
just need to make
sure all entries are in
SMRAM prior to using
them.
● Trying to push this fix
into EDK2.
Thank
you!
Any questions