Skip to content

Instantly share code, notes, and snippets.

@Cr4sh
Created March 1, 2026 20:07
Show Gist options
  • Select an option

  • Save Cr4sh/0adf33bdf1ee1c66e281b3291bfbf154 to your computer and use it in GitHub Desktop.

Select an option

Save Cr4sh/0adf33bdf1ee1c66e281b3291bfbf154 to your computer and use it in GitHub Desktop.
Claude experiments: Skylake based Intel NUC SW SMI vulnerabilities discovery

Intel NUC Skylake — SMM / SMI Handler Security Audit

Executive Summary

This report documents a security audit of the SMM (System Management Mode) SMI handlers present in the UEFI firmware image from an Intel NUC (Skylake generation). The firmware is an AMI Aptio V BIOS with clearly named modules. Analysis was performed using IDA Pro with MCP integration (ida-pro-mcp + idasql).

Overall Risk Assessment: CRITICAL

The firmware contains 8 CRITICAL and 3 MEDIUM severity findings (11 total) across 20 SW SMI handler registrations in 11 modules. Three distinct attack surfaces enable arbitrary SMRAM writes:

  1. EBDA-based constant-value SMRAM writes (UsbRt, NvmeSmm, SdioSmm) — Three modules read their communication buffer pointer from the Extended BIOS Data Area (EBDA) via physical address 0x40E, which is attacker-controlled from Ring 0. By corrupting the EBDA segment, an attacker can make the buffer pointer target any physical address including SMRAM. The handlers then write constant status values (0xF0 or 0x07) to the buffer — enabling single-byte arbitrary writes to SMRAM. Critically, even the two modules with custom SMRAM validation (NvmeSmm, SdioSmm) are vulnerable because their error-handling path writes the status code to the same buffer that failed validation.

  2. CPU saved-state pointer injection (ItkSmmVars) — Reads RSI/RBX register values from SMM CPU saved state via EFI_SMM_CPU_PROTOCOL.ReadSaveState(). The attacker controls these registers at SMI trigger time. Command 3 dereferences an embedded pointer chain for SetVariable; command 5 provides a full arbitrary memcpy primitive.

  3. Shared buffer pointer dereferences (UsbRt) — Multiple command handlers (0x2B, 0x2F, 0x2D) dereference 64-bit pointers read directly from the communication buffer, and the core USB transfer function writes to attacker-specified addresses — all without any SMRAM validation.

The standard SmmIsBufferOutsideSmmValid() function is absent. Two modules (SdioSmm, NvmeSmm) implement custom inline SMRAM validation, but this is defeated by the error-path write pattern described above.


Image Information

Field Value
Platform Intel NUC (Skylake)
Firmware Vendor AMI (Aptio V)
Image File flash_image_nuc.bin
Image Size 8 MB
MD5 664f34f760e8df77817282dd56f894df
Total Functions 32,016
SMM Entry Points ~176 (36+ unique SMM modules)
SW SMI Handlers 20 registrations across 11 modules
Architecture x86_64 (UEFI)

SMM Module Inventory

The following SMM modules were identified from named entry points in the IDA database:

# Module Name Entry Address SW SMI# Handler Address Risk
1 ItkSmmVars 0x951850 0xEF, 0x44 0x952D90 CRITICAL
2 UsbRt 0x7D3F80 0x31 sub_7D4888 (26-cmd dispatch) CRITICAL
3 NvmeSmm 0x7CA330 0x42 sub_7CAE40 (12-cmd dispatch) CRITICAL
4 SmmHddSecurity 0x7C28C0 0xD1 0x7C30A4 + 6 others MEDIUM
5 SmmLockBox 0x7D02D0 (GUID dispatch) 0x7D0648 MEDIUM
6 SdioSmm 0x7CD870 0x40 sub_7CDC94 (4-cmd dispatch) CRITICAL
7 OemSmi 0x95D840 0, 3, 4, 5 0x95DB84, 0x95DB44 Clean
8 SmmPlatform 0x76EBD0 3, 4, 5 sub_76EDF8 / sub_76EE64 / sub_76EE74 Clean
9 CrbSmi 0x7EEB80 0xBF, 3, 0 sub_7EED94 (stub) Clean
10 CpuSpSMI 0x61A40 0x56, 0x57 sub_61B1C / sub_61C90 Clean
11 AcpiModeEnable 0x76BBA0 0xA0, 0xA1 sub_76BF80 / sub_76C06C Clean
12 BootScriptHideSmm 0x7B5850 0xD6, 0xD7 sub_7B5990 / sub_7B5B20 Clean
13 CmosSmm 0x7B9D10 0x61 sub_7BA014 Clean
14 SmramSaveInfoHandler 0x76D2A0 (dynamic) sub_76D4F0 Clean
15 NbSmi 0x758CC0 (SW dispatch) 0x758ED4 Clean
16 FlashSmiSmm 0x7BE1D0 (ready-to-boot) 0x7BE67C Low
17 NvramSmi 0x74C840 (infrastructure) N/A Low
18 PchInitSmm 0x795B70 (GPI/periodic) 0x795D10 Clean
19 BiosGuardServices 0x775300 (MSR check) N/A Clean
20 CryptoSMM 0x7A2D10 (protocol) N/A Clean
21 TcgSmm 0x7D1340 (protocol) N/A Clean
22 PchSmiDispatcher 0x91E0C0 (root dispatcher) N/A Clean
23 PttWrapper 0x773B50 (protocol) N/A Clean
24 SleepSmi 0x764BB0 (Sx dispatch) sub_764DCC Clean
25 PowerMgmtSmm 0x78B5C0 (IO trap) sub_78BEE8 Clean
26 SaLateInitSmm 0x78E430 (periodic timer) sub_78E5D0 Clean
27 AhciSmm 0x79F800 (storage protocol) N/A Clean
28 RuntimeSmm 0x7B7810 (protocol) N/A Clean
29 KbcEmul 0x7C5A10 (IO trap) N/A Clean
30 UsbS5Wakeup 0x7EC850 (Sx dispatch) sub_7ED490 Clean
31 StatusCodeSmm 0x8BB520 (protocol) N/A Clean
32 FlashDriverSmm 0x736DA0 Infra
33 NVRAMSmm 0x73E390 Infra
34 CpuIo2Smm 0x74E2B0 Infra
35 PiSmmCpuDxeSmm 0x750D90 Infra
36 SmmExceptionInfo 0x757290 Infra
37 PowerButton 0x75CBB0 (HW button) Clean
38 SbRunSmm 0x761BE0 (SB runtime) Clean
39 TcoSmi 0x769800 (TCO HW) Clean
40 PchSmbusSmm 0x79B270 (SMBus HW) Clean
41 PchSpiSmm 0x79D2C0 (SPI HW) Clean
42 S3SaveSmm 0x7B19F0 Infra
43 PiSmmCommunicationSmm 0x756360 Infra

SW SMI Number Map

SW SMI# Hex Module Handler Purpose Risk
0 0x00 CrbSmi sub_7EED94 (stub) Placeholder Clean
3 0x03 OemSmi + SmmPlatform + CrbSmi sub_95DB84 / sub_76EDF8 / sub_7EED94 SIO config + HW regs Clean
4 0x04 OemSmi + SmmPlatform sub_95DB84 / sub_76EE64 SIO config + HW regs Clean
5 0x05 OemSmi + SmmPlatform sub_95DB84 / sub_76EE74 SIO config + PCI config Clean
49 0x31 UsbRt sub_7D4888 USB runtime SMM API (26-cmd, EBDA) CRITICAL
64 0x40 SdioSmm sub_7CDC94 SDIO storage ops (4-cmd, EBDA) CRITICAL
66 0x42 NvmeSmm sub_7CAE40 NVMe storage ops (12-cmd, EBDA) CRITICAL
68 0x44 ItkSmmVars sub_952D90 ITK variable ops CRITICAL
86 0x56 CpuSpSMI sub_61B1C MSR save Clean
87 0x57 CpuSpSMI sub_61C90 MSR restore Clean
97 0x61 CmosSmm sub_7BA014 CMOS flag clear Clean
160 0xA0 AcpiModeEnable sub_76BF80 ACPI enable Clean
161 0xA1 AcpiModeEnable sub_76C06C ACPI disable Clean
191 0xBF CrbSmi sub_7EED94 (stub) Placeholder Clean
209 0xD1 SmmHddSecurity sub_7C30A4 HDD security (7 sub-handlers) MEDIUM
214 0xD6 BootScriptHideSmm sub_7B5990 Boot script copy to SMRAM Clean
215 0xD7 BootScriptHideSmm sub_7B5B20 (stub) Returns UNSUPPORTED Clean
239 0xEF ItkSmmVars sub_952D90 NVRAM variable handler CRITICAL
dynamic SmramSaveInfoHandler sub_76D4F0 IO port / save state ops Clean

Vulnerability Findings

FINDING-1: CRITICAL — ItkSmmVars Pointer Injection (SW SMI# 0xEF)

Location: sub_952D90 at 0x952D90 (ItkSmmVars module) SW SMI#: 0xEF (239) CVSS Estimate: 8.2 (High) Vulnerability Class: CWE-822 (Untrusted Pointer Dereference), SMM Pointer Injection

Description

The SW SMI# 0xEF handler implements an AMI NVRAM variable management interface. Unlike most handlers, it acquires its communication buffer pointer by reading the RSI register from SMM CPU saved state via EFI_SMM_CPU_PROTOCOL.ReadSaveState() (protocol at qword_956710). The attacker controls RSI by setting it before triggering the SMI.

; sub_952D90 — register read via EFI_SMM_CPU_PROTOCOL
mov rax, cs:qword_956710       ; EFI_SMM_CPU_PROTOCOL
lea r8d, [rdi+2Ch]             ; register 0x2C (RSI)
call qword ptr [rax]           ; ReadSaveState → var_1D7C = low 32 bits of RSI
; ...
mov ebp, var_1D7C              ; ebp = communication buffer pointer (from RSI)

The handler reads byte 0 as signature (must be 0xEF), byte 1 as command (1-5), and dereferences a 32-bit embedded pointer at offset 4 without validation. Command 3 is the most critical path:

Buffer layout (at RSI-controlled address):
  offset 0: signature (0xEF)
  offset 1: command byte (1-5)
  offset 4: 32-bit pointer to parameter structure (v11)

When command == 3:
  v11 = *(uint32_t*)(buffer + 4)    // EMBEDDED POINTER

  // Dereferences without validation:
  variable_name = v11[4]    // Wide string pointer
  guid          = v11[0..3] // 128-bit GUID
  attributes    = v11[5]    // DWORD
  data_size     = v11[6]    // Size value
  data_pointer  = v11[7]    // ANOTHER pointer to data

  SetVariable(variable_name, guid, attributes, data_size, data_pointer)

The error path also writes to the RSI-derived pointer: or dword ptr [rbp+0], 0x8200 and or dword ptr [rbp+18h], 1 — enabling OR-based arbitrary writes to attacker-controlled addresses.

The handler special-cases variable names "Setup", "IDESecDev", and "POSTCounter" for additional processing.

Impact

An attacker with Ring 0 (kernel) access can:

  1. Write arbitrary NVRAM variables by controlling the embedded parameter structure
  2. Read/corrupt SMRAM contents by pointing v11 into SMRAM — the handler will dereference SMRAM data as variable name/GUID/size, potentially leaking SMRAM contents through NVRAM
  3. Achieve arbitrary SMM code execution through chained exploitation (write malicious variable → corrupt SMM data structures)
  4. Bypass Secure Boot by writing to protected NVRAM variables
  5. Install persistent firmware implants by manipulating flash-backed variables

Affected Commands

Command Risk Detail
3 CRITICAL Reads embedded pointer, dereferences for SetVariable parameters
5 HIGH Reads "TsegAddress", calls sub_956260 (memcpy) with embedded pointer values
2 Medium Calls sub_95326F with shared buffer data
1 Unknown JUMPOUT — decompiler couldn't resolve target
4 Low Reads "HiiDB" variable, internal manipulation

Proof of Concept Trigger

; Ring 0 exploit pseudocode
; 1. Prepare parameter structure in known physical memory
param_struct = allocate_physical_page()
param_struct[0..3] = target_guid
param_struct[4] = target_var_name  ; wide string
param_struct[5] = 0x7             ; NV+BS+RT attributes
param_struct[6] = payload_size
param_struct[7] = payload_data_ptr

; 2. Prepare communication buffer
buffer = allocate_physical_page()
buffer[0] = 0xEF              ; signature
buffer[1] = 3                 ; command: SetVariable
*(DWORD*)(buffer+4) = physical_addr(param_struct)

; 3. Set RSI to buffer address and trigger SW SMI# 0xEF
mov rsi, physical_addr(buffer)
mov al, 0xEF
out 0xB2, al

FINDING-2: CRITICAL — ItkSmmVars Command 5 Arbitrary Memory Copy (SW SMI# 0xEF)

Location: sub_952D90 at 0x952D90, command 5 path SW SMI#: 0xEF (239) CVSS Estimate: 8.2 (High) Vulnerability Class: CWE-822 (Untrusted Pointer Dereference), Arbitrary Memory Read/Write

Description

Command 5 of the same handler reads the "TsegAddress" NVRAM variable, then calls sub_956260 (a memcpy implementation) with three values read through an embedded pointer from the shared buffer. Since sub_956260 is an overlapping-safe memory copy function, and the source/destination/size are all derived from attacker-controlled pointers, this enables arbitrary memory read/write within SMM context.

The attacker controls:

  • Destination address (via embedded pointer field)
  • Source address (via embedded pointer field)
  • Copy length (via embedded pointer field)

Impact

Direct arbitrary memory copy within SMM context. Can be used to:

  • Copy shellcode into SMRAM
  • Overwrite SMM handler dispatch tables
  • Exfiltrate SMRAM contents to attacker-accessible memory

FINDING-3: MEDIUM — SmmHddSecurity CommBuffer Copy Without Validation (SW SMI# 0xD1)

Location: sub_7C30A4 at 0x7C30A4 (SmmHddSecurity module) SW SMI#: 0xD1 (209) CVSS Estimate: 5.5 (Medium) Vulnerability Class: CWE-20 (Improper Input Validation)

Description

The SmmHddSecurity handler checks a signature value (0x244B4044) in the CommBuffer, then copies 112 bytes from the CommBuffer directly into a newly allocated SMRAM buffer:

if (*a3 == 0x244B4044) {  // signature check
    allocate(6, 512, &qword_7C4318);     // allocate 512 bytes in SMRAM
    allocate(6, 112, &v8);               // allocate 112 bytes in SMRAM

    // Copy 112 bytes from CommBuffer to SMRAM — NO SMRAM validation on a3
    do {
        *(BYTE*)(v5 + v8) = *((BYTE*)a3 + v5);
        ++v5; --v4;
    } while (v4);

    // Set up linked list pointers
    qword_7C4408 = v8 + 96;
    qword_7C4400 = 1;
    qword_7C4410 = v8 + 96;
}

The CommBuffer pointer a3 is not validated against SMRAM boundaries before the copy. However, the fixed 112-byte copy size limits exploitation.

Impact

  • Attacker can inject controlled data into SMM-allocated structures
  • The copied data populates a linked list used by subsequent HDD security operations
  • Fixed copy size (112 bytes) limits severity compared to variable-size copies
  • Requires further analysis of how the copied data is subsequently used

FINDING-4: MEDIUM — SmmLockBox Missing SMRAM Boundary Validation

Location: sub_7D0648 at 0x7D0648 (SmmLockBox module) CVSS Estimate: 5.0 (Medium) Vulnerability Class: CWE-20 (Improper Input Validation)

Description

The SmmLockBox handler processes CommBuffer commands for storing/restoring LockBox data across S3 resume. The handler performs basic input validation:

  1. Checks CommBuffer (a3) is not NULL
  2. Checks CommBufferSize (a4) is not NULL
  3. Checks CommBufferSize >= 0x10
  4. Calls sub_7D041C(a3, *a4) — but this is only an integer overflow check
// sub_7D041C - "validation" function
bool sub_7D041C(uint64_t a1, int64_t a2) {
    return a1 <= -1 - a2;  // Only checks a1 + a2 doesn't overflow!
}

This check verifies buffer + size doesn't wrap around, but does NOT validate that the buffer resides outside SMRAM. The handler then dispatches on command codes:

Command Min Size Operation
1 (Store) 0x30 Copies 48 bytes from CommBuffer, dereferences inner pointers for sub_7D09B8
2 (Restore) 0x38 Calls sub_7D0488 with CommBuffer
3 (SetAttributes) 0x30 Calls sub_7D0578 with CommBuffer
4 (Save) 0x28 Copies 40 bytes, dereferences inner pointer for sub_7D0970
5 (RestoreAll) Iterates linked list, copies data between pointers

Impact

  • Command 1 copies data from CommBuffer and dereferences embedded pointers — potential SMRAM confusion
  • Command 5 iterates a linked list and performs memory copies between pointer pairs from list nodes
  • Exploitation difficulty is higher due to the structured command format requirements
  • LockBox operations are typically performed during S3 resume — timing constraints may limit attack window

FINDING-5: CRITICAL — UsbRt Pointer Dereference via Shared Buffer (SW SMI# 0x31, Commands 0x2B/0x2F)

Location: sub_7D579C (cmd 0x2B) and sub_7D5810 (cmd 0x2F) in UsbRt module SW SMI#: 0x31 (49) CVSS Estimate: 8.2 (High) Vulnerability Class: CWE-822 (Untrusted Pointer Dereference), SMM Arbitrary Read

Description

Two UsbRt command handlers dereference pointers read directly from the attacker-controlled shared buffer:

Command 0x2B (sub_7D579C): Reads a 64-bit pointer from shared buffer offset 3, then dereferences it to read a byte:

if ( *(_QWORD *)(a1 + 3) )  // Read 64-bit pointer from shared buffer
{
    if ( (**(_BYTE **)(a1 + 3) & 2) != 0 )  // DEREFERENCE: read byte at pointer
        flags = 0x10;
    if ( (**(_BYTE **)(a1 + 3) & 4) != 0 )  // DEREFERENCE again
        flags |= 0x20;
    if ( (*result & 1) != 0 )                // DEREFERENCE again
        flags |= 0x40;
}
// Also reads another 64-bit pointer from buffer+11:
v4 = *(_QWORD *)(a1 + 11);   // Second pointer from buffer
if (v4)
    sub_7E430C(v4, ...);      // Used as function argument

Command 0x2F (sub_7D5810): Reads a 32-bit pointer from shared buffer offset 3 and dereferences it:

if ( *(_DWORD *)(a1 + 3) )   // Read 32-bit address from shared buffer
{
    if ( (*(_BYTE *)*(unsigned int *)(a1 + 3) & 2) != 0 )   // DEREFERENCE
        ...
    if ( (*(_BYTE *)*(unsigned int *)(a1 + 3) & 4) != 0 )   // DEREFERENCE
        ...
}

No SMRAM validation is performed on either pointer before dereference.

Impact

An attacker with Ring 0 access can read arbitrary bytes from any physical address (including SMRAM) by:

  1. Setting the pointer in the shared buffer to a target address
  2. Triggering SW SMI# 0x31 with command 0x2B or 0x2F
  3. Observing the side effects on internal flags to determine bit values of the read byte

FINDING-6: CRITICAL — UsbRt Arbitrary Write via USB Transfer Handler (SW SMI# 0x31)

Location: sub_7D78D4 at 0x7D78D4 (USB transfer function called by multiple commands) SW SMI#: 0x31 (49) CVSS Estimate: 9.0 (Critical) Vulnerability Class: CWE-787 (Out-of-bounds Write), SMM Arbitrary Write

Description

The core USB transfer function sub_7D78D4 reads a 64-bit pointer from the shared buffer at offset 22 (*(QWORD*)(a3+19) where a3 is buffer+3) and writes to multiple offsets from that pointer without SMRAM validation:

// a3 points to shared_buffer + 3
// *(QWORD*)(a3+19) = *(QWORD*)(shared_buffer+22) = attacker-controlled pointer

*(_DWORD *)(*(_QWORD *)(a3 + 19) + 28LL) = 0;          // WRITE 0 at ptr+28
*(_WORD *)(v23 + 66) -= *(unsigned __int8 *)(a1 + 72);  // MODIFY word at ptr+66
*(_WORD *)(*(_QWORD *)(a3 + 19) + 70LL) -= ...;         // MODIFY word at ptr+70
*(_WORD *)(*(_QWORD *)(a3 + 19) + 74LL) -= ...;         // MODIFY word at ptr+74
*(_BYTE *)(v24 + 64) = 0;                                // WRITE 0 at ptr+64

The writes are conditional on signature checks at the target memory (e.g., comparing *(DWORD*)(ptr+3) to known magic values), but these can be satisfied by pointing to crafted memory.

This function is called from USB control transfer (cmd 0x20 group), bulk transfer (cmd 0x21), and interrupt transfer (cmd 0x22) handlers.

Impact

An attacker with Ring 0 access can:

  1. Write zeros and modify words at controlled offsets from any physical address
  2. Target SMRAM to corrupt SMM handler code or data structures
  3. Chain with read primitives (FINDING-5) for full SMM code execution

Proof of Concept Trigger

; Ring 0 exploit pseudocode
shared_buffer[0] = 0x20    ; command: USB control transfer
shared_buffer[3] = device_index
shared_buffer[8..15] = 0   ; transfer size
shared_buffer[22..29] = target_smram_addr  ; pointer to write target

outb(0xB2, 0x31)           ; trigger SW SMI# 0x31
; Handler will write to target_smram_addr+28, +64, +66, +70, +74

FINDING-7: CRITICAL — UsbRt Dynamic Function Call with Attacker-Controlled Arguments (SW SMI# 0x31, Command 0x2D)

Location: sub_7D5EE0 at 0x7D5EE0sub_7D5DD0 at 0x7D5DD0 SW SMI#: 0x31 (49) CVSS Estimate: 8.5 (High) Vulnerability Class: CWE-822 (Untrusted Pointer Dereference), Controlled Function Call

Description

Command 0x2D calls a dynamic function dispatcher (sub_7D5DD0) that:

  1. Selects an internal USB function from a table using indices from the shared buffer (*(BYTE*)(buffer+1) and *(DWORD*)(buffer+11))
  2. Unpacks arguments from a pointer array located at shared buffer offset 3 (*(QWORD*)(buffer+3))
  3. Calls the selected function with up to 7 attacker-controlled arguments
// sub_7D5EE0 — command 0x2D handler
sub_7D5DD0(
    internal_function_table[index],   // function selected by attacker
    *(_QWORD *)(a1 + 3),              // argument array from shared buffer
    (*(DWORD*)(a1 + 15) + 3) & ~3     // argument count from shared buffer
);

// sub_7D5DD0 — dynamic dispatcher
// Unpacks a2[0], a2[1], ... a2[n-1] and calls a1(a2[0], a2[1], ...)

While the function pointer comes from an internal table (not directly from the shared buffer), the arguments are entirely attacker-controlled. This allows calling internal USB protocol functions with arbitrary parameters, potentially achieving:

  • Arbitrary memory read/write through internal copy functions
  • USB hardware register manipulation
  • SMRAM corruption through internal memory management functions

FINDING-8: MEDIUM — NvmeSmm Data Buffer Address Not Validated Against SMRAM (SW SMI# 0x42)

Location: sub_7CA52C (read) and sub_7CA714 (write) in NvmeSmm module SW SMI#: 0x42 (66) CVSS Estimate: 5.0 (Medium) Vulnerability Class: CWE-20 (Improper Input Validation), Partial SMRAM Validation

Description

The NvmeSmm SW SMI# 0x42 handler (sub_7CAE40) implements a 12-command dispatch table at 0x7CA2C0. The handler validates the CommBuffer against SMRAM using a custom inline validation function (sub_7CBE68), and checks a signature byte (*buffer == 39) and command index (buffer[1] < 12).

However, commands 3 (read, sub_7CA52C) and 4 (write, sub_7CA714) extract a data transfer physical address from buffer+15 as a DWORD, and use it as a source/destination for sector data memcpy operations — without validating this address against SMRAM boundaries.

// sub_7CA52C (NVMe read handler)
v9 = *(_QWORD *)(v1 + 5);          // LBA
v11 = *(_WORD *)(v1 + 13);          // sector count
LODWORD(v19) = *(_DWORD *)(v1 + 15); // DATA BUFFER ADDRESS — NOT validated!
// ...
sub_7CBEF0(v12, v14, v15);          // memcpy with unvalidated destination

The custom SMRAM validation function sub_7CBE68 iterates through SMRAM descriptor ranges (stored at qword_7CC288) checking for overlap — this is a correct implementation. But it is only called once for the CommBuffer itself, not for the data buffer pointer at offset 15.

Impact

An attacker with Ring 0 access can:

  1. Point the data buffer address into SMRAM to write arbitrary NVMe sector data into SMRAM (via read command)
  2. Point the data buffer address into SMRAM to exfiltrate SMRAM contents to a controlled NVMe device (via write command)
  3. Exploitation requires a functional NVMe device to be present and the transfer to succeed

Mitigating Factors

  • The data buffer address is a DWORD (32-bit), limiting the addressable range
  • A successful NVMe I/O transfer must complete for data to actually move
  • The CommBuffer itself IS validated against SMRAM
  • Superseded by FINDING-11: The EBDA-based arbitrary write (below) provides a simpler and more reliable attack path against NvmeSmm

FINDING-9: CRITICAL — UsbRt EBDA-Based Arbitrary Write of 0xF0 to SMRAM (SW SMI# 0x31)

Location: sub_7D4B7Csub_7D4888 (UsbRt module) SW SMI#: 0x31 (49) CVSS Estimate: 8.8 (High) Vulnerability Class: CWE-822 (Untrusted Pointer Dereference), EBDA Confusion, Arbitrary SMRAM Write

Description

The UsbRt SW SMI# 0x31 handler (sub_7D4B7C) acquires its communication buffer pointer from the Extended BIOS Data Area (EBDA) when no cached pointer is available:

; sub_7D4B7C — buffer pointer acquisition
mov rcx, [rax+6D78h]           ; try cached pointer
test rcx, rcx
jz loc_7D4B9D                  ; if null → EBDA fallback

loc_7D4B9D:
movzx eax, word ptr ds:0x40E   ; read EBDA segment from physical 0x40E
shl eax, 4                      ; segment * 16
add eax, 104h                   ; + 0x104
mov ecx, [rax]                  ; read DWORD pointer from EBDA+0x104

Physical address 0x40E is in conventional memory (below 640K), fully writable by an OS-level attacker. The handler then passes this pointer to sub_7D4888 (command dispatcher), which writes 0xF0 to buffer+2 when the command byte is outside the valid 0x20-0x38 range:

// sub_7D4888 — command dispatcher
if ( v1 < 0x20u || v1 > 0x38u )
{
    a1[2] = 0xF0;   // WRITE 0xF0 to EBDA-derived pointer + 2
    return;
}

No SMRAM validation is performed on the EBDA-derived pointer.

Exploitation

  1. Write a controlled 16-bit value to physical address 0x40E to set the EBDA segment
  2. At the computed address (segment * 16) + 0x104, place a 32-bit value = target_SMRAM_addr - 2
  3. Trigger SW SMI# 0x31 with an invalid command byte (e.g., 0xFF)
  4. Handler writes 0xF0 to target_SMRAM_addr

This provides a single-byte arbitrary write of 0xF0 to any physical address including SMRAM. The blog post "Exploiting AMI Aptio firmware on example of Intel NUC" demonstrates using this to patch SMI entry code in SMRAM, modifying a MOV instruction to redirect SMM execution.


FINDING-10: CRITICAL — SdioSmm Error-Path SMRAM Write Bypasses Validation (SW SMI# 0x40)

Location: sub_7CDC94 (SdioSmm module) SW SMI#: 0x40 (64) CVSS Estimate: 8.8 (High) Vulnerability Class: CWE-822 (Untrusted Pointer Dereference), EBDA Confusion, Validation Bypass

Description

The SdioSmm handler acquires its buffer pointer exclusively from the EBDA (no CommBuffer fallback):

// sub_7CDC94 — SdioSmm handler (decompiled)
v0 = (unsigned __int8 *)*(unsigned int *)(16 * *(unsigned __int16 *)0x40E + 260);
if ( sub_7CEB08(v0, 103) < 0 || *v0 >= 4u )
    v0[2] = 7;    // ERROR STATUS WRITE — to the SAME pointer that failed validation!
else
    funcs_7CDCDD[*v0](v0);  // dispatch command

The handler calls sub_7CEB08 (custom SMRAM validation) on the EBDA-derived pointer. If the pointer overlaps SMRAM, validation correctly returns a negative value. However, the error-handling branch writes 0x07 to v0[2] — which is the pointer that was just detected as being inside SMRAM.

The validation is completely defeated by the error-path write.

; NvmeSmm disassembly confirms the same pattern:
loc_7CAE9A: mov byte ptr [rbx+2], 7    ; write 0x07 to buffer+2
                                         ; reached when sub_7CBE68 returns < 0 (SMRAM overlap!)

Impact

Single-byte arbitrary write of 0x07 to any SMRAM address + 2 offset. The attacker:

  1. Corrupts EBDA segment at 0x40E to make buffer pointer = target_SMRAM_addr - 2
  2. Triggers SW SMI# 0x40
  3. Validation detects SMRAM overlap → returns error
  4. Error handler writes 0x07 to target_SMRAM_addr

Design Flaw

The root cause is writing error status to the communication buffer before checking whether the buffer is safe to write to. The correct pattern would be to return immediately without any buffer writes when validation fails. This same flaw affects NvmeSmm (FINDING-11).


FINDING-11: CRITICAL — NvmeSmm Error-Path SMRAM Write Bypasses Validation (SW SMI# 0x42)

Location: sub_7CAE40 (NvmeSmm module) SW SMI#: 0x42 (66) CVSS Estimate: 8.8 (High) Vulnerability Class: CWE-822 (Untrusted Pointer Dereference), EBDA Confusion, Validation Bypass

Description

Identical vulnerability pattern to FINDING-10. The NvmeSmm handler uses EBDA as a fallback when no CommBuffer is provided:

// sub_7CAE40 — NvmeSmm handler
v3 = *a3;                    // try CommBuffer
if ( v3 )
    *a3 = 0;                 // clear it
else
    v3 = *(DWORD *)(16 * *(WORD *)0x40E + 0x104);  // EBDA fallback

v5 = sub_7CBE68(v3, 98);     // SMRAM validation
if ( v5 < 0 )
    goto LABEL_8;             // validation failed → error path
if ( *v3 != 39 || v3[1] >= 0xCu )
LABEL_8:
    v3[2] = 7;               // WRITE 0x07 to SMRAM-overlapping buffer!
    return;

Same error-path write: mov byte ptr [rbx+2], 7 at 0x7CAE9A. When validation detects SMRAM overlap and returns negative, the handler still writes 0x07 to buffer+2.

Impact

Same as FINDING-10: single-byte arbitrary write of 0x07 to SMRAM. This supersedes FINDING-8 (data buffer validation gap) as a simpler and more reliable attack path.


UsbRt Module Analysis Detail

Module Overview

Field Value
Module UsbRt (USB Runtime SMM)
Entry 0x7D3F80
SW SMI# 0x31 (49)
Handler sub_7D4888 at 0x7D4888
Functions 316 (0x7D3F80 — 0x7EA2B0)
Dispatch Table 26 entries at 0x7D3DF0
Secondary Dispatch 15 entries (funcs_7D4E66) via command 0x27

Architecture

The UsbRt handler uses a shared memory communication buffer. The SW SMI# 0x31 handler (sub_7D4B7C) retrieves a pointer to this buffer from a global variable, then dispatches to sub_7D4888 which reads byte 0 of the buffer as a command code:

  • Command 0x00: Device enumeration status query (sub_7D4E80) — CLEAN
  • Commands 0x20-0x38: USB operations dispatched via 26-entry function table
  • Command 0x27: Secondary dispatch to 15-entry sub-function table

Command Dispatch Table (0x7D3DF0)

Index Cmd Handler Purpose Risk
0 0x00 sub_7D4E80 Device enumeration Clean
1 0x20 sub_7D5778 (stub) Clean
2 0x21 sub_7D4F34 USB transfer setup Low
3-5 0x22-24 sub_7D4F60 NOP stubs Clean
6 0x25 sub_7D4F68 Device info query Low
7 0x26 sub_7D4FB4 Device lookup Medium
8 0x27 sub_7D4E3C Secondary dispatch (15 funcs) High
12 0x2B sub_7D579C Pointer dereference CRITICAL
13 0x2C sub_7D5D14 Flag toggle Clean
14 0x2D sub_7D5EE0 Dynamic function call CRITICAL
15 0x2E sub_7D5F38 Device info Low
16 0x2F sub_7D5810 Pointer dereference CRITICAL
17 0x30 sub_7D5984 (minimal) Clean
18 0x31 sub_7D598C USB controller ops Medium
19 0x32 sub_7D5B74 Device query Low
20 0x33 sub_7D5BC8 Virtual method call Medium
24 0x37 sub_7D4FF4 Device detail query Low
25 0x38 sub_7D5164 Device config Low

USB Transfer Path Vulnerability

The USB transfer functions (for control, bulk, and interrupt transfers) follow this chain:

  1. Command handler reads device index and transfer parameters from shared buffer
  2. Looks up device structure via sub_7D9E84 (internal device array)
  3. Calls sub_7D78D4 (core transfer function) with buffer+3 as parameter block
  4. sub_7D78D4 reads: transfer size (*(QWORD*)(buf+5)), endpoint (*(WORD*)(buf+13)), data pointer (*(QWORD*)(buf+19))
  5. Writes to the data pointer at offsets +28, +64, +66, +70, +74 — all without SMRAM validation

Design Observations

EBDA-Based Communication Buffer Pattern (Systemic)

Severity: CRITICAL (Systemic)

Three SMM modules (UsbRt, NvmeSmm, SdioSmm) acquire their communication buffer pointer from the Extended BIOS Data Area (EBDA) — a region in conventional memory below 640K that is fully writable by an OS-level attacker:

movzx eax, word ptr ds:0x40E   ; read EBDA segment (16-bit) from conventional memory
shl eax, 4                      ; segment * 16 = EBDA base address
add eax, 104h                   ; + 0x104
mov ecx/ebx, [rax]             ; read communication buffer pointer from EBDA

This pattern means the attacker controls the pointer itself, not just the buffer contents. By writing a crafted EBDA segment value to physical address 0x40E, the attacker can direct the handler to read its buffer pointer from any address in the first 1MB, and thus make the buffer point anywhere in physical memory — including SMRAM.

Module EBDA Usage Fallback Error-Path Write
UsbRt Fallback (if cached ptr null) Cached at [qword_7EA4F8+0x6D78] buffer[2] = 0xF0
NvmeSmm Fallback (if CommBuffer null) CommBuffer from a3 buffer[2] = 0x07
SdioSmm Always (no fallback) None buffer[2] = 0x07

CPU Saved State Communication Pattern (ItkSmmVars)

Severity: CRITICAL

The ItkSmmVars handler reads its communication buffer address from CPU saved state registers (RSI and RBX) via EFI_SMM_CPU_PROTOCOL.ReadSaveState() at qword_956710:

mov rax, cs:qword_956710        ; EFI_SMM_CPU_PROTOCOL
mov rdx, 4                       ; width = 4 bytes
lea r8d, [rdi+2Ch]              ; register 0x2C (RSI)
mov r9, r12                      ; CPU index
call qword ptr [rax]            ; ReadSaveState → rbp = low 32 bits of RSI

The attacker sets RSI to a controlled value before triggering the SMI via outb(0xB2, 0xEF). The handler then uses this as a direct memory pointer, writing error status codes via OR operations to [rbp+0] and [rbp+0x18].

Custom SMRAM Validation — Defeated by Error-Path Writes

Severity: Informational

Two modules implement custom inline SMRAM validation (functionally equivalent to SmmIsBufferOutsideSmmValid):

Module Function Implementation Defeated By
SdioSmm sub_7CEB08 SMRAM range iteration, correct Error-path v0[2]=7 writes to the failing buffer
NvmeSmm sub_7CBE68 SMRAM range iteration, correct Error-path v3[2]=7 writes to the failing buffer

Both functions correctly detect SMRAM overlap. However, the error handling code writes a status byte to the same buffer that was just identified as overlapping SMRAM. This completely defeats the validation — the attacker intentionally triggers validation failure to get the constant-value write into SMRAM.

Note: The IDA decompiler incorrectly showed both functions as trivial stubs returning EFI_UNSUPPORTED. The full SMRAM range-checking implementation was only visible in disassembly.

No Standard SmmIsBufferOutsideSmmValid

The standard SmmIsBufferOutsideSmmValid function is absent from the image. The remaining modules (UsbRt, ItkSmmVars, SmmHddSecurity, SmmLockBox) have no SMRAM validation at all. This indicates the firmware codebase predates industry-wide CommBuffer hardening (post-2016).

SMM_Code_Chk_En Hardware Mitigation

The Skylake platform supports SMM_Code_Chk_En (MSR 0x4E0 bit 0), which prevents code execution from physical addresses outside the SMRAM range. When enabled, attempts to execute non-SMRAM code from SMM trigger a machine check exception. On this NUC firmware, the capability is present (MSR 0x17D bit 58 = 1) but the feature lock status should be verified. This mitigation means exploitation via arbitrary write must target code/data within SMRAM rather than redirecting execution to attacker-controlled memory outside SMRAM.

NvmeSmm Module Analysis Detail

Field Value
Module NvmeSmm
Entry 0x7CA330 (init: sub_7CAEC8)
SW SMI# 0x42 (66)
Handler sub_7CAE40 at 0x7CAE40
Dispatch Table 12 entries at 0x7CA2C0
Buffer Source CommBuffer (primary), EBDA fallback
SMRAM Validation sub_7CBE68 (custom, correct but defeated by error-path write)

Architecture: The handler first tries CommBuffer; if null, falls back to EBDA. Validates buffer against SMRAM via sub_7CBE68, checks signature (*buffer == 39) and index (buffer[1] < 12). On ANY failure, writes buffer[2] = 7to the same buffer that may overlap SMRAM (see FINDING-11). Only commands 3 and 4 are active.

Command Table:

Index Handler Purpose Risk
(error path) Writes 0x07 to buffer+2 CRITICAL (SMRAM write via EBDA)
0-2 sub_7CA8F0 Stub Clean
3 sub_7CA52C NVMe sector read MEDIUM (unvalidated data ptr)
4 sub_7CA714 NVMe sector write MEDIUM (unvalidated data ptr)
5-11 sub_7CA8F0 / sub_7CA8E8 Stubs Clean

SdioSmm Module Analysis Detail

Field Value
Module SdioSmm
Entry 0x7CD870 (init: sub_7CDB04)
SW SMI# 0x40 (64)
Handler sub_7CDC94 at 0x7CDC94
Dispatch Table 4 entries at 0x7CD818
Buffer Source EBDA only (no CommBuffer fallback)
SMRAM Validation sub_7CEB08 (custom, correct but defeated by error-path write)

Architecture: The handler reads its buffer pointer exclusively from EBDA (no CommBuffer parameter). It then validates the buffer against SMRAM via sub_7CEB08. If validation fails OR command index >= 4, it writes buffer[2] = 7to the same buffer that was just detected as overlapping SMRAM (see FINDING-10). If validation passes, dispatches through 4-entry function table. Read and write commands additionally validate the secondary data buffer pointer against SMRAM.

Command Table:

Index Handler Purpose Risk
(error path) Writes 0x07 to buffer+2 CRITICAL (SMRAM write via EBDA)
0 sub_7CDCE8 SDIO sector read Low (data buffer validated)
1 sub_7CDE54 SDIO sector write Low (data buffer validated)
2 sub_7CE00C Get device info Clean
3 sub_7CE0A0 Device reset Clean

Shared Memory Buffer Patterns

Three distinct communication mechanisms are used by SMI handlers in this firmware:

1. EBDA pointer chain (UsbRt, NvmeSmm, SdioSmm): Reads EBDA segment from physical 0x40E → computes pointer address → dereferences. Fully attacker-controlled — the pointer itself can be redirected to any memory.

2. CPU saved state registers (ItkSmmVars): Reads RSI/RBX from SMM saved CPU state via EFI_SMM_CPU_PROTOCOL.ReadSaveState(). Fully attacker-controlled — registers are set by the caller before SMI.

3. NVRAM variable pointers (NvramSmi, FlashSmiSmm, NbSmi): Stores buffer addresses in NVRAM during DXE phase. Buffer addresses are set before SMM lockdown and are trustworthy, but buffer contents are attacker-controlled at runtime.

Module Mechanism Buffer Source Pointer Trust
UsbRt EBDA 0x40E → segment*16+0x104 Untrusted
NvmeSmm EBDA (fallback) 0x40E → segment*16+0x104 Untrusted
SdioSmm EBDA (always) 0x40E → segment*16+0x104 Untrusted
ItkSmmVars CPU saved state RSI/RBX registers Untrusted
NvramSmi NVRAM variable "NvramSmiBuffer" → qword_74D120 Trusted (contents untrusted)
FlashSmiSmm NVRAM variable "FlashSmiBuffer" → qword_7C1548 Trusted (contents untrusted)
NbSmi NVRAM variable "NbAslBufferPtrVar" → qword_75B5E8 Trusted (contents untrusted)

Clean Handler Analysis

OemSmi (SW SMI# 0, 3, 4, 5) — CLEAN

Handler: sub_95DB84 at 0x95DB84

The OemSmi handlers perform only hardware register I/O operations:

  • Super I/O (SIO) chip access via ports 0x2E/0x2F
  • MMIO write to 0xFDAF0568 (PCH register)
  • Secondary handler sub_95DB44: simple I/O port operations on 0xA01 and 0xA03

No user-controlled data is processed. Pure hardware management.

NbSmi (SW Dispatch) — CLEAN

Handler: sub_758ED4 at 0x758ED4

Minimal handler that validates CommBuffer is not null and *CommBuffer != -1, then calls internal enable/disable SMI functions. No data processing from CommBuffer contents.

PchInitSmm (GPI/Periodic Timer) — CLEAN

Handler: sub_795D10 at 0x795D10

Hardware SMI handler for PCH GPIO/GPI events. Reads PCIe configuration registers, programs I/O ports, manages PCH power states. No CommBuffer or shared memory processing.

ItkSmmVars Capsule Handler — CLEAN

Handler: sub_951C88 at 0x951C88

Handles capsule update preparation. Reads "CapsuleUpdateData" and "FlashUpdateSleepDelay" NVRAM variables, then performs RTC alarm programming via CMOS ports (0x70-0x73) and ACPI timer ports (0x1800-0x1804). No attacker-controlled data processing from shared buffers.

BiosGuardServices — CLEAN

Entry: 0x775300

Checks MSR 0xCE (PLATFORM_INFO) and MSR 0x110 (BIOS_GUARD_CFG) for Intel BIOS Guard hardware capability. If supported, configures the protection and installs a protocol interface for other SMM modules. No SW SMI handler registration. Pure hardware capability management.

CryptoSMM — CLEAN

Entry: 0x7A2D10

Allocates a 48KB SMRAM buffer, installs an internal SMM protocol interface. No SW dispatch handler — operates as an internal SMM service consumed by other modules through protocol calls.

TcgSmm — CLEAN

Entry: 0x7D1340

Minimal initialization that locates a TCG (Trusted Computing Group) protocol. No handler registration found — protocol consumer only.

SmmPlatform (SW SMI# 3, 4, 5) — CLEAN

Handlers: sub_76EDF8 (SMI# 3), sub_76EE64 (SMI# 4), sub_76EE74 (SMI# 5)

All three handlers perform pure hardware register operations:

  • sub_76EDF8: Saves/restores PCIe configuration space registers
  • sub_76EE64: Minimal handler, returns immediately
  • sub_76EE74: Reads/writes PCI configuration space (bus/device/function encoding)

Additionally registers sub_76FA94 (protocol locate only), sub_76EEEC (PCIe config save/restore), and sub_76FB60 (CPU context save, writes "OfflineCpuContext" NVRAM). No user-controlled data processing.

CrbSmi (SW SMI# 0xBF, 3, 0) — CLEAN

Handler: sub_7EED94 at 0x7EED94 (registered for all three SMI numbers)

The handler is a stub: xor eax, eax; ret (3 bytes). Confirmed via raw memory read (33 C0 C3 CC). Decompilation and disassembly both failed — the function is too small for IDA to recognize. Harmless placeholder.

CpuSpSMI (SW SMI# 0x56, 0x57) — CLEAN

Handlers: sub_61B1C (SMI# 0x56, MSR save), sub_61C90 (SMI# 0x57, MSR restore)

Both handlers operate exclusively on CPU Model-Specific Registers (MSRs):

  • sub_61B1C: Reads MSR values and saves them to internal SMRAM buffers
  • sub_61C90: Restores previously saved MSR values

No CommBuffer or shared memory processing. Pure CPU state management.

AcpiModeEnable (SW SMI# 0xA0, 0xA1) — CLEAN

Handlers: sub_76BF80 (SMI# 0xA0, ACPI enable), sub_76C06C (SMI# 0xA1, ACPI disable)

Pure ACPI register manipulation:

  • sub_76BF80: Programs ACPI PM1 control register to enable SCI, disables SMI sources
  • sub_76C06C: Reverses the ACPI enable — disables SCI, re-enables SMI sources

No user-controlled data. Standard ACPI mode switching.

BootScriptHideSmm (SW SMI# 0xD6, 0xD7) — CLEAN

Handlers: sub_7B5990 (SMI# 0xD6), sub_7B5B20 (SMI# 0xD7)

  • sub_7B5990: Copies boot script data into SMRAM for protection during S3 resume. Defensive measure — locks boot script away from OS-accessible memory.
  • sub_7B5B20: Returns EFI_UNSUPPORTED (stub). No operation.

CmosSmm (SW SMI# 0x61) — CLEAN

Handler: sub_7BA014 at 0x7BA014

Minimal handler that clears a single internal flag variable. No CommBuffer data processing.

SmramSaveInfoHandler (Dynamic SW SMI#) — CLEAN

Handler: sub_76D4F0 at 0x76D4F0

Reads IO ports and manipulates internal SMM save state data. The SW SMI number is dynamically assigned from a configuration byte. No shared memory or CommBuffer processing — operates on hardware state only.

Additional Confirmed Clean Modules (No SW SMI)

Module Dispatch Type Handler Analysis
SleepSmi Sx dispatch (S1/S3/S4/S5) sub_764DCC Sleep state management only
PowerMgmtSmm IO trap dispatch sub_78BEE8 Power management registers
SaLateInitSmm Periodic timer / IO trap sub_78E5D0 System agent register programming
AhciSmm Storage protocol N/A Internal AHCI protocol, no SW SMI
RuntimeSmm Protocol installation N/A Installs runtime SMM protocol interface
KbcEmul IO trap N/A Keyboard controller emulation via IO traps
UsbS5Wakeup Sx dispatch + USB event sub_7ED490 USB wake-from-S5 handler
StatusCodeSmm Protocol installation N/A Status code reporting protocol
PttWrapper Protocol lookup N/A Platform Trust Technology, protocol only

ItkSmmVars SW SMI# 0x44 Handler Analysis

Handler: sub_952850 at 0x952850 (via sub_952D90 dispatch) Trigger: SW SMI# 0x44 with signature 0xD042 at shared buffer offset 0

Command dispatcher based on byte at offset 4 of shared buffer:

Command Action Risk
0 Calls sub_9523BC, writes result to buffer (version query) Low
1 Calls sub_95246C Low
2 Validates byte at offset 5 (range 0-1), enables/disables flag Low
3 Calls sub_952758 Low

The 0x44 sub-handler is simpler than 0xEF and performs less dangerous operations. Commands manipulate flags and return version/status information through the shared buffer. Risk is lower but the same fundamental lack of SMRAM validation applies.


Recommendations

Immediate (Critical)

  1. Eliminate EBDA-based buffer pointer acquisition — Replace the EBDA pointer chain (0x40E → segment*16 + 0x104 → read ptr) in UsbRt, NvmeSmm, and SdioSmm with a trusted mechanism (e.g., SMRAM-resident pointer set during DXE, like the NVRAM variable pattern used by NvramSmi). The EBDA is attacker-controlled memory and must never be used as a source of trusted pointers in SMM.

  2. Fix error-path writes in NvmeSmm and SdioSmm — The validation functions (sub_7CBE68, sub_7CEB08) correctly detect SMRAM overlap, but the error handling code writes status bytes to the same untrusted buffer. The fix: return immediately without any buffer writes when SMRAM validation fails. Do not write error codes to untrusted memory.

  3. Patch UsbRt SW SMI# 0x31 handler — Beyond the EBDA issue, multiple command handlers dereference attacker-controlled pointers:

    • Commands 0x2B/0x2F: Add SMRAM validation before pointer dereferences
    • Core transfer function (sub_7D78D4): Validate *(QWORD*)(buffer+22) data pointer
    • Command 0x2D: Validate argument array pointer and all arguments
    • Error path in sub_7D4888: Do not write 0xF0 to unvalidated buffer
  4. Patch ItkSmmVars SW SMI# 0xEF handler — Add SMRAM boundary validation for the RSI-derived pointer and all embedded pointers before any dereference or write:

    • Validate RSI-derived buffer address is outside SMRAM before any access
    • Validate v11 (pointer at buffer+4) before dereference
    • Validate v11[4], v11[7] (variable name, data pointers) before use
    • For command 5: validate all three memcpy arguments
  5. Implement global SmmIsBufferOutsideSmmValid — Add a standard SMRAM boundary check function and apply it at every point where SMM dereferences or writes to externally-supplied addresses.

Short-Term (Medium)

  1. Patch SmmHddSecurity handler — Add CommBuffer SMRAM validation before the 112-byte copy.

  2. Patch SmmLockBox handler — Replace the integer overflow check (sub_7D041C) with proper SMRAM boundary validation.

Long-Term (Architectural)

  1. Upgrade to modern AMI Aptio with PI 1.4+ CommBuffer validation — The firmware codebase should be updated to a version with standard CommBuffer hardening and SmmIsBufferOutsideSmmValid.

  2. Audit remaining UsbRt secondary dispatch table — The 15-entry secondary dispatch (command 0x27) was not fully analyzed and likely contains additional pointer vulnerabilities.

  3. Verify SMM_Code_Chk_En lock status — Confirm that MSR 0x4E0 bit 0 (SMM code checking) is enabled and locked via MSR 0x4E0 bit 1 in production firmware, as this mitigates arbitrary code execution via SMRAM write primitives.


Methodology

  • Tools: IDA Pro 9.x with ida-pro-mcp (mrexodia) and idasql (allthingsida) MCP servers
  • Approach: Manual decompilation and analysis of all ~43 SMM module entry points, handler registration chains, and handler callback functions. Each module's initialization function was decompiled to identify dispatch protocol registrations (SW, Sx, IO trap, periodic timer, GPI). All SW SMI handlers were then decompiled and analyzed for pointer dereference, SMRAM validation, and input validation vulnerabilities.
  • Focus: SW SMI dispatch handlers, communication buffer acquisition patterns (EBDA, CPU saved state, NVRAM variables), SMRAM validation, and pointer dereference chains
  • Coverage: All 43 identified SMM modules were analyzed. 20 SW SMI handler registrations were discovered across 11 modules. All handlers were individually examined.
  • Validation: Findings were cross-referenced against the published vulnerability research "Exploiting AMI Aptio firmware on example of Intel NUC" (d-olex, October 2016) which analyzed the same firmware image. This comparison identified the EBDA-based communication mechanism and error-path validation bypass patterns (FINDING-9, 10, 11) that were initially missed.
  • Decompiler caveats: The IDA decompiler incorrectly rendered two custom SMRAM validation functions (sub_7CEB08 in SdioSmm, sub_7CBE68 in NvmeSmm) as trivial stubs returning EFI_UNSUPPORTED. Disassembly verification was required to discover the full SMRAM range-checking implementation. The EBDA pointer acquisition pattern (*(WORD*)0x40E * 16 + 0x104) was visible in decompiler output but required domain knowledge to recognize as a security-critical attacker-controlled input. One handler (sub_7EED94 in CrbSmi) was too small for decompilation — raw memory reads confirmed it was a stub.
  • Limitations: efiXplorer annotations were not relied upon per auditor guidance. The UsbRt secondary dispatch table (15 entries via command 0x27) was not fully analyzed. SmmHddSecurity has 6 additional sub-handlers beyond the primary that were not deeply analyzed.

Report generated: 2026-03-02 Auditor: Claude (AI-assisted static analysis via IDA Pro MCP) Cross-referenced against: d-olex "Exploiting AMI Aptio firmware" (2016)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment