forward rules powershell IncludeHidden
| | | | |

Detect hidden inbox forward rule in On-Premise Exchange

Today, we are going to discuss detecting hidden inbox forward rule in On-Premise Exchange.

In many exchange email account compromise case investigations, attacker tends to add an inbox rule and forward victims’ emails to an email account under the attacker’s control. In order to make the victim(s) even harder to detect the forward rules, attackers use some more advanced techniques to hide the forward rules.

There are different research articles discussing the hidden inbox forward rule on O365 including Compass SecurityMatthew Green, and GCITS. That’s why we will discuss it for On-Premise Exchange such as Exchange 2013, 2016 & 2019.

Red Team’s perspective

In this section, we are going to simulate the action performed by an attacker.

Lab Environment: Windows 2016 and Exchange 2016 with the latest patches installed.

Visible inbox forwarding rules in On-Premise Exchange
After compromising a user account, the attacker adds an evil forwarding rule.

MFCMAPI Editor is used in our lab. It is available here. In this experiment, we use the version MFCMAPI.x64.exe.20.0.20110.01.

MFCMAPI welcome screen
MFCMAPI Welcome Screen

To use MFCMAPI Editor, it is better to use it on a computer already with Microsoft Outlook and a user profile already configured. It makes things easier. Just click “Session”, then “Logon”.

MFCMAPI session logon screen
MFCMAPI choose outlook profile screen
Choose the correct “Outlook” profile in MFCMAPI

After logon, right-click and then “Open store”.

MFCMAPI open store screen

Expand Mailbox, IPM_SUBTREE, and finally Inbox.

MFCMAPI IPM_SUBTREE Inbox

Right-click Inbox and then select “Open associated contents table”.

MFCMAPI Open associated contents table

The top window does not clearly indicate which rule is the “Evil rule” we are looking for. We need to navigate one by one. The PR_RULE_MSG_NAME_W value in the bottom window will suggest us the name of the “Evil forwarding rule”.

MFCMAPI show evil forwarding rules

Clear the value “PR_RULE_MSG_NAME_W” and “PR_RULE_MSG_PROVIDER_W” value, and “Save Changes”.

MFCMAPI evil-forwarding rules save changes

When back to the OWA interface and Outlook interface, the evil forwarding rules are now hidden but still work. You may need to refresh the interface several times to see the new results. Now, attackers are watching your mailbox and hiding their existence. 

hidden inbox forwarding rules in On-Premise Exchange in OWA
hidden inbox forwarding rules in On-Premise Exchange in Outlook

Detection of hidden forward rule

So, how can we detect the hidden rules during the incident response?  We have modified a PowerShell script based on GCITS, which also includes “-IncludeHidden” parameters, “RedirectTo” conditions. This PowerShell script is also available on our GitHub here.

param ([String] $csv_file, $csv_path)

Add-PSSnapin Microsoft.Exchange.Management.PowerShell.SnapIn;

$LogTime = Get-Date -Format "MM-dd-yyyy_hh-mm-ss"

$domains = Get-AcceptedDomain
$mailboxes = Get-Mailbox -ResultSize Unlimited | Select-Object -Property SamAccountName, UserPrincipalName, PrimarySmtpAddress
 
foreach ($mailbox in $mailboxes) {
 
    $forwardingRules = $null
    #Write-Host "Checking rules for $($mailbox.displayname) - $($mailbox.primarysmtpaddress)" -foregroundColor Green
    $rules = get-inboxrule -Mailbox $mailbox.UserPrincipalName -IncludeHidden
     
    $forwardingRules = $rules | Where-Object { $_.RedirectTo -or $_.ForwardTo -or $_.ForwardAsAttachmentTo }
 
    foreach ($rule in $forwardingRules) {
        $recipients = @()
        if ($rule.ForwardTo) {
            $recipients += $rule.ForwardTo | Where-Object { $_ -match "SMTP" }
        }
        if ($rule.ForwardAsAttachmentTo) {
            $recipients += $rule.ForwardAsAttachmentTo | Where-Object { $_ -match "SMTP" }
        }
        if ($rule.RedirectTo) {            
            $recipients += $rule.RedirectTo | Where-Object { $_ -match "SMTP" }
        }
     
        $externalRecipients = @()
 
        foreach ($recipient in $recipients) {
            $email = ($recipient -split "SMTP:")[1].Trim("]")
            $domain = ($email -split "@")[1]
    
            if ($domains.DomainName -notcontains $domain) {
                $externalRecipients += $email
            }
        }
 
        if ($externalRecipients) {
            $extRecString = $externalRecipients -join "; "
            Write-Host "User: $($mailbox.SamAccountName) Rule: $($rule.Name) forwards to $extRecString" -ForegroundColor Yellow
 
            $ruleHash = $null
            $ruleHash = [ordered]@{
                SamAccountName        = $mailbox.SamAccountName
                UserPrincipalName     = $mailbox.UserPrincipalName
                PrimarySmtpAddress    = $mailbox.PrimarySmtpAddress
                RuleId                = $rule.Identity
                RuleEnabled           = $rule.Enabled
                RuleName              = $rule.Name
                ExternalRecipients    = $extRecString
                RedirectTo            = $rule.RedirectTo -join ';'
                ForwardTo             = $rule.ForwardTo -join ';'
                ForwardAsAttachmentTo = $rule.ForwardAsAttachmentTo -join ';'
                RuleDescription       = $rule.Description
            }
            $ruleObject = New-Object PSObject -Property $ruleHash
            if ($csv_file) {
                if (!$csv_path) {
                    Set-Variable -Name "csv_path" -Value "$SplunkHome\var\log\TA_ExchangeForwardingRules_for_splunk"
                }
                If (!(test-path $csv_path)) {
                    New-Item -ItemType Directory -Force -Path $csv_path
                }
                $ruleObject | Export-CSV $csv_path\$csv_file"_"$LogTime.csv -NoTypeInformation -Append
            }
            else {
                $ruleObject
                # $ruleObject | Format-Table -Wrap -Property SamAccountName,UserPrincipalName,PrimarySmtpAddress,RuleId,RuleEnabled,RuleName,ExternalRecipients,RedirectTo,ForwardTo,ForwardAsAttachmentTo,RuleDescription
            }
        }
    }
}

As you can see below, the rule name changed to rule ID, and the IncludeHidden parameter successfully showed the hidden rules.

forward rules powershell IncludeHidden

In addition, this PowerShell script also exports a CSV under the path given by $csv_path\$csv_file arguments which can give you more context of the forwarding rule.

Containment

We should reset the user password in case the user account compromise is confirmed.

Eradication/Remediation

As other posts suggested, run “outlook /cleanrules” which will clean up ALL user rules. You will clean up all rules by user and attacker.
So, can I delete the inbox forwarding rules using MFCMAPI Editor? While I do not suggest it. In our lab environment, it does suggest only inbox rules has the attribute “PR_RULE_MSG_NAME_W” and “PR_RULE_MSG_PROVIDER_W”, and we can locate and delete the entry which makes the inbox rule entry disappears. However, we still do not clear about the impact of this delete action.

Recovery & Lessons Learned

Use Splunk to monitor hidden forward rule

We have included some configuration file samples included below

inputs.conf

[monitor://C:\Splunk\MSExchange_ForwardRule_*.csv]
disabled = 0
crcSalt = <SOURCE>
sourcetype = msexchange:mailforward:csv
index=mail

props.conf

[msexchange:mailforward:csv]
# Splunk magic 8 props
SHOULD_LINEMERGE = false
LINE_BREAKER = ([\r\n]+)
# TIME_PREFIX = ^
# MAX_TIMESTAMP_LOOKAHEAD = 28
# TIME_FORMAT=%Y-%m-%d %H:%M:%S.%Q %Z
# TRUNCATE = 700
# For_Load_Balancing_On_UF
EVENT_BREAKER_ENABLE = true
EVENT_BREAKER = ([\r\n]+)
DATETIME_CONFIG=CURRENT
NO_BINARY_CHECK=true
CHARSET=UTF-8
KV_MODE=none
category=Mail
description=Comma-separated value format. Set header and other settings in "Delimited Settings"
pulldown_type=true
FIELD_NAMES=SamAccountName,UserPrincipalName,PrimarySmtpAddress,RuleId,RuleEnabled,RuleName,ExternalRecipients,RedirectTo,ForwardTo,ForwardAsAttachmentTo,RuleDescription
REPORT-auto_kv_for_msexchange_mailforward = auto_kv_for_msexchange_mailforward
EVAL-ForwardTo=replace(ForwardTo, "\"\"", "\"")
EVAL-RedirectTo=replace(RedirectTo, "\"\"", "\"")

transforms.conf

[auto_kv_for_msexchange_mailforward]
DELIMS = ","
FIELDS = "SamAccountName","UserPrincipalName","PrimarySmtpAddress","RuleId","RuleEnabled","RuleName","ExternalRecipients","RedirectTo","ForwardTo","ForwardAsAttachmentTo","RuleDescription"

Sample Correlation Rule:

index=mail sourcetype=msexchange:mailforward:csv NOT RuleEnabled="RuleEnabled" NOT [ | inputlookup msexchange_mailforward_exclusion.csv ] | table SamAccountName,UserPrincipalName,PrimarySmtpAddress,RuleId,RuleEnabled,RuleName,ExternalRecipients,RedirectTo,ForwardTo,ForwardAsAttachmentTo,RuleDescription | eval user=SamAccountName

If any of users had a valid business reason to forward to an external domain including a business partner, add the exception in msexchange_mailforward_exclusion.csv.

Similar Posts

發佈留言

Your email address will not be published. Required fields are marked *