Whats HAFNIUM with Exchange On-Premises?

Scenario: Microsoft recently reported 4 new 0-day exploits that may impact Exchange On-Premises servers.

The vulnerabilities being exploited are CVE-2021-26855, CVE-2021-26857, CVE-2021-26858, and CVE-2021-27065

Patch your Exchange On-Premises servers with the latest security patch to protect your environment!!!!

To see if you were impacted or exploited, you can check your log files. Please see the reference article/URL listed at the bottom of this post. My commands used are built off of Microsofts PowerShell commands, except I needed my commands to run on multiple servers, in parallel, and I needed a faster way of evaluating my log files for CVE-2021-26855.

Here are my PowerShell notes that I used:

CVE-2021-26855 – Review the output file for Authenticateduser = $null and AnchorMailbox is like ServerInfo~*/*

$s = “ExOnPremSrv1″,”ExOnPremSrv2”

$S | %{
$Server= $_
$files = get-childitem -recurse -path “\$server\c$\PROGRAM FILES\Microsoft\Exchange Server\V15\Logging\HttpProxy” -Filter ‘*.log’
$FileCount = $Files.Count
$c = 0
$results = @()
$outfile = “\FileServer01\c$\temp\$server.txt”

$files.fullname | %{
    $C++
    $f = $_
    "$c OF $FILECOUNT :::  $F"
    $temp =  findstr "ServerInfo" "$F"
    $temp | out-file $outfile -Append
    }

}


CVE-2021-26858

$server = “ExOnPremSrv1″,”ExOnPremSrv2”
$server | %{
$s = $_
“Checking $S”
findstr /snip /c:”Download failed and temporary file” “\$s\c$\PROGRAM FILES\Microsoft\Exchange Server\V15\Logging\OABGeneratorLog*.log”
}

CVE-2021-26857

$server = “ExOnPremSrv1″,”ExOnPremSrv2”

$Server | %{
$s = $_
“Checking $S”
Get-EventLog -ComputerName $S -LogName Application -Source “MSExchange Unified Messaging” -EntryType Error | Where-Object { $_.Message -like “System.InvalidCastException” }
}

CVE-2021-27065

$server = “ExOnPremSrv1″,”ExOnPremSrv2”

$server | %{
$s = $_
“Checking $S”
Select-String -Path “\$s\c$\PROGRAM FILES\Microsoft\Exchange Server\V15\Logging\ECP\Server*.log” -Pattern ‘Set-.+VirtualDirectory’
}






Ref: https://www.microsoft.com/security/blog/2021/03/02/hafnium-targeting-exchange-servers/

Configure your Exchange Online PowerShell Script to leverage OAUTH/Modern Authentication and Authenticate Silently

Scenario: You need to connect to Exchange Online PowerShell via a script that will silently authenticate using Modern Authentication/OAuth.

Microsoft is deprecating Legacy/Basic Authentication when connecting to Exchange Online. Your existing scripts that leverages a username/password to authenticate silently, either by hardcoding a username or password into the script OR using encrypted keys that PowerShell calls in, will break when legacy authentication is officially disabled. You will need to convert the logic us to now start connecting to Exchange Online via Modern Authentication/Oauth.

If you haven’t yet asked ‘How to do we do that’? I am glad I asked for you….

1. You need the latest release of the ExchangeOnlineManagement (Connect-ExchangeOnline) module installed in PowerShell : Install-Module -name ExchangeOnlineManagement.

2. Setup App-only application in Azure.

2a. Register a new application object in Azure Active Directory

2b. Provide the Azure applications the following API permission: Exchange.ManageAsApp

2c. Create a self-signed cert in PowerShell that will be used to authenticate to the Azure App.
# Create certificate
$mycert = New-SelfSignedCertificate -DnsName “whatever.com” -CertStoreLocation “cert:\LocalMachine\My” -NotAfter (Get-Date).AddYears(3) -KeySpec KeyExchange

#Export certificate to .pfx file
$mycert | Export-PfxCertificate -FilePath c:\temp\mycert.pfx -Password $(ConvertTo-SecureString -String “PasswordForCert!” -Force -AsPlainText)

#Export certificate to .cer file
$mycert | Export-Certificate -FilePath c:\temp\mycert.cer


2d. Upload the Certificate in the Certificates & Secrets of the Azure App.

3. Assign the Exchange Administrator role (via Azure Roles or MSOL Roles) to the new Registered App.

4. Now that the app is configured with Exchange Permissions, Exchange Access, and the Certificate uploaded, connect to Exchange Online using the pfx Cert from PowerShell:

Connect-ExchangeOnline -CertificateFilePath “C:\temp\mycert.pfx” -CertificatePassword (ConvertTo-SecureString -String “PasswordForCert!” -AsPlainText -Force) -AppID “<AppID of your new registered app>” -Organization “<your tenant organization name>”





Error: PackageManagement\Install-PackageProvider : No match was found for the specified search criteria for the provider ‘Nuget’

Scenario: When attempting to install the newer Exchange Online Management PowerShell tools, you receive a wall of red errors similar to the following:

PackageManagement\Install-PackageProvider : No match was found for the specified search criteria for the provider ‘Nuget’

PackageManagement\Get-PackageProvider : Unable to find package provider ‘NuGet’. It may not be imported yet.

Install-Module : NuGet provider is required to interact with NuGet-based repositories.


Solution: Run PowerShell as Administrator and run the following:

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12


Running PowerShell commands against a large group of mailboxes or returning large data returns

Scenario: While attempting to run Exchange Online PowerShell commands against a large group of mailboxes and/or returning large datasets, you may run into mico delays or other errors once you breach any number of throttles that Microsoft Online imposes against your PowerShell session. Although throttles protect Microsoft Online for good reason, your still left with the question “WHY ME?” and how do we get around these strict restrictions.

Solutions: There’s a few ways to execute commands in Exchange Online PowerShell, but each have their own advantages and disadvantages. Below are a few examples with running the command: get-mobiledevicestastics which is naturally heavy in processing and subject to breaching throttles.


Standard Command – This may work if you only have a small number of mailboxes in your environment. Its quick, but also dangerous.
$AllMailboxes.alias | Get-mobiledevicestatistics -mailbox $_



ForEach with a Mini-Sleep – This command will help with some of the throttling, its not difficult to execute by implementing a 2-command loop and will help with the recharge rate for how many commands you are allowed to execute within a time period.

$AllMailboxes.alias | %{ Get-mobiledevicestatistics -mailbox $_; Start-Sleep -milliseconds 500}
-or-
$AllMailboxes.alias | ForEach { Get-mobiledevicestatistics -mailbox $_; Start-Sleep -milliseconds 500}


Invoke-Command to help with Large Data Return – Invoke with Select-Object forces the O365 servers run the command and limits the data returned. This takes your local client out of the loop helping to ease local client throttling. HOWEVER invoke command doesn’t allow complex PowerShell commands either.

Invoke-Command -session (Get-Pssession) -scriptblock {Get-mobiledevicestatistics -mailbox $_ | select-object identity, Device*,LastSuccessSync}
-or-
Invoke-Command -session (Get-Pssession) -scriptblock {Get-Mailbox -resultsize unlimited | select-object -property Displayname,Identity,PrimarySMTPAddress}


Microsoft Module: RobustCloudCommand – Microsoft created a module that can be used, originally it used to be a script. The module is designed to stay under the throttling limitations imposed by Microsoft. The module keeps an eye on the amount of commands issued, the amount of time or data collected, throttling errors, and so on. The module will tear down and rebuild the PowerShell session when needed and pickup where the script left off. AND one of the coolest things is that it supports Modern Auth and will renew your OAUTH tokens automatically. Let those big scripts fly! The only issue I see is that its limited in complex PowerShell commands. However if you want to run a single command, such as adding a BlockEverything Authentication Policy for every single one my theoretical 400K users, the workhorse below will do the trick

Install-Module -Name RobustCloudCommand #https://www.powershellgallery.com/packages/RobustCloudCommand

$users = Import-csv C:\temp\AllMailboxes.csv

Start-RobustCloudCommand -recipients $Users -logfile C:\temp\out.log -ScriptBlock {Get-user $input.userprincipalname -AuthenticationPolicy BlockEverything}











Manage Quarantined Messages in the Security and Compliance Center via PowerShell

Scenario: You want to start managing the Microsoft Online Quarantine via PowerShell. Its about time! The Microsoft GUI doesn’t play nice with wildcard queries.

First, you need to have the Exchange Online PowerShell Module, or another PS method to connect-IPPSSession.

Once you are connected to the Security and Compliance Center via PowerShell, you can run commands similar to this:

Get Quarantined Emails
Get-QuarantineMessage -StartReceivedDate 1/14/2021 -EndReceivedDate 1/16/2021 | FL

Get-QuarantineMessage -StartReceivedDate 1/14/2021 -EndReceivedDate 1/16/2021 -Type transportrule | Where SenderAddress -like *@gmail.com




Loop with Pages for Quarantined Messages
$P = 1
$messages = $null
do
{
Write-Host “Message Trace – Page $P…”
$temp_Messages = Get-QuarantineMessage -StartReceivedDate 1/15/2021 -EndReceivedDate 1/16/2021 -Type transportrule -page $p -pagesize 50
$P++
$Messages += $temp_Messages
}until ($temp_Messages -eq $null)




Release Quarantined Emails
Get-QuarantineMessage -StartReceivedDate 1/14/2021 -EndReceivedDate 1/16/2021 -Type transportrule | Where SenderAddress -like *@gmail.com | Release-QuarantineMessage -ReleaseToAll







Search for all Exchange Online Mailboxes that match a specific sending address pattern

Scenario: You need a scriptlet that will search for all messages in Exchange Online looking for a specific sending email address pattern. Specifically I am looking for any email sent by any impersonating email address that looks like this: Steve.Contoso.com@gmail.com. I want to filter on the “.com@” pattern.

Scriptlet: Edit the “Configure these Variables” section and copy and paste the remainder of the script below.

#Look for the text pattern “.com@” as the sending addresses

#Configure these Variables
$filter = “.com@”
$start = “1/11/2021 00:00”
$end = “1/11/2021 23:59”
$pageSize = 1000
$P = 1
$messages = @()
$report = @()
$totalRecipients = 0
#End_Configure these Variables#######


#The Loop – no need to edit anything below
#Create Starting Loop Variables
$Loop_start = get-date($start) -format “MM/dd/yyyy HH:00:00”
$Loop_end = get-date($end) -format “MM/dd/yyyy HH:00:00”
$1Hour_end = get-date($Loop_start)
$1Hour_end = $1Hour_end.AddHours(1)
$1Hour_end = get-date($1Hour_end) -format “MM/dd/yyyy HH:00:00”

#Loop through All Messages
do
{
Do{
Write-Host “Message Trace $Loop_Start : $1Hour_end – Page $P…”
$temp_Messages = Get-MessageTrace -startdate $loop_Start -enddate $1Hour_End -PageSize $pagesize -Page $P
$filtered_messages = $temp_messages | Where SenderAddress -like “$filter
$P++
$Messages += $filtered_Messages
}until ($temp_Messages -eq $null)

#recreate new variables
$P = 1
$Loop_Start = $1hour_end
$1Hour_end = get-date($Loop_start)
$1Hour_end = $1Hour_end.AddHours(1)
$1Hour_end = get-date($1Hour_end) -format “MM/dd/yyyy HH:00:00”
}While((get-date($Loop_start)) -lt (Get-date($Loop_End)))


#View the Results
$Messages

Clutter Settings are not available to a Exchange Online Mailbox

Scenario: A user wants to get rid of the Clutter functionality for their Mailbox, but does not see the Clutter settings within their Outlook client or Outlook on the Web (aka OWA or whichever name you want to refer to it as since its been rebranded so many times). Typically there are clutter options available to the end user within their client. However Clutter settings will only appear when:

If user currently has Clutter enabled:
-Clutter settings appear

If user currently has Focused Inbox enabled:
-Clutter settings will not appear

If neither Clutter or Focused Inbox is enabled:
-Both Clutter and Focused Inbox appear as options in the user’s Mail Settings



Solution: If disabling the Focused Inbox doesnt allow it to appear, feel free to disable Clutter from the backend by running commands similar to this:

set-clutter -identity steve -enable $False (Or $true to turn it back on)
get-clutter -identity steve | Select IsEnabled

Dumpster of Exchange Online Mailboxes that are on a Hold are maxed out due to bloated recurring meetings

Scenario: We noticed that a handful of mailboxes that are on a hold had their dumpsters maxed out hitting their 110GB RecoverableItemsQuota. The RecoverableItemsQuota increased from 100GB to 110GB when we enabled the AutoExpandingArchiveEnabled property. The users were experiencing these symptoms:
– Users cannot delete items from the Deleted Items folder
-ManagedFolderAssistant may have been hanging on large items, preventing smaller items from moving into the archive via our retention policies
-Users cannot managed or accept updated meeting requests
-Weird intermittent sending/bounceback issues for each user.

Investigating: We discovered a bloated recurring calendar item stored in the Versions folder (Recoverable Items/Dumpster folder). These mailboxes have archive mailboxes as well as retention policies, but it seemed if the retention policy was not moving the items out of the Versions folder into the Archive Versions folder. What also stuck out was there were only 400-500 items in the Versions folder, yet the total size of the Versions folder was near the 100GB mark. We found this by running a command similar to: get-mailboxfolderstatistics steve | Select Name, ItemsinFolder,FolderSize

We also used MFCMAPI to enter into the mailbox to view the contents of the Versions folder. Of the hundreds of items listed in the Versions folder, it was all the same meeting (just a different version of it) and the size of each item ranged from 200MB to 300MB a piece. This means that native Exchange functionality such as Retention Policies would not move the email items into the archive mailbox because they exceeded the MaxSendSize and MaxReceiveSize.

Further investigation, we asked the meeting owner how they were managing the meeting. The meeting owner would manage each occurrence of the meeting separately by updating it with a daily agenda and attachments. This meeting happens every day, meaning it did not take too long for this recurring meeting to bloat past the size that Microsoft can handle.

The Fix: The Holds placed on the mailbox put us into a bind, because at the time there wasn’t an easy way of getting rid of these items by simply deleting them via a Search And Destroy Script, MFCMAPI, or Native Exchange Retention Policies. However it was discovered that we could run this one-liner which was able to remove all of the excess versions for the recurring meeting:

Start-ManagedFolderAssistant steve -HoldCleanup

In prep for the fix, we made sure we put all the items in the versions folder because we were moving them around experimenting. Then ran the command. A few of the users made immediate progress, while others didn’t budge. For those that didnt budge, we ran the -StopHoldCleanup switch and reissued the -HoldCleanup switch. Eventually within a few days, they were cleaned up too.