An attacker can exploit this vulnerability to elevate privileges from ring 0 to ring -2, execute arbitrary code in System Management Mode - an environment more privileged than operating system (OS) and completely isolated from it. Running arbitrary code in SMM additionally bypasses SMM-based SPI flash protections against modifications, which can help an attacker to install a firmware backdoor/implant into BIOS. Such a malicious firmware code in BIOS could persist across operating system re-installs. Additionally, this vulnerability potentially could be used by malicious actors to bypass security mechanisms provided by UEFI firmware (for example, Secure Boot and some types of memory isolation for hypervisors).
This vulnerability was detected by the Deep Vulnerability Analysis (DVA) component from Binarly Platform
Binarly REsearch Team has discovered a SMM memory corruption vulnerability in a Fujitsu device allowing a possible attacker to write fixed or predictable data to SMRAM. Exploiting this issue could lead to escalating privileges to SMM.
An attacker can exploit this vulnerability to elevate privileges from ring 0 to ring -2, execute arbitrary code in System Management Mode - an environment more privileged than operating system (OS) and completely isolated from it. Running arbitrary code in SMM additionally bypasses SMM-based SPI flash protections against modifications, which can help an attacker to install a firmware backdoor/implant into BIOS. Such a malicious firmware code in BIOS could persist across operating system re-installs. Additionally, this vulnerability potentially could be used by malicious actors to bypass security mechanisms provided by UEFI firmware (for example, Secure Boot and some types of memory isolation for hypervisors).
Let's consider the vulnerability on the example of a module with SHA256 1b1c3a5604bc0b526d3eeb7d331f82f385f9e795048bd5daab474dcaf3226ba3. The pseudocode of the vulnerable ChildSwSmiHandler function (with the HandlerType: EFI_HECI_SMM_PROTOCOL_GUID) is presented below:
MACRO_EFI __fastcall ChildSwSmiHandler(
        EFI_HANDLE DispatchHandle,
        const void *Context,
        unsigned int *CommBuffer,
        UINTN *CommBufferSize)
{
  __int64 Command; // rax
  __int64 v7; // rax
  __int64 v8; // rax
  __int64 v9; // rax
  __int64 v10; // rax
  __int64 v11; // rax
  __int64 v12; // rdx
  __int64 v13; // r8
  int v14; // r9d
  unsigned int v15; // ebp
  __int64 v16; // rbx
  __int64 v17; // rax
  __int64 v18; // rax
  __int64 v19; // rax
  __int64 v20; // rax
  __int64 v21; // r8
  __int64 v22; // r9
  __int64 v23; // rdx
  char v24; // [rsp+28h] [rbp-40h]
  EFI_HANDLE Handle; // [rsp+30h] [rbp-38h] BYREF
  __int64 v26; // [rsp+38h] [rbp-30h] BYREF
  EFI_SMM_SW_REGISTER_CONTEXT RegisterContext; // [rsp+40h] [rbp-28h] BYREF
  EFI_SMM_SW_DISPATCH2_PROTOCOL *EfiSmmSwDispatch2Protocol; // [rsp+48h] [rbp-20h] BYREF
  EFI_HANDLE DispatchHandlea[2]; // [rsp+50h] [rbp-18h] BYREF
  char v30; // [rsp+80h] [rbp+18h] BYREF
  if ( CommBuffer && CommBufferSize && *CommBufferSize >= 0x18 )
  {
    if ( !ValidateMemoryBuffer(CommBuffer, *CommBufferSize) )
      return 0;
    if ( (*(gPhysicalAddr + 0x78040) & 0xF0000) != 0 )
      return EFI_UNSUPPORTED;
    Command = *CommBuffer;
    if ( *CommBuffer <= 6 )
    {
      if ( *CommBuffer == 6 )
      {
        if ( !ValidateMemoryBuffer(CommBuffer + 4, 8) )
          return 0;
        v11 = sub_1624(CommBuffer[4], CommBuffer[5]);
        goto LABEL_48;
      }
      ...
    }
    ...
  }
  ...
}Inside the sub_1624 function, another function (sub_1624) with the same parameter (CommBuffer[4]) will be called:
unsigned __int64 __fastcall sub_1624(__int64 a1, int a2)
{
  __int64 v3; // rax
  unsigned int v4; // r10d
  unsigned int v5; // ebx
  __int64 v6; // r11
  v3 = sub_ED0(a1);
  ...
}The pseudocode of the sub_ED0 function is shown below:
__int64 __fastcall sub_ED0(int Value)
{
  __int64 v1; // rbx
  _DWORD *Addr; // rdx
  __int64 (**v3)(void); // rax
  __int64 v4; // r11
  int v6; // eax
  int v7; // ecx
  __int64 v8; // [rsp+38h] [rbp+10h]
  __int64 (**v9)(void); // [rsp+40h] [rbp+18h] BYREF
  v1 = 0;
  v9 = 0;
  // Controllable Value + integer overflow:
  // * Value is controllable by the attacker(CommBuffer[4])
  // * Due to the integer overflow, Address can take
  //    any value in 32-bit address space
  //    that is a multiple of the page size (0x1000)
  Addr = (((Value + 120) << 12) + 0xE0000000);
  if ( *(((Value + 120) << 12) + 0xE0000002) == 0xFFFF )
  {
    if ( Value == 1 )
    {
      v3 = gEfiHeci2PmProtocol;
      if ( gEfiHeci2PmProtocol )
      {
        v4 = 0;
      }
      else
      {
        v4 = sub_1B3C(&v9);
        v3 = v9;
      }
      if ( v4 >= 0 )
      {
        if ( v3 )
          return v3[3]();
      }
    }
    return v1;
  }
  else
  {
    v6 = *(((Value + 120) << 12) + 0xE0000010);
    v7 = 0;
    v8 = Addr[4] & 0xFFFFFFF0;
    if ( (v6 & 6) == 4 )
    {
      v7 = Addr[5];
      HIDWORD(v8) = v7;
    }
    if ( (Addr[4] & 0xFFFFFFF0) != 0 || v7 )
    {
      Addr[1] |= 0x106; // unchecked write (SMRAM corruption)
      return v8;
    }
    else
    {
      return 0;
    }
  }
}Since attacker is able to control Ptr and the offset ((Ptr + 120) << 12) is not checked, attacker is able to control Addr pointer and perform an arbitrary write operation here:
Addr[1] |= 0x106; // unchecked write (SMRAM corruption)It should be noted that the sub_ED0 function is reachable from several locations within the SMI handler.
In order to fix this vulnerability, all user-controllable offsets and pointers should be checked.
Binarly REsearch Team