PowerShell and Malicious O365 Email Rules

Author: anne.mroczynski October 11, 2018
~ by Britton Manahan


Everyday more and more companies are taking advantage of the benefits offered by cloud-based solutions. Security for these different cloud services is often misunderstood, and threat actors have taken notice. One of the most common cloud offerings is Office 365 (O365), and information security professionals have witnessed a prolific rise in O365 email compromises this year. For threat actors, O365 presents an enticing mix of potentially sensitive information and weak default security. The Crypsis Group has put together a list of O365 Security best practices based on findings from our O365 compromise investigations.

Malicious O365 Email Rules

This blog post and accompanying PowerShell script focus on one of the post exploitation actions a threat actor can take after compromising an O365 email account: malicious email rule creation. By creating email rules to forward or hide emails for viewing later, a threat actor can continue to easily harvest sensitive information after an initial compromise. Two of the most common types of Malicious O365 email rules that Crypsis consultants have observed are in the following formats:

Forwarding Email Rule  

Forwarding Email Rule

Mark as Read and Delete Email Rule 

Mark as Read and Delete Email Rule

The first of these email rules automatically forwards emails matching the criteria to an external email address. It allows an attacker to continue to collect valuable data without having to log in but stands out quickly in a search based on external email addresses. In contrast, the second rule hides emails in plain sight inside the user’s deleted items folder. By marking them “read”, the number of unread emails for the folder will remain the same. If a threat actor begins a new email chain, they can use this technique to attempt to hide responses from the mailbox owner and continue the conversation. The threat actor will need continued access to the mailbox in order to utilize this method.

O365 PowerShell Cmdlets

Microsoft provides a number of O365 PowerShell cmdlets to automate different management and security functionality. At first glance, this would appear to present a painfully simple solution for automating the task of collecting current email rules. There is both a cmdlet for enumerating all mailboxes (Get-Mailbox) and inbox rules for a given mailbox (Get-InboxRule). The following For loop around Get-InboxRule that uses each value returned by Get-Mailbox will work for smaller environments.
$mbs = get-mailbox
ForEach($mb in $mbs)


$rules = get-InboxRule -Mailbox $mb.Name

However, there are a number of factors that need to be considered when pulling rules from larger environments (Running PowerShell cmdlets for large numbers of users in Office 365).  These include:
  • Longer running O365 PSSessions can often break, requiring the ability to re-create a session without losing progress.
  • Avoiding triggering cmdlet throttling, which is an automatic resource protection mechanism built into O365.
  • Cmdlets that involve large data sets can generate an I/O timeout error.

The broken O365 PSSession issue can be solved by keeping calls to O365 cmdlets inside a try\catch exception handing block combined with validation of an active open O365 PSSession.

Broken PSSession

The code above will detect if an active Microsoft.Exchange PSSession is present in the current PowerShell instance.  If one is not found, the script will loop on a ping test for outlook.office365.com until network connectivity is confirmed. After that, it’s a simple process to automatically recreate the PSSession with the credential object created and used earlier. However, if multifactor authenication (MFA) has been applied to the account, the user will need to go through the MFA process again.

Broken PSSession Detection and Re-creation  

Broken PSSession Detection

The second issue, cmdlet throttling, has a straight forward solution. A small sleep of 500 milliseconds in the script between O365 cmdlet calls is sufficient enough to ensure that the script does not activate any cmdlet throttling warnings. For the third issue, the I/O timeout error, the O365 cmdlets being run are the largest factor. Some of these cmdlets will return objects with an extraneous number of attributes that can be filtered out on the server side. In this case, the objects returned by Get-InboxRule are fairly trim, and the issue shouldn’t appear after adding explicit calls for garbage collection in the script. By default, PowerShell does not do a great job of garbage collection. The command “[System.GC]::Collect()]” will force the script to deallocate any unused memory objects. Implementing garbage collection along with the previously mentioned sleep command has kept the I/O time error from appearing for me when running against extremely large O365 environments.

The I/O Timeout Error

Timeout Error

An additional consideration exclusive to Get-InboxRule is that a warning in the following format can appear with some regularity - “WARNING: The Inbox rule "my_inbox_rule” contains errors. To resolve the error, please edit the rule or re-create it.” These rules are still returned by Get-InboxRule, so to maintain aesthetics, warnings from the cmdlet can be hidden.

JSON Conversion

The rule objects returned by Get-InboxRule contain an attribute named ‘description’ that contains the actual the rule logic. This text string is broken up with newlines and has two main sections - the conditions and the actions – as seen in the below example:
“If the message:

the sender requested any action

and my name is in the To box

and the message includes specific words in the subject 'Accounting'

Take the following actions:

mark the message as High importance”
In order to make the data highly accessible, it can be transformed into JSON. Each JSON member represents a rule and includes its priority, mailbox, name, and a variable number of condition and action attributes.

"priority":  2,

"mailbox":  "britton@example.onmicrosoft.com",

"name":  "my_rule_10119",

"condition1":  "the sender requested any action",

"condition2":  "and my name is in the To box",

"condition3":  "and the message includes specific words in the subject 'accounting'",

"action1":  "mark the message as High importance"


Mailbox Forwarding

One last related factor that should be discussed is the second way attackers can set up automatic email forwarding. Rather than setting a forwarding inbox rule, a mailbox setting can be configured to forward all mailbox rules to an address (Forward email from Office 365 to another email account). Mailboxes set to forward emails can easily be enumerated with the following command:
Get-Mailbox | Where-Object {$_.ForwardingSmtpAddress -ne $null} | Select UserPrincipalName,

ForwardingSmtpAddress,DelivertoMailboxAndForward | ConvertTo-Csv -NoTypeInformation


All of the discussed functionality, including the JSON conversion process, and additional features are implemented by the Get-O365Rules.ps1 script. This script, given proper credentials, will:
  • Create a new O365 PSSession.
  • Validate that the PSSession has the required permissions to enumerate mailboxes and collect their email rules.
  • Output any forwarding email addresses to a csv file named “EmailForwarding.csv”.
  • Collect mailbox rules for each O365 mailbox in the provided instance hosting the account used for authentication.
  • Parse the components of each rule and add them to the JSON output file.


O365 Rules

The Get-O365Rules PowerShell script provides reactive capabilities to detect existing malicious properties in an O365 mailbox. Both produce output that can easily be forwarded to a SIEM or other data analysis tools to automatically detect unauthorized activity. A more complicated but proactive approach involves blocking or restricting email forwarding (Disable automatic forwarding in Office 365 and Exchange Server to prevent information leakage). While it requires a level of O365 administration knowledge and the configuration of a new role group, the security benefits are certainly worth it. Since trusting any security control to be 100% is a mistake, the best setup a company can implement is combining both the proactive and reactive controls.

Topics: Tech Talk