From d68ce48d45e1cd39c2c9eea6cf2cc37341159665 Mon Sep 17 00:00:00 2001 From: Friedrich Weinmann Date: Fri, 5 Mar 2021 16:00:16 +0100 Subject: [PATCH 01/14] Rewrite for remoting, objects and parallel processing --- Security/Test-Hafnium.ps1 | 310 +++++++++++++++++++++++++++----------- 1 file changed, 218 insertions(+), 92 deletions(-) diff --git a/Security/Test-Hafnium.ps1 b/Security/Test-Hafnium.ps1 index 306a0423fe..f80a04752e 100644 --- a/Security/Test-Hafnium.ps1 +++ b/Security/Test-Hafnium.ps1 @@ -1,97 +1,223 @@ #Checks for signs of exploit from CVE-2021-26855, 26858, 26857, and 27065. -$exchangePath = (Get-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ExchangeServer\v15\Setup).MsiInstallPath - -function Get-26855() { - Write-Host "Checking for CVE-2021-26855 in the HttpProxy logs" - $files = (Get-ChildItem -Recurse -Path "$exchangePath\Logging\HttpProxy" -Filter '*.log').FullName - $count = 0 - $allResults = @() - $sw = New-Object System.Diagnostics.Stopwatch - $sw.Start() - $files | ForEach-Object { - $count++ - if ($sw.ElapsedMilliseconds -gt 500) { - Write-Progress -Activity "Checking for CVE-2021-26855 in the HttpProxy logs" -Status "$count / $($files.Count)" -PercentComplete ($count * 100 / $files.Count) - $sw.Restart() - } - if ((Get-ChildItem $_ -ErrorAction SilentlyContinue | Select-String "ServerInfo~").Count -gt 0) { - $fileResults = @(Import-Csv -Path $_ -ErrorAction SilentlyContinue | Where-Object { $_.AnchorMailbox -like 'ServerInfo~*/*' }) - $fileResults | ForEach-Object { - $allResults += $_ - } - } - } - - Write-Progress -Activity "Checking for CVE-2021-26855 in the HttpProxy logs" -Completed - - if ($allResults.Length -gt 0) { - Write-Warning "Suspicious entries found in $exchangePath\Logging\HttpProxy. Check the .\CVE-2021-26855.csv log for specific entries." - if (Test-Path "$PSScriptRoot\CVE-2021-26855.log") { - Remove-Item $PSScriptRoot\CVE-2021-26855.log -Force - } - $allResults | Select-Object DateTime, AnchorMailbox | Export-Csv $PSScriptRoot\CVE-2021-26855.log - } else { - Write-Host "No suspicious entries found." -ForegroundColor Green - } -} - -function Get-26858() { - Write-Host "`r`nChecking for CVE-2021-26858 in the OABGenerator logs" - $logs = Get-ChildItem -Recurse -Path "$exchangePath\Logging\OABGeneratorLog" | Select-String "Download failed and temporary file" -List | Select-Object Path - if ($logs.Path.Count -gt 0) { - Write-Warning "Suspicious OAB download entries found in the following logs, please review them for `"Download failed and temporary file`" entries:" - $logs.Path - } else { - Write-Host "No suspicious entries found." -ForegroundColor Green - } -} - -function Get-26857() { - Write-Host "`r`nChecking for CVE-2021-26857 in the Event Logs" - $eventLogs = @(Get-WinEvent -FilterHashtable @{LogName = 'Application'; ProviderName = 'MSExchange Unified Messaging'; Level = '2' } -ErrorAction SilentlyContinue | Where-Object { $_.Message -like "*System.InvalidCastException*" }) - if ($eventLogs.Count -gt 0) { - Write-Warning "Suspicious event log entries for Source `"MSExchange Unified Messaging`" and Message `"System.InvalidCastException`" were found. These may indicate exploitation. Please review these event log entries for more details." - } else { - Write-Host "No suspicious entries found." -ForegroundColor Green - } -} - -function Get-27065() { - Write-Host "`r`nChecking for CVE-2021-27065 in the ECP Logs" - $logs = Get-ChildItem -Recurse -Path "$exchangePath\Logging\ECP\Server\*.log" | Select-String "Set-.*VirtualDirectory" -List | Select-Object Path - if ($logs.Path.Count -gt 0) { - Write-Warning "Suspicious virtual directory modifications found in the following logs, please review them for `"Set-*VirtualDirectory`" entries:" - $logs.Path - } else { - Write-Host "No suspicious entries found." -ForegroundColor Green - } +function Test-ExchangeHafnium { +<# + .SYNOPSIS + Checks targeted exchange servers for signs of Hafnium vulnerability compromise. + + .DESCRIPTION + Checks targeted exchange servers for signs of Hafnium vulnerability compromise. + Will do so in parallel if more than one server is specified, so long as names aren't provided by pipeline. + + The vulnerabilities are described in CVE-2021-26855, 26858, 26857, and 27065 + + .PARAMETER ComputerName + The list of server names to scan for signs of compromise. + Do not provide these by pipeline if you want parallel processing. + + .PARAMETER Credential + Credentials to use for remote connections. + + .EXAMPLE + PS C:\> Test-ExchangeHafnium + + Scans the current computer for signs of Hafnium vulnerability compromise. + + .EXAMPLE + PS C:\> Test-ExchangeHafnium -ComputerName (Get-ExchangeServer).Fqdn + + Scans all exchange servers in the organization for Hafnium vulnerability compromises +#> + [CmdletBinding()] + param ( + [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] + [string[]] + $ComputerName = $env:COMPUTERNAME, + + [pscredential] + $Credential + ) + begin { + #region Remoting Scriptblock + $scriptBlock = { + #region Functions + function Get-Cve26855 { + [CmdletBinding()] + param () + + $exchangePath = (Get-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ExchangeServer\v15\Setup).MsiInstallPath + + foreach ($httpProxyLogfile in Get-ChildItem -Recurse -Path "$exchangePath\Logging\HttpProxy" -Filter '*.log') { + Import-Csv -Path $httpProxyLogfile.FullName | Where-Object AnchorMailbox -Like 'ServerInfo~*/*' | Select-Object -Property DateTime, AnchorMailbox + } + } + + function Get-Cve26857 { + [CmdletBinding()] + param () + + Get-WinEvent -FilterHashtable @{ + LogName = 'Application' + ProviderName = 'MSExchange Unified Messaging' + Level = '2' + } -ErrorAction SilentlyContinue | Where-Object Message -like "*System.InvalidCastException*" + } + + function Get-Cve26858 { + [CmdletBinding()] + param () + + $exchangePath = (Get-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ExchangeServer\v15\Setup).MsiInstallPath + + Get-ChildItem -Recurse -Path "$exchangePath\Logging\OABGeneratorLog" | Select-String "Download failed and temporary file" -List | Select-Object -ExpandProperty Path + } + + function Get-Cve27065 { + [CmdletBinding()] + param () + + $exchangePath = (Get-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ExchangeServer\v15\Setup).MsiInstallPath + + Get-ChildItem -Recurse -Path "$exchangePath\Logging\ECP\Server\*.log" | Select-String "Set-.*VirtualDirectory" -List | Select-Object -ExpandProperty Path + } + + function Get-SuspiciousFile { + [CmdletBinding()] + param () + + foreach ($file in Get-ChildItem -Recurse -Path "$env:WINDIR\temp\lsass.*dmp") { + [PSCustomObject]@{ + ComputerName = $env:COMPUTERNAME + Type = 'LsassDump' + Path = $file.FullName + Name = $file.Name + } + } + foreach ($file in Get-ChildItem -Recurse -Path "c:\root\lsass.*dmp") { + [PSCustomObject]@{ + ComputerName = $env:COMPUTERNAME + Type = 'LsassDump' + Path = $file.FullName + Name = $file.Name + } + } + foreach ($file in Get-ChildItem -Recurse -Path $env:ProgramData -ErrorAction SilentlyContinue | Where-Object Extension -match ".7z|.zip|.rar") { + [PSCustomObject]@{ + ComputerName = $env:COMPUTERNAME + Type = 'SuspiciousArchive' + Path = $file.FullName + Name = $file.Name + } + } + } + #endregion Functions + + [PSCustomObject]@{ + ComputerName = $env:COMPUTERNAME + Cve26855 = Get-Cve26855 + Cve26857 = Get-Cve26857 + Cve26858 = Get-Cve26858 + Cve27065 = Get-Cve27065 + Suspicious = Get-SuspiciousFile + } + } + #endregion Remoting Scriptblock + $parameters = @{ + ScriptBlock = $scriptBlock + } + if ($Credential) { $parameters.Credential = $Credential } + } + process { + Invoke-Command @parameters -ComputerName $ComputerName + } } -function Get-SuspiciousFiles() { - Write-Host "`r`nChecking for suspicious files" - $lsassFiles = @(Get-ChildItem -Recurse -Path "$env:WINDIR\temp\lsass.*dmp") - $lsassFiles += @(Get-ChildItem -Recurse -Path "c:\root\lsass.*dmp") - if ($lsassFiles.Count -gt 0) { - Write-Warning "lsass.exe dumps found, please verify these are expected:" - $lsassFiles.FullName - } else { - Write-Host "No suspicious lsass dumps found." -ForegroundColor Green - } - - $zipFiles = @(Get-ChildItem -Recurse -Path "$env:ProgramData" -ErrorAction SilentlyContinue | Where-Object { $_.Extension -match ".7z|.zip|.rar" }) - - if ($zipFiles.Count -gt 0) { - Write-Warning "`r`nZipped files found in $env:ProgramData, please verify these are expected:" - $zipFiles.FullName - } else { - Write-Host "`r`nNo suspicious zip files found." -ForegroundColor Green - } +function Write-HafniumReport { +<# + .SYNOPSIS + Processes output of Test-ExchangeHafnium for reporting on the console screen. + + .DESCRIPTION + Processes output of Test-ExchangeHafnium for reporting on the console screen. + + .PARAMETER InputObject + The reports provided by Test-ExchangeHafnium + + .PARAMETER OutPath + Path to a FOLDER in which to generate output logfiles. + This command will only write to the console screen if no path is provided. + + .EXAMPLE + PS C:\> Test-ExchangeHafnium -ComputerName (Get-ExchangeServer).Fqdn | Write-HafniumReport -OutPath C:\logs + + Gather data from all exchange servers in the organization and write a report to C:\logs +#> + [CmdletBinding()] + param ( + [parameter(ValueFromPipeline = $true)] + $InputObject, + + [string] + $OutPath + ) + + process { + foreach ($report in $InputObject) { + Write-Host "Hafnium Status: Exchange Server $($report.ComputerName)" + if (-not ($report.Cve26855 -or $report.Cve26857 -or $report.Cve26858 -or $report.Cve27065 -or $report.Suspicious)) { + Write-Host " Nothing suspicious detected" -ForegroundColor Green + Write-Host "" + continue + } + + if ($report.Cve26855) { + Write-Host " [CVE-2021-26855] Suspicious activity found in Http Proxy log!" -ForegroundColor Red + if ($OutPath) { + $newFile = Join-Path -Path $OutPath -ChildPath "$($report.ComputerName)-Cve-2021-26855.csv" + $report.Cve26855 | Export-Csv -Path $newFile + Write-Host " Report exported to: $newFile" + } + else { + $report.Cve26855 | Format-Table -AutoSize | Out-Host + } + Write-Host "" + } + if ($report.Cve26857) { + Write-Host " [CVE-2021-26857] Suspicious activity found in Eventlog!" -ForegroundColor Red + Write-Host " $(@($report.Cve26857).Count) events found" + if ($OutPath) { + $newFile = Join-Path -Path $OutPath -ChildPath "$($report.ComputerName)-Cve-2021-26857.csv" + $report.Cve26857 | Select-Object TimeCreated, MachineName, Message | Export-Csv -Path $newFile + Write-Host " Report exported to: $newFile" + } + Write-Host "" + } + if ($report.Cve26858) { + Write-Host " [CVE-2021-26858] Suspicious activity found in OAB generator logs!" -ForegroundColor Red + Write-Host " Please review the following files for 'Download failed and temporary file' entries:" + foreach ($entry in $report.Cve26858) { + Write-Host " $entry" + } + if ($OutPath) { + $newFile = Join-Path -Path $OutPath -ChildPath "$($report.ComputerName)-Cve-2021-26858.log" + $report.Cve26858 | Set-Content -Path $newFile + Write-Host " Report exported to: $newFile" + } + Write-Host "" + } + if ($report.Suspicious) { + Write-Host " Other suspicious files found: $(@($report.Suspicious).Count)" + if ($OutPath) { + $newFile = Join-Path -Path $OutPath -ChildPath "$($report.ComputerName)-other.csv" + $report.Suspicious | Export-Csv -Path $newFile + Write-Host " Report exported to: $newFile" + } + else { + foreach ($entry in $report.Suspicious) { + Write-Host " $($entry.Type) : $($entry.Path)" + } + } + } + } + } } - -Write-Host "This script checks for exploits using the instructions outlined in https://www.microsoft.com/security/blog/2021/03/02/hafnium-targeting-exchange-servers`r`n" -Get-26855 -Get-26858 -Get-26857 -Get-27065 -Get-SuspiciousFiles From c7ab84b0f7e5a6c00f8b571a65af0f0a330f1501 Mon Sep 17 00:00:00 2001 From: Friedrich Weinmann Date: Fri, 5 Mar 2021 16:08:07 +0100 Subject: [PATCH 02/14] Adding properties for 26855 To replicate change from https://github.com/microsoft/CSS-Exchange/pull/67 --- Security/Test-Hafnium.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Security/Test-Hafnium.ps1 b/Security/Test-Hafnium.ps1 index f80a04752e..9c3fbe2d33 100644 --- a/Security/Test-Hafnium.ps1 +++ b/Security/Test-Hafnium.ps1 @@ -48,7 +48,7 @@ function Test-ExchangeHafnium { $exchangePath = (Get-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ExchangeServer\v15\Setup).MsiInstallPath foreach ($httpProxyLogfile in Get-ChildItem -Recurse -Path "$exchangePath\Logging\HttpProxy" -Filter '*.log') { - Import-Csv -Path $httpProxyLogfile.FullName | Where-Object AnchorMailbox -Like 'ServerInfo~*/*' | Select-Object -Property DateTime, AnchorMailbox + Import-Csv -Path $httpProxyLogfile.FullName | Where-Object AnchorMailbox -Like 'ServerInfo~*/*' | Select-Object -Property DateTime, RequestId, ClientIPAddress, UrlHost, UrlStem, RoutingHint, UserAgent, AnchorMailbox } } From f4d1a09349081314b0f3e6120d201c29975dd1f8 Mon Sep 17 00:00:00 2001 From: Friedrich Weinmann Date: Fri, 5 Mar 2021 16:20:12 +0100 Subject: [PATCH 03/14] Adopted questionable formatting convention --- Security/Test-Hafnium.ps1 | 106 +++++++++++++++++++------------------- 1 file changed, 52 insertions(+), 54 deletions(-) diff --git a/Security/Test-Hafnium.ps1 b/Security/Test-Hafnium.ps1 index 9c3fbe2d33..74cb1de2d2 100644 --- a/Security/Test-Hafnium.ps1 +++ b/Security/Test-Hafnium.ps1 @@ -1,31 +1,31 @@ -#Checks for signs of exploit from CVE-2021-26855, 26858, 26857, and 27065. +#Checks for signs of exploit from CVE-2021-26855, 26858, 26857, and 27065. function Test-ExchangeHafnium { -<# + <# .SYNOPSIS Checks targeted exchange servers for signs of Hafnium vulnerability compromise. - + .DESCRIPTION Checks targeted exchange servers for signs of Hafnium vulnerability compromise. Will do so in parallel if more than one server is specified, so long as names aren't provided by pipeline. - + The vulnerabilities are described in CVE-2021-26855, 26858, 26857, and 27065 - + .PARAMETER ComputerName The list of server names to scan for signs of compromise. Do not provide these by pipeline if you want parallel processing. - + .PARAMETER Credential Credentials to use for remote connections. - + .EXAMPLE PS C:\> Test-ExchangeHafnium - + Scans the current computer for signs of Hafnium vulnerability compromise. - + .EXAMPLE PS C:\> Test-ExchangeHafnium -ComputerName (Get-ExchangeServer).Fqdn - + Scans all exchange servers in the organization for Hafnium vulnerability compromises #> [CmdletBinding()] @@ -33,7 +33,7 @@ function Test-ExchangeHafnium { [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [string[]] $ComputerName = $env:COMPUTERNAME, - + [pscredential] $Credential ) @@ -44,80 +44,80 @@ function Test-ExchangeHafnium { function Get-Cve26855 { [CmdletBinding()] param () - + $exchangePath = (Get-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ExchangeServer\v15\Setup).MsiInstallPath - + foreach ($httpProxyLogfile in Get-ChildItem -Recurse -Path "$exchangePath\Logging\HttpProxy" -Filter '*.log') { Import-Csv -Path $httpProxyLogfile.FullName | Where-Object AnchorMailbox -Like 'ServerInfo~*/*' | Select-Object -Property DateTime, RequestId, ClientIPAddress, UrlHost, UrlStem, RoutingHint, UserAgent, AnchorMailbox } } - + function Get-Cve26857 { [CmdletBinding()] param () - + Get-WinEvent -FilterHashtable @{ - LogName = 'Application' + LogName = 'Application' ProviderName = 'MSExchange Unified Messaging' - Level = '2' - } -ErrorAction SilentlyContinue | Where-Object Message -like "*System.InvalidCastException*" + Level = '2' + } -ErrorAction SilentlyContinue | Where-Object Message -Like "*System.InvalidCastException*" } - + function Get-Cve26858 { [CmdletBinding()] param () - + $exchangePath = (Get-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ExchangeServer\v15\Setup).MsiInstallPath - + Get-ChildItem -Recurse -Path "$exchangePath\Logging\OABGeneratorLog" | Select-String "Download failed and temporary file" -List | Select-Object -ExpandProperty Path } - + function Get-Cve27065 { [CmdletBinding()] param () - + $exchangePath = (Get-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ExchangeServer\v15\Setup).MsiInstallPath - + Get-ChildItem -Recurse -Path "$exchangePath\Logging\ECP\Server\*.log" | Select-String "Set-.*VirtualDirectory" -List | Select-Object -ExpandProperty Path } - + function Get-SuspiciousFile { [CmdletBinding()] param () - + foreach ($file in Get-ChildItem -Recurse -Path "$env:WINDIR\temp\lsass.*dmp") { [PSCustomObject]@{ ComputerName = $env:COMPUTERNAME - Type = 'LsassDump' - Path = $file.FullName - Name = $file.Name + Type = 'LsassDump' + Path = $file.FullName + Name = $file.Name } } foreach ($file in Get-ChildItem -Recurse -Path "c:\root\lsass.*dmp") { [PSCustomObject]@{ ComputerName = $env:COMPUTERNAME - Type = 'LsassDump' - Path = $file.FullName - Name = $file.Name + Type = 'LsassDump' + Path = $file.FullName + Name = $file.Name } } - foreach ($file in Get-ChildItem -Recurse -Path $env:ProgramData -ErrorAction SilentlyContinue | Where-Object Extension -match ".7z|.zip|.rar") { + foreach ($file in Get-ChildItem -Recurse -Path $env:ProgramData -ErrorAction SilentlyContinue | Where-Object Extension -Match ".7z|.zip|.rar") { [PSCustomObject]@{ ComputerName = $env:COMPUTERNAME - Type = 'SuspiciousArchive' - Path = $file.FullName - Name = $file.Name + Type = 'SuspiciousArchive' + Path = $file.FullName + Name = $file.Name } } } #endregion Functions - + [PSCustomObject]@{ ComputerName = $env:COMPUTERNAME - Cve26855 = Get-Cve26855 - Cve26857 = Get-Cve26857 - Cve26858 = Get-Cve26858 - Cve27065 = Get-Cve27065 + Cve26855 = Get-Cve26855 + Cve26857 = Get-Cve26857 + Cve26858 = Get-Cve26858 + Cve27065 = Get-Cve27065 Suspicious = Get-SuspiciousFile } } @@ -133,34 +133,34 @@ function Test-ExchangeHafnium { } function Write-HafniumReport { -<# + <# .SYNOPSIS Processes output of Test-ExchangeHafnium for reporting on the console screen. - + .DESCRIPTION Processes output of Test-ExchangeHafnium for reporting on the console screen. - + .PARAMETER InputObject The reports provided by Test-ExchangeHafnium - + .PARAMETER OutPath Path to a FOLDER in which to generate output logfiles. This command will only write to the console screen if no path is provided. - + .EXAMPLE PS C:\> Test-ExchangeHafnium -ComputerName (Get-ExchangeServer).Fqdn | Write-HafniumReport -OutPath C:\logs - + Gather data from all exchange servers in the organization and write a report to C:\logs #> [CmdletBinding()] param ( [parameter(ValueFromPipeline = $true)] $InputObject, - + [string] $OutPath ) - + process { foreach ($report in $InputObject) { Write-Host "Hafnium Status: Exchange Server $($report.ComputerName)" @@ -169,15 +169,14 @@ function Write-HafniumReport { Write-Host "" continue } - + if ($report.Cve26855) { Write-Host " [CVE-2021-26855] Suspicious activity found in Http Proxy log!" -ForegroundColor Red if ($OutPath) { $newFile = Join-Path -Path $OutPath -ChildPath "$($report.ComputerName)-Cve-2021-26855.csv" $report.Cve26855 | Export-Csv -Path $newFile Write-Host " Report exported to: $newFile" - } - else { + } else { $report.Cve26855 | Format-Table -AutoSize | Out-Host } Write-Host "" @@ -211,8 +210,7 @@ function Write-HafniumReport { $newFile = Join-Path -Path $OutPath -ChildPath "$($report.ComputerName)-other.csv" $report.Suspicious | Export-Csv -Path $newFile Write-Host " Report exported to: $newFile" - } - else { + } else { foreach ($entry in $report.Suspicious) { Write-Host " $($entry.Type) : $($entry.Path)" } From 4984ccec4a170c0c79c574e825e0425888e84771 Mon Sep 17 00:00:00 2001 From: Friedrich Weinmann Date: Fri, 5 Mar 2021 16:26:03 +0100 Subject: [PATCH 04/14] More formatting headaches --- Security/Test-Hafnium.ps1 | 340 +++++++++++++++++++------------------- 1 file changed, 170 insertions(+), 170 deletions(-) diff --git a/Security/Test-Hafnium.ps1 b/Security/Test-Hafnium.ps1 index 74cb1de2d2..09f07c6e2c 100644 --- a/Security/Test-Hafnium.ps1 +++ b/Security/Test-Hafnium.ps1 @@ -1,7 +1,7 @@ #Checks for signs of exploit from CVE-2021-26855, 26858, 26857, and 27065. function Test-ExchangeHafnium { - <# + <# .SYNOPSIS Checks targeted exchange servers for signs of Hafnium vulnerability compromise. @@ -28,112 +28,112 @@ function Test-ExchangeHafnium { Scans all exchange servers in the organization for Hafnium vulnerability compromises #> - [CmdletBinding()] - param ( - [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] - [string[]] - $ComputerName = $env:COMPUTERNAME, - - [pscredential] - $Credential - ) - begin { - #region Remoting Scriptblock - $scriptBlock = { - #region Functions - function Get-Cve26855 { - [CmdletBinding()] - param () - - $exchangePath = (Get-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ExchangeServer\v15\Setup).MsiInstallPath - - foreach ($httpProxyLogfile in Get-ChildItem -Recurse -Path "$exchangePath\Logging\HttpProxy" -Filter '*.log') { - Import-Csv -Path $httpProxyLogfile.FullName | Where-Object AnchorMailbox -Like 'ServerInfo~*/*' | Select-Object -Property DateTime, RequestId, ClientIPAddress, UrlHost, UrlStem, RoutingHint, UserAgent, AnchorMailbox - } - } - - function Get-Cve26857 { - [CmdletBinding()] - param () - - Get-WinEvent -FilterHashtable @{ - LogName = 'Application' - ProviderName = 'MSExchange Unified Messaging' - Level = '2' - } -ErrorAction SilentlyContinue | Where-Object Message -Like "*System.InvalidCastException*" - } - - function Get-Cve26858 { - [CmdletBinding()] - param () - - $exchangePath = (Get-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ExchangeServer\v15\Setup).MsiInstallPath - - Get-ChildItem -Recurse -Path "$exchangePath\Logging\OABGeneratorLog" | Select-String "Download failed and temporary file" -List | Select-Object -ExpandProperty Path - } - - function Get-Cve27065 { - [CmdletBinding()] - param () - - $exchangePath = (Get-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ExchangeServer\v15\Setup).MsiInstallPath - - Get-ChildItem -Recurse -Path "$exchangePath\Logging\ECP\Server\*.log" | Select-String "Set-.*VirtualDirectory" -List | Select-Object -ExpandProperty Path - } - - function Get-SuspiciousFile { - [CmdletBinding()] - param () - - foreach ($file in Get-ChildItem -Recurse -Path "$env:WINDIR\temp\lsass.*dmp") { - [PSCustomObject]@{ - ComputerName = $env:COMPUTERNAME - Type = 'LsassDump' - Path = $file.FullName - Name = $file.Name - } - } - foreach ($file in Get-ChildItem -Recurse -Path "c:\root\lsass.*dmp") { - [PSCustomObject]@{ - ComputerName = $env:COMPUTERNAME - Type = 'LsassDump' - Path = $file.FullName - Name = $file.Name - } - } - foreach ($file in Get-ChildItem -Recurse -Path $env:ProgramData -ErrorAction SilentlyContinue | Where-Object Extension -Match ".7z|.zip|.rar") { - [PSCustomObject]@{ - ComputerName = $env:COMPUTERNAME - Type = 'SuspiciousArchive' - Path = $file.FullName - Name = $file.Name - } - } - } - #endregion Functions - - [PSCustomObject]@{ - ComputerName = $env:COMPUTERNAME - Cve26855 = Get-Cve26855 - Cve26857 = Get-Cve26857 - Cve26858 = Get-Cve26858 - Cve27065 = Get-Cve27065 - Suspicious = Get-SuspiciousFile - } - } - #endregion Remoting Scriptblock - $parameters = @{ - ScriptBlock = $scriptBlock - } - if ($Credential) { $parameters.Credential = $Credential } - } - process { - Invoke-Command @parameters -ComputerName $ComputerName - } + [CmdletBinding()] + param ( + [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] + [string[]] + $ComputerName = $env:COMPUTERNAME, + + [pscredential] + $Credential + ) + begin { + #region Remoting Scriptblock + $scriptBlock = { + #region Functions + function Get-Cve26855 { + [CmdletBinding()] + param () + + $exchangePath = (Get-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ExchangeServer\v15\Setup).MsiInstallPath + + foreach ($httpProxyLogfile in Get-ChildItem -Recurse -Path "$exchangePath\Logging\HttpProxy" -Filter '*.log') { + Import-Csv -Path $httpProxyLogfile.FullName | Where-Object AnchorMailbox -Like 'ServerInfo~*/*' | Select-Object -Property DateTime, RequestId, ClientIPAddress, UrlHost, UrlStem, RoutingHint, UserAgent, AnchorMailbox + } + } + + function Get-Cve26857 { + [CmdletBinding()] + param () + + Get-WinEvent -FilterHashtable @{ + LogName = 'Application' + ProviderName = 'MSExchange Unified Messaging' + Level = '2' + } -ErrorAction SilentlyContinue | Where-Object Message -Like "*System.InvalidCastException*" + } + + function Get-Cve26858 { + [CmdletBinding()] + param () + + $exchangePath = (Get-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ExchangeServer\v15\Setup).MsiInstallPath + + Get-ChildItem -Recurse -Path "$exchangePath\Logging\OABGeneratorLog" | Select-String "Download failed and temporary file" -List | Select-Object -ExpandProperty Path + } + + function Get-Cve27065 { + [CmdletBinding()] + param () + + $exchangePath = (Get-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ExchangeServer\v15\Setup).MsiInstallPath + + Get-ChildItem -Recurse -Path "$exchangePath\Logging\ECP\Server\*.log" | Select-String "Set-.*VirtualDirectory" -List | Select-Object -ExpandProperty Path + } + + function Get-SuspiciousFile { + [CmdletBinding()] + param () + + foreach ($file in Get-ChildItem -Recurse -Path "$env:WINDIR\temp\lsass.*dmp") { + [PSCustomObject]@{ + ComputerName = $env:COMPUTERNAME + Type = 'LsassDump' + Path = $file.FullName + Name = $file.Name + } + } + foreach ($file in Get-ChildItem -Recurse -Path "c:\root\lsass.*dmp") { + [PSCustomObject]@{ + ComputerName = $env:COMPUTERNAME + Type = 'LsassDump' + Path = $file.FullName + Name = $file.Name + } + } + foreach ($file in Get-ChildItem -Recurse -Path $env:ProgramData -ErrorAction SilentlyContinue | Where-Object Extension -Match ".7z|.zip|.rar") { + [PSCustomObject]@{ + ComputerName = $env:COMPUTERNAME + Type = 'SuspiciousArchive' + Path = $file.FullName + Name = $file.Name + } + } + } + #endregion Functions + + [PSCustomObject]@{ + ComputerName = $env:COMPUTERNAME + Cve26855 = Get-Cve26855 + Cve26857 = Get-Cve26857 + Cve26858 = Get-Cve26858 + Cve27065 = Get-Cve27065 + Suspicious = Get-SuspiciousFile + } + } + #endregion Remoting Scriptblock + $parameters = @{ + ScriptBlock = $scriptBlock + } + if ($Credential) { $parameters.Credential = $Credential } + } + process { + Invoke-Command @parameters -ComputerName $ComputerName + } } function Write-HafniumReport { - <# + <# .SYNOPSIS Processes output of Test-ExchangeHafnium for reporting on the console screen. @@ -152,70 +152,70 @@ function Write-HafniumReport { Gather data from all exchange servers in the organization and write a report to C:\logs #> - [CmdletBinding()] - param ( - [parameter(ValueFromPipeline = $true)] - $InputObject, - - [string] - $OutPath - ) - - process { - foreach ($report in $InputObject) { - Write-Host "Hafnium Status: Exchange Server $($report.ComputerName)" - if (-not ($report.Cve26855 -or $report.Cve26857 -or $report.Cve26858 -or $report.Cve27065 -or $report.Suspicious)) { - Write-Host " Nothing suspicious detected" -ForegroundColor Green - Write-Host "" - continue - } - - if ($report.Cve26855) { - Write-Host " [CVE-2021-26855] Suspicious activity found in Http Proxy log!" -ForegroundColor Red - if ($OutPath) { - $newFile = Join-Path -Path $OutPath -ChildPath "$($report.ComputerName)-Cve-2021-26855.csv" - $report.Cve26855 | Export-Csv -Path $newFile - Write-Host " Report exported to: $newFile" - } else { - $report.Cve26855 | Format-Table -AutoSize | Out-Host - } - Write-Host "" - } - if ($report.Cve26857) { - Write-Host " [CVE-2021-26857] Suspicious activity found in Eventlog!" -ForegroundColor Red - Write-Host " $(@($report.Cve26857).Count) events found" - if ($OutPath) { - $newFile = Join-Path -Path $OutPath -ChildPath "$($report.ComputerName)-Cve-2021-26857.csv" - $report.Cve26857 | Select-Object TimeCreated, MachineName, Message | Export-Csv -Path $newFile - Write-Host " Report exported to: $newFile" - } - Write-Host "" - } - if ($report.Cve26858) { - Write-Host " [CVE-2021-26858] Suspicious activity found in OAB generator logs!" -ForegroundColor Red - Write-Host " Please review the following files for 'Download failed and temporary file' entries:" - foreach ($entry in $report.Cve26858) { - Write-Host " $entry" - } - if ($OutPath) { - $newFile = Join-Path -Path $OutPath -ChildPath "$($report.ComputerName)-Cve-2021-26858.log" - $report.Cve26858 | Set-Content -Path $newFile - Write-Host " Report exported to: $newFile" - } - Write-Host "" - } - if ($report.Suspicious) { - Write-Host " Other suspicious files found: $(@($report.Suspicious).Count)" - if ($OutPath) { - $newFile = Join-Path -Path $OutPath -ChildPath "$($report.ComputerName)-other.csv" - $report.Suspicious | Export-Csv -Path $newFile - Write-Host " Report exported to: $newFile" - } else { - foreach ($entry in $report.Suspicious) { - Write-Host " $($entry.Type) : $($entry.Path)" - } - } - } - } - } + [CmdletBinding()] + param ( + [parameter(ValueFromPipeline = $true)] + $InputObject, + + [string] + $OutPath + ) + + process { + foreach ($report in $InputObject) { + Write-Host "Hafnium Status: Exchange Server $($report.ComputerName)" + if (-not ($report.Cve26855 -or $report.Cve26857 -or $report.Cve26858 -or $report.Cve27065 -or $report.Suspicious)) { + Write-Host " Nothing suspicious detected" -ForegroundColor Green + Write-Host "" + continue + } + + if ($report.Cve26855) { + Write-Host " [CVE-2021-26855] Suspicious activity found in Http Proxy log!" -ForegroundColor Red + if ($OutPath) { + $newFile = Join-Path -Path $OutPath -ChildPath "$($report.ComputerName)-Cve-2021-26855.csv" + $report.Cve26855 | Export-Csv -Path $newFile + Write-Host " Report exported to: $newFile" + } else { + $report.Cve26855 | Format-Table -AutoSize | Out-Host + } + Write-Host "" + } + if ($report.Cve26857) { + Write-Host " [CVE-2021-26857] Suspicious activity found in Eventlog!" -ForegroundColor Red + Write-Host " $(@($report.Cve26857).Count) events found" + if ($OutPath) { + $newFile = Join-Path -Path $OutPath -ChildPath "$($report.ComputerName)-Cve-2021-26857.csv" + $report.Cve26857 | Select-Object TimeCreated, MachineName, Message | Export-Csv -Path $newFile + Write-Host " Report exported to: $newFile" + } + Write-Host "" + } + if ($report.Cve26858) { + Write-Host " [CVE-2021-26858] Suspicious activity found in OAB generator logs!" -ForegroundColor Red + Write-Host " Please review the following files for 'Download failed and temporary file' entries:" + foreach ($entry in $report.Cve26858) { + Write-Host " $entry" + } + if ($OutPath) { + $newFile = Join-Path -Path $OutPath -ChildPath "$($report.ComputerName)-Cve-2021-26858.log" + $report.Cve26858 | Set-Content -Path $newFile + Write-Host " Report exported to: $newFile" + } + Write-Host "" + } + if ($report.Suspicious) { + Write-Host " Other suspicious files found: $(@($report.Suspicious).Count)" + if ($OutPath) { + $newFile = Join-Path -Path $OutPath -ChildPath "$($report.ComputerName)-other.csv" + $report.Suspicious | Export-Csv -Path $newFile + Write-Host " Report exported to: $newFile" + } else { + foreach ($entry in $report.Suspicious) { + Write-Host " $($entry.Type) : $($entry.Path)" + } + } + } + } + } } From d578b3c6c1d246b9398f417393f1f1fd4814f7e9 Mon Sep 17 00:00:00 2001 From: Bill Long Date: Fri, 5 Mar 2021 10:47:47 -0600 Subject: [PATCH 05/14] Bring over perf improvements for HttpProxy check --- Security/Test-Hafnium.ps1 | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/Security/Test-Hafnium.ps1 b/Security/Test-Hafnium.ps1 index 079507deeb..dc10f32cde 100644 --- a/Security/Test-Hafnium.ps1 +++ b/Security/Test-Hafnium.ps1 @@ -1,4 +1,4 @@ -#Checks for signs of exploit from CVE-2021-26855, 26858, 26857, and 27065. +#Checks for signs of exploit from CVE-2021-26855, 26858, 26857, and 27065. function Test-ExchangeHafnium { <# @@ -45,11 +45,34 @@ function Test-ExchangeHafnium { [CmdletBinding()] param () + Write-Progress -Activity "Checking for CVE-2021-26855 in the HttpProxy logs" + $exchangePath = (Get-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ExchangeServer\v15\Setup).MsiInstallPath - foreach ($httpProxyLogfile in Get-ChildItem -Recurse -Path "$exchangePath\Logging\HttpProxy" -Filter '*.log') { - Import-Csv -Path $httpProxyLogfile.FullName | Where-Object AnchorMailbox -Like 'ServerInfo~*/*' | Select-Object -Property DateTime, RequestId, ClientIPAddress, UrlHost, UrlStem, RoutingHint, UserAgent, AnchorMailbox, HttpStatus + $files = (Get-ChildItem -Recurse -Path "$exchangePath\Logging\HttpProxy" -Filter '*.log').FullName + $count = 0 + $allResults = @() + $sw = New-Object System.Diagnostics.Stopwatch + $sw.Start() + $files | ForEach-Object { + $count++ + + if ($sw.ElapsedMilliseconds -gt 500) { + Write-Progress -Activity "Checking for CVE-2021-26855 in the HttpProxy logs" -Status "$count / $($files.Count)" -PercentComplete ($count * 100 / $files.Count) + $sw.Restart() + } + + if ((Get-ChildItem $_ -ErrorAction SilentlyContinue | Select-String "ServerInfo~").Count -gt 0) { + $fileResults = @(Import-Csv -Path $_ -ErrorAction SilentlyContinue | Where-Object AnchorMailbox -Like 'ServerInfo~*/*' | Select-Object -Property DateTime, RequestId, ClientIPAddress, UrlHost, UrlStem, RoutingHint, UserAgent, AnchorMailbox, HttpStatus) + $fileResults | ForEach-Object { + $allResults += $_ + } + } } + + Write-Progress -Activity "Checking for CVE-2021-26855 in the HttpProxy logs" -Completed + + return $allResults } function Get-Cve26857 { From 82b4f663170589b3f817d268842549db5f046504 Mon Sep 17 00:00:00 2001 From: Bill Long Date: Fri, 5 Mar 2021 15:36:16 -0600 Subject: [PATCH 06/14] Return collections and check count to avoid false positives --- Security/Test-ProxyLogon.ps1 | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Security/Test-ProxyLogon.ps1 b/Security/Test-ProxyLogon.ps1 index dc10f32cde..2ccc85fd2b 100644 --- a/Security/Test-ProxyLogon.ps1 +++ b/Security/Test-ProxyLogon.ps1 @@ -137,11 +137,11 @@ function Test-ExchangeHafnium { [PSCustomObject]@{ ComputerName = $env:COMPUTERNAME - Cve26855 = Get-Cve26855 - Cve26857 = Get-Cve26857 - Cve26858 = Get-Cve26858 - Cve27065 = Get-Cve27065 - Suspicious = Get-SuspiciousFile + Cve26855 = @(Get-Cve26855) + Cve26857 = @(Get-Cve26857) + Cve26858 = @(Get-Cve26858) + Cve27065 = @(Get-Cve27065) + Suspicious = @(Get-SuspiciousFile) } } #endregion Remoting Scriptblock @@ -187,13 +187,13 @@ function Write-HafniumReport { process { foreach ($report in $InputObject) { Write-Host "Hafnium Status: Exchange Server $($report.ComputerName)" - if (-not ($report.Cve26855 -or $report.Cve26857 -or $report.Cve26858 -or $report.Cve27065 -or $report.Suspicious)) { + if (-not ($report.Cve26855.Count -or $report.Cve26857.Count -or $report.Cve26858.Count -or $report.Cve27065.Count -or $report.Suspicious.Count)) { Write-Host " Nothing suspicious detected" -ForegroundColor Green Write-Host "" continue } - if ($report.Cve26855) { + if ($report.Cve26855.Count -gt 0) { Write-Host " [CVE-2021-26855] Suspicious activity found in Http Proxy log!" -ForegroundColor Red if ($OutPath) { $newFile = Join-Path -Path $OutPath -ChildPath "$($report.ComputerName)-Cve-2021-26855.csv" @@ -204,7 +204,7 @@ function Write-HafniumReport { } Write-Host "" } - if ($report.Cve26857) { + if ($report.Cve26857.Count -gt 0) { Write-Host " [CVE-2021-26857] Suspicious activity found in Eventlog!" -ForegroundColor Red Write-Host " $(@($report.Cve26857).Count) events found" if ($OutPath) { @@ -214,7 +214,7 @@ function Write-HafniumReport { } Write-Host "" } - if ($report.Cve26858) { + if ($report.Cve26858.Count -gt 0) { Write-Host " [CVE-2021-26858] Suspicious activity found in OAB generator logs!" -ForegroundColor Red Write-Host " Please review the following files for 'Download failed and temporary file' entries:" foreach ($entry in $report.Cve26858) { @@ -227,7 +227,7 @@ function Write-HafniumReport { } Write-Host "" } - if ($report.Suspicious) { + if ($report.Suspicious.Count -gt 0) { Write-Host " Other suspicious files found: $(@($report.Suspicious).Count)" if ($OutPath) { $newFile = Join-Path -Path $OutPath -ChildPath "$($report.ComputerName)-other.csv" From 32d8889a79f180a0d5090eebb06a55fce3914013 Mon Sep 17 00:00:00 2001 From: Bill Long Date: Fri, 5 Mar 2021 15:44:46 -0600 Subject: [PATCH 07/14] Accept pipeline input --- Security/Test-ProxyLogon.ps1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Security/Test-ProxyLogon.ps1 b/Security/Test-ProxyLogon.ps1 index 2ccc85fd2b..982538e42c 100644 --- a/Security/Test-ProxyLogon.ps1 +++ b/Security/Test-ProxyLogon.ps1 @@ -242,3 +242,5 @@ function Write-HafniumReport { } } } + +$input | Test-ExchangeHafnium | Write-HafniumReport From bfe43f278abbcb90d417d597ec8385ff5a547a57 Mon Sep 17 00:00:00 2001 From: Bill Long Date: Fri, 5 Mar 2021 15:55:49 -0600 Subject: [PATCH 08/14] Bring back -OutputPath --- Security/Test-ProxyLogon.ps1 | 343 ++++++++++++++++++----------------- 1 file changed, 178 insertions(+), 165 deletions(-) diff --git a/Security/Test-ProxyLogon.ps1 b/Security/Test-ProxyLogon.ps1 index 982538e42c..4b8c19778a 100644 --- a/Security/Test-ProxyLogon.ps1 +++ b/Security/Test-ProxyLogon.ps1 @@ -1,7 +1,19 @@ #Checks for signs of exploit from CVE-2021-26855, 26858, 26857, and 27065. -function Test-ExchangeHafnium { - <# +[CmdletBinding()] +param ( + [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] + [string[]] + $ComputerName = $env:COMPUTERNAME, + + [string] + $OutPath +) + +process { + + function Test-ExchangeHafnium { + <# .SYNOPSIS Checks targeted exchange servers for signs of Hafnium vulnerability compromise. @@ -28,135 +40,135 @@ function Test-ExchangeHafnium { Scans all exchange servers in the organization for Hafnium vulnerability compromises #> - [CmdletBinding()] - param ( - [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] - [string[]] - $ComputerName = $env:COMPUTERNAME, - - [pscredential] - $Credential - ) - begin { - #region Remoting Scriptblock - $scriptBlock = { - #region Functions - function Get-Cve26855 { - [CmdletBinding()] - param () - - Write-Progress -Activity "Checking for CVE-2021-26855 in the HttpProxy logs" - - $exchangePath = (Get-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ExchangeServer\v15\Setup).MsiInstallPath - - $files = (Get-ChildItem -Recurse -Path "$exchangePath\Logging\HttpProxy" -Filter '*.log').FullName - $count = 0 - $allResults = @() - $sw = New-Object System.Diagnostics.Stopwatch - $sw.Start() - $files | ForEach-Object { - $count++ - - if ($sw.ElapsedMilliseconds -gt 500) { - Write-Progress -Activity "Checking for CVE-2021-26855 in the HttpProxy logs" -Status "$count / $($files.Count)" -PercentComplete ($count * 100 / $files.Count) - $sw.Restart() - } + [CmdletBinding()] + param ( + [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] + [string[]] + $ComputerName = $env:COMPUTERNAME, + + [pscredential] + $Credential + ) + begin { + #region Remoting Scriptblock + $scriptBlock = { + #region Functions + function Get-Cve26855 { + [CmdletBinding()] + param () + + Write-Progress -Activity "Checking for CVE-2021-26855 in the HttpProxy logs" + + $exchangePath = (Get-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ExchangeServer\v15\Setup).MsiInstallPath + + $files = (Get-ChildItem -Recurse -Path "$exchangePath\Logging\HttpProxy" -Filter '*.log').FullName + $count = 0 + $allResults = @() + $sw = New-Object System.Diagnostics.Stopwatch + $sw.Start() + $files | ForEach-Object { + $count++ + + if ($sw.ElapsedMilliseconds -gt 500) { + Write-Progress -Activity "Checking for CVE-2021-26855 in the HttpProxy logs" -Status "$count / $($files.Count)" -PercentComplete ($count * 100 / $files.Count) + $sw.Restart() + } - if ((Get-ChildItem $_ -ErrorAction SilentlyContinue | Select-String "ServerInfo~").Count -gt 0) { - $fileResults = @(Import-Csv -Path $_ -ErrorAction SilentlyContinue | Where-Object AnchorMailbox -Like 'ServerInfo~*/*' | Select-Object -Property DateTime, RequestId, ClientIPAddress, UrlHost, UrlStem, RoutingHint, UserAgent, AnchorMailbox, HttpStatus) - $fileResults | ForEach-Object { - $allResults += $_ + if ((Get-ChildItem $_ -ErrorAction SilentlyContinue | Select-String "ServerInfo~").Count -gt 0) { + $fileResults = @(Import-Csv -Path $_ -ErrorAction SilentlyContinue | Where-Object AnchorMailbox -Like 'ServerInfo~*/*' | Select-Object -Property DateTime, RequestId, ClientIPAddress, UrlHost, UrlStem, RoutingHint, UserAgent, AnchorMailbox, HttpStatus) + $fileResults | ForEach-Object { + $allResults += $_ + } } } - } - Write-Progress -Activity "Checking for CVE-2021-26855 in the HttpProxy logs" -Completed + Write-Progress -Activity "Checking for CVE-2021-26855 in the HttpProxy logs" -Completed - return $allResults - } + return $allResults + } - function Get-Cve26857 { - [CmdletBinding()] - param () + function Get-Cve26857 { + [CmdletBinding()] + param () - Get-WinEvent -FilterHashtable @{ - LogName = 'Application' - ProviderName = 'MSExchange Unified Messaging' - Level = '2' - } -ErrorAction SilentlyContinue | Where-Object Message -Like "*System.InvalidCastException*" - } + Get-WinEvent -FilterHashtable @{ + LogName = 'Application' + ProviderName = 'MSExchange Unified Messaging' + Level = '2' + } -ErrorAction SilentlyContinue | Where-Object Message -Like "*System.InvalidCastException*" + } - function Get-Cve26858 { - [CmdletBinding()] - param () + function Get-Cve26858 { + [CmdletBinding()] + param () - $exchangePath = (Get-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ExchangeServer\v15\Setup).MsiInstallPath + $exchangePath = (Get-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ExchangeServer\v15\Setup).MsiInstallPath - Get-ChildItem -Recurse -Path "$exchangePath\Logging\OABGeneratorLog" | Select-String "Download failed and temporary file" -List | Select-Object -ExpandProperty Path - } + Get-ChildItem -Recurse -Path "$exchangePath\Logging\OABGeneratorLog" | Select-String "Download failed and temporary file" -List | Select-Object -ExpandProperty Path + } - function Get-Cve27065 { - [CmdletBinding()] - param () + function Get-Cve27065 { + [CmdletBinding()] + param () - $exchangePath = (Get-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ExchangeServer\v15\Setup).MsiInstallPath + $exchangePath = (Get-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ExchangeServer\v15\Setup).MsiInstallPath - Get-ChildItem -Recurse -Path "$exchangePath\Logging\ECP\Server\*.log" | Select-String "Set-.*VirtualDirectory" -List | Select-Object -ExpandProperty Path - } + Get-ChildItem -Recurse -Path "$exchangePath\Logging\ECP\Server\*.log" | Select-String "Set-.*VirtualDirectory" -List | Select-Object -ExpandProperty Path + } - function Get-SuspiciousFile { - [CmdletBinding()] - param () + function Get-SuspiciousFile { + [CmdletBinding()] + param () - foreach ($file in Get-ChildItem -Recurse -Path "$env:WINDIR\temp\lsass.*dmp") { - [PSCustomObject]@{ - ComputerName = $env:COMPUTERNAME - Type = 'LsassDump' - Path = $file.FullName - Name = $file.Name + foreach ($file in Get-ChildItem -Recurse -Path "$env:WINDIR\temp\lsass.*dmp") { + [PSCustomObject]@{ + ComputerName = $env:COMPUTERNAME + Type = 'LsassDump' + Path = $file.FullName + Name = $file.Name + } } - } - foreach ($file in Get-ChildItem -Recurse -Path "c:\root\lsass.*dmp") { - [PSCustomObject]@{ - ComputerName = $env:COMPUTERNAME - Type = 'LsassDump' - Path = $file.FullName - Name = $file.Name + foreach ($file in Get-ChildItem -Recurse -Path "c:\root\lsass.*dmp") { + [PSCustomObject]@{ + ComputerName = $env:COMPUTERNAME + Type = 'LsassDump' + Path = $file.FullName + Name = $file.Name + } } - } - foreach ($file in Get-ChildItem -Recurse -Path $env:ProgramData -ErrorAction SilentlyContinue | Where-Object Extension -Match ".7z|.zip|.rar") { - [PSCustomObject]@{ - ComputerName = $env:COMPUTERNAME - Type = 'SuspiciousArchive' - Path = $file.FullName - Name = $file.Name + foreach ($file in Get-ChildItem -Recurse -Path $env:ProgramData -ErrorAction SilentlyContinue | Where-Object Extension -Match ".7z|.zip|.rar") { + [PSCustomObject]@{ + ComputerName = $env:COMPUTERNAME + Type = 'SuspiciousArchive' + Path = $file.FullName + Name = $file.Name + } } } + #endregion Functions + + [PSCustomObject]@{ + ComputerName = $env:COMPUTERNAME + Cve26855 = @(Get-Cve26855) + Cve26857 = @(Get-Cve26857) + Cve26858 = @(Get-Cve26858) + Cve27065 = @(Get-Cve27065) + Suspicious = @(Get-SuspiciousFile) + } } - #endregion Functions - - [PSCustomObject]@{ - ComputerName = $env:COMPUTERNAME - Cve26855 = @(Get-Cve26855) - Cve26857 = @(Get-Cve26857) - Cve26858 = @(Get-Cve26858) - Cve27065 = @(Get-Cve27065) - Suspicious = @(Get-SuspiciousFile) + #endregion Remoting Scriptblock + $parameters = @{ + ScriptBlock = $scriptBlock } + if ($Credential) { $parameters.Credential = $Credential } } - #endregion Remoting Scriptblock - $parameters = @{ - ScriptBlock = $scriptBlock + process { + Invoke-Command @parameters -ComputerName $ComputerName } - if ($Credential) { $parameters.Credential = $Credential } } - process { - Invoke-Command @parameters -ComputerName $ComputerName - } -} -function Write-HafniumReport { - <# + function Write-HafniumReport { + <# .SYNOPSIS Processes output of Test-ExchangeHafnium for reporting on the console screen. @@ -175,72 +187,73 @@ function Write-HafniumReport { Gather data from all exchange servers in the organization and write a report to C:\logs #> - [CmdletBinding()] - param ( - [parameter(ValueFromPipeline = $true)] - $InputObject, - - [string] - $OutPath - ) - - process { - foreach ($report in $InputObject) { - Write-Host "Hafnium Status: Exchange Server $($report.ComputerName)" - if (-not ($report.Cve26855.Count -or $report.Cve26857.Count -or $report.Cve26858.Count -or $report.Cve27065.Count -or $report.Suspicious.Count)) { - Write-Host " Nothing suspicious detected" -ForegroundColor Green - Write-Host "" - continue - } - - if ($report.Cve26855.Count -gt 0) { - Write-Host " [CVE-2021-26855] Suspicious activity found in Http Proxy log!" -ForegroundColor Red - if ($OutPath) { - $newFile = Join-Path -Path $OutPath -ChildPath "$($report.ComputerName)-Cve-2021-26855.csv" - $report.Cve26855 | Export-Csv -Path $newFile - Write-Host " Report exported to: $newFile" - } else { - $report.Cve26855 | Format-Table -AutoSize | Out-Host + [CmdletBinding()] + param ( + [parameter(ValueFromPipeline = $true)] + $InputObject, + + [string] + $OutPath + ) + + process { + foreach ($report in $InputObject) { + Write-Host "Hafnium Status: Exchange Server $($report.ComputerName)" + if (-not ($report.Cve26855.Count -or $report.Cve26857.Count -or $report.Cve26858.Count -or $report.Cve27065.Count -or $report.Suspicious.Count)) { + Write-Host " Nothing suspicious detected" -ForegroundColor Green + Write-Host "" + continue } - Write-Host "" - } - if ($report.Cve26857.Count -gt 0) { - Write-Host " [CVE-2021-26857] Suspicious activity found in Eventlog!" -ForegroundColor Red - Write-Host " $(@($report.Cve26857).Count) events found" - if ($OutPath) { - $newFile = Join-Path -Path $OutPath -ChildPath "$($report.ComputerName)-Cve-2021-26857.csv" - $report.Cve26857 | Select-Object TimeCreated, MachineName, Message | Export-Csv -Path $newFile - Write-Host " Report exported to: $newFile" + + if ($report.Cve26855.Count -gt 0) { + Write-Host " [CVE-2021-26855] Suspicious activity found in Http Proxy log!" -ForegroundColor Red + if ($OutPath) { + $newFile = Join-Path -Path $OutPath -ChildPath "$($report.ComputerName)-Cve-2021-26855.csv" + $report.Cve26855 | Export-Csv -Path $newFile + Write-Host " Report exported to: $newFile" + } else { + $report.Cve26855 | Format-Table -AutoSize | Out-Host + } + Write-Host "" } - Write-Host "" - } - if ($report.Cve26858.Count -gt 0) { - Write-Host " [CVE-2021-26858] Suspicious activity found in OAB generator logs!" -ForegroundColor Red - Write-Host " Please review the following files for 'Download failed and temporary file' entries:" - foreach ($entry in $report.Cve26858) { - Write-Host " $entry" + if ($report.Cve26857.Count -gt 0) { + Write-Host " [CVE-2021-26857] Suspicious activity found in Eventlog!" -ForegroundColor Red + Write-Host " $(@($report.Cve26857).Count) events found" + if ($OutPath) { + $newFile = Join-Path -Path $OutPath -ChildPath "$($report.ComputerName)-Cve-2021-26857.csv" + $report.Cve26857 | Select-Object TimeCreated, MachineName, Message | Export-Csv -Path $newFile + Write-Host " Report exported to: $newFile" + } + Write-Host "" } - if ($OutPath) { - $newFile = Join-Path -Path $OutPath -ChildPath "$($report.ComputerName)-Cve-2021-26858.log" - $report.Cve26858 | Set-Content -Path $newFile - Write-Host " Report exported to: $newFile" + if ($report.Cve26858.Count -gt 0) { + Write-Host " [CVE-2021-26858] Suspicious activity found in OAB generator logs!" -ForegroundColor Red + Write-Host " Please review the following files for 'Download failed and temporary file' entries:" + foreach ($entry in $report.Cve26858) { + Write-Host " $entry" + } + if ($OutPath) { + $newFile = Join-Path -Path $OutPath -ChildPath "$($report.ComputerName)-Cve-2021-26858.log" + $report.Cve26858 | Set-Content -Path $newFile + Write-Host " Report exported to: $newFile" + } + Write-Host "" } - Write-Host "" - } - if ($report.Suspicious.Count -gt 0) { - Write-Host " Other suspicious files found: $(@($report.Suspicious).Count)" - if ($OutPath) { - $newFile = Join-Path -Path $OutPath -ChildPath "$($report.ComputerName)-other.csv" - $report.Suspicious | Export-Csv -Path $newFile - Write-Host " Report exported to: $newFile" - } else { - foreach ($entry in $report.Suspicious) { - Write-Host " $($entry.Type) : $($entry.Path)" + if ($report.Suspicious.Count -gt 0) { + Write-Host " Other suspicious files found: $(@($report.Suspicious).Count)" + if ($OutPath) { + $newFile = Join-Path -Path $OutPath -ChildPath "$($report.ComputerName)-other.csv" + $report.Suspicious | Export-Csv -Path $newFile + Write-Host " Report exported to: $newFile" + } else { + foreach ($entry in $report.Suspicious) { + Write-Host " $($entry.Type) : $($entry.Path)" + } } } } } } -} -$input | Test-ExchangeHafnium | Write-HafniumReport + $ComputerName | Test-ExchangeHafnium | Write-HafniumReport -OutPath $OutPath +} \ No newline at end of file From 6aba37563dec68f04de22949c9eb8faa4a010ce0 Mon Sep 17 00:00:00 2001 From: Bill Long Date: Fri, 5 Mar 2021 16:04:42 -0600 Subject: [PATCH 09/14] Only display DateTime and AnchorMailbox when not writing to a file --- Security/Test-ProxyLogon.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Security/Test-ProxyLogon.ps1 b/Security/Test-ProxyLogon.ps1 index 4b8c19778a..61198fb441 100644 --- a/Security/Test-ProxyLogon.ps1 +++ b/Security/Test-ProxyLogon.ps1 @@ -212,7 +212,7 @@ process { $report.Cve26855 | Export-Csv -Path $newFile Write-Host " Report exported to: $newFile" } else { - $report.Cve26855 | Format-Table -AutoSize | Out-Host + $report.Cve26855 | Format-Table DateTime, AnchorMailbox -AutoSize | Out-Host } Write-Host "" } From 5974710c0e57be01634d8c8597c317c42367f6d0 Mon Sep 17 00:00:00 2001 From: Bill Long Date: Fri, 5 Mar 2021 16:15:24 -0600 Subject: [PATCH 10/14] Check for 2010 --- Security/Test-ProxyLogon.ps1 | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/Security/Test-ProxyLogon.ps1 b/Security/Test-ProxyLogon.ps1 index 61198fb441..d1e7edb71e 100644 --- a/Security/Test-ProxyLogon.ps1 +++ b/Security/Test-ProxyLogon.ps1 @@ -53,13 +53,22 @@ process { #region Remoting Scriptblock $scriptBlock = { #region Functions + function Get-ExchangeInstallPath { + $p = (Get-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ExchangeServer\v15\Setup -ErrorAction SilentlyContinue).MsiInstallPath + if ($null -eq $p) { + $p = (Get-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ExchangeServer\v14\Setup -ErrorAction SilentlyContinue).MsiInstallPath + } + + return $p + } + function Get-Cve26855 { [CmdletBinding()] param () Write-Progress -Activity "Checking for CVE-2021-26855 in the HttpProxy logs" - $exchangePath = (Get-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ExchangeServer\v15\Setup).MsiInstallPath + $exchangePath = Get-ExchangeInstallPath $files = (Get-ChildItem -Recurse -Path "$exchangePath\Logging\HttpProxy" -Filter '*.log').FullName $count = 0 @@ -102,7 +111,7 @@ process { [CmdletBinding()] param () - $exchangePath = (Get-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ExchangeServer\v15\Setup).MsiInstallPath + $exchangePath = Get-ExchangeInstallPath Get-ChildItem -Recurse -Path "$exchangePath\Logging\OABGeneratorLog" | Select-String "Download failed and temporary file" -List | Select-Object -ExpandProperty Path } @@ -111,7 +120,7 @@ process { [CmdletBinding()] param () - $exchangePath = (Get-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ExchangeServer\v15\Setup).MsiInstallPath + $exchangePath = Get-ExchangeInstallPath Get-ChildItem -Recurse -Path "$exchangePath\Logging\ECP\Server\*.log" | Select-String "Set-.*VirtualDirectory" -List | Select-Object -ExpandProperty Path } From 265aa6d51f37a9ff1ce2ec45f858af1b1c22fef3 Mon Sep 17 00:00:00 2001 From: Bill Long Date: Fri, 5 Mar 2021 16:27:55 -0600 Subject: [PATCH 11/14] Fail gracefully on 2010 and ignore dotnet binaries that have .ZipFile in the name --- Security/Test-ProxyLogon.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Security/Test-ProxyLogon.ps1 b/Security/Test-ProxyLogon.ps1 index d1e7edb71e..52742cb716 100644 --- a/Security/Test-ProxyLogon.ps1 +++ b/Security/Test-ProxyLogon.ps1 @@ -122,7 +122,7 @@ process { $exchangePath = Get-ExchangeInstallPath - Get-ChildItem -Recurse -Path "$exchangePath\Logging\ECP\Server\*.log" | Select-String "Set-.*VirtualDirectory" -List | Select-Object -ExpandProperty Path + Get-ChildItem -Recurse -Path "$exchangePath\Logging\ECP\Server\*.log" -ErrorAction SilentlyContinue | Select-String "Set-.*VirtualDirectory" -List | Select-Object -ExpandProperty Path } function Get-SuspiciousFile { @@ -137,7 +137,7 @@ process { Name = $file.Name } } - foreach ($file in Get-ChildItem -Recurse -Path "c:\root\lsass.*dmp") { + foreach ($file in Get-ChildItem -Recurse -Path "c:\root\lsass.*dmp" -ErrorAction SilentlyContinue) { [PSCustomObject]@{ ComputerName = $env:COMPUTERNAME Type = 'LsassDump' @@ -145,7 +145,7 @@ process { Name = $file.Name } } - foreach ($file in Get-ChildItem -Recurse -Path $env:ProgramData -ErrorAction SilentlyContinue | Where-Object Extension -Match ".7z|.zip|.rar") { + foreach ($file in Get-ChildItem -Recurse -Path $env:ProgramData -ErrorAction SilentlyContinue | Where-Object Extension -Match ".7z$|.zip$|.rar$") { [PSCustomObject]@{ ComputerName = $env:COMPUTERNAME Type = 'SuspiciousArchive' From c15c586b69ec0c5bbf12a5aeb32668855ea3e0b7 Mon Sep 17 00:00:00 2001 From: Bill Long Date: Fri, 5 Mar 2021 16:32:46 -0600 Subject: [PATCH 12/14] Make sure OutPath exists --- Security/Test-ProxyLogon.ps1 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Security/Test-ProxyLogon.ps1 b/Security/Test-ProxyLogon.ps1 index 52742cb716..63c7878eb2 100644 --- a/Security/Test-ProxyLogon.ps1 +++ b/Security/Test-ProxyLogon.ps1 @@ -205,6 +205,10 @@ process { $OutPath ) + begin { + New-Item $OutPath -ItemType Directory -Force | Out-Null + } + process { foreach ($report in $InputObject) { Write-Host "Hafnium Status: Exchange Server $($report.ComputerName)" From 1a085f8ba1e73894f710ef12e1691762209ae3dd Mon Sep 17 00:00:00 2001 From: Bill Long Date: Fri, 5 Mar 2021 16:38:29 -0600 Subject: [PATCH 13/14] Add examples at the top --- Security/Test-ProxyLogon.ps1 | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Security/Test-ProxyLogon.ps1 b/Security/Test-ProxyLogon.ps1 index 63c7878eb2..16d2904c50 100644 --- a/Security/Test-ProxyLogon.ps1 +++ b/Security/Test-ProxyLogon.ps1 @@ -1,4 +1,16 @@ -#Checks for signs of exploit from CVE-2021-26855, 26858, 26857, and 27065. +# Checks for signs of exploit from CVE-2021-26855, 26858, 26857, and 27065. +# +# Examples +# +# Check the local Exchange server only and save the report: +# .\Test-ProxyLogon.ps1 -OutputPath $home\desktop\logs +# +# Check all Exchange servers and save the reports: +# Get-ExchangeServer | .\Test-ProxyLogon.ps1 -OutputPath $home\desktop\logs +# +# Check all Exchange servers, but only display the results, don't save them: +# Get-ExchangeServer | .\Test-ProxyLogon.ps1 + [CmdletBinding()] param ( From 275d33161b4932b15f8fae874a67a7d84508ae02 Mon Sep 17 00:00:00 2001 From: Bill Long Date: Fri, 5 Mar 2021 16:44:07 -0600 Subject: [PATCH 14/14] Update readme --- Security/README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Security/README.md b/Security/README.md index 2d07f3c39f..ab3d1e2316 100644 --- a/Security/README.md +++ b/Security/README.md @@ -25,3 +25,16 @@ Formerly known as Test-Hafnium, this script automates all four of the commands f Download the latest release here: [Download Test-ProxyLogon.ps1](https://github.com/microsoft/CSS-Exchange/releases/latest/download/Test-ProxyLogon.ps1) + +The most typical usage of this script is to check all Exchange servers and save the output, +by using the following syntax from Exchange Management Shell: + +`Get-ExchangeServer | .\Test-ProxyLogon.ps1 -OutPath $home\desktop\logs` + +To check the local server only, just run the script: + +`.\Test-ProxyLogon.ps1 -OutPath $home\desktop\logs` + +To display the results without saving them, drop the -Outpath parameter from either example above: + +`.\Test-ProxyLogon.ps1`