<# .SYNOPSIS CVE Detection - CVE-2022-41099 .DESCRIPTION This script mounts the Windows Recovery Environment (WinRE) image and tests whether it is vulnerable to CVE-2022-41099 or whether it is of sufficient version or contains the correct packages to be considered patched against the CVE. .NOTES 2023-04-13: Checks for the vulnerability status are now more explicity and the script will equivocate if it cannot determine the status. 2023-03-24: Now checks whether Windows Recovery Environment (WinRE) is enabled before attempting to check the WinRE image. 2023-03-21: Major refactor, now supports checking for the presence of the SafeOS Dynamic Update packages. 2023-01-17: Better logic, more versions of Windows supported. 2023-01-13: Initial version .LINK Blog post: https://homotechsual.dev/2023/03/15/CVE-Monitoring-NinjaOne/ #> [CmdletBinding()] param ( [Parameter(ParameterSetName = 'Package', Mandatory = $true)] [Switch]$CheckPackage, [Parameter(ParameterSetName = 'Image', Mandatory = $true)] [Switch]$CheckImage, [Parameter(ParameterSetName = 'Package')] [System.IO.DirectoryInfo]$MountDirectory = 'C:\RMM\WinRE\Mount', [Parameter(ParameterSetName = 'Package')] [System.IO.DirectoryInfo]$LogDirectory = 'C:\RMM\WinRE\Logs' ) $WinREEnabled = (reagentc /info | findstr 'Enabled').Replace('Windows RE status: ', '').Trim() if (-not ($WinREEnabled)) { Write-Warning 'Windows RE is disabled - exiting...' return $false } $WinREImagePath = (reagentc /info | findstr '\\?\GLOBALROOT\device').Replace('Windows RE location: ', '').Trim() + '\winre.wim' $WinREBuild = (Get-WindowsImage -ImagePath $WinREImagePath -Index 1).SPBuild # $WinREModified = (Get-WindowsImage -ImagePath $WinREImagePath -Index 1).ModifiedTime $WinOSBuild = [System.Environment]::OSVersion.Version.Build $BuildtoKBMap = @{ 22623 = 5023527 22621 = 5023527 22000 = 5021040 19045 = 5021043 19044 = 5021043 19043 = 5021043 19042 = 5021043 } function Mount-WinRE { if (-not(Test-Path $MountDirectory)) { New-Item $MountDirectory -ItemType Directory } else { $MountDirectoryContents = Get-ChildItem $MountDirectory if ($MountDirectoryContents) { Write-Warning "Mount directory isn't empty - exiting..." return $false } } if ((Get-WindowsImage -Mounted).count -ge 1) { Write-Warning 'There is at least one other image mounted already = exiting...' return $false } $Mount = ReAgentC.exe /mountre /path $MountDirectory if ($Mount) { if ($Mount[0] -notmatch '.*\d+.*' -and (Get-WindowsImage -Mounted).count -ge 1 -and $LASTEXITCODE -eq 0) { return $true } } else { Write-Warning 'Could not mount WinRE image.' Write-Warning "$Mount" return $false } } function Dismount-WinRE { $DismountImageLogFile = Join-Path -Path $LogDirectory -ChildPath ('Dismount-WindowsImage_{0}.log' -f $DateTime) $DismountWinRECommonParameters = @{ Path = $MountDirectory LogLevel = 'WarningsInfo' } $UnmountDiscard = ReAgentC.exe /unmountre /path $($MountDirectory) /discard if (($UnmountDiscard[0] -match '.*\d+.*') -or $LASTEXITCODE -ne 0) { Write-Warning 'Attempting to unmount and discard failed - trying alternative method' Dismount-WindowsImage @DismountWinRECommonParameters -LogPath $DismountImageLogFile -Discard if ($(Get-WindowsImage -Mounted).count -ge 1) { Write-Warning 'Unmounting failed, including alternative methods.' return $false } else { return $true } } else { return $true } } if ($CheckPackage) { if (-not (Mount-WinRE)) { Write-Warning 'Could not mount WinRE image - exiting...' exit 1 } $KB = ('KB{0}' -f $BuildtoKBMap[$WinOSBuild]) $PackageApplied = (Get-WindowsPackage -Path $MountDirectory | Where-Object { $_.PackageName -like "*$KB*" }).PackageState -eq 'Installed' if (-not (Dismount-WinRE)) { Write-Warning 'Could not dismount WinRE image - exiting...' exit 1 } if (-not ($PackageApplied)) { Write-Warning 'SafeOS Dynamic Update Package not present in WinRE image.' $Vulnerable = $true } else { Write-Output 'SafeOS Dynamic Update Package present in WinRE image.' $Vulnerable = $false } } if ($CheckImage) { if (($WinOSBuild -in @(22623, 22621)) -and ($WinREBuild -lt 1105)) { $Vulnerable = $true } elseif (($WinOSBuild -eq 22000) -and ($WinREBuild -lt 1455)) { $Vulnerable = $true } elseif (($WinOSBuild -in @(19045, 19044, 19042)) -and ($WinREBuild -lt 2486)) { $Vulnerable = $true } elseif (($WinOSBuild -eq 19043) -and ($WinREBuild -lt 2364)) { $Vulnerable = $true } else { $Vulnerable = $false } } if ($true -eq $Vulnerable) { Write-Warning 'Vulnerable to CVE-2022-41099' Ninja-Property-Set CVE202241099 1 } elseif ($false -eq $Vulnerable) { Write-Output 'Not vulnerable to CVE-2022-41099' Ninja-Property-Set CVE202241099 0 } else { Write-Warning 'Could not determine vulnerability status.' }