If you’ve not heard by now and this is your first time hearing it, there’s a 0-day in the wild that has been dubbed “HAFNIUM.” HAFNIUM targets the following Exchange server versions:
- Microsoft Exchange Server 2013
- Microsoft Exchange Server 2016
- Microsoft Exchange Server 2019
Exchange Online is not affected.
The vulnerabilities being exploited are CVE-2021-26855, CVE-2021-26857, CVE-2021-26858, and CVE-2021-27065 and further information about the update to resolve these vulnerabilities can be found here: Multiple Security Updates Released for Exchange Server – Microsoft Security Response Center
The Microsoft security support teams have already issued the IOCs, but have also supplied product detections and queries for Azure Sentinel and Defender so SOCs can Hunt in their own environment and raise alerts for remediation.
UPDATE, March 8, 2021: The HAFNIUM rules for Azure Sentinel are now synched to the console. You just need to enable them.
The following page supplies all the information about this serious issue and also provides links to new Azure Sentinel Analytics Rules and Hunting queries: HAFNIUM targeting Exchange Servers with 0-day exploits – Microsoft Security
But, for quick turnaround I’ll also expose the links to the collateral here:
Azure Sentinel Detections:
- HAFNIUM Suspicious Exchange Request
- HAFNIUM UM Service writing suspicious file
- HAFNIUM New UM Service Child Process
- HAFNIUM Suspicious UM Service Errors
- Exchange OAB Virtual Directory Attribute Containing Potential Webshell
- HAFNIUM Suspicious File Downloads **
**One quick caveat with that last one (Suspicious File Downloads)…This query uses the Exchange HttpProxy AOBGeneratorLog. You will need to onboard this log as a custom log under the table http_proxy_oab_CL before using this query. See how to do this below…
BTW: All the above will be available in the Azure Sentinel console, i.e., the prod team is pushing these to all customerrs.
- Azure-Sentinel/ExchangePowerShellSnapin.yaml at master · Azure/Azure-Sentinel (github.com)
- Azure-Sentinel/Invoke-PowerShellTcpOneLine.yaml at master · Azure/Azure-Sentinel (github.com)
- Azure-Sentinel/PowerCatDownload.yaml at master · Azure/Azure-Sentinel (github.com)
If you’re running Exchange on-premises, now is the time to patch. Don’t wait.
Security updates are available for the following specific versions of Exchange:
- Exchange Server 2010 (RU 31 for Service Pack 3 – this is a Defense in Depth update)
- Exchange Server 2013 (CU 23)
- Exchange Server 2016 (CU 19, CU 18)
- Exchange Server 2019 (CU 8, CU 7)
Onboarding the Exchange HttpProxy AOBGeneratorLog
To onboard the HTTPProxy AOBGeneratorLog, you need to enable (if it’s not already) the Security Events Data Connector in Azure Sentinel and install the Log Analytics agent on the Exchange server. Then go into the Advanced Settings of the Log Analytics Workspace for Azure Sentinel and setup custom log ingestion. Make sure you are connected to the Exchange server through the file system so you can access C:\Program Files\Microsoft\Exchange Server\V15\Logging\OABGeneratorLog to include in the custom log setup wizard. During the wizard, name the new table http_proxy_oab_CL to match the Analytics Rule requirement.
IF YOU DON’T SEE THE OABGeneratorLog file…
Thanks to John Joyner (@john_joyner), there’s a way to bring the OABGeneratorLog file back to life in the event it doesn’t exist for some reason…
…The Exchange server had been upgraded and the OAB was broke. These commands restored OAB and the OABGeneratorLog folder was there.
New-Mailbox -Arbitration -Name "OAB Gen 2" -UserPrincipalName <yourUserPrincipalName> Set-Mailbox -Identity "OAB Gen 2" -Arbitration -OABGen $true -MaxSendSize 1GB Update-OfflineAddressBook -Identity "Default Offline Address Book"
After you onboard the log file, you’ll need to modify the original detection rule because the data from the log is placed in a RAWDATA column.
New query (again, thanks to John Joyner for this):
let scriptExtensions = dynamic([".php", ".jsp", ".js", ".aspx", ".asmx", ".asax", ".cfm", ".shtml"]); http_proxy_oab_CL | where RawData contains "Download failed and temporary file" | extend File = extract("([^\\\\]*)(\\\\[^']*)",2,RawData) | extend Extension = strcat(".",split(File, ".")[-1]) | extend InteractiveFile = iif(Extension in (scriptExtensions), "Yes", "No") // Uncomment the following line to alert only on interactive file download type //| where InteractiveFile =~ "Yes" | extend timestamp = TimeGenerated, HostCustomEntity = Computer
P.S. The original detection rule is in the process of getting updated on the GitHub repository.