<# .SYNOPSIS CVE Detection - CVE-2023-23397.ps1 .DESCRIPTION This script checks the installed version of Office "Click-to-Run" installations to ascertain whether the installed version is vulnerable to CVE-2023-23397 which affects Outlook for Windows. .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-17: Fix URL handling to avoid errors when the key exists with a null value. 2023-03-17: Improved output, fixed a bug where the update channel GUID was failing to match despite actually matching! 2023-03-17: Silently continue if missing registry properties. 2023-03-17: Handle more Office update channel configuration locations. Fix incorrect channel detection logic when using the GPO UpdateChannel. 2023-03-16: Check versions using a "less than" comparison for vulnerability to allow future proof usage. 2023-03-16: Check GPO channel config, adjust target version for Semi-Annual Enterprise (Preview) channel, fix Write-Warning/Write-Output mixup, more output info. 2023-03-16: Fix O365 app misdetection, better error handling, don't omit warning on success. 2023-03-15: Initial version .LINK Blog post: https://homotechsual.dev/2023/03/15/CVE-Monitoring-NinjaOne/ #> $IsC2R = Test-Path 'HKLM:\SOFTWARE\Microsoft\Office\ClickToRun' if ($IsC2R) { # Get the installed Office Version $OfficeVersion = [version]( Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Office\ClickToRun\Configuration' | Select-Object -ExpandProperty VersionToReport ) # Get the installed Office Product IDs $OfficeProductIds = ( Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Office\ClickToRun\Configuration' | Select-Object -ExpandProperty ProductReleaseIds ) } else { Write-Error 'No Click-to-Run Office installation detected. This script only works with Click-to-Run Office installations.' Exit 1 } $IsO365 = $OfficeProductIds -like '*O365*' if ($IsO365) { # Check the Office GPO settings for the update channel. $OfficeUpdateChannelGPO = (Get-ItemProperty -Path 'HKLM:\SOFTWARE\Policies\Microsoft\Office\16.0\Common\OfficeUpdate' -ErrorAction 'SilentlyContinue' | Select-Object -ExpandProperty UpdateBranch -ErrorAction 'SilentlyContinue') if ($OfficeUpdateChannelGPO) { Write-Output 'Office is configured to use a GPO update channel.' # Define the Office Update Channels $Channels = @( @{ ID = 'Current' Name = 'Current' PatchedVersion = [version]'16.0.16130.20306' }, @{ ID = 'FirstReleaseCurrent' Name = 'Current (Preview)' PatchedVersion = [version]'16.0.16227.20094' }, @{ ID = 'MonthlyEnterprise' Name = 'Monthly Enterprise' PatchedVersion = [version]'16.0.16026.20238' }, @{ ID = 'Deferred' Name = 'Semi-Annual Enterprise' PatchedVersion = [version]'16.0.15601.20578' }, @{ # This does not match Microsoft's documented version but is the latest available update on tested SAE-Preview channel installations. ID = 'FirstReleaseDeferred' Name = 'Semi-Annual Enterprise (Preview)' PatchedVersion = [version]'16.0.16026.20238' }, @{ ID = 'InsiderFast' Name = 'Beta' PatchedVersion = [version]'16.0.16310.20000' } ) foreach ($Channel in $Channels) { if ($OfficeUpdateChannelGPO -eq $Channel.ID) { $OfficeChannel = $Channel } } } else { $C2RConfigurationPath = 'HKLM:\SOFTWARE\Microsoft\Office\ClickToRun\Configuration' Write-Output 'Office is not configured to use a GPO update channel.' # Get the UpdateUrl if set $OfficeUpdateURL = [System.Uri](Get-ItemProperty -Path $C2RConfigurationPath -ErrorAction 'SilentlyContinue' | Select-Object -ExpandProperty UpdateURL -ErrorAction 'SilentlyContinue') # Get the UnmanagedUpdateUrl if set $OfficeUnmanagedUpdateURL = [System.Uri](Get-ItemProperty -Path $C2RConfigurationPath -ErrorAction 'SilentlyContinue' | Select-Object -ExpandProperty UnmanagedUpdateURL -ErrorAction 'SilentlyContinue') # Get the Office Update CDN URL $OfficeUpdateChannelCDNURL = [System.Uri](Get-ItemProperty -Path $C2RConfigurationPath -ErrorAction 'SilentlyContinue' | Select-Object -ExpandProperty CDNBaseUrl -ErrorAction 'SilentlyContinue') # Get just the channel GUID if ($OfficeUpdateURL.IsAbsoluteUri) { $OfficeUpdateGUID = $OfficeUpdateURL.Segments[2] } elseif ($OfficeUnmanagedUpdateURL.IsAbsoluteUri) { $OfficeUpdateGUID = $OfficeUnmanagedUpdateURL.Segments[2] } elseif ($OfficeUpdateChannelCDNURL.IsAbsoluteUri) { $OfficeUpdateGUID = $OfficeUpdateChannelCDNURL.Segments[2] } else { Write-Error 'Unable to determine Office update channel URL.' Exit 1 } # Define the Office Update Channels $Channels = @( @{ ID = '492350f6-3a01-4f97-b9c0-c7c6ddf67d60' Name = 'Current' PatchedVersion = [version]'16.0.16130.20306' }, @{ ID = '64256afe-f5d9-4f86-8936-8840a6a4f5be' Name = 'Current (Preview)' PatchedVersion = [version]'16.0.16227.20094' }, @{ ID = '55336b82-a18d-4dd6-b5f6-9e5095c314a6' Name = 'Monthly Enterprise' PatchedVersion = [version]'16.0.16026.20238' }, @{ ID = '7ffbc6bf-bc32-4f92-8982-f9dd17fd3114' Name = 'Semi-Annual Enterprise' PatchedVersion = [version]'16.0.15601.20578' }, @{ # This does not match Microsoft's documented version but is the latest available update on tested SAE-Preview channel installations. ID = 'b8f9b850-328d-4355-9145-c59439a0c4cf' Name = 'Semi-Annual Enterprise (Preview)' PatchedVersion = [version]'16.0.16026.20238' }, @{ ID = '5440fd1f-7ecb-4221-8110-145efaa6372f' Name = 'Beta' PatchedVersion = [version]'16.0.16310.20000' } ) foreach ($Channel in $Channels) { if ($OfficeUpdateGUID -eq $Channel.ID) { $OfficeChannel = $Channel } } } if (-not $OfficeChannel) { Write-Error 'Unable to determine Office update channel.' Exit 1 } else { Write-Output ("{0} found using the {1} update channel. `r`nChannel ID: {2}. `r`nTarget Version: {3}. `r`nDetected Version: {4}" -f 'Microsoft 365 Apps', $OfficeChannel.Name, $OfficeChannel.ID, $OfficeChannel.PatchedVersion, $OfficeVersion) } } if ( $OfficeVersion.Major -eq '16' ) { if ( ( $OfficeVersion.Build -ge 7571 ) -and ( $OfficeVersion.Build -le 16130 ) -and $IsO365 ) { # Handle Microsoft 365 Apps if ($OfficeVersion -lt $OfficeChannel.PatchedVersion) { $Vulnerable = $true } } elseif ( ( $OfficeVersion.Build -ge 10356) -and ( $OfficeVersion.Build -le 10396 ) -and ( $OfficeProductIds -like '*2019Volume*' ) -and ( $OfficeProductIds -like '*2019Volume*' ) ) { # Handle VL Office 2019 if ( ( $OfficeVersion.Build -lt 10396 ) -and ( $OfficeVersion.Revision -lt 20023 ) ) { Write-Output ("{0} found. `r`nTarget Version: {1}. `r`nDetected Version: {2}" -f 'Office 2019 VL', [Version]'16.0.10396.20023', $OfficeVersion) $Vulnerable = $true } } elseif ( ( $OfficeVersion.Build -ge 12527 ) -and ( $OfficeVersion.Build -le 16130 ) -and ( $OfficeProductIds -like '*Retail*' ) ) { # Handle Office 2021 Retail, Office 2019 Retail and Office 2016 Retail if ( ( $OfficeVersion.Build -lt 16130 ) -and ( $OfficeVersion.Revision -lt 20306 ) ) { Write-Output ("{0} found. `r`nTarget Version: {1}. `r`nDetected Version: {2}" -f 'Office 2021, 2019 or 2016 Retail', [Version]'16.0.16130.20306', $OfficeVersion) $Vulnerable = $true } } elseif ( ( $OfficeVersion.Build -eq 14332 ) -and ( $OfficeProductIds -like '*2021Volume*' ) ) { # Handle VL Office LTSC 2021 if ( ( $OfficeVersion.Build -ne 14332 ) -and ( $OfficeVersion.Revision -lt 20481 ) ) { Write-Output ("{0} found. `r`nTarget Version: {1}. `r`nDetected Version: {2}" -f 'Office LTSC 2021', [Version]'16.0.14332.20481', $OfficeVersion) $Vulnerable = $true } } } elseif ( $OfficeVersion.Major -eq '15' ) { if ( [version]'15.0.5537.1000' -gt $OfficeVersion ) { Write-Output ("{0} found. `r`nTarget Version: {1}. `r`nDetected Version: {2}" -f 'Office 2013', [Version]'15.0.5537.1000', $OfficeVersion) $Vulnerable = $true } } if ($true -eq $Vulnerable) { Write-Warning 'This version of Office is vulnerable to CVE-2023-23397.' Ninja-Property-Set CVE202323397 1 } elseif ($false -eq $Vulnerable) { Write-Output 'This version of Office is not vulnerable to CVE-2023-23397.' Ninja-Property-Set CVE202323397 0 } else { Write-Warning 'Could not determine vulnerability status.' }