Verifying Spectre / Meltdown protections remotely


In this post we will take a look at the SpeculationControl PowerShell module that was recently released by the Microsoft Security Response Center to help with verifying Spectre / Meltdown protections.

SpeculationControl can be found on the PowerShell Gallery at the following link: https://www.powershellgallery.com/packages/SpeculationControl

Installing this module onto a system adds a new function called Get-SpeculationControlSettings and this function can be run on a system to provide details on whether Spectre / Meltdown protections have been enabled.

What if you wanted to run this remotely against multiple systems?

To run the Get-SpeculationControlSettings function against multiple systems, see the example code below:
(Credit goes to Keith Hitchcock for his help on this)

This example only requires that you have the SpeculationControl PowerShell module installed on the system that you execute this code from. Because of the way the Get-SpeculationControlSettings function is structured, we can simply load the function remotely as part of the call to Invoke-Command.

In order to run this sample code in an environment, the only update required is the list of machines that follow -ComputerName. If you prefer to pass in a list of systems in a text file, the sample code can easily be modified to take in an input text file by utilizing the Get-Content cmdlet.

Sample output

While this is nice, we can take things a step further by outputting the results to CSV which will make things easier to consume, especially as we start adding more systems to the list.

Example code below:

Sample output

This is now easier to digest, and we can sort and apply filters as needed.

At this point, we have taken the SpeculationControl PowerShell module and run it through a few examples that take it beyond local execution and help us review remote systems in an environment.

Next, we will take a look at using the SpeculationControl PowerShell module along with another PowerShell module called DSCEA. DSCEA provides configuration testing and reporting capabilities for Windows based systems, and we will take a look at how we can use it to gain some intelligence from the data that we are able to gather remotely.

For example, let’s say your management team is looking for numbers, specifically how many machines exist in your environment that have not yet been patched for the CVE-2017-5754 rogue data cache load (Meltdown) vulnerability.

While we could ask someone to look through the CSV file and compare systems across multiple columns, I’d rather have a computer provide me with this information.

There are a few points to make though before we go down the DSCEA path. DSCEA requires a minimum PowerShell version of 5.0, with 5.1 being recommended. Also, DSCEA would require that the SpeculationControl PowerShell module be installed on all endpoints that are being scanned. While there are some easy ways to handle this which include pushing out a DSC configuration that utilizes the DSC File resource, or just a file copy script, for this example I am including the entire Get-SpeculationControlSettings function as a part of my custom DSC configuration. This just makes this a whole lot easier to demonstrate, but it does require code updates if there are updates to the SpeculationControl PowerShell module in the future.

This section will assume you have downloaded DSCEA and have some knowledge of its usage. If you don’t, click here to learn more.

I have copied the DSC configuration at the end of this post that will be used to verify if systems have been patched for Meltdown. You will use this configuration to build a MOF file that you will use with DSCEA to scan systems to see if they have the proper updates and configurations enabled.

The configuration comes with the following logic defined to determine if a system has been properly configured in regards to Meltdown:

DSCEA HTML Report Example
In this case, all 3 systems are non-compliant, meaning they need to be reviewed to get the proper updates and settings applied.

DSC Configuration


Comments (17)

  1. Rob Beyreis says:

    Powershell on my system bonks on the complication to scriptblock. Needed to strip the signature to get that approach working: $scriptstring = Get-Content -Path (Get-Module SpeculationControl).Path | % { if (-not ($_ -match “^\# “)) { $_ }} | Out-String

    1. Ralph Kyttle says:

      Thank you Rob! It looks like my code samples ran into issues once the module was updated with a signature block. I have integrated your suggestion into the code and everything seems to be working properly now. For those with comments below that relate to this issue, please grab the new code snippets and try again. I have updated both the PowerShell and DSC code.

  2. Mikael Andersson says:

    When running “$script=[scriptblock]::create($scriptstring)” I get this error:

    Exception calling “Create” with “1” argument(s): “At line:407 char:1
    + function Write-Host {}Get-SpeculationControlSettings
    + ~~~~~~~~~~~~~~~~~~~~~~
    Executable script code found in signature block.
    At line:407 char:23
    + function Write-Host {}Get-SpeculationControlSettings
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Executable script code found in signature block.”
    At line:1 char:1
    + $script=[scriptblock]::create($scriptstring)
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : ParseException

  3. SunnyN says:

    I seem to be having trouble running the scriptblock (I am running this on 5.1). I get a “Executable script code found in signature block”.

    Also, the DSC Configuration seems to have errors.

  4. Javier Lleo says:

    Great Job!!!!, Thank u!!

  5. I think one of the best practicies to overcome meltdown is using this website first :
    https://meltdownattack.com/

    by the way, your post was quite interesting, thank you!

  6. BritV8 says:

    Hi Ralph great if you use DSC, but I am looking for SCCM compliance settings , any idea if your colleagues in SCCM land are looking to do something similar to assist an enterprise looking to manage this path release?

    1. Ralph Kyttle says:

      Hi BritV8, please review the following sample that Ken Wygant, Microsoft Sr PFE – Configuration Manager has shared out:
      https://twitter.com/pfeken/status/949395268696530945

  7. Dave says:

    I receive:
    Exception calling “Create” with “1” argument(s): “At line:407 char:1
    + function Write-Host {}Get-SpeculationControlSettings
    + ~~~~~~~~~~~~~~~~~~~~~~
    Executable script code found in signature block.
    At line:407 char:23
    + function Write-Host {}Get-SpeculationControlSettings
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Executable script code found in signature block.”
    At line:7 char:1
    + $scriptblock = [scriptblock]::create($scriptstring)
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : ParseException

    Invoke-Command : Cannot validate argument on parameter ‘ScriptBlock’. The argument is null. Provide a valid value
    for the argument, and then try running the command again.
    At line:9 char:55
    + Invoke-Command -ComputerName COMPUTER -ScriptBlock $scriptblock
    + ~~~~~~~~~~~~
    + CategoryInfo : InvalidData: (:) [Invoke-Command], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.InvokeCommandCommand

  8. I wrote a little wrapper script for this, hope you find it useful.

    function Get-SpectreMeltdownStatus
    {

    [CmdletBinding()]
    Param
    (
    # Computername
    [Parameter(Mandatory=$true,
    ValueFromPipelineByPropertyName=$true,
    Position=0)]
    [ValidateNotNullOrEmpty()]
    [string[]]$ComputerName,

    #The Full FileName of the export file.

    [Parameter(Mandatory=$true,
    ValueFromPipelineByPropertyName=$true,
    Position=0)]
    [ValidateNotNullOrEmpty()]
    [string[]]$ExportFileName

    )
    Begin
    {
    if (-not(Get-Module -name SpeculationControl)){
    Try{
    Import-Module Import-Module SpeculationControl
    }
    Catch{
    Write-Warning “PowerShell Module SpeculationControl is not installed on this client”
    Write-Warning “Install module first: https://www.powershellgallery.com/packages/SpeculationControl/1.0.2
    Throw
    }
    }
    }
    Process
    {

    $OutPut = @()
    ForEach ($RemoteComp in $ComputerName)
    {
    Write-Verbose “Processing: $RemoteComp”
    $scriptstring = Get-Content -Path (Get-Module SpeculationControl).Path | % { if (-not ($_ -match “^\# “)) { $_ }} | Out-String
    $scriptstring +=
    function Write-Host {}

    $scriptstring += “Get-SpeculationControlSettings”
    $script=[scriptblock]::create($scriptstring)
    $results = Invoke-Command -ComputerName $RemoteComp -ScriptBlock $script

    $compliance = $false
    if ($results.KVAShadowRequired -eq $False) {
    $compliance = $True
    }

    elseif ($results.KVAShadowRequired -eq $True -and `
    $results.KVAShadowWindowsSupportPresent -eq $True -and `
    $results.KVAShadowWindowsSupportEnabled -eq $True -and `
    $results.KVAShadowPcidEnabled -eq $True) {
    $compliance = $True
    }
    Write-Verbose “Compliance: $($compliance)”
    $results | Add-Member -MemberType NoteProperty -Name “Compliant” -Value $compliance
    $OutPut = $OutPut + $results
    }
    }
    End
    {
    Write-Verbose “Exporting Results to $ExportFileName”
    If (Test-Path $ExportFileName)
    {
    Write-Warning “File $ExportFileName already exists, delete the file manually or specify another file name”
    }
    Else
    {
    $OutPut | Export-Csv -Path “$ExportFileName” -NoTypeInformation -NoClobber
    }
    }
    }

  9. Steven W says:

    Thanks guys!
    To mitigate this completely you’d have to install a patch right? (Windows patch and Vendor patch)
    I can see the vendor patch could be a challenge for you to control, but ideally the script should check for installed Microsoft patches.
    I’m struggling a little to find which hotfix to check for. What to you recommend to check for? – KB 4056888-4056892 or 4054022?

    Secondly – The script returns $compliance = true if the KVAShadowRequired is disabled – regardsless of any of the remaining “KVA…” settings? And if KVAShadowRequired is enabled – all 4 “KVA..” settings has to be true to be compliant.
    I’m asking since there are already a bunch of alternative checks available and I see some conflicting messages.
    Can you provide any input to make the check even more effecient?

  10. Dan says:

    Running this against various lists of servers, I receive repeated instances of the following error:

    Unsupported processor manufacturer:
    + CategoryInfo : OperationStopped: (Unsupported processor manufacturer: :String) [], RuntimeException
    + FullyQualifiedErrorId : Unsupported processor manufacturer:
    + PSComputerName :

  11. Teddy R says:

    I can’t get these scripts to work. They run until they hit the first error and then stop operating. The error is:

    Unsupported processor manufacturer:
    At script.ps1:22 char:1
    + $results = Invoke-Command -ComputerName $Server -ScriptBlock $script -ErrorActio …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : OperationStopped: (Unsupported processor manufacturer: :String) [], RuntimeException
    + FullyQualifiedErrorId : Unsupported processor manufacturer:

    1. Ralph Kyttle says:

      Teddy R and Dan, take a look at the source code for the Get-SpeculationControlSettings function in the DSC configuration that I included above (SpeculationControlSettings5.ps1)

      Line 157 showcases the message you are seeing, and we can see that the function logic will return this when your CPU manufacturer does not match either AuthenticAMD or GenuineIntel

      You can run the following PowerShell code on one of your affected systems to see what is returned as the CPU manufacturer:
      $cpu = Get-WmiObject Win32_Processor
      $cpu.Manufacturer

      1. Mark Wolsey says:

        In some cases I have this, it appears to be the Model number that is not matching, yet am sure the CPU is on the affected hardware list.

        One example I have gives this on the WMI query:

        Intel(R) Xeon(R) CPU E5-2630 v3 @ 2.40GHz
        Intel64 Family 6 Model 63 Stepping 2
        63 = 0x3F in Hex and is not in the script. Is this an unaffected CPU?

        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
        }

        1. Bill Becker says:

          The code above for verifying the CPU manufacturer does not support multiple CPUs.

Skip to main content