From 69d5096bf558871cf7517b719e2b5adcfff7e20a Mon Sep 17 00:00:00 2001 From: Daniel Bacon Date: Mon, 15 Mar 2021 12:10:33 -0700 Subject: [PATCH 1/4] adding EOMT --- Security/README.md | 121 +++---- Security/src/EOMT.ps1 | 795 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 849 insertions(+), 67 deletions(-) create mode 100644 Security/src/EOMT.ps1 diff --git a/Security/README.md b/Security/README.md index 830af59dae..c106778de0 100644 --- a/Security/README.md +++ b/Security/README.md @@ -1,12 +1,64 @@ Script|More Info|Download -|-|- -BackendCookieMitigation.ps1 | [More Info](https://github.com/microsoft/CSS-Exchange/tree/main/Security#backendcookiemitigationps1) | [Download](https://github.com/microsoft/CSS-Exchange/releases/latest/download/BackendCookieMitigation.ps1) +EOMT | [More Info](https://github.com/microsoft/CSS-Exchange/tree/main/Security#exchange-on-premises-mitigation-tool-eomt) | [Download](https://github.com/microsoft/CSS-Exchange/releases/latest/download/EOMT.ps1) CompareExchangeHashes.ps1 | [More Info](https://github.com/microsoft/CSS-Exchange/tree/main/Security#compareexchangehashesps1) | [Download](https://github.com/microsoft/CSS-Exchange/releases/latest/download/CompareExchangeHashes.ps1) ExchangeMitigations.ps1 | [More Info](https://github.com/microsoft/CSS-Exchange/tree/main/Security#exchangemitigationsps1) | [Download](https://github.com/microsoft/CSS-Exchange/releases/latest/download/ExchangeMitigations.ps1) http-vuln-cve2021-26855.nse | [More Info](https://github.com/microsoft/CSS-Exchange/tree/main/Security#http-vuln-cve2021-26855nse) | [Download](https://github.com/microsoft/CSS-Exchange/releases/latest/download/http-vuln-cve2021-26855.nse) Test-ProxyLogon.ps1 | [More Info](https://github.com/microsoft/CSS-Exchange/tree/main/Security#test-proxylogonps1) | [Download](https://github.com/microsoft/CSS-Exchange/releases/latest/download/Test-ProxyLogon.ps1) # Security scripts + +## Exchange On-premises Mitigation Tool (EOMT) +This script contains mitigations to help address the following vulnerabilities. + +* CVE-2021-26855 + +This is the most effective way to help quickly protect and mitigate your Exchange Servers prior to patching. **We recommend this script over the previous ExchangeMitigations.ps1 script.** EOMT automatically downloads any dependencies and runs the Microsoft Safety Scanner. 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. EOMT.ps1 is completely automated and uses familiar mitigation methods previously documented. This script has three operations it performs: + +* Mitigation of CVE-2021-26855 via a URL Rewrite configuration. Note: This mitigates the known methods of this exploit. +* Malware scan of the Exchange Server via the Microsoft Safety Scanner (https://docs.microsoft.com/en-us/windows/security/threat-protection/intelligence/safety-scanner-download) +* Attempt to remeidate compromises detected by the Microsoft Safety Scanner. + +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. + +### Requirements to run EOMT + +* External Internet Connection from your Exchange server (required to download the safety scanner and the IIS URL Rewrite Module). +* PowerShell script must be run as Administrator. + +### System Requirements +* PowerShell 3 or later +* IIS 7.5 and later +* Exchange 2013, 2016, or 2019 +* Windows Server 2008 R2, Server 2012, Server 2012 R2, Server 2016, Server 2019 + +### Who should run EOMT + +Situation | Guidance +-|- +If you have done nothing to date to patch or mitigate this issue… | Run EOMT.PS1 as soon as possible.This will both attempt to remediate as well as mitigate your servers against further attacks. Once complete, follow patching guidance to update your servers on http://aka.ms/exchangevulns +If you have mitigated using any/all of the mitigation guidance Microsoft has given (Exchangemitigations.Ps1, Blog post, etc..) | Run EOMT.PS1 as soon as possible. This will both attempt to remediate as well as mitigate your servers against further attacks. Once complete, follow patching guidance to update your servers on http://aka.ms/exchangevulns +If you have already patched your systems and are protected, but did NOT investigate for any adversary activity, indicators of compromise, etc…. | Run EOMT.PS1 as soon as possible. This will attempt to remediate any existing compromise that may not have been full remediated before patching. +If you have already patched and investigated your systems for any indicators of compromise, etc…. | No action is required + +### Important note regarding Microsoft Safety Scanner + EOMT runs the Microsoft Safety Scanner in a quick scan mode. If you suspect any compromise, we highly recommend you run it in the FULL SCAN mode. FULL SCAN mode can take a long time but if you are not running Mirosoft Defender AV as your default AV, FULL SCAN will be required to remediate threats. + +### EOMT Examples +The default recommended way of using of EOMT.ps1. This will determine if your server is vulnerable, mitigate if vulnerable, and run MSERT in quick scan mode. If the server is not vulnerable only MSERT quick scan will run. + +`.\EOMT.ps1` + +To run a Full MSERT Scan - We only recommend this option only if the initial quick scan discovered threats. The full scan may take hours or days to complete. + +`.\EOMT.ps1 -RunFullScan -DoNotRunMitigation` + +To roll back EOMT mitigations + +`.\EOMT.ps1 -Rollbackmitigation` + +Note: If ExchangeMitigations.ps1 was used previously to apply mitigations, Use ExchangeMitigations.ps1 for rollback. + ## [Test-ProxyLogon.ps1](https://github.com/microsoft/CSS-Exchange/releases/latest/download/Test-ProxyLogon.ps1) Formerly known as Test-Hafnium, this script automates all four of the commands found in the [Hafnium blog post](https://www.microsoft.com/security/blog/2021/03/02/hafnium-targeting-exchange-servers/). It also has a progress bar and some performance tweaks to make the CVE-2021-26855 test run much faster. @@ -15,8 +67,6 @@ Download the latest release here: [Download Test-ProxyLogon.ps1](https://github.com/microsoft/CSS-Exchange/releases/latest/download/Test-ProxyLogon.ps1) -### Usage - The most typical usage of this script is to check all Exchange servers and save the reports, by using the following syntax from Exchange Management Shell: @@ -34,27 +84,6 @@ To display the results without saving them, pass -DisplayOnly: `.\Test-ProxyLogon.ps1 -DisplayOnly` -### Frequently Asked Questions - -**The script says it found suspicious files, and it lists a bunch of zip files. What does this mean?** - -The script will flag any zip/7x/rar files that it finds in ProgramData. As noted in -[this blog post](https://www.microsoft.com/security/blog/2021/03/02/hafnium-targeting-exchange-servers/), web -shells have been observed using such files for exfiltration. An administrator should review the files to -determine if they are valid. Determining if a zip file is a valid part of an installed -product is outside the scope of this script, and whitelisting files by name would only encourage -the use of those specific names by attackers. - -**I'm having trouble running the script on Exchange 2010.** - -If PowerShell 3 is present, the script can be run on Exchange 2010. It will not run on PowerShell 2. One can -also enable PS Remoting and run the script remotely against Exchange 2010. However, -the script has minimal functionality in these scenarios, as Exchange 2010 is only affected by one of the -four announced exploits - CVE-2021-26857. Further, this exploit is only available if the Unified Messaging role -is present. As a result, it is often easier to simply run the Get-EventLog command from the -[blog post](https://www.microsoft.com/security/blog/2021/03/02/hafnium-targeting-exchange-servers/), -rather than using Test-ProxyLogon. - ## [ExchangeMitigations.ps1](https://github.com/microsoft/CSS-Exchange/releases/latest/download/ExchangeMitigations.ps1) This script contains 4 mitigations to help address the following vulnerabilities: @@ -116,17 +145,13 @@ For more information please go to [https://aka.ms/exchangevulns](https://aka.ms/ `.\CompareExchangeHashes.ps1` -This script takes the following actions: -* Checks file hashes in exchange vdirs against known good baseline of hashes. -* Any file under IIS root which is edited after Dec 1st 2020 is marked as suspicious. - +The script currently only validates files in exchange virtual directories only, it does not check any files in the IIS root. **This script needs to be run as administrator on all the exchange servers separately**. The script determines the version of exchange installed on the server and then downloads the hashes for known exchange files from the [published known good hashes of exchange files](https://github.com/microsoft/CSS-Exchange/releases/latest). The result generated is stored in a file locally with the following format: _result.csv If potential malicious files are found during comparision there is an error generated on the cmdline. -* Note: If the result file contains huge number of rows, it is potentially due to missing baseline hashes, please find the exchange versions found on the machine and leave a comment on issue [313](https://github.com/microsoft/CSS-Exchange/issues/313) To read the output, open the result csv file in excel or in powershell: @@ -138,44 +163,6 @@ Submitting files for analysis: * Please submit the output file for analysis in the malware analysis portal [here](https://www.microsoft.com/en-us/wdsi/filesubmission). Please add the text "ExchangeMarchCVE" in "Additional Information" field on the portal submission form. * Instructions on how to use the portal can be found [here](https://docs.microsoft.com/en-us/windows/security/threat-protection/intelligence/submission-guide). -## [BackendCookieMitigation.ps1](https://github.com/microsoft/CSS-Exchange/releases/latest/download/BackendCookieMitigation.ps1) - -This mitigation will filter https requests that contain malicious X-AnonResource-Backend and malformed X-BEResource cookies which were found to be used in CVE-2021-26855. - -This will help with defense against the known patterns observed but not the SSRF as a whole. For more information please visit https://aka.ms/exchangevulns. - -**For this script to work you must have the IIS URL Rewrite Module installed which can be done via this script using the -FullPathToMSI parameter.** - -For IIS 10 and higher URL Rewrite Module 2.1 must be installed, you can download version 2.1 here: - -* x86 & x64 -https://www.iis.net/downloads/microsoft/url-rewrite - -For IIS 8.5 and lower Rewrite Module 2.0 must be installed, you can download version 2.0 here: - -* x86 - https://www.microsoft.com/en-us/download/details.aspx?id=5747 - -* x64 - https://www.microsoft.com/en-us/download/details.aspx?id=7435 - -Installing URL Rewrite version 2.1 on IIS versions 8.5 and lower may cause IIS and Exchange to become unstable. If there is a mismatch between the URL Rewrite module and IIS version, BackendCookieMitigation.ps1 will not apply the mitigation for CVE-2021-26855. You must uninstall the URL Rewrite module and reinstall the correct version. - -**Script requires PowerShell 3.0 and later and must be executed from an elevated PowerShell Session.** - -Download the latest release here: - -[Download BackendCookieMitigation.ps1](https://github.com/microsoft/CSS-Exchange/releases/latest/download/BackendCookieMitigation.ps1) - -To apply with MSI install of the URL Rewrite module - Note: version may vary depending on system info - -`PS C:\> BackendCookieMitigation.ps1 -FullPathToMSI "C:\temp\rewrite_amd64_en-US.msi" -WebSiteNames "Default Web Site" -Verbose ` - -To apply without MSI install - -`PS C:\> BackendCookieMitigation.ps1 -WebSiteNames "Default Web Site" -Verbose` - -To rollback - Note: This does not remove the IIS Rewrite module, only the rules. - -`PS C:\> BackendCookieMitigation.ps1 -WebSiteNames "Default Web Site" -RollbackMitigation -Verbose` - ## [http-vuln-cve2021-26855.nse](https://github.com/microsoft/CSS-Exchange/releases/latest/download/http-vuln-cve2021-26855.nse) This file is for use with nmap. It detects whether the specified URL is vulnerable to the Exchange Server SSRF Vulnerability (CVE-2021-26855). diff --git a/Security/src/EOMT.ps1 b/Security/src/EOMT.ps1 new file mode 100644 index 0000000000..64cfa5630e --- /dev/null +++ b/Security/src/EOMT.ps1 @@ -0,0 +1,795 @@ +<# + .SYNOPSIS + This script contains mitigations to help address the following vulnerabilities. + CVE-2021-26855 + + For more information on each mitigation please visit https://aka.ms/exchangevulns + + .DESCRIPTION + This script has three operations it performs: + Mitigation of CVE-2021-26855 via a URL Rewrite configuration. Note: this mitigates current known attacks. + Malware scan of the Exchange Server via the Microsoft Safety Scanner + Attempt to reverse any changes made by identified threats. + + .PARAMETER RunFullScan + If true will determine if the server is vulnerable and run MSERT in full scan mode. + + .PARAMETER RollbackMitigation + If true will only reverse the mitigations if present. + + .PARAMETER DoNotRunMSERT + If true will not run MSERT. + + .PARAMETER DoNotRunMitigation + If true will not apply mitigations. + + .EXAMPLE + PS C:\> EOMT.ps1 + + This will run the default mode which does the following: + 1. Checks if your server is vulnerable based on the presence of the SU patch or Exchange version + 2. Downloads and installs the IIS URL rewrite tool. + 3. Applies the URL rewrite mitigation (only if vulnerable). + 4. Runs the Microsoft Safety Scanner in "Quick Scan" mode. + + .EXAMPLE + PS C:\> EOMT.ps1 -RollbackMitigation + + This will only rollback the URL rewrite mitigation. + + .EXAMPLE + PS C:\> EOMT.ps1 -RunFullScan -DoNotRunMitigation + + This will only run the Microsoft Safety Scanner in "Full Scan" mode. We only recommend this option only if the initial quick scan discovered threats. The full scan may take hours or days to complete. + + .Link + https://aka.ms/exchangevulns + https://www.iis.net/downloads/microsoft/url-rewrite + https://docs.microsoft.com/en-us/windows/security/threat-protection/intelligence/safety-scanner-download +#> +[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '', Justification = 'Invalid rule result')] +[Cmdletbinding()] +param ( + [switch]$RunFullScan, + [switch]$RollbackMitigation, + [switch]$DoNotRunMSERT, + [switch]$DoNotRunMitigation +) + +$ProgressPreference = "SilentlyContinue" +$EOMTDir = Join-Path $env:TEMP "msert" +$EOMTLogFile = Join-Path $EOMTDir "EOMT.log" +$msertLogPath = "$env:SystemRoot\debug\msert.log" +$msertLogArchivePath = "$env:SystemRoot\debug\msert.old.log" +$detectionFollowUpURL = 'https://go.microsoft.com/fwlink/?linkid=2157359' +$SummaryFile = "$env:SystemDrive\EOMTSummary.txt" + +# Force TLS1.2 to make sure we can download from HTTPS +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + +function Run-Mitigate { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseApprovedVerbs', '', Justification = 'Invalid rule result')] + param( + [string]$WebSiteName = "Default Web Site", + [string]$Stage = "MitigationProcess", + [switch]$RollbackMitigation + + ) + + function GetMsiProductVersion { + param ( + [string]$filename + ) + + try { + $windowsInstaller = New-Object -com WindowsInstaller.Installer + + $database = $windowsInstaller.GetType().InvokeMember( + "OpenDatabase", "InvokeMethod", $Null, + $windowsInstaller, @($filename, 0) + ) + + $q = "SELECT Value FROM Property WHERE Property = 'ProductVersion'" + + $View = $database.GetType().InvokeMember( + "OpenView", "InvokeMethod", $Null, $database, ($q) + ) + + try { + $View.GetType().InvokeMember("Execute", "InvokeMethod", $Null, $View, $Null) | Out-Null + + $record = $View.GetType().InvokeMember( + "Fetch", "InvokeMethod", $Null, $View, $Null + ) + + $productVersion = $record.GetType().InvokeMember( + "StringData", "GetProperty", $Null, $record, 1 + ) + + 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-InstalledSoftwareVersion { + param ( + [ValidateNotNullOrEmpty()] + [string[]]$Name + ) + + try { + $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" + } + + 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") + } + } + } + } + } catch { + Write-Error -Message "Error: $($_.Exception.Message) - Line Number: $($_.InvocationInfo.ScriptLineNumber)" + } + } + + function GetURLRewriteLink { + $DownloadLinks = @{ + "v2.1" = @{ + "x86" = @{ + "de-DE" = "https://download.microsoft.com/download/D/8/1/D81E5DD6-1ABB-46B0-9B4B-21894E18B77F/rewrite_x86_de-DE.msi" + "en-US" = "https://download.microsoft.com/download/D/8/1/D81E5DD6-1ABB-46B0-9B4B-21894E18B77F/rewrite_x86_en-US.msi" + "es-ES" = "https://download.microsoft.com/download/D/8/1/D81E5DD6-1ABB-46B0-9B4B-21894E18B77F/rewrite_x86_es-ES.msi" + "fr-FR" = "https://download.microsoft.com/download/D/8/1/D81E5DD6-1ABB-46B0-9B4B-21894E18B77F/rewrite_x86_fr-FR.msi" + "it-IT" = "https://download.microsoft.com/download/D/8/1/D81E5DD6-1ABB-46B0-9B4B-21894E18B77F/rewrite_x86_it-IT.msi" + "ja-JP" = "https://download.microsoft.com/download/D/8/1/D81E5DD6-1ABB-46B0-9B4B-21894E18B77F/rewrite_x86_ja-JP.msi" + "ko-KR" = "https://download.microsoft.com/download/D/8/1/D81E5DD6-1ABB-46B0-9B4B-21894E18B77F/rewrite_x86_ko-KR.msi" + "ru-RU" = "https://download.microsoft.com/download/D/8/1/D81E5DD6-1ABB-46B0-9B4B-21894E18B77F/rewrite_x86_ru-RU.msi" + "zh-CN" = "https://download.microsoft.com/download/D/8/1/D81E5DD6-1ABB-46B0-9B4B-21894E18B77F/rewrite_x86_zh-CN.msi" + "zh-TW" = "https://download.microsoft.com/download/D/8/1/D81E5DD6-1ABB-46B0-9B4B-21894E18B77F/rewrite_x86_zh-TW.msi" + } + + "x64" = @{ + "de-DE" = "https://download.microsoft.com/download/1/2/8/128E2E22-C1B9-44A4-BE2A-5859ED1D4592/rewrite_amd64_de-DE.msi" + "en-US" = "https://download.microsoft.com/download/1/2/8/128E2E22-C1B9-44A4-BE2A-5859ED1D4592/rewrite_amd64_en-US.msi" + "es-ES" = "https://download.microsoft.com/download/1/2/8/128E2E22-C1B9-44A4-BE2A-5859ED1D4592/rewrite_amd64_es-ES.msi" + "fr-FR" = "https://download.microsoft.com/download/1/2/8/128E2E22-C1B9-44A4-BE2A-5859ED1D4592/rewrite_amd64_fr-FR.msi" + "it-IT" = "https://download.microsoft.com/download/1/2/8/128E2E22-C1B9-44A4-BE2A-5859ED1D4592/rewrite_amd64_it-IT.msi" + "ja-JP" = "https://download.microsoft.com/download/1/2/8/128E2E22-C1B9-44A4-BE2A-5859ED1D4592/rewrite_amd64_ja-JP.msi" + "ko-KR" = "https://download.microsoft.com/download/1/2/8/128E2E22-C1B9-44A4-BE2A-5859ED1D4592/rewrite_amd64_ko-KR.msi" + "ru-RU" = "https://download.microsoft.com/download/1/2/8/128E2E22-C1B9-44A4-BE2A-5859ED1D4592/rewrite_amd64_ru-RU.msi" + "zh-CN" = "https://download.microsoft.com/download/1/2/8/128E2E22-C1B9-44A4-BE2A-5859ED1D4592/rewrite_amd64_zh-CN.msi" + "zh-TW" = "https://download.microsoft.com/download/1/2/8/128E2E22-C1B9-44A4-BE2A-5859ED1D4592/rewrite_amd64_zh-TW.msi" + } + } + "v2.0" = @{ + "x86" = @{ + "de-DE" = "https://download.microsoft.com/download/0/5/0/05045383-D280-4DC6-AE8C-81764118B0F9/rewrite_x86_de-DE.msi" + "en-US" = "https://download.microsoft.com/download/6/9/C/69C1195A-123E-4BE8-8EDF-371CDCA4EC6C/rewrite_2.0_rtw_x86.msi" + "es-ES" = "https://download.microsoft.com/download/1/D/9/1D9464B8-9F3B-4A86-97F2-AEC2AB48F481/rewrite_x86_es-ES.msi" + "fr-FR" = "https://download.microsoft.com/download/1/2/9/129A2686-9654-4B2A-82ED-FC7BCE2BCE93/rewrite_x86_fr-FR.msi" + "it-IT" = "https://download.microsoft.com/download/2/4/A/24AE553F-CA8F-43B3-ACF8-DAC526FC84F2/rewrite_x86_it-IT.msi" + "ja-JP" = "https://download.microsoft.com/download/A/6/9/A69D23A5-7CE3-4F80-B5AE-CF6478A5DE19/rewrite_x86_ja-JP.msi" + "ko-KR" = "https://download.microsoft.com/download/2/6/F/26FCA84A-48BC-4AEE-BD6A-B28ED595832E/rewrite_x86_ko-KR.msi" + "ru-RU" = "https://download.microsoft.com/download/B/1/F/B1FDE19F-B4F9-4EBF-9E50-5C9CDF0302D2/rewrite_x86_ru-RU.msi" + "zh-CN" = "https://download.microsoft.com/download/4/9/C/49CD28DB-4AA6-4A51-9437-AA001221F606/rewrite_x86_zh-CN.msi" + "zh-TW" = "https://download.microsoft.com/download/1/9/4/1947187A-8D73-4C3E-B62C-DC6C7E1B353C/rewrite_x86_zh-TW.msi" + } + "x64" = @{ + "de-DE" = "https://download.microsoft.com/download/3/1/C/31CE0BF6-31D7-415D-A70A-46A430DE731F/rewrite_x64_de-DE.msi" + "en-US" = "https://download.microsoft.com/download/6/7/D/67D80164-7DD0-48AF-86E3-DE7A182D6815/rewrite_2.0_rtw_x64.msi" + "es-ES" = "https://download.microsoft.com/download/9/5/5/955337F6-5A11-417E-A95A-E45EE8C7E7AC/rewrite_x64_es-ES.msi" + "fr-FR" = "https://download.microsoft.com/download/3/D/3/3D359CD6-147B-42E9-BD5B-407D3A1F0B97/rewrite_x64_fr-FR.msi" + "it-IT" = "https://download.microsoft.com/download/6/8/B/68B8EFA8-9404-45A3-A51B-53D940D5E742/rewrite_x64_it-IT.msi" + "ja-JP" = "https://download.microsoft.com/download/3/7/5/375C965C-9D98-438A-8F11-7F417D071DC9/rewrite_x64_ja-JP.msi" + "ko-KR" = "https://download.microsoft.com/download/2/A/7/2A746C73-467A-4BC6-B5CF-C4E88BB40406/rewrite_x64_ko-KR.msi" + "ru-RU" = "https://download.microsoft.com/download/7/4/E/74E569F7-44B9-4D3F-BCA7-87C5FE36BD62/rewrite_x64_ru-RU.msi" + "zh-CN" = "https://download.microsoft.com/download/4/E/7/4E7ECE9A-DF55-4F90-A354-B497072BDE0A/rewrite_x64_zh-CN.msi" + "zh-TW" = "https://download.microsoft.com/download/8/2/C/82CE350D-2068-4DAC-99D5-AEB2241DB545/rewrite_x64_zh-TW.msi" + } + } + } + + $IISVersion = Get-ItemProperty HKLM:\SOFTWARE\Microsoft\InetStp\ | Select-Object versionstring + + if ($IISVersion.VersionString -like "* 10.*") { + $Version = "v2.1" + } else { + $Version = "v2.0" + } + + if ([Environment]::Is64BitOperatingSystem) { + $Architecture = "x64" + } else { + $Architecture = "x86" + } + + if ((Get-Culture).Name -in @("de-DE", "en-US", "es-ES", "fr-FR", "it-IT", "ja-JP", "ko-KR", "ru-RU", "zn-CN", "zn-TW")) { + $Language = (Get-Culture).Name + } else { + $Language = "en-US" + } + + return $DownloadLinks[$Version][$Architecture][$Language] + } + + #Configure Rewrite Rule consts + $HttpCookieInput = '{HTTP_COOKIE}' + $root = 'system.webServer/rewrite/rules' + $inbound = '.*' + $name = 'X-AnonResource-Backend Abort - inbound' + $name2 = 'X-BEResource Abort - inbound' + $pattern = '(.*)X-AnonResource-Backend(.*)' + $pattern2 = '(.*)X-BEResource=(.+)/(.+)~(.+)' + $filter = "{0}/rule[@name='{1}']" -f $root, $name + $filter2 = "{0}/rule[@name='{1}']" -f $root, $name2 + + Import-Module WebAdministration + + if ($RollbackMitigation) { + $Message = "Starting rollback of mitigation on $env:computername" + $RegMessage = "Starting rollback of mitigation" + Set-LogActivity -Stage $Stage -RegMessage $RegMessage -Message $Message + + $site = "IIS:\Sites\$WebSiteName" + + $mitigationFound = $false + foreach ($f in @($filter, $filter2)) { + if (Get-WebConfiguration -Filter $f -PSPath $site) { + $mitigationFound = $true + Clear-WebConfiguration -Filter $f -PSPath $site + } + } + + if ($mitigationFound) { + $Rules = Get-WebConfiguration -Filter 'system.webServer/rewrite/rules/rule' -Recurse + if ($null -eq $Rules) { + Clear-WebConfiguration -PSPath $site -Filter 'system.webServer/rewrite/rules' + } + + $Message = "Rollback of mitigation complete on $env:computername" + $RegMessage = "Rollback of mitigation complete" + Set-LogActivity -Stage $Stage -RegMessage $RegMessage -Message $Message + } else { + $Message = "Mitigation not present on $env:computername" + $RegMessage = "Mitigation not present" + Set-LogActivity -Stage $Stage -RegMessage $RegMessage -Message $Message + } + } else { + $Message = "Starting mitigation process on $env:computername" + $RegMessage = "Starting mitigation process" + Set-LogActivity -Stage $Stage -RegMessage $RegMessage -Message $Message + + #If IIS 10 check for URL rewrite 2.1 else URL rewrite 2.0 + $RewriteModule = Get-InstalledSoftwareVersion -Name "*IIS*", "*URL*", "*2*" + $IISVersion = Get-ItemProperty HKLM:\SOFTWARE\Microsoft\InetStp\ | Select-Object versionstring + + #Install module + if ($RewriteModule) { + + #Throwing an exception if incorrect rewrite module version is installed + if ($IISVersion.VersionString -like "* 10.*" -and ($RewriteModule -eq "7.2.2")) { + $Message = "Incorrect IIS URL Rewrite Module previously installed on $env:computername" + $RegMessage = "Incorrect IIS URL Rewrite Module previously installed" + Set-LogActivity -Error -Stage $Stage -RegMessage $RegMessage -Message $Message + throw + } + if ($IISVersion.VersionString -notlike "* 10.*" -and ($RewriteModule -eq "7.2.1993")) { + $Message = "Incorrect IIS URL Rewrite Module previously installed on $env:computername" + $RegMessage = "Incorrect IIS URL Rewrite Module previously installed" + Set-LogActivity -Error -Stage $Stage -RegMessage $RegMessage -Message $Message + throw + } + + $Message = "IIS URL Rewrite Module is already installed on $env:computername" + $RegMessage = "IIS URL Rewrite Module already installed" + Set-LogActivity -Stage $Stage -RegMessage $RegMessage -Message $Message + } else { + $DownloadLink = GetURLRewriteLink + $DownloadPath = Join-Path $EOMTDir "\$($DownloadLink.Split("/")[-1])" + $RewriteModuleInstallLog = Join-Path $EOMTDir "\RewriteModuleInstall.log" + + $response = Invoke-WebRequest $DownloadLink -UseBasicParsing + [IO.File]::WriteAllBytes($DownloadPath, $response.Content) + + $MSIProductVersion = GetMsiProductVersion -filename $DownloadPath + + #If IIS 10 assert URL rewrite 2.1 else URL rewrite 2.0 + if ($IISVersion.VersionString -like "* 10.*" -and $MSIProductVersion -eq "7.2.2") { + $Message = "Incorrect IIS URL Rewrite Module downloaded on $env:computername" + $RegMessage = "Incorrect IIS URL Rewrite Module downloaded" + Set-LogActivity -Error -Stage $Stage -RegMessage $RegMessage -Message $Message + throw + } + + if ($IISVersion.VersionString -notlike "* 10.*" -and $MSIProductVersion -eq "7.2.1993") { + $Message = "Incorrect IIS URL Rewrite Module downloaded on $env:computername" + $RegMessage = "Incorrect IIS URL Rewrite Module downloaded" + Set-LogActivity -Error -Stage $Stage -RegMessage $RegMessage -Message $Message + throw + } + + $Message = "Installing the IIS URL Rewrite Module on $env:computername" + $RegMessage = "Installing IIS URL Rewrite Module" + Set-LogActivity -Stage $Stage -RegMessage $RegMessage -Message $Message + + $arguments = "/i `"$DownloadPath`" /quiet /log `"$RewriteModuleInstallLog`"" + $msiexecPath = $env:WINDIR + "\System32\msiexec.exe" + Start-Process -FilePath $msiexecPath -ArgumentList $arguments -Wait + Start-Sleep -Seconds 15 + $RewriteModule = Get-InstalledSoftwareVersion -Name "*IIS*", "*URL*", "*2*" + + if ($RewriteModule) { + $Message = "IIS URL Rewrite Module installed on $env:computername" + $RegMessage = "IIS URL Rewrite Module installed" + Set-LogActivity -Stage $Stage -RegMessage $RegMessage -Message $Message + } else { + $Message = "Issue installing IIS URL Rewrite Module $env:computername" + $RegMessage = "Issue installing IIS URL Rewrite Module" + Set-LogActivity -Error -Stage $Stage -RegMessage $RegMessage -Message $Message + throw + } + } + + $Message = "Applying URL Rewrite configuration to $env:COMPUTERNAME :: $WebSiteName" + $RegMessage = "Applying URL Rewrite configuration" + Set-LogActivity -Stage $Stage -RegMessage $RegMessage -Message $Message + + $site = "IIS:\Sites\$WebSiteName" + + try { + if ((Get-WebConfiguration -Filter $filter -PSPath $site).name -eq $name) { + Clear-WebConfiguration -Filter $filter -PSPath $site + } + + if ((Get-WebConfiguration -Filter $filter2 -PSPath $site).name -eq $name2) { + Clear-WebConfiguration -Filter $filter2 -PSPath $site + } + + Add-WebConfigurationProperty -PSPath $site -filter $root -name '.' -value @{name = $name; patternSyntax = 'Regular Expressions'; stopProcessing = 'False' } + Set-WebConfigurationProperty -PSPath $site -filter "$filter/match" -name 'url' -value $inbound + Set-WebConfigurationProperty -PSPath $site -filter "$filter/conditions" -name '.' -value @{input = $HttpCookieInput; matchType = '0'; pattern = $pattern; ignoreCase = 'True'; negate = 'False' } + Set-WebConfigurationProperty -PSPath $site -filter "$filter/action" -name 'type' -value 'AbortRequest' + + Add-WebConfigurationProperty -PSPath $site -filter $root -name '.' -value @{name = $name2; patternSyntax = 'Regular Expressions'; stopProcessing = 'True' } + Set-WebConfigurationProperty -PSPath $site -filter "$filter2/match" -name 'url' -value $inbound + Set-WebConfigurationProperty -PSPath $site -filter "$filter2/conditions" -name '.' -value @{input = $HttpCookieInput; matchType = '0'; pattern = $pattern2; ignoreCase = 'True'; negate = 'False' } + Set-WebConfigurationProperty -PSPath $site -filter "$filter2/action" -name 'type' -value 'AbortRequest' + + $Message = "Mitigation complete on $env:COMPUTERNAME :: $WebSiteName" + $RegMessage = "Mitigation complete" + Set-LogActivity -Stage $Stage -RegMessage $RegMessage -Message $Message + } catch { + $Message = "Mitigation failed on $env:COMPUTERNAME :: $WebSiteName" + $RegMessage = "Mitigation failed" + Set-LogActivity -Error -Stage $Stage -RegMessage $RegMessage -Message $Message + throw + } + } +} + +function Run-MSERT { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseApprovedVerbs', '', Justification = 'Invalid rule result')] + param( + [switch] $RunFullScan + ) + $Stage = "MSERTProcess" + if ($DoNotRunMSERT) { + $Message = "Skipping mitigation -DoNotRunMSERT set on $env:computername" + $RegMessage = "Skipping mitigation -DoNotRunMSERT" + Set-LogActivity -Stage $Stage -RegMessage $RegMessage -Message $Message + return + } + + #Check for KB4474419 + $OS = [System.Environment]::OSVersion + if ($OS.Version.Major -eq 6 -and $OS.Version.Minor -eq 1) { + $Hotfix = Get-HotFix -Id KB4474419 -ErrorAction SilentlyContinue + + if (-not ($Hotfix)) { + $Message = "Unable to run MSERT: KB4474419 is missing on Server 2008 R2" + $RegMessage = "Unable to run MSERT KB4474419 missing" + + Set-LogActivity -Error -Stage $Stage -RegMessage $RegMessage -Message $Message + throw + } + } + + #Check for running MSERT or MRT process before download + $procsToWaitFor = @("mrt", "msert") + :checkForRunningCleaner while ($true) { + foreach ($procName in $procsToWaitFor) { + $proc = Get-Process -Name $procName -ErrorAction SilentlyContinue + if ($proc) { + $pids = [string]::Join(",", $proc.Id) + + $Message = "Found $procName already running ($pids). Waiting for it to exit." + $RegMessage = "msert already running waiting" + $Stage = "MSERTProcess" + Set-LogActivity -Stage $Stage -RegMessage $RegMessage -Message $Message + + Start-Sleep -Seconds 60 + continue checkForRunningCleaner + } + } + break + } + + if ([System.Environment]::Is64BitOperatingSystem) { + $MSERTUrl = "https://go.microsoft.com/fwlink/?LinkId=212732" + } else { + $MSERTUrl = "https://go.microsoft.com/fwlink/?LinkId=212733" + } + + $Message = "Starting MSERTProcess on $env:computername" + $RegMessage = "Starting MSERTProcess" + Set-LogActivity -Stage $Stage -RegMessage $RegMessage -Message $Message + + try { + $msertExe = Join-Path $EOMTDir "\msert.exe" + $response = Invoke-WebRequest $MSERTUrl -UseBasicParsing + [IO.File]::WriteAllBytes($msertExe, $response.Content) + + $Message = "MSERT download complete on $env:computername" + $RegMessage = "MSERT download complete" + Set-LogActivity -Stage $Stage -RegMessage $RegMessage -Message $Message + } catch { + $Message = "MSERT download failed on $env:computername" + $RegMessage = "MSERT download failed" + Set-LogActivity -Error -Stage $Stage -RegMessage $RegMessage -Message $Message + throw + } + + #Start MSERT + + function RunMsert { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidAssignmentToAutomaticVariable', '', Justification = 'Invalid rule result')] + param( + [switch]$FullScan + ) + + $msertLogPath = "$env:SystemRoot\debug\msert.log" + $msertLogArchivePath = "$env:SystemRoot\debug\msert.old.log" + + if (Test-Path $msertLogPath) { + Get-Content $msertLogPath | Out-File $msertLogArchivePath -Append + Remove-Item $msertLogPath + } + + $msertArguments = "/Q" + if ($FullScan) { + $msertArguments = "/F /Q" + } + + Start-Process $msertExe -ArgumentList $msertArguments -Wait + + $detected = $false + + if (Test-Path $msertLogPath) { + $matches = Select-String -Path $msertLogPath -Pattern "Threat Detected" + if ($matches) { + $detected = $true + } + } else { + $Message = "Did not find expected scanner log file at $msertLogPath" + $RegMessage = "No scanner log" + Set-LogActivity -Error -Stage $Stage -RegMessage $RegMessage -Message $Message + throw + } + + return $detected + } + + if ($RunFullScan) { + Write-Warning -Message "Running a full scan can take hours or days to complete." + Write-Warning -Message "Would you like to continue with the Full MSERT Scan?" + + while ($true) { + $Confirm = Read-Host "(Y/N)" + if ($Confirm -like "N") { + return + } + if ($Confirm -like "Y") { + break + } + } + + $Message = "Running Microsoft Safety Scanner - Mode: Full Scan on $env:computername" + $RegMessage = "Running Microsoft Safety Scanner Full Scan" + Set-LogActivity -Stage $Stage -RegMessage $RegMessage -Message $Message + + $msertDetected = RunMsert -FullScan + } else { + Write-Verbose -Message "Quick scan will take several minutes to complete, please wait.." -Verbose + + $Message = "Running Microsoft Safety Scanner - Mode: Quick Scan on $env:computername" + $RegMessage = "Running Microsoft Safety Scanner Quick Scan" + Set-LogActivity -Stage $Stage -RegMessage $RegMessage -Message $Message + + $msertDetected = RunMsert + } + + if ($msertDetected) { + Write-Warning -Message "THREATS DETECTED on $env:computername!" + Get-Content $msertLogPath + $Message = "Threats detected! Please review `"$msertLogPath`" as soon as possible. " + if (!$RunFullScan) { + $Message += "We highly recommend re-running this script with -RunFullScan. " + } + $Message += "For additional guidance, see `"$SummaryFile`"." + $RegMessage = "Microsoft Safety Scanner is complete: THREATS DETECTED" + 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 { + param( + $Version = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\ExchangeServer\v15\Setup\') + ) + + $Version = $Version.OwaVersion + $FutureCUs = @{ + E19CU9 = "15.2.858.5" + E16CU20 = "15.1.2242.4" + } + + if ($version -like "15.2.*") { + $LatestCU = $FutureCUs.E19CU9 + } elseif ($version -like "15.1.*") { + $LatestCU = $FutureCUs.E16CU20 + } else { + $LatestCU = "15.2.000.0000" #version higher than 15.0 to trigger SecurityHotfix check for E15 + } + + if ([version]$LatestCU -ge [version]$Version) { + + $SecurityHotfix = Get-ItemProperty HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\* ` + | Where-Object displayname -Like "*KB5000871*" ` + | Select-Object displayname -ErrorAction SilentlyContinue + + if (!$SecurityHotfix) { + return $true + } + } + return $false +} + +function Write-Log { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidOverwritingBuiltInCmdlets', '', Justification = 'Invalid rule result')] + param + ( + [string]$Message, + [string]$Path = $EOMTLogFile, + [string]$Level = "Info" + ) + + $FormattedDate = Get-Date -Format "yyyy-MM-dd HH:mm:ss" + + # Write log entry to $Path + "$FormattedDate $($Level): $Message" | Out-File -FilePath $Path -Append +} + +function Set-LogActivity { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidAssignmentToAutomaticVariable', '', Justification = 'Invalid rule result')] + [CmdletBinding(SupportsShouldProcess)] + param ( + $Stage, + $RegMessage, + $Message, + [switch] $Error + ) + + if ($Error) { + $FullRegMessage = "0 $RegMessage" + $Level = "Error" + } else { + $FullRegMessage = "1 $RegMessage" + $Level = "Info" + } + If ($Level -eq "Info") { + Write-Verbose -Message $Message -Verbose + } else { + Write-Error -Message $Message + } + + Write-Log -Message $Message -Level $Level + Set-Registry -RegKey "HKLM:\Software\MSERTBootstrap\PatchState" -RegValue "Timestamp" -RegData (Get-Date).ToString("MM/dd/yyyy hh:mm:ss") -RegType String | Out-Null + Set-Registry -RegKey "HKLM:\Software\MSERTBootstrap\PatchState" -RegValue $Stage -RegData $FullRegMessage -RegType String | Out-Null +} + +function Set-Registry { + [CmdletBinding(SupportsShouldProcess)] + param ( + $RegKey, + $RegValue, + $RegData, + [ValidateSet('String', 'DWord', 'Binary', 'ExpandString', 'MultiString', 'None', 'QWord', 'Unknown')] + $RegType = 'String' + ) + + if (-not (Test-Path $RegKey)) { + Write-Verbose "The key $RegKey does not exist. Trying to create it..." + + try { + New-Item -Path $RegKey -Force + Write-Verbose "Creation of $RegKey was successful." + } catch { + Write-Error -Message $_ + return + } + } + + Set-ItemProperty -Path $RegKey -Name $RegValue -Value $RegData -Type $RegType -Force +} + +function Write-Summary { + param( + [switch]$Pass + ) + + if ($Pass) { + $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. +Please review locations and files as soon as possible and take the recommended action. +"@ + } else { + $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 unsuccessful. +Please review locations and files as soon as possible and take the recommended action. +"@ + } + + $summary = @" +$header + +Microsoft saved several files to your system to "$EOMTDir". The only files that should be present in this directory are: + a - msert.exe + b - EOMT.log + c - RewriteModuleInstall.log + d - one of the following IIS URL rewrite MSIs: + rewrite_amd64_[de-DE,en-US,es-ES,fr-FR,it-IT,ja-JP,ko-KR,ru-RU,zh-CN,zh-TW].msi + rewrite_ x86_[de-DE,es-ES,fr-FR,it-IT,ja-JP,ko-KR,ru-RU,zh-CN,zh-TW].msi + rewrite_x64_[de-DE,es-ES,fr-FR,it-IT,ja-JP,ko-KR,ru-RU,zh-CN,zh-TW].msi + rewrite_2.0_rtw_x86.msi + rewrite_2.0_rtw_x64.msi + +1 - Confirm the IIS URL Rewrite Module is installed. This module is required for the mitigation of CVE-2021-26855, the module and the configuration (present or not) will not impact this system negatively. + a - If installed, Confirm the following entry exists in the "$env:SystemDrive\inetpub\wwwroot\web.config". If this configuration is not present, your server is not mitigated. This may have occurred if the module was not successfully installed with a supported version for your system. + + + + + + + + + + + + + + + + + + + + + +2 - Review the results of the Microsoft Safety Scanner + Microsoft Safety Scanner log can be found at "$msertLogPath" and "$msertLogArchivePath" If any threats were detected, please review the guidance here: $detectionFollowUpURL + +"@ + + if (Test-Path $SummaryFile) { + Remove-Item $SummaryFile -Force + } + + $summary = $summary.Replace("`r`n", "`n").Replace("`n", "`r`n") + $summary | Out-File -FilePath $SummaryFile -Encoding ascii -Force +} + +# Main +try { + $Stage = "EOMTStart" + + if (!(Test-Path $EOMTDir)) { + New-Item -ItemType Directory $EOMTDir | Out-Null + } + + $Message = "Starting EOMT.ps1 on $env:computername" + $RegMessage = "Starting EOMT.ps1" + Set-LogActivity -Stage $Stage -RegMessage $RegMessage -Message $Message + + #IsAdmin? + if (!([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) { + $Message = "Unable to launch EOMT.ps1: please re-run as administrator." + $RegMessage = "Insufficient permissions" + Set-LogActivity -Error -Stage $Stage -RegMessage $RegMessage -Message $Message + throw + } + + #IsPS3 or later? + if ($PSVersionTable.PSVersion.Major -lt 3) { + $Message = "Unsupported Powershell on $env:computername" + $RegMessage = "Unsupported Powershell" + Set-LogActivity -Error -Stage $Stage -RegMessage $RegMessage -Message $Message + throw + } + + $Message = "EOMT precheck complete on $env:computername" + $RegMessage = "EOMT precheck complete" + Set-LogActivity -Stage $Stage -RegMessage $RegMessage -Message $Message + + #Execute Mitigation + if ($DoNotRunMitigation) { + $Stage = "DoNotRunMitigation" + $Message = "Skipping mitigation -DoNotRunMitigation set on $env:computername" + $RegMessage = "Skipping mitigation -DoNotRunMitigation" + Set-LogActivity -Stage $Stage -RegMessage $RegMessage -Message $Message + } + + if ($RollbackMitigation) { + Run-Mitigate -RollbackMitigation + } + + if (!$DoNotRunMitigation -and !$RollbackMitigation) { + #Normal run + $IsVulnerable = Get-ServerVulnStatus + if ($IsVulnerable) { + $Message = "$env:computername is vulnerable: applying mitigation" + $RegMessage = "Server is vulnerable" + Set-LogActivity -Stage $Stage -RegMessage $RegMessage -Message $Message + Run-Mitigate + } else { + $Message = "$env:computername is not vulnerable: mitigation not needed" + $RegMessage = "Server is not vulnerable" + Set-LogActivity -Stage $Stage -RegMessage $RegMessage -Message $Message + } + } + + #Execute Msert + if ($RunFullScan) { + Run-MSERT -RunFullScan + } elseif (!$RollbackMitigation) { + Run-MSERT + } + + $Message = "EOMT.ps1 complete on $env:computername, please review EOMT logs at $EOMTLogFile and the summary file at $SummaryFile" + $RegMessage = "EOMT.ps1 failed to complete" + Set-LogActivity -Stage $Stage -RegMessage $RegMessage -Message $Message + Write-Summary -Pass #Pass +} catch { + $Message = "EOMT.ps1 failed to complete on $env:computername, please review EOMT logs at $EOMTLogFile and the summary file at $SummaryFile - $_" + $RegMessage = "EOMT.ps1 failed to complete" + Set-LogActivity -Error -Stage $Stage -RegMessage $RegMessage -Message $Message + Write-Summary #Fail +} From 71a927ec9593beae5d39efc309fe21144f8c85d2 Mon Sep 17 00:00:00 2001 From: Daniel Bacon Date: Mon, 15 Mar 2021 12:12:23 -0700 Subject: [PATCH 2/4] spelling fix --- Security/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Security/README.md b/Security/README.md index c106778de0..25c4269fab 100644 --- a/Security/README.md +++ b/Security/README.md @@ -17,7 +17,7 @@ This is the most effective way to help quickly protect and mitigate your Exchang * Mitigation of CVE-2021-26855 via a URL Rewrite configuration. Note: This mitigates the known methods of this exploit. * Malware scan of the Exchange Server via the Microsoft Safety Scanner (https://docs.microsoft.com/en-us/windows/security/threat-protection/intelligence/safety-scanner-download) -* Attempt to remeidate compromises detected by the Microsoft Safety Scanner. +* Attempt to remediate compromises detected by the Microsoft Safety Scanner. 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. From 68620749344f1dcb35caf9d6c061706ef0a90eff Mon Sep 17 00:00:00 2001 From: Daniel Bacon Date: Mon, 15 Mar 2021 12:18:53 -0700 Subject: [PATCH 3/4] removing backend cookie mitigation adding header link --- Security/README.md | 2 +- Security/src/BackendCookieMitigation.ps1 | 320 ----------------------- 2 files changed, 1 insertion(+), 321 deletions(-) delete mode 100644 Security/src/BackendCookieMitigation.ps1 diff --git a/Security/README.md b/Security/README.md index 25c4269fab..004fa2e0bd 100644 --- a/Security/README.md +++ b/Security/README.md @@ -8,7 +8,7 @@ Test-ProxyLogon.ps1 | [More Info](https://github.com/microsoft/CSS-Exchange/tree # Security scripts -## Exchange On-premises Mitigation Tool (EOMT) +## [Exchange On-premises Mitigation Tool (EOMT)](https://github.com/microsoft/CSS-Exchange/releases/latest/download/EOMT.ps1) This script contains mitigations to help address the following vulnerabilities. * CVE-2021-26855 diff --git a/Security/src/BackendCookieMitigation.ps1 b/Security/src/BackendCookieMitigation.ps1 deleted file mode 100644 index 7e67ac52bc..0000000000 --- a/Security/src/BackendCookieMitigation.ps1 +++ /dev/null @@ -1,320 +0,0 @@ -<# - .SYNOPSIS - This script contains a mitigation for CVE-2021-26855 - For more information please https://aka.ms/exchangevulns - - .DESCRIPTION - This mitigation will filter https requests that contain malicious X-AnonResource-Backend and malformed X-BEResource cookies which were found to be used in cve2021-26855. - This will help with defense against the known patterns observed but not the SSRF as a whole. - - For IIS 10 and higher URL Rewrite Module 2.1 must be installed, you can download version 2.1 (x86 and x64) here: - - * x86 & x64 -https://www.iis.net/downloads/microsoft/url-rewrite - - For IIS 8.5 and lower Rewrite Module 2.0 must be installed, you can download version 2.0 here: - - * x86 - https://www.microsoft.com/en-us/download/details.aspx?id=5747 - - * x64 - https://www.microsoft.com/en-us/download/details.aspx?id=7435 - - It is important to follow these version guidelines as it was found installing the newer version of the URL rewrite module on older versions of IIS (IIS 8.5 and lower) can cause IIS and Exchange to become unstable. - If you find yourself in a scenario where a newer version of the IIS URL rewrite module was installed on an older version of IIS, uninstalling the URL rewrite module and reinstalling the recommended version listed above should resolve any instability issues. - - Script requires PowerShell 3.0 and later and must be executed from an elevated PowerShell Session. - - .PARAMETER FullPathToMSI - This is string parameter is used to specify path of MSI file of URL Rewrite Module. - - .PARAMETER WebSiteNames - This is string array parameter is used to specify name of the Default Web Site in IIS. - - .PARAMETER RollbackMitigation - This is a switch parameter is used to roll back the Backend Cookie Mitigation - - .EXAMPLE - PS C:\> BackendCookieMitigation.ps1 -FullPathToMSI "C:\temp\rewrite_amd64_en-US.msi" -WebSiteNames "Default Web Site" -Verbose - - To apply with MSI install of the URL Rewrite module - Note: version may vary depending on system info - - .EXAMPLE - PS C:\> BackendCookieMitigation.ps1 -WebSiteNames "Default Web Site" -Verbose - - To apply without MSI install - - .EXAMPLE - PS C:\> BackendCookieMitigation.ps1 -WebSiteNames "Default Web Site" -RollbackMitigation -Verbose - - To rollback - Note: This does not uninstall the IIS Rewrite module, only the rules. - - .LINK - https://aka.ms/exchangevulns - https://www.iis.net/downloads/microsoft/url-rewrite - https://www.microsoft.com/en-us/download/details.aspx?id=5747 - https://www.microsoft.com/en-us/download/details.aspx?id=7435 - -#> - -[CmdLetBinding()] -param( - [System.IO.FileInfo]$FullPathToMSI, - [ValidateNotNullOrEmpty()] - [string[]]$WebSiteNames, - [switch]$RollbackMitigation -) -function GetMsiProductVersion { - param ( - [System.IO.FileInfo]$filename - ) - - try { - $windowsInstaller = New-Object -com WindowsInstaller.Installer - - $database = $windowsInstaller.GetType().InvokeMember( - "OpenDatabase", "InvokeMethod", $Null, - $windowsInstaller, @($filename.FullName, 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 - ) - - $productVersion = $record.GetType().InvokeMember( - "StringData", "GetProperty", $Null, $record, 1 - ) - - $View.GetType().InvokeMember("Close", "InvokeMethod", $Null, $View, $Null) - - return $productVersion - } 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()] - param ( - - [Parameter()] - [ValidateNotNullOrEmpty()] - [string]$ComputerName = $env:COMPUTERNAME, - - [Parameter()] - [ValidateNotNullOrEmpty()] - [string]$Name, - - [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 - } - } - } - } - } - - 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)" - } - } -} - -#Configure Rewrite Rule consts -$HttpCookieInput = '{HTTP_COOKIE}' -$root = 'system.webServer/rewrite/rules' -$inbound = '.*' -$name = 'X-AnonResource-Backend Abort - inbound' -$name2 = 'X-BEResource Abort - inbound' -$pattern = '(.*)X-AnonResource-Backend(.*)' -$pattern2 = '(.*)X-BEResource=(.+)/(.+)~(.+)' -$filter = "{0}/rule[@name='{1}']" -f $root, $name -$filter2 = "{0}/rule[@name='{1}']" -f $root, $name2 - -if (!$RollbackMitigation) { - Write-Verbose "[INFO] Starting mitigation process on $env:computername" - - #Check if IIS URL Rewrite Module 2 is installed - 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*" } - $IISVersion = Get-ItemProperty HKLM:\SOFTWARE\Microsoft\InetStp\ | Select-Object versionstring - - $RewriteModuleInstallLog = ($PSScriptRoot + '\' + 'RewriteModuleInstallLog.log') - - #Install module - if ($RewriteModule) { - - #Throwing an exception if incorrect rewrite module version is installed - if ($IISVersion.VersionString -like "*10.*" -and ($RewriteModule.Version -eq "7.2.2")) { - throw "Incorrect IIS URL Rewrite Module 2.0 Installed. You need to install IIS URL Rewrite Module 2.1 to avoid instability issues." - } - if ($IISVersion.VersionString -notlike "*10.*" -and ($RewriteModule.Version -eq "7.2.1993")) { - throw "Incorrect IIS URL Rewrite Module 2.1 Installed. You need to install IIS URL Rewrite Module 2.0 to avoid instability issues." - } - - Write-Verbose "[INFO] IIS URL Rewrite Module 2 already installed on $env:computername" -Verbose - } else { - - if ($FullPathToMSI) { - - $MSIProductVersion = GetMsiProductVersion -filename $FullPathToMSI - - #If IIS 10 assert URL rewrite 2.1 else URL rewrite 2.0 - if ($IISVersion.VersionString -like "*10.*" -and $MSIProductVersion -eq "7.2.2") { - throw "Incorrect MSI for IIS $($IISVersion.VersionString), please use URL rewrite 2.1" - } - if ($IISVersion.VersionString -notlike "*10.*" -and $MSIProductVersion -eq "7.2.1993") { - throw "Incorrect MSI for IIS $($IISVersion.VersionString), please use URL rewrite 2.0" - } - - Write-Verbose "[INFO] Installing IIS URL Rewrite Module 2" -Verbose - $arguments = " /i " + '"' + $FullPathToMSI.FullName + '"' + " /quiet /log " + '"' + $RewriteModuleInstallLog + '"' - $msiexecPath = $env:WINDIR + "\System32\msiexec.exe" - Start-Process -FilePath $msiexecPath -ArgumentList $arguments -Wait - Start-Sleep -Seconds 15 - $RewriteModule = Get-InstalledSoftware -Name *IIS* | Where-Object { $_.Name -like "*URL*" -and $_.Name -like "*2*" } - if ($RewriteModule) { - Write-Verbose "[OK] IIS URL Rewrite Module 2 installed on $env:computername" - } else { - throw "[ERROR] Issue installing IIS URL Rewrite Module 2, please review $($RewriteModuleInstallLog)" - } - } else { - throw "[ERROR] Unable to proceed on $env:computername, path to IIS URL Rewrite Module MSI not provided and module is not installed." - } - } - - foreach ($website in $WebSiteNames) { - Write-Verbose "[INFO] Applying rewrite rule configuration to $env:COMPUTERNAME :: $website" - - $site = "IIS:\Sites\$($website)" - - try { - if ((Get-WebConfiguration -Filter $filter -PSPath $site).name -eq $name) { - Clear-WebConfiguration -Filter $filter -PSPath $site - } - - if ((Get-WebConfiguration -Filter $filter2 -PSPath $site).name -eq $name2) { - Clear-WebConfiguration -Filter $filter2 -PSPath $site - } - - - Add-WebConfigurationProperty -PSPath $site -filter $root -name '.' -value @{name = $name; patterSyntax = 'Regular Expressions'; stopProcessing = 'False' } - Set-WebConfigurationProperty -PSPath $site -filter "$filter/match" -name 'url' -value $inbound - Set-WebConfigurationProperty -PSPath $site -filter "$filter/conditions" -name '.' -value @{input = $HttpCookieInput; matchType = '0'; pattern = $pattern; ignoreCase = 'True'; negate = 'False' } - Set-WebConfigurationProperty -PSPath $site -filter "$filter/action" -name 'type' -value 'AbortRequest' - - Add-WebConfigurationProperty -PSPath $site -filter $root -name '.' -value @{name = $name2; patternSyntax = 'Regular Expressions'; stopProcessing = 'True' } - Set-WebConfigurationProperty -PSPath $site -filter "$filter2/match" -name 'url' -value $inbound - Set-WebConfigurationProperty -PSPath $site -filter "$filter2/conditions" -name '.' -value @{input = $HttpCookieInput; matchType = '0'; pattern = $pattern2; ignoreCase = 'True'; negate = 'False' } - Set-WebConfigurationProperty -PSPath $site -filter "$filter2/action" -name 'type' -value 'AbortRequest' - - Write-Verbose "[OK] Rewrite rule configuration complete for $env:COMPUTERNAME :: $website" - Get-WebConfiguration -Filter $filter -PSPath $site - Get-WebConfiguration -Filter $filter2 -PSPath $site - } catch { - throw $_ - } - } -} else { - Write-Verbose "[INFO] Starting mitigation rollback process on $env:computername" - foreach ($website in $WebSiteNames) { - - $site = "IIS:\Sites\$($website)" - - $MitigationConfig = Get-WebConfiguration -Filter $filter -PSPath $site - if ($MitigationConfig) { - Clear-WebConfiguration -Filter $filter -PSPath $site - Clear-WebConfiguration -Filter $filter2 -PSPath $site - - $Rules = Get-WebConfiguration -Filter 'system.webServer/rewrite/rules/rule' -Recurse - if ($null -eq $Rules) { - Clear-WebConfiguration -PSPath $site -Filter 'system.webServer/rewrite/rules' - } - Write-Verbose "[OK] Rewrite rule mitigation removed for $env:COMPUTERNAME :: $website" - } else { - Write-Verbose "[INFO] Rewrite rule mitigation does not exist for $env:COMPUTERNAME :: $website" - } - } -} From 8e8494dfa3ff67deee91b17f9b9eef9eb0f9ca23 Mon Sep 17 00:00:00 2001 From: Daniel Bacon Date: Mon, 15 Mar 2021 12:24:40 -0700 Subject: [PATCH 4/4] re-adding latest test-proxy and CompareHashes readme txt --- Security/README.md | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/Security/README.md b/Security/README.md index 004fa2e0bd..c7d7dbfb97 100644 --- a/Security/README.md +++ b/Security/README.md @@ -67,6 +67,8 @@ Download the latest release here: [Download Test-ProxyLogon.ps1](https://github.com/microsoft/CSS-Exchange/releases/latest/download/Test-ProxyLogon.ps1) +### Usage + The most typical usage of this script is to check all Exchange servers and save the reports, by using the following syntax from Exchange Management Shell: @@ -84,6 +86,27 @@ To display the results without saving them, pass -DisplayOnly: `.\Test-ProxyLogon.ps1 -DisplayOnly` +### Frequently Asked Questions + +**The script says it found suspicious files, and it lists a bunch of zip files. What does this mean?** + +The script will flag any zip/7x/rar files that it finds in ProgramData. As noted in +[this blog post](https://www.microsoft.com/security/blog/2021/03/02/hafnium-targeting-exchange-servers/), web +shells have been observed using such files for exfiltration. An administrator should review the files to +determine if they are valid. Determining if a zip file is a valid part of an installed +product is outside the scope of this script, and whitelisting files by name would only encourage +the use of those specific names by attackers. + +**I'm having trouble running the script on Exchange 2010.** + +If PowerShell 3 is present, the script can be run on Exchange 2010. It will not run on PowerShell 2. One can +also enable PS Remoting and run the script remotely against Exchange 2010. However, +the script has minimal functionality in these scenarios, as Exchange 2010 is only affected by one of the +four announced exploits - CVE-2021-26857. Further, this exploit is only available if the Unified Messaging role +is present. As a result, it is often easier to simply run the Get-EventLog command from the +[blog post](https://www.microsoft.com/security/blog/2021/03/02/hafnium-targeting-exchange-servers/), +rather than using Test-ProxyLogon. + ## [ExchangeMitigations.ps1](https://github.com/microsoft/CSS-Exchange/releases/latest/download/ExchangeMitigations.ps1) This script contains 4 mitigations to help address the following vulnerabilities: @@ -145,13 +168,17 @@ For more information please go to [https://aka.ms/exchangevulns](https://aka.ms/ `.\CompareExchangeHashes.ps1` -The script currently only validates files in exchange virtual directories only, it does not check any files in the IIS root. +This script takes the following actions: +* Checks file hashes in exchange vdirs against known good baseline of hashes. +* Any file under IIS root which is edited after Dec 1st 2020 is marked as suspicious. + **This script needs to be run as administrator on all the exchange servers separately**. The script determines the version of exchange installed on the server and then downloads the hashes for known exchange files from the [published known good hashes of exchange files](https://github.com/microsoft/CSS-Exchange/releases/latest). The result generated is stored in a file locally with the following format: _result.csv If potential malicious files are found during comparision there is an error generated on the cmdline. +* Note: If the result file contains huge number of rows, it is potentially due to missing baseline hashes, please find the exchange versions found on the machine and leave a comment on issue [313](https://github.com/microsoft/CSS-Exchange/issues/313) To read the output, open the result csv file in excel or in powershell: