Skip to content

Commit

Permalink
Merge pull request #368 from microsoft/main
Browse files Browse the repository at this point in the history
Release
  • Loading branch information
erinIs1337 authored Mar 16, 2021
2 parents 64d616c + 7a29a51 commit ac9ffb7
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 123 deletions.
2 changes: 2 additions & 0 deletions Security/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ This is the most effective way to help quickly protect and mitigate your Exchang

This a better approach for Exchange deployments with Internet access and for those who want an attempt at automated remediation. We have not observed any impact to Exchange Server functionality via these mitigation methods nor do these mitigation methods make any direct changes that disable features of Exchange.

Use of the Exchange On-premises Mitigation Tool and the Microsoft Saftey Scanner are subject to the terms of the Microsoft Privacy Statement: https://aka.ms/privacy

### Requirements to run the Exchange On-premises Mitigation Tool

* External Internet Connection from your Exchange server (required to download the Microsoft Safety Scanner and the IIS URL Rewrite Module).
Expand Down
12 changes: 7 additions & 5 deletions Security/src/EOMT.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -537,13 +537,15 @@ function Run-MSERT {
$Message += "We highly recommend re-running this script with -RunFullScan. "
}
$Message += "For additional guidance, see `"$SummaryFile`"."
Write-Host $Message
$RegMessage = "Microsoft Safety Scanner is complete: THREATS DETECTED"
Set-LogActivity -Stage $Stage -RegMessage $RegMessage -Message $Message
} else {
$Message = "Microsoft Safety Scanner is complete on $env:computername No known threats detected."
Write-Host $Message
$RegMessage = "Microsoft Safety Scanner is complete"
Set-LogActivity -Stage $Stage -RegMessage $RegMessage -Message $Message
}

$Message = "Microsoft Safety Scanner is complete on $env:computername No known threats detected."
$RegMessage = "Microsoft Safety Scanner is complete"
Set-LogActivity -Stage $Stage -RegMessage $RegMessage -Message $Message
}

function Get-ServerVulnStatus {
Expand Down Expand Up @@ -655,7 +657,7 @@ function Write-Summary {
$header = @"
Microsoft Safety Scanner and CVE-2021-26855 mitigation summary
Message: Microsoft attempted to mitigate and protect your Exchange server from CVE-2021-26855 and clear malicious files.
For more information on these vulnerabilities please visit https://aka.ms/Exchangevulns. This attempt was successful.
For more information on these vulnerabilities please visit https://aka.ms/Exchangevulns.
Please review locations and files as soon as possible and take the recommended action.
"@
} else {
Expand Down
174 changes: 56 additions & 118 deletions Security/src/ExchangeMitigations.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -115,140 +115,77 @@ param(

function GetMsiProductVersion {
param (
[System.IO.FileInfo]$filename
[string]$filename
)

try {
$windowsInstaller = New-Object -com WindowsInstaller.Installer

$database = $windowsInstaller.GetType().InvokeMember(
"OpenDatabase", "InvokeMethod", $Null,
$windowsInstaller, @($filename.FullName, 0)
$windowsInstaller, @($filename, 0)
)

$q = "SELECT Value FROM Property WHERE Property = 'ProductVersion'"

$View = $database.GetType().InvokeMember(
"OpenView", "InvokeMethod", $Null, $database, ($q)
)

$View.GetType().InvokeMember("Execute", "InvokeMethod", $Null, $View, $Null)

$record = $View.GetType().InvokeMember(
"Fetch", "InvokeMethod", $Null, $View, $Null
)
try {
$View.GetType().InvokeMember("Execute", "InvokeMethod", $Null, $View, $Null) | Out-Null

$productVersion = $record.GetType().InvokeMember(
"StringData", "GetProperty", $Null, $record, 1
)
$record = $View.GetType().InvokeMember(
"Fetch", "InvokeMethod", $Null, $View, $Null
)

$View.GetType().InvokeMember("Close", "InvokeMethod", $Null, $View, $Null)
$productVersion = $record.GetType().InvokeMember(
"StringData", "GetProperty", $Null, $record, 1
)

return $productVersion
return $productVersion
} finally {
if ($View) {
$View.GetType().InvokeMember("Close", "InvokeMethod", $Null, $View, $Null) | Out-Null
}
}
} catch {
throw "Failed to get MSI file version the error was: {0}." -f $_
}
}
function Get-InstalledSoftware {
<#
.SYNOPSIS
Retrieves a list of all software installed on a Windows computer.
.EXAMPLE
PS> Get-InstalledSoftware
This example retrieves all software installed on the local computer.
.PARAMETER ComputerName
If querying a remote computer, use the computer name here.
.PARAMETER Name
The software title you'd like to limit the query to.
.PARAMETER Guid
The software GUID you'e like to limit the query to
#>
[CmdletBinding()]
function Get-InstalledSoftwareVersion {
param (

[Parameter()]
[ValidateNotNullOrEmpty()]
[string]$ComputerName = $env:COMPUTERNAME,
[string[]]$Name
)

[Parameter()]
[ValidateNotNullOrEmpty()]
[string]$Name,
try {
$UninstallKeys = @(
"HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall",
"HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
)

[Parameter()]
[guid]$Guid
)
process {
try {
$scriptBlock = {
$args[0].GetEnumerator() | ForEach-Object { New-Variable -Name $_.Key -Value $_.Value }

$UninstallKeys = @(
"HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall",
"HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
)
New-PSDrive -Name HKU -PSProvider Registry -Root Registry::HKEY_USERS | Out-Null
$UninstallKeys += Get-ChildItem HKU: | Where-Object { $_.Name -match 'S-\d-\d+-(\d+-){1,14}\d+$' } | ForEach-Object {
"HKU:\$($_.PSChildName)\Software\Microsoft\Windows\CurrentVersion\Uninstall"
}
if (-not $UninstallKeys) {
Write-Warning -Message 'No software registry keys found'
} else {
foreach ($UninstallKey in $UninstallKeys) {
$friendlyNames = @{
'DisplayName' = 'Name'
'DisplayVersion' = 'Version'
}
Write-Verbose -Message "Checking uninstall key [$($UninstallKey)]"
if ($Name) {
$WhereBlock = { $_.GetValue('DisplayName') -like "$Name*" }
} elseif ($GUID) {
$WhereBlock = { $_.PsChildName -eq $Guid.Guid }
} else {
$WhereBlock = { $_.GetValue('DisplayName') }
}
$SwKeys = Get-ChildItem -Path $UninstallKey -ErrorAction SilentlyContinue | Where-Object $WhereBlock
if (-not $SwKeys) {
Write-Verbose -Message "No software keys in uninstall key $UninstallKey"
} else {
foreach ($SwKey in $SwKeys) {
$output = @{ }
foreach ($ValName in $SwKey.GetValueNames()) {
if ($ValName -ne 'Version') {
$output.InstallLocation = ''
if ($ValName -eq 'InstallLocation' -and
($SwKey.GetValue($ValName)) -and
(@('C:', 'C:\Windows', 'C:\Windows\System32', 'C:\Windows\SysWOW64') -notcontains $SwKey.GetValue($ValName).TrimEnd('\'))) {
$output.InstallLocation = $SwKey.GetValue($ValName).TrimEnd('\')
}
[string]$ValData = $SwKey.GetValue($ValName)
if ($friendlyNames[$ValName]) {
$output[$friendlyNames[$ValName]] = $ValData.Trim() ## Some registry values have trailing spaces.
} else {
$output[$ValName] = $ValData.Trim() ## Some registry values trailing spaces
}
}
}
$output.GUID = ''
if ($SwKey.PSChildName -match '\b[A-F0-9]{8}(?:-[A-F0-9]{4}){3}-[A-F0-9]{12}\b') {
$output.GUID = $SwKey.PSChildName
}
New-Object -TypeName PSObject -Prop $output
}
}
New-PSDrive -Name HKU -PSProvider Registry -Root Registry::HKEY_USERS | Out-Null

$UninstallKeys += Get-ChildItem HKU: | Where-Object { $_.Name -match 'S-\d-\d+-(\d+-){1,14}\d+$' } | ForEach-Object {
"HKU:\$($_.PSChildName)\Software\Microsoft\Windows\CurrentVersion\Uninstall"
}

foreach ($UninstallKey in $UninstallKeys) {
$SwKeys = Get-ChildItem -Path $UninstallKey -ErrorAction SilentlyContinue
foreach ($n in $Name) {
$SwKeys = $SwKeys | Where-Object { $_.GetValue('DisplayName') -like "$n" }
}
if ($SwKeys) {
foreach ($SwKey in $SwKeys) {
if ($SwKey.GetValueNames().Contains("DisplayVersion")) {
return $SwKey.GetValue("DisplayVersion")
}
}
}

if ($ComputerName -eq $env:COMPUTERNAME) {
& $scriptBlock $PSBoundParameters
} else {
Invoke-Command -ComputerName $ComputerName -ScriptBlock $scriptBlock -ArgumentList $PSBoundParameters
}
} catch {
Write-Error -Message "Error: $($_.Exception.Message) - Line Number: $($_.InvocationInfo.ScriptLineNumber)"
}
} catch {
Write-Error -Message "Error: $($_.Exception.Message) - Line Number: $($_.InvocationInfo.ScriptLineNumber)"
}
}
Function BackendCookieMitigation {
Expand Down Expand Up @@ -278,7 +215,7 @@ Function BackendCookieMitigation {
Write-Verbose "[INFO] Checking for IIS URL Rewrite Module 2 on $env:computername"

#If IIS 10 check for URL rewrite 2.1 else URL rewrite 2.0
$RewriteModule = Get-InstalledSoftware -Name *IIS* | Where-Object { $_.Name -like "*URL*" -and $_.Name -like "*2*" }
$RewriteModule = Get-InstalledSoftwareVersion -Name "*IIS*", "*URL*", "*2*"
$IISVersion = Get-ItemProperty HKLM:\SOFTWARE\Microsoft\InetStp\ | Select-Object versionstring

$RewriteModuleInstallLog = ($PSScriptRoot + '\' + 'RewriteModuleInstallLog.log')
Expand Down Expand Up @@ -387,8 +324,8 @@ Function UnifiedMessagingMitigation {
)

# UM doesn't apply to Exchange Server 2019
$exchangeVersion = (Get-ExchangeServer).AdminDisplayVersion
if ($exchangeVersion.Major -eq 15 -and $exchangeVersion.Minor -eq 2) {
$exchangeVersion = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\ExchangeServer\v15\Setup\')
if ($exchangeVersion.OwaVersion -notlike "15.0.*") {
return
}

Expand Down Expand Up @@ -452,8 +389,8 @@ Function ECPAppPoolMitigation {
Get-WebAppPoolState -Name $AppPoolName
}
if ($RollbackMitigation) {
$exchangeVersion = (Get-ExchangeServer).AdminDisplayVersion
if ($exchangeVersion.Major -eq 15 -and $exchangeVersion.Minor -eq 2) {
$exchangeVersion = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\ExchangeServer\v15\Setup\')
if ($exchangeVersion.OwaVersion -notlike "15.0.*") {
if (-not((Get-WebAppPoolState -Name "MSExchangeOABAppPool").value -eq "Stopped")) {
StartAndCheckHM
}
Expand Down Expand Up @@ -504,8 +441,9 @@ Function OABAppPoolMitigation {
Get-WebAppPoolState -Name $AppPoolName
}
if ($RollbackMitigation) {
$exchangeVersion = (Get-ExchangeServer).AdminDisplayVersion
if ($exchangeVersion.Major -eq 15 -and $exchangeVersion.Minor -eq 2) {

$exchangeVersion = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\ExchangeServer\v15\Setup\')
if ($exchangeVersion.OwaVersion -notlike "15.0.*") {
if (-not((Get-WebAppPoolState -Name "MSExchangeECPAppPool").value -eq "Stopped")) {
StartAndCheckHM
}
Expand Down Expand Up @@ -562,8 +500,8 @@ Function StopAndCheckHM {
Set-Service MSExchangeHM -StartupType Disabled
}

$exchangeVersion = (Get-ExchangeServer).AdminDisplayVersion
if (-not ($exchangeVersion.Major -eq 15 -and $exchangeVersion.Minor -eq 0)) {
$exchangeVersion = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\ExchangeServer\v15\Setup\')
if ($exchangeVersion.OwaVersion -notlike "15.0.*") {

$MSExchangeHMR = Get-Service MSExchangeHMRecovery
if ($MSExchangeHMR.Status -ne "Stopped") {
Expand All @@ -585,7 +523,7 @@ Function StopAndCheckHM {
}

Get-Service MSExchangeHM
if (-not ($exchangeVersion.Major -eq 15 -and $exchangeVersion.Minor -eq 0)) {
if ($exchangeVersion.OwaVersion -notlike "15.0.*") {
Get-Service MSExchangeHMRecovery
}
}
Expand All @@ -599,8 +537,8 @@ Function StartAndCheckHM {
Start-Service MSExchangeHM
}

$exchangeVersion = (Get-ExchangeServer).AdminDisplayVersion
if (-not ($exchangeVersion.Major -eq 15 -and $exchangeVersion.Minor -eq 0)) {
$exchangeVersion = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\ExchangeServer\v15\Setup\')
if ($exchangeVersion.OwaVersion -notlike "15.0.*") {

$MSExchangeHMR = Get-Service MSExchangeHMRecovery
If (((gwmi -Class win32_service | Where-Object { $_.name -eq "MSExchangeHMRecovery" }).StartMode -ne "Auto" )) {
Expand All @@ -623,7 +561,7 @@ Function StartAndCheckHM {

Get-Service MSExchangeHM

if (-not ($exchangeVersion.Major -eq 15 -and $exchangeVersion.Minor -eq 0)) {
if ($exchangeVersion.OwaVersion -notlike "15.0.*") {
Get-Service MSExchangeHMRecovery
}
}
Expand Down

0 comments on commit ac9ffb7

Please sign in to comment.