A potential attacker can execute an arbitrary code at the time of the PEI phase and influence the subsequent boot stages. This can lead to the mitigasions bypassing, physical memory contents disclosure, discovery of any secrets from any Virtual Machines (VMs) and bypassing memory isolation and confidential computing boundaries. Additionally, an attacker can build a payload which can be injected into the SMRAM memory.
Binarly REsearch Team has discovered an arbitrary write vulnerability on Intel platforms allowing a possible attacker to execute arbitrary code during PEI phase.
A potential attacker can execute an arbitrary code at the time of the PEI phase and influence the subsequent boot stages. This can lead to the mitigasions bypassing, physical memory contents disclosure, discovery of any secrets from any Virtual Machines (VMs) and bypassing memory isolation and confidential computing boundaries. Additionally, an attacker can build a payload which can be injected into the SMRAM memory.
The pseudocode for vulnerable function is shown below:
int sub_FFEBFB2C()
{
// [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]
DataSize = 4;
S3PerformanceTablePointer = 0;
Status = sub_FFEC0607(&EFI_PEI_READ_ONLY_VARIABLE2_PPI_GUID, &This);
if ( Status >= 0 )
{
Status = This->GetVariable(
This,
L"FPDT_Variable_NV",
&AMI_GLOBAL_VARIABLE_GUID,
0,
&DataSize,
&S3PerformanceTablePointer);
if ( Status >= 0 )
{
Status = S3PerformanceTablePointer;
// Extracted from memory pointed by FPDT_Variable_NV variable value
AcpiS3PerformanceTable = S3PerformanceTablePointer->AcpiS3PerformanceTable;
if ( *S3PerformanceTablePointer->AcpiS3PerformanceTable == 'TP3S' )
{
if ( *&S3PerformanceTablePointer->ResumeCount )
{
if ( !AcpiS3PerformanceTable->S3Resume.Header.Type )
{
S3ResumeTotal = MultU64x32(__rdtsc(), *&S3PerformanceTablePointer->ResumeCount);
LODWORD(v3) = S3ResumeTotal;
HIDWORD(v3) = HIDWORD(S3ResumeTotal) % 0xF4240;
FullResumeLo = v3 / 0xF4240;
FullResumeHi = HIDWORD(S3ResumeTotal) / 0xF4240;
v6 = __PAIR64__(HIDWORD(S3ResumeTotal) / 0xF4240, FullResumeLo)
+ AcpiS3PerformanceTable->S3Resume.AverageResume * AcpiS3PerformanceTable->S3Resume.ResumeCount;
ResumeCount = AcpiS3PerformanceTable->S3Resume.ResumeCount + 1;
LODWORD(v3) = v6;
HIDWORD(v3) = HIDWORD(v6) % ResumeCount;
Status = v3 / ResumeCount;
AcpiS3PerformanceTable->S3Resume.ResumeCount = ResumeCount;
LODWORD(AcpiS3PerformanceTable->S3Resume.AverageResume) = Status;
HIDWORD(AcpiS3PerformanceTable->S3Resume.AverageResume) = HIDWORD(v6) / ResumeCount;
LODWORD(AcpiS3PerformanceTable->S3Resume.FullResume) = FullResumeLo;
HIDWORD(AcpiS3PerformanceTable->S3Resume.FullResume) = FullResumeHi;
}
}
}
}
}
return Status;
}
The AcpiS3PerformanceTable
pointer is controlled by the attacker: * S3PerformanceTablePointer
value is occured from value of FPDT_Variable_NV
NVRAM variable * AcpiS3PerformanceTable = S3PerformanceTablePointer->AcpiS3PerformanceTable
(extracted from memory pointed by FPDT_Variable_NV variable value)
Thus the memory pointed to by AcpiS3PerformanceTable
can be overwritten with predictable values:
AcpiS3PerformanceTable->S3Resume.ResumeCount = ResumeCount;
LODWORD(AcpiS3PerformanceTable->S3Resume.AverageResume) = Status;
HIDWORD(AcpiS3PerformanceTable->S3Resume.AverageResume) = HIDWORD(v6) / ResumeCount;
LODWORD(AcpiS3PerformanceTable->S3Resume.FullResume) = FullResumeLo;
HIDWORD(AcpiS3PerformanceTable->S3Resume.FullResume) = FullResumeHi;
This can lead to arbitrary write during the PEI stage.
The primitive described above allows to perform privilege escalation from the PEI to the DXE/SMM phase (or from PEI to the SMM during S3 sleep/wake up circle).In turn, code execution in PEI allows the disable security features that are initialized at the PEI-DXE junction (like PPAM or Intel BIOS Guard).
This bug is subject to a 90 day disclosure deadline. After 90 days elapsed or a patch has been made broadly available (whichever is earlier), the bug report will become visible to the public.
Binarly REsearch Team