Check-SpeculativeMitigations.ps1
|
<# .SYNOPSIS Comprehensive check of speculative execution mitigations for Windows Server. .DESCRIPTION Queries NtQuerySystemInformation and registry to report mitigation status for: CVE-2017-5715 Branch Target Injection (BTI) CVE-2017-5753 Bounds Check Bypass (BCB / Spectre Variant 1) CVE-2017-5754 Rogue Data Cache Load (RDCL / Meltdown) CVE-2018-3639 Speculative Store Bypass (SSBD) CVE-2018-3615, CVE-2018-3620, CVE-2018-3646 (L1 Terminal Fault) CVE-2018-11091, CVE-2018-12126, CVE-2018-12127, CVE-2018-12130 (MDS) CVE-2022-21123 (SBDR) CVE-2022-21125 (SBDS) CVE-2022-21127 (SRBDS Update) CVE-2022-21166 (DRPW) CVE-2022-0001 (Intel BHI) CVE-2022-23825 (Branch Type Confusion / Retbleed) CVE-2023-20569 (Return Address Predictor / SRSO) CVE-2022-40982 (GDS) CVE-2023-20588 (Divide By Zero) CVE-2023-28746 (RFDS) .EXAMPLE .\Check-SpeculativeMitigations.ps1 Reports mitigation status in human-readable format. .EXAMPLE .\Check-SpeculativeMitigations.ps1 -OutputXml Outputs results in both human-readable format and XML. .EXAMPLE .\Check-SpeculativeMitigations.ps1 -OutputXml -OutputPath "C:\Reports\speculation.xml" Outputs results in both formats to the specified XML path. .NOTES Author: Krishnaramanan.S License: No restriction in use or modify Tested in Dev Environment only. Test this module in your Dev Environment first before using in Production. User must make changes if required on their own risk. Run as Administrator for full results. XML output can be consumed by Set-WindowsSpeculativeMitigation.ps1 for targeted remediation. .PARAMETER OutputXml Switch parameter to output results in XML format in addition to human-readable format. .PARAMETER OutputPath Specify the file path for XML output. If not specified, defaults to the TEMP directory. #> [CmdletBinding()] param( [switch]$OutputXml, [string]$OutputPath ) Set-StrictMode -Version Latest $ErrorActionPreference = 'Stop' $RegistryPath = 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management' $NtQSIDefinition = @' [DllImport("ntdll.dll")] public static extern int NtQuerySystemInformation(uint systemInformationClass, IntPtr systemInformation, uint systemInformationLength, IntPtr returnLength); '@ function Test-Administrator { $identity = [Security.Principal.WindowsIdentity]::GetCurrent() $principal = [Security.Principal.WindowsPrincipal]::new($identity) return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) } function Get-RegistryValue { param([string]$Name) try { $val = Get-ItemProperty -Path $RegistryPath -Name $Name -ErrorAction SilentlyContinue if ($null -ne $val -and $null -ne $val.$Name) { return [uint32]$val.$Name } } catch { } return $null } function Get-CpuInfo { $cpu = Get-CimInstance Win32_Processor -ErrorAction SilentlyContinue if ($cpu -is [array]) { $cpu = $cpu[0] } [PSCustomObject]@{ Manufacturer = $cpu.Manufacturer Name = $cpu.Name NumberOfCores = $cpu.NumberOfCores NumberOfLogicalProcessors = $cpu.NumberOfLogicalProcessors Description = $cpu.Description } } function Get-OsInfo { $os = Get-CimInstance Win32_OperatingSystem -ErrorAction SilentlyContinue [PSCustomObject]@{ Caption = $os.Caption Version = $os.Version BuildNumber = [uint32]$os.BuildNumber ProductType = $os.ProductType } } function Get-MinimumBuilds { [ordered]@{ 'Windows Server 2022' = 20348 'Windows Server 2019' = 17763 'Windows Server 2016' = 14393 'Windows 10 21H2' = 19044 'Windows 11 21H2' = 22000 } } function Test-SrbdsDrpwMitigation { param([string]$OsCaption, [uint32]$BuildNumber) $minimums = Get-MinimumBuilds $requiredKbs = @{ 'Windows Server 2022' = 'KB5015018' 'Windows Server 2019' = 'KB5015017' 'Windows Server 2016' = 'KB5015019' 'Windows 10 21H2' = 'KB5015020' 'Windows 11 21H2' = 'KB5015020' } $captionKey = $minimums.Keys | Where-Object { $OsCaption -like "*$_*" } | Select-Object -First 1 if (-not $captionKey) { $captionKey = $minimums.Keys | Where-Object { $OsCaption -like "*Server*" } | Select-Object -First 1 } if (-not $captionKey) { return [PSCustomObject]@{ Status = 'Unknown OS'; RequiredKB = 'N/A'; CurrentBuild = $BuildNumber } } $minBuild = $minimums[$captionKey] $requiredKb = $requiredKbs[$captionKey] $mitigated = $BuildNumber -ge $minBuild [PSCustomObject]@{ Status = if ($mitigated) { 'Mitigated' } else { 'Vulnerable - Update Required' } RequiredKB = $requiredKb MinimumBuild = $minBuild CurrentBuild = $BuildNumber } } function Export-MitigationReportToXml { param( [PSCustomObject]$Report, [string]$OutputPath ) $xmlWriter = New-Object System.Xml.XmlTextWriter($OutputPath, $null) $xmlWriter.Formatting = 'Indented' $xmlWriter.Indentation = 2 $xmlWriter.WriteStartDocument() $xmlWriter.WriteStartElement('SpeculativeMitigationReport') $xmlWriter.WriteStartElement('SystemInfo') $xmlWriter.WriteElementString('ComputerName', $Report.ComputerName) $xmlWriter.WriteElementString('Date', $Report.Date) $xmlWriter.WriteElementString('CPU', $Report.CPU) $xmlWriter.WriteElementString('Manufacturer', $Report.Manufacturer) $xmlWriter.WriteElementString('OS', $Report.OS) $xmlWriter.WriteElementString('OSBuild', $Report.OSBuild.ToString()) $xmlWriter.WriteElementString('Admin', $Report.Admin.ToString()) $xmlWriter.WriteEndElement() $xmlWriter.WriteStartElement('RegistrySettings') $xmlWriter.WriteElementString('FeatureSettingsOverrideMask', "0x$($Report.RegistryOverrideMask.ToString('X8'))") $xmlWriter.WriteElementString('FeatureSettingsOverride', "0x$($Report.RegistryOverride.ToString('X8'))") if ($Report.PSObject.Properties.Name -contains 'SpeculationControlFlags' -and $Report.SpeculationControlFlags) { $xmlWriter.WriteElementString('SpeculationControlFlags', "0x$($Report.SpeculationControlFlags.ToString('X8'))") } $xmlWriter.WriteEndElement() $xmlWriter.WriteStartElement('Mitigations') foreach ($entry in $Report.Mitigations.GetEnumerator()) { $cveName = $entry.Key $cveData = $entry.Value if ($null -eq $cveData) { continue } $xmlWriter.WriteStartElement('CVE') $xmlWriter.WriteAttributeString('Name', [string]$cveName) if ($cveData.PSObject.Properties.Name -contains 'Status') { $xmlWriter.WriteAttributeString('Status', [string]$cveData.Status) } foreach ($prop in $cveData.PSObject.Properties) { $propName = $prop.Name $propValue = $prop.Value if ($null -ne $propValue) { $xmlWriter.WriteElementString($propName, [string]$propValue) } } $xmlWriter.WriteEndElement() } $xmlWriter.WriteEndElement() $xmlWriter.WriteStartElement('RawData') $jsonData = $Report | ConvertTo-Json -Depth 5 -Compress $xmlWriter.WriteCData($jsonData) $xmlWriter.WriteEndElement() $xmlWriter.WriteEndElement() $xmlWriter.WriteEndDocument() $xmlWriter.Flush() $xmlWriter.Close() return [xml](Get-Content $OutputPath -Raw) } function Main { Write-Host '=== Windows Speculative Execution Mitigation Checker ===' -ForegroundColor Cyan Write-Host '' Write-Host "Date: $(Get-Date)" -ForegroundColor DarkGray Write-Host "Computer: $env:COMPUTERNAME" -ForegroundColor DarkGray Write-Host "User: $env:USERNAME" -ForegroundColor DarkGray Write-Host "Admin: $(Test-Administrator)" -ForegroundColor DarkGray Write-Host '' if (-not (Test-Administrator)) { Write-Warning 'Not running as Administrator. Some mitigation details may be unavailable.' Write-Host '' } $cpu = Get-CpuInfo $os = Get-OsInfo Write-Host "CPU: $($cpu.Name)" -ForegroundColor Yellow Write-Host "Manufacturer: $($cpu.Manufacturer)" -ForegroundColor Yellow Write-Host "Cores / Logical: $($cpu.NumberOfCores) / $($cpu.NumberOfLogicalProcessors)" -ForegroundColor Yellow Write-Host "OS: $($os.Caption) Build $($os.BuildNumber)" -ForegroundColor Yellow Write-Host '' $overrideMask = Get-RegistryValue -Name 'FeatureSettingsOverrideMask' $override = Get-RegistryValue -Name 'FeatureSettingsOverride' $specCtrlFlags = Get-RegistryValue -Name 'SpeculationControlFlags' Write-Host '--- Registry Settings ---' -ForegroundColor Cyan Write-Host "FeatureSettingsOverrideMask : 0x$($overrideMask.ToString('X8'))" Write-Host "FeatureSettingsOverride : 0x$($override.ToString('X8'))" if ($null -ne $specCtrlFlags) { Write-Host "SpeculationControlFlags : 0x$($specCtrlFlags.ToString('X8'))" } else { Write-Host "SpeculationControlFlags : Not present" } Write-Host '' $ntdll = Add-Type -MemberDefinition $NtQSIDefinition -Name 'ntdll' -Namespace 'Win32' -PassThru $length = 8 $ptr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($length) $retLen = [System.Runtime.InteropServices.Marshal]::AllocHGlobal(4) $class201 = 201 $flags = [uint32]0 $flags2 = [uint32]0 try { $ret = $ntdll::NtQuerySystemInformation($class201, $ptr, $length, $retLen) if ($ret -eq 0) { $flags = [uint32][System.Runtime.InteropServices.Marshal]::ReadInt32($ptr) $returnLen = [uint32][System.Runtime.InteropServices.Marshal]::ReadInt32($retLen) if ($returnLen -gt 4) { $flags2 = [uint32][System.Runtime.InteropServices.Marshal]::ReadInt32($ptr, 4) } } } catch { Write-Warning "Failed to query System Speculation Control Information: $_" } $manufacturer = $cpu.Manufacturer $isIntel = $manufacturer -eq 'GenuineIntel' $isAmd = $manufacturer -eq 'AuthenticAMD' if ($isIntel -and $cpu.Description -match 'Family (\d+) Model (\d+) Stepping (\d+)') { $intelFamily = [uint32]$Matches[1] $intelModel = [uint32]$Matches[2] $intelStepping = [uint32]$Matches[3] } $PROCESSOR_ARCHITECTURE_ARM64 = 12 $PROCESSOR_ARCHITECTURE_ARM = 5 $arch = (Get-CimInstance Win32_Processor).Architecture $isArm = ($arch -eq $PROCESSOR_ARCHITECTURE_ARM) -or ($arch -eq $PROCESSOR_ARCHITECTURE_ARM64) $scfBpbEnabled = 0x01 $scfBpbDisabledSystemPolicy = 0x02 $scfBpbDisabledNoHardwareSupport = 0x04 $scfSpecCtrlEnumerated = 0x08 $scfSpecCmdEnumerated = 0x10 $scfIbrsPresent = 0x20 $scfStibpPresent = 0x40 $scfSmepPresent = 0x80 $scfSsbdAvailable = 0x100 $scfSsbdSupported = 0x200 $scfSsbdSystemWide = 0x400 $scfSsbdRequired = 0x1000 $scfSpecCtrlRetpolineEnabled = 0x4000 $scfSpecCtrlImportOptimizationEnabled = 0x8000 $scfEnhancedIbrs = 0x10000 $scfHvL1tfStatusAvailable = 0x20000 $scfHvL1tfProcessorNotAffected = 0x40000 $scfHvL1tfMigitationEnabled = 0x80000 $scfHvL1tfMigitationNotEnabled_Hardware = 0x100000 $scfHvL1tfMigitationNotEnabled_LoadOption = 0x200000 $scfHvL1tfMigitationNotEnabled_CoreScheduler = 0x400000 $scfEnhancedIbrsReported = 0x800000 $scfMdsHardwareProtected = 0x1000000 $scfMbClearEnabled = 0x2000000 $scfMbClearReported = 0x4000000 $scf2SbdrSsdpHardwareProtected = 0x01 $scf2FbsdpHardwareProtected = 0x02 $scf2PsdpHardwareProtected = 0x04 $scf2FbClearEnabled = 0x08 $scf2FbClearReported = 0x10 $scf2BhbEnabled = 0x20 $scf2BhbDisabledSystemPolicy = 0x40 $scf2BhbDisabledNoHardwareSupport = 0x80 $scf2BranchConfusionStatus = 0x300 $scf2BranchConfusionReported = 0x400 $scf2RdclHardwareProtectedReported = 0x800 $scf2RdclHardwareProtected = 0x1000 $scf2GdsReported = 0x2000 $scf2GdsStatus = 0x1C000 $scf2SrsoReported = 0x20000 $scf2SrsoStatus = 0xC0000 $scf2DivideByZeroReported = 0x100000 $scf2DivideByZeroStatus = 0x200000 $scf2RfdsReported = 0x400000 $scf2RfdsStatus = 0x1800000 $btiHardwarePresent = ((($flags -band $scfSpecCtrlEnumerated) -ne 0) -or (($flags -band $scfSpecCmdEnumerated) -ne 0)) $btiWindowsSupportPresent = $true $btiWindowsSupportEnabled = (($flags -band $scfBpbEnabled) -ne 0) $btiDisabledBySystemPolicy = $false $btiDisabledByNoHardwareSupport = $false $btiRetpolineEnabled = (($flags -band $scfSpecCtrlRetpolineEnabled) -ne 0) $btiImportOptimizationEnabled = (($flags -band $scfSpecCtrlImportOptimizationEnabled) -ne 0) if ($btiWindowsSupportEnabled -eq $false) { $btiDisabledBySystemPolicy = (($flags -band $scfBpbDisabledSystemPolicy) -ne 0) $btiDisabledByNoHardwareSupport = (($flags -band $scfBpbDisabledNoHardwareSupport) -ne 0) } $ssbdAvailable = (($flags -band $scfSsbdAvailable) -ne 0) $ssbdHardwarePresent = (($flags -band $scfSsbdSupported) -ne 0) $ssbdSystemWide = (($flags -band $scfSsbdSystemWide) -ne 0) $ssbdRequired = (($flags -band $scfSsbdRequired) -ne 0) $sbdrSsdpHardwareProtected = (($flags2 -band $scf2SbdrSsdpHardwareProtected) -ne 0) $fbsdpHardwareProtected = (($flags2 -band $scf2FbsdpHardwareProtected) -ne 0) $psdpHardwareProtected = (($flags2 -band $scf2PsdpHardwareProtected) -ne 0) $fbClearEnabled = (($flags2 -band $scf2FbClearEnabled) -ne 0) $fbClearReported = (($flags2 -band $scf2FbClearReported) -ne 0) $rdclHardwareProtectedReported = (($flags2 -band $scf2RdclHardwareProtectedReported) -ne 0) $rdclHardwareProtected = (($flags2 -band $scf2RdclHardwareProtected) -ne 0) $bhbEnabled = (($flags2 -band $scf2BhbEnabled) -ne 0) $bhbDisabledSystemPolicy = (($flags2 -band $scf2BhbDisabledSystemPolicy) -ne 0) $bhbDisabledNoHardwareSupport = (($flags2 -band $scf2BhbDisabledNoHardwareSupport) -ne 0) $branchConfusionReported = (($flags2 -band $scf2BranchConfusionReported) -ne 0) $gdsReported = (($flags2 -band $scf2GdsReported) -ne 0) $gdsStatus = (($flags2 -band $scf2GdsStatus) -shr 14) $srsoReported = (($flags2 -band $scf2SrsoReported) -ne 0) $srsoStatus = (($flags2 -band $scf2SrsoStatus) -shr 18) $divideByZeroReported = (($flags2 -band $scf2DivideByZeroReported) -ne 0) $divideByZeroStatus = (($flags2 -band $scf2DivideByZeroStatus) -shr 21) $rfdsReported = (($flags2 -band $scf2RfdsReported) -ne 0) $rfdsStatus = (($flags2 -band $scf2RfdsStatus) -shr 23) $mdsMbClearReported = (($flags -band $scfMbClearReported) -ne 0) $mdsMbClearEnabled = (($flags -band $scfMbClearEnabled) -ne 0) $mdsHardwareProtected = (($flags -band $scfMdsHardwareProtected) -ne 0) if (($isAmd) -or ($isArm)) { $mdsHardwareProtected = $true $sbdrSsdpHardwareProtected = $true $fbsdpHardwareProtected = $true $psdpHardwareProtected = $true } $l1tfVulnerableCpus = [tuple]::Create(6, 26, 4), [tuple]::Create(6, 26, 5), [tuple]::Create(6, 30, 4), [tuple]::Create(6, 30, 5), [tuple]::Create(6, 37, 2), [tuple]::Create(6, 37, 5), [tuple]::Create(6, 42, 7), [tuple]::Create(6, 44, 2), [tuple]::Create(6, 45, 6), [tuple]::Create(6, 45, 7), [tuple]::Create(6, 46, 6), [tuple]::Create(6, 47, 2), [tuple]::Create(6, 58, 9), [tuple]::Create(6, 60, 3), [tuple]::Create(6, 61, 4), [tuple]::Create(6, 62, 4), [tuple]::Create(6, 62, 7), [tuple]::Create(6, 63, 2), [tuple]::Create(6, 63, 4), [tuple]::Create(6, 69, 1), [tuple]::Create(6, 70, 1), [tuple]::Create(6, 78, 3), [tuple]::Create(6, 79, 1), [tuple]::Create(7, 69, 1), [tuple]::Create(6, 85, 3), [tuple]::Create(6, 85, 4), [tuple]::Create(6, 86, 2), [tuple]::Create(6, 86, 3), [tuple]::Create(6, 86, 4), [tuple]::Create(6, 86, 5), [tuple]::Create(6, 94, 3), [tuple]::Create(6, 102, 3), [tuple]::Create(6, 142, 9), [tuple]::Create(6, 142, 10), [tuple]::Create(6, 142, 11), [tuple]::Create(6, 158, 9), [tuple]::Create(6, 158, 10), [tuple]::Create(6, 158, 11), [tuple]::Create(6, 158, 12) $l1tfRequired = $false if ($isIntel) { if (($rdclHardwareProtectedReported -eq $true) -and ($rdclHardwareProtected -eq $true)) { $l1tfRequired = $false } elseif (($flags -band $scfHvL1tfStatusAvailable) -and ($flags -band $scfHvL1tfProcessorNotAffected)) { $l1tfRequired = $false } else { $fms = [tuple]::Create([int]$intelFamily, [int]$intelModel, [int]$intelStepping) if (-not $l1tfVulnerableCpus.Contains($fms)) { $l1tfRequired = $false } else { $l1tfRequired = $true } } } $kvaPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal(4) $kvaFlags = [uint32]0 $kvaShadowPresent = $false try { $kvaRet = $ntdll::NtQuerySystemInformation(196, $kvaPtr, 4, $retLen) if ($kvaRet -eq 0) { $kvaFlags = [uint32][System.Runtime.InteropServices.Marshal]::ReadInt32($kvaPtr) } } catch { } finally { if ($kvaPtr -ne [System.IntPtr]::Zero) { [System.Runtime.InteropServices.Marshal]::FreeHGlobal($kvaPtr) } } $kvaShadowEnabledFlag = 0x01 $kvaShadowUserGlobalFlag = 0x02 $kvaShadowPcidFlag = 0x04 $kvaShadowInvpcidFlag = 0x08 $kvaShadowRequiredFlag = 0x10 $kvaShadowRequiredAvailableFlag = 0x20 $l1tfInvalidPteBitMask = 0xfc0 $l1tfInvalidPteBitShift = 6 $l1tfFlushSupportedFlag = 0x1000 $l1tfMitigationPresentFlag = 0x2000 $kvaShadowEnabled = ($kvaFlags -band $kvaShadowEnabledFlag) -ne 0 $kvaShadowPcidEnabled = ((($kvaFlags -band $kvaShadowPcidFlag) -ne 0) -and (($kvaFlags -band $kvaShadowInvpcidFlag) -ne 0)) $kvaShadowPresent = $true if (($kvaFlags -band $kvaShadowRequiredAvailableFlag) -ne 0) { $kvaShadowRequired = ($kvaFlags -band $kvaShadowRequiredFlag) -ne 0 } else { if ($isAmd) { $kvaShadowRequired = $false } elseif ($isIntel -and $intelFamily -eq 0x6 -and $intelModel -in @(0x1c,0x26,0x27,0x36,0x35)) { $kvaShadowRequired = $false } else { $kvaShadowRequired = $true } } $l1tfInvalidPteBit = [math]::Floor(($kvaFlags -band $l1tfInvalidPteBitMask) * [math]::Pow(2, -$l1tfInvalidPteBitShift)) $l1tfFlushSupported = ($kvaFlags -band $l1tfFlushSupportedFlag) -ne 0 $l1tfMitigationEnabled = ($l1tfInvalidPteBit -ne 0) -and $kvaShadowEnabled $l1tfMitigationPresent = ($kvaFlags -band $l1tfMitigationPresentFlag) -ne 0 -or $l1tfMitigationEnabled -or $l1tfFlushSupported $srbdsCheck = Test-SrbdsDrpwMitigation -OsCaption $os.Caption -BuildNumber $os.BuildNumber $drpwCheck = Test-SrbdsDrpwMitigation -OsCaption $os.Caption -BuildNumber $os.BuildNumber $branchConfusionStatus = $null if ($branchConfusionReported) { if ($isAmd) { $branchConfusionStatus = (($flags2 -band $scf2BranchConfusionStatus) -shr 8) } elseif ($isIntel) { if ($btiHardwarePresent -eq $false) { $branchConfusionStatus = 2 } elseif ($btiWindowsSupportEnabled -eq $true) { $branchConfusionStatus = 3 } else { $branchConfusionStatus = 1 } } } $results = [ordered]@{ 'CVE-2017-5715 (BTI)' = [PSCustomObject]@{ HardwarePresent = $btiHardwarePresent WindowsSupportEnabled = $btiWindowsSupportEnabled RetpolineEnabled = $btiRetpolineEnabled Status = if ($btiHardwarePresent -and $btiWindowsSupportEnabled) { 'Mitigated' } else { 'Vulnerable / Not Mitigated' } } 'CVE-2017-5753 (BCB)' = [PSCustomObject]@{ HardwarePresent = 'N/A (Software/Compiler mitigation)' WindowsSupportEnabled = 'N/A (Requires /Qspectre or /guard:cf)' Status = 'Verify compiler flags and application recompilation' } 'CVE-2017-5754 (RDCL)' = [PSCustomObject]@{ HardwareProtected = if ($rdclHardwareProtectedReported) { $rdclHardwareProtected } else { 'Unknown' } KVARequired = $kvaShadowRequired KVAEnabled = $kvaShadowEnabled Status = if ($rdclHardwareProtected) { 'Hardware Immune' } elseif ($kvaShadowRequired -and $kvaShadowEnabled) { 'Mitigated' } else { 'Vulnerable / Not Mitigated' } } 'CVE-2018-3639 (SSBD)' = [PSCustomObject]@{ HardwarePresent = $ssbdHardwarePresent OSEnabledSystemWide = $ssbdSystemWide Status = if (-not $ssbdRequired) { 'Not Vulnerable' } elseif ($ssbdSystemWide) { 'Mitigated' } else { 'Vulnerable / Not Mitigated' } } 'CVE-2018-3620 / -3646 (L1TF)' = [PSCustomObject]@{ HardwareVulnerable = $l1tfRequired MitigationPresent = $l1tfMitigationPresent MitigationEnabled = $l1tfMitigationEnabled FlushSupported = $l1tfFlushSupported Status = if (-not $l1tfRequired) { 'Not Vulnerable' } elseif ($l1tfMitigationEnabled) { 'Mitigated' } else { 'Vulnerable / Not Mitigated' } } 'CVE-2018-11091/12126/12127/12130 (MDS)' = [PSCustomObject]@{ HardwareProtected = $mdsHardwareProtected OSEnabled = $mdsMbClearEnabled Status = if ($mdsHardwareProtected) { 'Hardware Immune' } elseif ($mdsMbClearReported -and $mdsMbClearEnabled) { 'Mitigated' } else { 'Vulnerable / Not Mitigated' } } 'CVE-2022-21123 (SBDR)' = [PSCustomObject]@{ HardwareProtected = $sbdrSsdpHardwareProtected OSEnabled = $fbClearEnabled Status = if ($sbdrSsdpHardwareProtected) { 'Hardware Immune' } elseif ($fbClearReported -and $fbClearEnabled) { 'Mitigated' } else { 'Vulnerable / Not Mitigated' } } 'CVE-2022-21125 (SBDS)' = [PSCustomObject]@{ HardwareProtected = $fbsdpHardwareProtected OSEnabled = $fbClearEnabled Status = if ($fbsdpHardwareProtected) { 'Hardware Immune' } elseif ($fbClearReported -and $fbClearEnabled) { 'Mitigated' } else { 'Vulnerable / Not Mitigated' } } 'CVE-2022-21127 (SRBDS Update)' = [PSCustomObject]@{ Status = $srbdsCheck.Status RequiredKB = $srbdsCheck.RequiredKB MinimumBuild = $srbdsCheck.MinimumBuild CurrentBuild = $srbdsCheck.CurrentBuild } 'CVE-2022-21166 (DRPW)' = [PSCustomObject]@{ Status = $drpwCheck.Status RequiredKB = $drpwCheck.RequiredKB MinimumBuild = $drpwCheck.MinimumBuild CurrentBuild = $drpwCheck.CurrentBuild } 'CVE-2022-0001 (BHI)' = [PSCustomObject]@{ Enabled = $bhbEnabled Status = if ($bhbEnabled) { 'Mitigated' } else { 'Vulnerable / Not Mitigated' } } 'CVE-2022-23825 (BTC/Retbleed)' = [PSCustomObject]@{ Reported = $branchConfusionReported StatusValue = $branchConfusionStatus Status = if (-not $branchConfusionReported) { 'Not Reported by OS' } else { switch ($branchConfusionStatus) { 0 { 'Unsupported' } 1 { 'Mitigation Disabled' } 2 { 'Hardware Immune' } 3 { 'Mitigated' } default { 'Unknown' } } } } 'CVE-2023-20569 (SRSO)' = [PSCustomObject]@{ Reported = $srsoReported StatusValue = $srsoStatus Status = switch ($srsoStatus) { 0 { 'Unsupported' } 1 { 'Disabled' } 2 { 'Hardware Immune' } 3 { 'Mitigated' } default { 'Unknown' } } } 'CVE-2022-40982 (GDS)' = [PSCustomObject]@{ Reported = $gdsReported StatusValue = $gdsStatus Status = switch ($gdsStatus) { 0 { 'Unsupported' } 1 { 'Disabled' } 2 { 'Hardware Immune' } 3 { 'Mitigated' } 4 { 'Mitigated and Locked' } default { 'Unknown' } } } 'CVE-2023-20588 (DivByZero)' = [PSCustomObject]@{ Reported = $divideByZeroReported StatusValue = $divideByZeroStatus Status = switch ($divideByZeroStatus) { 0 { 'Hardware Immune' } 1 { 'Mitigated' } default { 'Unknown' } } } 'CVE-2023-28746 (RFDS)' = [PSCustomObject]@{ Reported = $rfdsReported StatusValue = $rfdsStatus Status = switch ($rfdsStatus) { 0 { 'Unsupported' } 1 { 'Disabled' } 2 { 'Hardware Immune' } 3 { 'Mitigated' } default { 'Unknown' } } } } $report = [PSCustomObject]@{ ComputerName = $env:COMPUTERNAME Date = Get-Date CPU = $cpu.Name Manufacturer = $manufacturer OS = $os.Caption OSBuild = $os.BuildNumber Admin = Test-Administrator RegistryOverride = $override RegistryOverrideMask= $overrideMask Mitigations = $results } $divider = '=' * 90 $thinDivider = '-' * 90 Write-Host '' Write-Host $divider -ForegroundColor Cyan Write-Host ' SPECULATIVE EXECUTION MITIGATION ASSESSMENT REPORT' -ForegroundColor White Write-Host $divider -ForegroundColor Cyan Write-Host '' Write-Host " For more information about the output below, please refer to https://support.microsoft.com/help/4074629" -ForegroundColor DarkGray Write-Host '' Write-Host ' SYSTEM INFORMATION' -ForegroundColor Yellow Write-Host $thinDivider -ForegroundColor DarkGray $sysInfo = @( @('Computer Name', $env:COMPUTERNAME), @('Date/Time', (Get-Date -Format 'yyyy-MM-dd HH:mm:ss')), @('User', "$env:USERNAME ($(if (Test-Administrator) { 'Administrator' } else { 'Standard User' }))"), @('CPU', $cpu.Name), @('Manufacturer', $cpu.Manufacturer), @('Cores / Logical', "$($cpu.NumberOfCores) / $($cpu.NumberOfLogicalProcessors)"), @('OS', "$($os.Caption) Build $($os.BuildNumber)"), @('Admin Privileges', $(if (Test-Administrator) { 'Yes' } else { 'No' })) ) foreach ($row in $sysInfo) { $label = $row[0].PadRight(20) $value = $row[1] Write-Host " $label`: $value" } Write-Host '' Write-Host ' REGISTRY CONFIGURATION' -ForegroundColor Yellow Write-Host $thinDivider -ForegroundColor DarkGray Write-Host " FeatureSettingsOverrideMask : 0x$($overrideMask.ToString('X8'))" Write-Host " FeatureSettingsOverride : 0x$($override.ToString('X8'))" if ($null -ne $specCtrlFlags) { Write-Host " SpeculationControlFlags : 0x$($specCtrlFlags.ToString('X8'))" } else { Write-Host " SpeculationControlFlags : Not present (legacy OS / missing KB)" } Write-Host '' function Write-CveSection { param( [string]$Title, [string]$Cve, [string[]]$Lines ) Write-Host '' Write-Host " $Title" -ForegroundColor Cyan foreach ($line in $Lines) { Write-Host " $line" } } Write-Host ' DETAILED MITIGATION ANALYSIS' -ForegroundColor Yellow Write-Host $thinDivider -ForegroundColor DarkGray Write-CveSection -Title 'Speculation control settings for CVE-2017-5715 [branch target injection]' -Cve 'CVE-2017-5715' -Lines @( "Hardware support for branch target injection mitigation is present: $btiHardwarePresent", "Windows OS support for branch target injection mitigation is present: $btiWindowsSupportPresent", "Windows OS support for branch target injection mitigation is enabled: $btiWindowsSupportEnabled" ) Write-CveSection -Title 'Speculation control settings for CVE-2017-5754 [rogue data cache load]' -Cve 'CVE-2017-5754' -Lines @( "Hardware is vulnerable to rogue data cache load: $($rdclHardwareProtected -ne $true)", "Hardware requires kernel VA shadowing: $kvaShadowRequired", "Windows OS support for kernel VA shadow is present: $kvaShadowPresent", "Windows OS support for kernel VA shadow is enabled: $kvaShadowEnabled" ) Write-CveSection -Title 'Speculation control settings for CVE-2018-3639 [speculative store bypass]' -Cve 'CVE-2018-3639' -Lines @( "Hardware is vulnerable to speculative store bypass: $ssbdRequired", "Hardware support for speculative store bypass disable is present: $ssbdHardwarePresent", "Windows OS support for speculative store bypass disable is present: $ssbdAvailable", "Windows OS support for speculative store bypass disable is enabled system-wide: $ssbdSystemWide" ) Write-CveSection -Title 'Speculation control settings for CVE-2018-3620 [L1 terminal fault]' -Cve 'CVE-2018-3620' -Lines @( "Hardware is vulnerable to L1 terminal fault: $l1tfRequired", "Windows OS support for L1 terminal fault mitigation is present: $l1tfMitigationPresent", "Windows OS support for L1 terminal fault mitigation is enabled: $l1tfMitigationEnabled", "L1DFlushSupported: $l1tfFlushSupported" ) Write-CveSection -Title 'Speculation control settings for MDS [microarchitectural data sampling]' -Cve 'MDS' -Lines @( "Windows OS support for MDS mitigation is present: $mdsMbClearReported", "Hardware is vulnerable to MDS: $(($mdsHardwareProtected -ne $true))", "Windows OS support for MDS mitigation is enabled: $mdsMbClearEnabled" ) Write-CveSection -Title 'Speculation control settings for SBDR [shared buffers data read]' -Cve 'SBDR' -Lines @( "Windows OS support for SBDR mitigation is present: $fbClearReported", "Hardware is vulnerable to SBDR: $(($sbdrSsdpHardwareProtected -ne $true))", "Windows OS support for SBDR mitigation is enabled: $fbClearEnabled" ) Write-CveSection -Title 'Speculation control settings for FBSDP [fill buffer stale data propagator]' -Cve 'FBSDP' -Lines @( "Windows OS support for FBSDP mitigation is present: $fbClearReported", "Hardware is vulnerable to FBSDP: $(($fbsdpHardwareProtected -ne $true))", "Windows OS support for FBSDP mitigation is enabled: $fbClearEnabled" ) Write-CveSection -Title 'Speculation control settings for PSDP [primary stale data propagator]' -Cve 'PSDP' -Lines @( "Windows OS support for PSDP mitigation is present: $fbClearReported", "Hardware is vulnerable to PSDP: $(($psdpHardwareProtected -ne $true))", "Windows OS support for PSDP mitigation is enabled: $fbClearEnabled" ) $bhbStatus = if ($bhbEnabled) { 'Enabled' } else { 'Disabled' } Write-CveSection -Title 'Speculation control settings for BHB CVE-2022-0001, CVE-2022-0002' -Cve 'BHI' -Lines @( "BHB Enabled: $bhbEnabled", "BHB Disabled by System Policy: $bhbDisabledSystemPolicy", "BHB Disabled by No Hardware Support: $bhbDisabledNoHardwareSupport" ) $branchConfusionString = switch ($branchConfusionStatus) { 0 { 'SYSTEM_SPECULATION_CONTROL_BRANCH_CONFUSION_MITIGATION_UNSUPPORTED' } 1 { 'SYSTEM_SPECULATION_CONTROL_BRANCH_CONFUSION_MITIGATION_DISABLED' } 2 { 'SYSTEM_SPECULATION_CONTROL_BRANCH_CONFUSION_HARDWARE_IMMUNE' } 3 { 'SYSTEM_SPECULATION_CONTROL_BRANCH_CONFUSION_MITIGATED' } default { 'UNKNOWN_VALUE' } } Write-CveSection -Title 'Speculation control settings for BranchConfusion/Retbleed CVE-2022-23825' -Cve 'Retbleed' -Lines @( "BranchConfusionReported: $branchConfusionReported", "BranchConfusionStatus: $branchConfusionString" ) $gdsString = switch ($gdsStatus) { 0 { 'SYSTEM_SPECULATION_CONTROL_GDS_MITIGATION_UNSUPPORTED' } 1 { 'SYSTEM_SPECULATION_CONTROL_GDS_MITIGATION_DISABLED' } 2 { 'SYSTEM_SPECULATION_CONTROL_GDS_HARDWARE_IMMUNE' } 3 { 'SYSTEM_SPECULATION_CONTROL_GDS_MITIGATED' } 4 { 'SYSTEM_SPECULATION_CONTROL_GDS_MITIGATED_AND_LOCKED' } default { 'UNKNOWN_VALUE' } } Write-CveSection -Title 'Speculation control settings for GDS (Gather Data Sample) CVE-2022-40982' -Cve 'GDS' -Lines @( "GDS Reported: $gdsReported", "GDS Status: $gdsString" ) $srsoString = switch ($srsoStatus) { 0 { 'SYSTEM_SPECULATION_CONTROL_SRSO_MITIGATION_UNSUPPORTED' } 1 { 'SYSTEM_SPECULATION_CONTROL_SRSO_MITIGATION_DISABLED' } 2 { 'SYSTEM_SPECULATION_CONTROL_SRSO_HARDWARE_IMMUNE' } 3 { 'SYSTEM_SPECULATION_CONTROL_SRSO_MITIGATED' } default { 'UNKNOWN_VALUE' } } Write-CveSection -Title 'Speculation control settings for SRSO (Speculative Return Stack Overflow) CVE-2023-20569' -Cve 'SRSO' -Lines @( "SRSO Reported: $srsoReported", "SRSO Status: $srsoString" ) $divideByZeroString = switch ($divideByZeroStatus) { 0 { 'SYSTEM_SPECULATION_CONTROL_DIVIDE_BY_ZERO_HARDWARE_IMMUNE' } 1 { 'SYSTEM_SPECULATION_CONTROL_DIVIDE_BY_ZERO_MITIGATED' } default { 'UNKNOWN_VALUE' } } Write-CveSection -Title 'Speculation control settings for DivideByZero CVE-2023-20588' -Cve 'DivideByZero' -Lines @( "DivideByZero Reported: $divideByZeroReported", "DivideByZero Status: $divideByZeroString" ) $rfdsString = switch ($rfdsStatus) { 0 { 'SYSTEM_SPECULATION_CONTROL_RFDS_MITIGATION_UNSUPPORTED' } 1 { 'SYSTEM_SPECULATION_CONTROL_RFDS_MITIGATION_DISABLED' } 2 { 'SYSTEM_SPECULATION_CONTROL_RFDS_HARDWARE_IMMUNE' } 3 { 'SYSTEM_SPECULATION_CONTROL_RFDS_MITIGATED' } default { 'UNKNOWN_VALUE' } } Write-CveSection -Title 'Speculation control settings for RFDS (Register File Data Sampling) CVE-2023-28746' -Cve 'RFDS' -Lines @( "RFDS Reported: $rfdsReported", "RFDS Status: $rfdsString" ) Write-Host '' Write-Host $thinDivider -ForegroundColor DarkGray Write-Host ' COMPLIANCE SCORECARD' -ForegroundColor Yellow Write-Host $thinDivider -ForegroundColor DarkGray $mitigationData = @() foreach ($cve in $results.Keys) { $r = $results[$cve] $status = $r.Status $indicator = switch -regex ($status) { 'Mitigated|Hardware Immune|Not Vulnerable' { '[PASS]' } 'Vulnerable|Disabled|Unsupported' { '[FAIL]' } default { '[INFO]' } } $mitigationData += [PSCustomObject]@{ CVE = $cve Status = $status Indicator = $indicator } } $passCount = ($mitigationData | Where-Object { $_.Status -match 'Mitigated|Hardware Immune|Not Vulnerable' }).Count $totalCount = $mitigationData.Count $passPercent = [math]::Round(($passCount / $totalCount) * 100) foreach ($item in $mitigationData) { $color = switch -regex ($item.Status) { 'Mitigated|Hardware Immune|Not Vulnerable' { 'Green' } 'Vulnerable|Disabled|Unsupported' { 'Red' } default { 'Yellow' } } Write-Host " $($item.Indicator) $($item.CVE.PadRight(40)) $($item.Status)" -ForegroundColor $color } Write-Host '' Write-Host " SUMMARY: $passCount / $totalCount checks passed ($passPercent%)" -ForegroundColor $(if ($passPercent -eq 100) { 'Green' } elseif ($passPercent -ge 80) { 'Yellow' } else { 'Red' }) Write-Host '' Write-Host ' REMEDIATION RECOMMENDATIONS' -ForegroundColor Yellow Write-Host $thinDivider -ForegroundColor DarkGray $actions = @() if (-not $btiHardwarePresent) { $actions += '[BIOS] Update CPU microcode / firmware for BTI hardware support.' } if (-not $btiWindowsSupportEnabled) { $actions += '[Registry] Enable BTI via FeatureSettingsOverride or Windows Update.' } if ($kvaShadowRequired -and -not $kvaShadowEnabled) { $actions += '[Registry] Enable Kernel VA Shadow for RDCL/L1TF mitigation.' } if ($l1tfRequired -and -not $l1tfMitigationEnabled) { $actions += '[Performance] Enable L1TF mitigation or disable Hyper-Threading.' } if ($ssbdRequired -and -not $ssbdSystemWide) { $actions += '[Registry] Enable SSBD system-wide via registry.' } if ($mdsMbClearReported -and -not $mdsHardwareProtected -and -not $mdsMbClearEnabled) { $actions += '[Registry] Enable MDS mitigation (MB clear).' } if ($fbClearReported -and -not $sbdrSsdpHardwareProtected -and -not $fbClearEnabled) { $actions += '[Registry] Enable FB clear for SBDR/SBDS/PSDP.' } if ($srbdsCheck.Status -eq 'Vulnerable - Update Required') { $actions += "[Windows Update] Install $($srbdsCheck.RequiredKB) or later for SRBDS mitigation." } if ($drpwCheck.Status -eq 'Vulnerable - Update Required') { $actions += "[Windows Update] Install $($drpwCheck.RequiredKB) or later for DRPW mitigation." } if ($actions.Count -eq 0) { Write-Host ' All checks passed. No immediate action required.' -ForegroundColor Green } else { $i = 1 foreach ($action in $actions) { Write-Host " $i. $action" $i++ } } Write-Host '' Write-Host ' RAW DATA OUTPUT' -ForegroundColor Yellow Write-Host $thinDivider -ForegroundColor DarkGray Write-Host ($report | ConvertTo-Json -Depth 5) Write-Host '' Write-Host ' OBJECT PROPERTIES' -ForegroundColor Yellow Write-Host $thinDivider -ForegroundColor DarkGray $hvL1tfStatusAvailableVal = ($flags -band $scfHvL1tfStatusAvailable) -ne 0 $hvL1tfProcessorNotAffectedVal = ($flags -band $scfHvL1tfProcessorNotAffected) -ne 0 $mdsHardwareVulnerableVal = $mdsHardwareProtected -ne $true $sbdrSsdpHardwareVulnerableVal = $sbdrSsdpHardwareProtected -ne $true $fbsdpHardwareVulnerableVal = $fbsdpHardwareProtected -ne $true $psdpHardwareVulnerableVal = $psdpHardwareProtected -ne $true $props = @( @('BTIHardwarePresent', $btiHardwarePresent), @('BTIWindowsSupportPresent', $btiWindowsSupportPresent), @('BTIWindowsSupportEnabled', $btiWindowsSupportEnabled), @('BTIDisabledBySystemPolicy', $btiDisabledBySystemPolicy), @('BTIDisabledByNoHardwareSupport', $btiDisabledByNoHardwareSupport), @('BTIKernelRetpolineEnabled', $btiRetpolineEnabled), @('BTIKernelImportOptimizationEnabled', $btiImportOptimizationEnabled), @('RdclHardwareProtectedReported', $rdclHardwareProtectedReported), @('RdclHardwareProtected', $rdclHardwareProtected), @('KVAShadowRequired', $kvaShadowRequired), @('KVAShadowWindowsSupportPresent', $kvaShadowPresent), @('KVAShadowWindowsSupportEnabled', $kvaShadowEnabled), @('KVAShadowPcidEnabled', $kvaShadowPcidEnabled), @('SSBDWindowsSupportPresent', $ssbdAvailable), @('SSBDHardwareVulnerable', $ssbdRequired), @('SSBDHardwarePresent', $ssbdHardwarePresent), @('SSBDWindowsSupportEnabledSystemWide', $ssbdSystemWide), @('L1TFHardwareVulnerable', $l1tfRequired), @('L1TFWindowsSupportPresent', $l1tfMitigationPresent), @('L1TFWindowsSupportEnabled', $l1tfMitigationEnabled), @('L1TFInvalidPteBit', $l1tfInvalidPteBit), @('L1DFlushSupported', $l1tfFlushSupported), @('HvL1tfStatusAvailable', $hvL1tfStatusAvailableVal), @('HvL1tfProcessorNotAffected', $hvL1tfProcessorNotAffectedVal), @('MDSWindowsSupportPresent', $mdsMbClearReported), @('MDSHardwareVulnerable', $mdsHardwareVulnerableVal), @('MDSWindowsSupportEnabled', $mdsMbClearEnabled), @('FBClearWindowsSupportPresent', $fbClearReported), @('SBDRSSDPHardwareVulnerable', $sbdrSsdpHardwareVulnerableVal), @('FBSDPHardwareVulnerable', $fbsdpHardwareVulnerableVal), @('PSDPHardwareVulnerable', $psdpHardwareVulnerableVal), @('FBClearWindowsSupportEnabled', $fbClearEnabled), @('BhbEnabled', $bhbEnabled), @('BhbDisabledSystemPolicy', $bhbDisabledSystemPolicy), @('BhbDisabledNoHardwareSupport', $bhbDisabledNoHardwareSupport), @('BranchConfusionReported', $branchConfusionReported), @('BranchConfusionStatus', $branchConfusionString), @('GdsReported', $gdsReported), @('GdsStatus', $gdsString), @('SrsoReported', $srsoReported), @('SrsoStatus', $srsoString), @('DivideByZeroReported', $divideByZeroReported), @('DivideByZeroStatus', $divideByZeroString), @('RfdsReported', $rfdsReported), @('RfdsStatus', $rfdsString) ) foreach ($p in $props) { try { $name = $p[0].PadRight(40) $val = $p[1] Write-Host " $name`: $val" } catch { Write-Host " ERROR processing prop: $_" } } Write-Host '' $msActions = @() if (($btiWindowsSupportPresent -eq $false) -or ($kvaShadowPresent -eq $false) -or ($ssbdAvailable -eq $false) -or ($l1tfMitigationPresent -eq $false) -or ($mdsMbClearReported -eq $false) -or ($fbClearReported -eq $false) -or ($rdclHardwareProtectedReported -eq $false)) { $msActions += 'Install the latest available updates for Windows with support for speculation control mitigations.' } if (($btiWindowsSupportPresent -eq $true -and $btiWindowsSupportEnabled -eq $false) -or ($kvaShadowRequired -eq $true -and $kvaShadowEnabled -eq $false) -or ($l1tfRequired -eq $true -and $l1tfMitigationEnabled -eq $false) -or ($mdsMbClearReported -eq $true -and $mdsHardwareProtected -eq $false -and $mdsMbClearEnabled -eq $false) -or ($fbClearReported -eq $true -and $sbdrSsdpHardwareProtected -eq $false -and $fbClearEnabled -eq $false) -or ($fbClearReported -eq $true -and $fbsdpHardwareProtected -eq $false -and $fbClearEnabled -eq $false) -or ($fbClearReported -eq $true -and $psdpHardwareProtected -eq $false -and $fbClearEnabled -eq $false)) { $guidanceUri = "" if ($os.ProductType -eq 1) { $guidanceUri = "https://support.microsoft.com/help/4073119" } else { $guidanceUri = "https://support.microsoft.com/help/4072698" } $msActions += "Follow the guidance for enabling Windows support for speculation control mitigations described in $guidanceUri" } if ($msActions.Count -gt 0) { Write-Host ' SUGGESTED ACTIONS' -ForegroundColor Yellow Write-Host $thinDivider -ForegroundColor DarkGray foreach ($action in $msActions) { Write-Host " * $action" } Write-Host '' } Write-Host ' REFERENCES' -ForegroundColor Yellow Write-Host $thinDivider -ForegroundColor DarkGray Write-Host ' Microsoft Guidance : https://support.microsoft.com/help/4074629' Write-Host ' Windows Speculative Execution Mitigations: https://portal.msrc.microsoft.com/en-us/security-guidance/advisory/ADV180002' Write-Host '' Write-Host $divider -ForegroundColor Cyan Write-Host ' END OF REPORT' -ForegroundColor White Write-Host $divider -ForegroundColor Cyan Write-Host '' if ($OutputXml) { if (-not $OutputPath) { $timestamp = Get-Date -Format 'yyyyMMdd_HHmmss' $OutputPath = Join-Path $env:TEMP "SpeculativeMitigation_$env:COMPUTERNAME`_$timestamp.xml" } Write-Host 'Exporting XML report...' -ForegroundColor Cyan try { $xmlReport = Export-MitigationReportToXml -Report $report -OutputPath $OutputPath Write-Host "XML report saved to: $OutputPath" -ForegroundColor Green } catch { Write-Warning "Failed to export XML report: $_" } } if ($ptr -ne [System.IntPtr]::Zero) { [System.Runtime.InteropServices.Marshal]::FreeHGlobal($ptr) } if ($retLen -ne [System.IntPtr]::Zero) { [System.Runtime.InteropServices.Marshal]::FreeHGlobal($retLen) } } Main |