SpeculationControlCompliance.ps1
#Requires -Version 2 <#PSScriptInfo .VERSION 1.1 .GUID 603a9cb0-cf96-4f68-8edb-e4dd22f2369a .AUTHOR Merlin from Belgium .COMPANYNAME .COPYRIGHT .TAGS Security ADV180002 Compliance Windows Meltdown Spectre .LICENSEURI .PROJECTURI .ICONURI .EXTERNALMODULEDEPENDENCIES .REQUIREDSCRIPTS .EXTERNALSCRIPTDEPENDENCIES .RELEASENOTES #> <# .SYNOPSIS Script to detect and report compliance on speculation control settings on a system in light of the #Meltdown and #Spectre CPU vulnerabilities. .DESCRIPTION Jan 9 2018, Created by Merlin from Belgium @merlin_with_a_j Original function Get-SpeculationControlSettings written by Matt Miller @MS Securirty Response team. Taken from https://www.powershellgallery.com/packages/SpeculationControl/1.0.3 Script modified to write values to registry instead of console output. - all Write-Host lines replaced by Write-Verbose - $regpath can be changed to a custom path .PARAMETER regpath Choose a custom registry path to write the compliance results to. Must be a valid registry path accessible to SYSTEM or to the user in whose context the script is run. .EXAMPLE Get-SpeculationControlCompliance Detect compliance and writes results to 'HKLM:\SOFTWARE\ConfigMgr\SpeculationControl' .EXAMPLE Get-SpeculationControlCompliance -regpath 'HKLM:\SOFTWARE\<yourchoice>' Detect compliance and writes results to 'HKLM:\SOFTWARE\<yourchoice>' .EXAMPLE Get-SpeculationControlCompliance -Verbose Writes output to the console as the original script would, without the pretty colours though. .LINK https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/ADV180002 .LINK https://www.powershellgallery.com/packages/SpeculationControl #> param ( [String] [Parameter(Mandatory = $false, HelpMessage='Choose a custom registry path to write the compliance results to.')] [ValidateScript({if (!(Test-Path -Path $_)) {New-Item -Path $_ -Force -ea Stop} else {$true}})] $regpath = 'HKLM:\SOFTWARE\ConfigMgr\SpeculationControl' ) begin { function Get-SpeculationControlSettings { <# .SYNOPSIS This function queries the speculation control settings for the system. � .DESCRIPTION This function queries the speculation control settings for the system. � Version 1.3. #> [CmdletBinding()] param ( ) process { $NtQSIDefinition = @' [DllImport("ntdll.dll")] public static extern int NtQuerySystemInformation(uint systemInformationClass, IntPtr systemInformation, uint systemInformationLength, IntPtr returnLength); '@ $ntdll = Add-Type -MemberDefinition $NtQSIDefinition -Name 'ntdll' -Namespace 'Win32' -PassThru [System.IntPtr]$systemInformationPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal(4) [System.IntPtr]$returnLengthPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal(4) $object = New-Object -TypeName PSObject try { # # Query branch target injection information. # Write-Verbose -Message "Speculation control settings for CVE-2017-5715 [branch target injection]" $btiHardwarePresent = $false $btiWindowsSupportPresent = $false $btiWindowsSupportEnabled = $false $btiDisabledBySystemPolicy = $false $btiDisabledByNoHardwareSupport = $false [System.UInt32]$systemInformationClass = 201 [System.UInt32]$systemInformationLength = 4 $retval = $ntdll::NtQuerySystemInformation($systemInformationClass, $systemInformationPtr, $systemInformationLength, $returnLengthPtr) if ($retval -eq 0xc0000003 -or $retval -eq 0xc0000002) { # fallthrough } elseif ($retval -ne 0) { throw (("Querying branch target injection information failed with error {0:X8}" -f $retval)) } else { [System.UInt32]$scfBpbEnabled = 0x01 [System.UInt32]$scfBpbDisabledSystemPolicy = 0x02 [System.UInt32]$scfBpbDisabledNoHardwareSupport = 0x04 [System.UInt32]$scfHwReg1Enumerated = 0x08 [System.UInt32]$scfHwReg2Enumerated = 0x10 [System.UInt32]$scfHwMode1Present = 0x20 [System.UInt32]$scfHwMode2Present = 0x40 [System.UInt32]$scfSmepPresent = 0x80 [System.UInt32]$flags = [System.UInt32][System.Runtime.InteropServices.Marshal]::ReadInt32($systemInformationPtr) $btiHardwarePresent = ((($flags -band $scfHwReg1Enumerated) -ne 0) -or (($flags -band $scfHwReg2Enumerated))) $btiWindowsSupportPresent = $true $btiWindowsSupportEnabled = (($flags -band $scfBpbEnabled) -ne 0) if ($btiWindowsSupportEnabled -eq $false) { $btiDisabledBySystemPolicy = (($flags -band $scfBpbDisabledSystemPolicy) -ne 0) $btiDisabledByNoHardwareSupport = (($flags -band $scfBpbDisabledNoHardwareSupport) -ne 0) } if ($PSBoundParameters['Verbose']) { Write-Verbose -Message "BpbEnabled : $(($flags -band $scfBpbEnabled) -ne 0)" Write-Verbose -Message "BpbDisabledSystemPolicy : $(($flags -band $scfBpbDisabledSystemPolicy) -ne 0)" Write-Verbose -Message "BpbDisabledNoHardwareSupport : $(($flags -band $scfBpbDisabledNoHardwareSupport) -ne 0)" Write-Verbose -Message "HwReg1Enumerated : $(($flags -band $scfHwReg1Enumerated) -ne 0)" Write-Verbose -Message "HwReg2Enumerated : $(($flags -band $scfHwReg2Enumerated) -ne 0)" Write-Verbose -Message "HwMode1Present : $(($flags -band $scfHwMode1Present) -ne 0)" Write-Verbose -Message "HwMode2Present : $(($flags -band $scfHwMode2Present) -ne 0)" Write-Verbose -Message "SmepPresent : $(($flags -band $scfSmepPresent) -ne 0)" } } Write-Verbose -Message "Hardware support for branch target injection mitigation is present: $btiHardwarePresent" Write-Verbose -Message "Windows OS support for branch target injection mitigation is present: $btiWindowsSupportPresent" Write-Verbose -Message "Windows OS support for branch target injection mitigation is enabled: $btiWindowsSupportEnabled" if ($btiWindowsSupportPresent -eq $true -and $btiWindowsSupportEnabled -eq $false) { Write-Verbose -Message "Windows OS support for branch target injection mitigation is disabled by system policy: $btiDisabledBySystemPolicy" Write-Verbose -Message "Windows OS support for branch target injection mitigation is disabled by absence of hardware support: $btiDisabledByNoHardwareSupport" } $object | Add-Member -MemberType NoteProperty -Name BTIHardwarePresent -Value $btiHardwarePresent $object | Add-Member -MemberType NoteProperty -Name BTIWindowsSupportPresent -Value $btiWindowsSupportPresent $object | Add-Member -MemberType NoteProperty -Name BTIWindowsSupportEnabled -Value $btiWindowsSupportEnabled $object | Add-Member -MemberType NoteProperty -Name BTIDisabledBySystemPolicy -Value $btiDisabledBySystemPolicy $object | Add-Member -MemberType NoteProperty -Name BTIDisabledByNoHardwareSupport -Value $btiDisabledByNoHardwareSupport # # Query kernel VA shadow information. # Write-Verbose -Message "Speculation control settings for CVE-2017-5754 [rogue data cache load]" $kvaShadowRequired = $true $kvaShadowPresent = $false $kvaShadowEnabled = $false $kvaShadowPcidEnabled = $false $cpu = Get-WmiObject -Class Win32_Processor if ($cpu.Manufacturer -eq "AuthenticAMD") { $kvaShadowRequired = $false } elseif ($cpu.Manufacturer -eq "GenuineIntel") { $regex = [regex]'Family (\d+) Model (\d+) Stepping (\d+)' $result = $regex.Match($cpu.Description) if ($result.Success) { $family = [System.UInt32]$result.Groups[1].Value $model = [System.UInt32]$result.Groups[2].Value $stepping = [System.UInt32]$result.Groups[3].Value if (($family -eq 0x6) -and (($model -eq 0x1c) -or ($model -eq 0x26) -or ($model -eq 0x27) -or ($model -eq 0x36) -or ($model -eq 0x35))) { $kvaShadowRequired = $false } } } else { throw ("Unsupported processor manufacturer: {0}" -f $cpu.Manufacturer) } [System.UInt32]$systemInformationClass = 196 [System.UInt32]$systemInformationLength = 4 $retval = $ntdll::NtQuerySystemInformation($systemInformationClass, $systemInformationPtr, $systemInformationLength, $returnLengthPtr) if ($retval -eq 0xc0000003 -or $retval -eq 0xc0000002) { } elseif ($retval -ne 0) { throw (("Querying kernel VA shadow information failed with error {0:X8}" -f $retval)) } else { [System.UInt32]$kvaShadowEnabledFlag = 0x01 [System.UInt32]$kvaShadowUserGlobalFlag = 0x02 [System.UInt32]$kvaShadowPcidFlag = 0x04 [System.UInt32]$kvaShadowInvpcidFlag = 0x08 [System.UInt32]$flags = [System.UInt32][System.Runtime.InteropServices.Marshal]::ReadInt32($systemInformationPtr) $kvaShadowPresent = $true $kvaShadowEnabled = (($flags -band $kvaShadowEnabledFlag) -ne 0) $kvaShadowPcidEnabled = ((($flags -band $kvaShadowPcidFlag) -ne 0) -and (($flags -band $kvaShadowInvpcidFlag) -ne 0)) if ($PSBoundParameters['Verbose']) { Write-Verbose -Message "KvaShadowEnabled : $(($flags -band $kvaShadowEnabledFlag) -ne 0)" Write-Verbose -Message "KvaShadowUserGlobal : $(($flags -band $kvaShadowUserGlobalFlag) -ne 0)" Write-Verbose -Message "KvaShadowPcid : $(($flags -band $kvaShadowPcidFlag) -ne 0)" Write-Verbose -Message "KvaShadowInvpcid : $(($flags -band $kvaShadowInvpcidFlag) -ne 0)" } } Write-Verbose -Message "Hardware requires kernel VA shadowing: $kvaShadowRequired" if ($kvaShadowRequired) { Write-Verbose -Message "Windows OS support for kernel VA shadow is present: $kvaShadowPresent" Write-Verbose -Message "Windows OS support for kernel VA shadow is enabled: $kvaShadowEnabled" if ($kvaShadowEnabled) { Write-Verbose -Message "Windows OS support for PCID optimization is enabled: $kvaShadowPcidEnabled" } } $object | Add-Member -MemberType NoteProperty -Name KVAShadowRequired -Value $kvaShadowRequired $object | Add-Member -MemberType NoteProperty -Name KVAShadowWindowsSupportPresent -Value $kvaShadowPresent $object | Add-Member -MemberType NoteProperty -Name KVAShadowWindowsSupportEnabled -Value $kvaShadowEnabled $object | Add-Member -MemberType NoteProperty -Name KVAShadowPcidEnabled -Value $kvaShadowPcidEnabled # # Provide guidance as appropriate. # $actions = @() if ($btiHardwarePresent -eq $false) { $actions += "Install BIOS/firmware update provided by your device OEM that enables hardware support for the branch target injection mitigation." } if ($btiWindowsSupportPresent -eq $false -or $kvaShadowPresent -eq $false) { $actions += "Install the latest available updates for Windows with support for speculation control mitigations." } if ($btiWindowsSupportEnabled -eq $false -or ($kvaShadowRequired -eq $true -and $kvaShadowEnabled -eq $false)) { $actions += "Follow the guidance for enabling Windows support for speculation control mitigations are described in https://support.microsoft.com/help/4072698" } if ($actions.Length -gt 0) { Write-Verbose -Message "Suggested actions" foreach ($action in $actions) { Write-Verbose -Message " *$action" } } Write-Registry -object $object -regpath $regpath #return $object } finally { if ($systemInformationPtr -ne [System.IntPtr]::Zero) { [System.Runtime.InteropServices.Marshal]::FreeHGlobal($systemInformationPtr) } if ($returnLengthPtr -ne [System.IntPtr]::Zero) { [System.Runtime.InteropServices.Marshal]::FreeHGlobal($returnLengthPtr) } } } } function Write-Registry { param ( [String] [Parameter(Mandatory = $true)] [ValidateScript({if (!(Test-Path -Path $_)) {New-Item -Path $_ -Force -ea Stop} else {$true}})] $regpath, [psobject] [Parameter(Mandatory = $true)] $object ) process { try { foreach ($property in (Get-Member -InputObject $object -MemberType NoteProperty)) { $null = New-ItemProperty -Path $regpath -Name $property.Name -Value $object.($property.Name) -Force } } catch { "Error was $_" $line = $_.InvocationInfo.ScriptLineNumber "Error was in Line $line" } } } } process { Get-SpeculationControlSettings } end {} # SIG # Begin signature block # MIIEAgYJKoZIhvcNAQcCoIID8zCCA+8CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUAZbHVF5YVBAeScRfXCPJUOnt # cEGgggIVMIICETCCAXqgAwIBAgIQIEdYbegzX6dDmpkHwr7+mDANBgkqhkiG9w0B # AQUFADAjMSEwHwYDVQQDDBhNZXJsaWpuIFZhbiBXYWV5ZW5iZXJnaGUwHhcNMTgw # MTA5MDgwMzM2WhcNMjIwMTA5MDAwMDAwWjAjMSEwHwYDVQQDDBhNZXJsaWpuIFZh # biBXYWV5ZW5iZXJnaGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOPuMwFv # 6WNsq6QnhpQtFrSD5D+FQoDZMwz7gWrI3h4GriZbbOKn8EvMY8ihdaW+8Ayzn+iW # RiERlPfSyl3D9Nnktkg2uO5Y3qZhnOxxnnID/rfq5GQrjiEeNpLQxUW4ZQCgPcnf # wKgFA7VzwjWUFCS2ag7Aa1AJRf0e8Fs3/02jAgMBAAGjRjBEMBMGA1UdJQQMMAoG # CCsGAQUFBwMDMB0GA1UdDgQWBBRBgg9RMriUceIJycTznHTAmmkMPTAOBgNVHQ8B # Af8EBAMCB4AwDQYJKoZIhvcNAQEFBQADgYEAgnolmwaMgBRww9GfnGSRfLy8Qm7q # 3+4B/WfOQPIf1wKpEUmDMe6xifDDnBdPdEPMYJUU9sIyJgxQ/LlFsXfhzVWxijKA # EkfNHoHmcif50MM/S/iphBYYboY3AfyNAqcuu2srjBCwVCIA/Bz+/NNZ+YUXtoz8 # ymtSJEgw3NKDhmYxggFXMIIBUwIBATA3MCMxITAfBgNVBAMMGE1lcmxpam4gVmFu # IFdhZXllbmJlcmdoZQIQIEdYbegzX6dDmpkHwr7+mDAJBgUrDgMCGgUAoHgwGAYK # KwYBBAGCNwIBDDEKMAigAoAAoQKAADAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIB # BDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAjBgkqhkiG9w0BCQQxFgQU # RMV9q5DN0sVymEpeNjseV9rhmcowDQYJKoZIhvcNAQEBBQAEgYBAFrfOoa/GNgq2 # qaWbMAT1HSfGRmHTjRox11NucpfsrplsqPWJdsG7U7/KlmAqxglrAHNF5O6Z9vPD # m4zRX3Ib43ze6UU4ne6KLIhs6cUVjsmmB4gG8kTAL6vjtchz1Xmt14wbVB4KFxxm # WTSyV73xHm/pNJEgcCki9UhLReu2dw== # SIG # End signature block |