-
Notifications
You must be signed in to change notification settings - Fork 341
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1819 from microsoft/dpaul-TokenCacheModuleUpdate
Token Cache Module Update
- Loading branch information
Showing
6 changed files
with
239 additions
and
264 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,7 +5,7 @@ | |
.SYNOPSIS | ||
This script removes the TokenCacheModule from IIS to protect Exchange Server against CVE-2023-21709. | ||
.DESCRIPTION | ||
The script removes the TokenCacheModule from IIS to protect Exchange Server against CVE-2023-21709. | ||
The script removes the TokenCacheModule from IIS to protect Exchange Server against CVE-2023-21709. | ||
It comes with a parameter that allows you to explicitly specify a subset of Exchange servers on which the TokenCacheModule | ||
should be removed or restored (ExchangeServerNames). | ||
It's also possible to exclude a subset of Exchange servers from the operation performed by the script (SkipExchangeServerNames). | ||
|
@@ -14,7 +14,11 @@ | |
.PARAMETER SkipExchangeServerNames | ||
Use this parameter to explicitly exclude Exchange servers from removing or restoring the TokenCacheModule. | ||
.PARAMETER Rollback | ||
Use this parameter rollback the CVE-2023-21709 solution and add the TokenCacheModule back to IIS. | ||
Use this parameter rollback the CVE-2023-21709 configuration and add the TokenCacheModule back to IIS. | ||
.PARAMETER ScriptUpdateOnly | ||
This optional parameter allows you to only update the script without performing any other actions. | ||
.PARAMETER SkipVersionCheck | ||
This optional parameter allows you to skip the automatic version check and script update. | ||
.EXAMPLE | ||
PS C:\> .\CVE-2023-21709.ps1 | ||
It will remove the TokenCacheModule from all of the Exchange servers in the organization. | ||
|
@@ -28,67 +32,101 @@ | |
PS C:\> .\CVE-2023-21709.ps1 -Rollback | ||
It will restore the TokenCacheModule on all Exchange servers within the organization. | ||
#> | ||
[CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')] | ||
|
||
[CmdletBinding(DefaultParameterSetName = "Default", SupportsShouldProcess = $true, ConfirmImpact = 'High')] | ||
param( | ||
[Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = "Default")] | ||
[Alias("Name", "Fqdn")] | ||
[string[]]$ExchangeServerNames = $null, | ||
|
||
[Parameter(Mandatory = $false, ParameterSetName = "Default")] | ||
[string[]]$SkipExchangeServerNames = $null, | ||
|
||
[switch]$Rollback | ||
[Parameter(Mandatory = $false, ParameterSetName = "Default")] | ||
[switch]$Rollback, | ||
|
||
[Parameter(Mandatory = $false, ParameterSetName = "ScriptUpdateOnly")] | ||
[switch]$ScriptUpdateOnly, | ||
|
||
[Parameter(Mandatory = $false, ParameterSetName = "Default")] | ||
[switch]$SkipVersionCheck | ||
) | ||
|
||
begin { | ||
$BuildVersion = "" | ||
|
||
. $PSScriptRoot\WriteFunctions.ps1 | ||
. $PSScriptRoot\ConfigurationAction\Invoke-ConfigureMitigation.ps1 | ||
. $PSScriptRoot\ConfigurationAction\Invoke-Rollback.ps1 | ||
. $PSScriptRoot\ConfigurationAction\Invoke-TokenCacheModuleAction.ps1 | ||
. $PSScriptRoot\..\..\..\Shared\OutputOverrides\Write-Host.ps1 | ||
. $PSScriptRoot\..\..\..\Shared\OutputOverrides\Write-Progress.ps1 | ||
. $PSScriptRoot\..\..\..\Shared\OutputOverrides\Write-Verbose.ps1 | ||
. $PSScriptRoot\..\..\..\Shared\OutputOverrides\Write-Warning.ps1 | ||
. $PSScriptRoot\..\..\..\Shared\ScriptUpdateFunctions\Test-ScriptVersion.ps1 | ||
. $PSScriptRoot\..\..\..\Shared\Confirm-Administrator.ps1 | ||
. $PSScriptRoot\..\..\..\Shared\Confirm-ExchangeShell.ps1 | ||
. $PSScriptRoot\..\..\..\Shared\LoggerFunctions.ps1 | ||
. $PSScriptRoot\..\..\..\Shared\Out-Columns.ps1 | ||
. $PSScriptRoot\..\..\..\Shared\Show-Disclaimer.ps1 | ||
|
||
$Script:Logger = Get-NewLoggerInstance -LogName "CVE-2023-21709-$((Get-Date).ToString("yyyyMMddhhmmss"))-Debug" ` | ||
-AppendDateTimeToFileName $false ` | ||
-ErrorAction SilentlyContinue | ||
function Write-VerboseLog ($Message) { | ||
$Script:Logger = $Script:Logger | Write-LoggerInstance $Message | ||
} | ||
|
||
function Write-HostLog ($Message) { | ||
$Script:Logger = $Script:Logger | Write-LoggerInstance $Message | ||
} | ||
|
||
$loggerInstanceParams = @{ | ||
LogName = "CVE-2023-21709-$((Get-Date).ToString("yyyyMMddhhmmss"))-Debug" | ||
AppendDateTimeToFileName = $false | ||
ErrorAction = "SilentlyContinue" | ||
} | ||
|
||
$Script:Logger = Get-NewLoggerInstance @loggerInstanceParams | ||
|
||
SetWriteHostAction ${Function:Write-HostLog} | ||
SetWriteVerboseAction ${Function:Write-VerboseLog} | ||
SetWriteWarningAction ${Function:Write-HostLog} | ||
SetWriteProgressAction ${Function:Write-HostLog} | ||
|
||
$exchangeServersToProcess = New-Object "System.Collections.Generic.List[string]" | ||
} process { | ||
if ($null -ne $ExchangeServerNames) { | ||
Write-Verbose ("Adding server(s): $([string]::Join(", ", $ExchangeServerNames)) to the list of servers to be processed...") | ||
$exchangeServersToProcess.AddRange($ExchangeServerNames) | ||
} else { | ||
Write-Verbose ("No server was passed via the ExchangeServerNames parameter") | ||
} | ||
} end { | ||
if (-not (Confirm-Administrator)) { | ||
Write-Warning "The script needs to be executed in elevated mode. Start the shell as an Administrator." | ||
if (-not(Confirm-Administrator)) { | ||
Write-Host "The script needs to be executed in elevated mode. Start the PowerShell as an administrator." -ForegroundColor Yellow | ||
exit | ||
} | ||
|
||
Write-Host ("CVE-2023-21709 script version $($BuildVersion)") -ForegroundColor Green | ||
$versionsUrl = "https://aka.ms/CVE-2023-21709-VersionsUrl" | ||
if (Test-ScriptVersion -AutoUpdate -VersionsUrl $versionsUrl -Confirm:$false) { | ||
Write-Host ("CVE-2023-21709 script version $($BuildVersion)") -ForegroundColor Green | ||
|
||
if ($ScriptUpdateOnly) { | ||
switch (Test-ScriptVersion -AutoUpdate -VersionsUrl $versionsUrl -Confirm:$false) { | ||
($true) { Write-Host ("Script was successfully updated") -ForegroundColor Green } | ||
($false) { Write-Host ("No update of the script performed") -ForegroundColor Yellow } | ||
default { Write-Host ("Unable to perform ScriptUpdateOnly operation") -ForegroundColor Red } | ||
} | ||
return | ||
} | ||
|
||
if ((-not($SkipVersionCheck)) -and | ||
(Test-ScriptVersion -AutoUpdate -VersionsUrl $versionsUrl -Confirm:$false)) { | ||
Write-Host ("Script was updated. Please re-run the command") -ForegroundColor Yellow | ||
return | ||
} | ||
|
||
$exchangeShell = Confirm-ExchangeShell | ||
if (-not($exchangeShell.ShellLoaded)) { | ||
Write-Warning "Failed to load the Exchange Management Shell. Start the script using the Exchange Management Shell." | ||
exit | ||
} elseif (-not($exchangeShell.EMS)) { | ||
Write-Warning "This script requires to be run inside of Exchange Management Shell. Please run on an Exchange Management Server or an Exchange Server with Exchange Management Shell." | ||
Write-Host "Failed to load the Exchange Management Shell. Start the script using the Exchange Management Shell." -ForegroundColor Yellow | ||
exit | ||
} | ||
|
||
try { | ||
$iisAppPoolWording = "Note that each Exchange server's IIS Application Pool will be restarted after either applying the setting change or restore action." | ||
$vulnerabilityMoreInformationWording = "More information about the vulnerability can be found here: https://portal.msrc.microsoft.com/security-guidance/advisory/CVE-2023-21709." | ||
if (-not $Rollback) { | ||
if (-not($Rollback)) { | ||
$params = @{ | ||
Message = "Display Warning about TokenCacheModule removal operation" | ||
Target = "Removal of TokenCacheModule from IIS is recommended for security reasons. " + | ||
|
@@ -110,37 +148,45 @@ begin { | |
} | ||
Show-Disclaimer @params | ||
|
||
Write-Verbose ("Running Get-ExchangeServer to get list of all exchange servers") | ||
Write-Verbose ("Running Get-ExchangeServer to get list of all Exchange servers") | ||
Set-ADServerSettings -ViewEntireForest $true | ||
$ExchangeServers = Get-ExchangeServer | Where-Object { $_.AdminDisplayVersion -like "Version 15*" -and $_.ServerRole -ne "Edge" } | ||
|
||
if ($null -ne $ExchangeServerNames -and $ExchangeServerNames.Count -gt 0) { | ||
Write-Verbose "Running only on servers: $([string]::Join(", " ,$ExchangeServerNames))" | ||
$ExchangeServers = $ExchangeServers | Where-Object { ($_.Name -in $ExchangeServerNames) -or ($_.FQDN -in $ExchangeServerNames) } | ||
$ExchangeServers = Get-ExchangeServer | Where-Object { | ||
(($_.AdminDisplayVersion -like "Version 15*") -and | ||
($_.ServerRole -ne "Edge")) | ||
} | ||
|
||
if ($null -ne $SkipExchangeServerNames -and $SkipExchangeServerNames.Count -gt 0) { | ||
Write-Verbose "Skipping servers: $([string]::Join(", ", $SkipExchangeServerNames))" | ||
if (($null -ne $exchangeServersToProcess) -and | ||
($exchangeServersToProcess.Count -gt 0)) { | ||
Write-Host "Running only on Exchange servers: $([string]::Join(", " ,$exchangeServersToProcess))" | ||
$ExchangeServers = $ExchangeServers | Where-Object { | ||
(($_.Name -in $exchangeServersToProcess) -or | ||
($_.FQDN -in $exchangeServersToProcess)) | ||
} | ||
} | ||
|
||
if (($null -ne $SkipExchangeServerNames) -and | ||
($SkipExchangeServerNames.Count -gt 0)) { | ||
Write-Host "Skipping Exchange servers: $([string]::Join(", ", $SkipExchangeServerNames))" | ||
# Remove all the servers present in the SkipExchangeServerNames list | ||
$ExchangeServers = $ExchangeServers | Where-Object { ($_.Name -notin $SkipExchangeServerNames) -and ($_.FQDN -notin $SkipExchangeServerNames) } | ||
$ExchangeServers = $ExchangeServers | Where-Object { | ||
(($_.Name -notin $SkipExchangeServerNames) -and | ||
($_.FQDN -notin $SkipExchangeServerNames)) | ||
} | ||
} | ||
|
||
if ($null -eq $ExchangeServers) { | ||
Write-Host "No exchange servers to process. Please specify server filters correctly" | ||
Write-Host "No Exchange servers to process. Please specify server filters correctly" -ForegroundColor Red | ||
exit | ||
} | ||
|
||
if ($Rollback) { | ||
Invoke-Rollback -ExchangeServers $ExchangeServers | ||
return | ||
$tokenCacheActionParams = @{ | ||
ExchangeServers = $ExchangeServers | ||
Action = if (-not($Rollback)) { "Protect" } else { "Rollback" } | ||
} | ||
|
||
Invoke-ConfigureMitigation -ExchangeServers $ExchangeServers | ||
return | ||
Invoke-TokenCacheModuleAction @tokenCacheActionParams | ||
} finally { | ||
Write-Host "" | ||
Write-Host "Script Completed successfully!" | ||
Write-Host "Do you have feedback regarding the script? Please email [email protected]." | ||
Write-Host "Do you have feedback regarding the script? Please let us know: [email protected]." | ||
} | ||
} |
107 changes: 0 additions & 107 deletions
107
Security/src/CVE-2023-21709/ConfigurationAction/Invoke-ConfigureMitigation.ps1
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.