BECS - An Office 365 Incident Response Tool

Gosh golly, another blog post?! #

Woah


I seem to have found myself doing a lot of incident response (IR) engagements here lately. I mean, I’m not complaining; it’s bittersweet in that I have a lot of fun during these engagements, but also sad because they negatively impact businesses that have better things to do.

Several times now, I’ve needed to do some sort of DFIR in Office 365, where I just manually grabbed whatever data I needed at the time. But for the sake of automation (being lazy), tooling, and giving back to the community, I though gee, I should make a tool. With that, BECS was born, which is available on my GitHub:


    ---------------------------------------------

    ______       _____       _____       _____   
    | ___ \     |  ___|     /  __ \     /  ___|  
    | |_/ /     | |__       | /  \/     \ `--.   
    | ___ \     |  __|      | |          `--. \  
    | |_/ /  _  | |___   _  | \__/\  _  /\__/ /  
    \____/  (_) \____/  (_)  \____/ (_) \____/   

    'Business Email Compromise Search'      
    An Office 365 Information Gathering Tool   

    ---------------------------------------------

Let’s get what the tool does and how to run it out of the way first. The we’ll get into the juicy, technical goodness.

TL;DR: Run this tool to review any changes, new users, mailboxes, or questionable inbox rules in your Office 365 tenant


All right, what does it do? #

I’m so glad you asked! Like the name implies, BECS crawls an Office 365 tenant for information that would be pertinent to someone during an DFIR engagement. This includes:

Note: #

Now, you may be asking if this is a suitable replacement to the Office 365 Security & Compliance Center features, or a traditional SIEM (Splunk, Graylog, ELK, etc), and by all means this does not replace either of those. This tool comes in handy if you’re in a pinch and don’t have either of those available, or if you’re an outside tech and need to quickly get familiar with an Office 365 tenant.

A traditional SIEM, or at a minimum the Security & Compliance center, is always recommended for properly monitoring an Office 365 tenant.


How do I use this thing? #

It’s pretty straight forward if you’ve ran a PowerShell script before:

Once you have all of the above, connect to Exchange Online and Office 365 and navigate to where you downloaded the tool to. When you run the tool, you will be prompted with several different options:

BECS_menu.png

Depending on your selection, that will determine what data is retrieved:

All data that is fetched by BECS will be sent to a new folder on the users Desktop and the tool does not alter or create any new objects in either Office 365 or Exchange Online.


Let’s talk code #

YesPlease

BECS, a controller script, is comprised of 6 main functions, which have been named appropriately to hint at their roles.


Let’s go through each function one by one:

New-OutputDirectory #

This function has the simple task of creating the folder structure on the user’s desktop to store all of the output data. The environment variable $env:USERPROFILE is used so it can be ran on any Windows users workstation.

New-OutputDirectory.png

Get-TenantInformation #

This and New-OutputDirectory are the only two functions that will be ran no matter what selection you make when you run the script.
This one runs the following cmdlets, converts the output to string data, and writes out to a text file.

It also does the additional check for auditing; if the organization config property AuditDisabled is set to $True, it’ll warn the user running the tool:

AuditDisabled.png

I do plan on adding more checks in this function, but when I wrote this tool there was some sense of urgency since I needed it for an incident response engagement. It grabs everything you would need, but it would be nice to make some checks at run-time so you don’t have to sift through the text file.

Get-ExchangeOnlineData #

The purpose of this guy is to grab any relevant data in Exchange Online. To do so, several functions were nested inside this function:

The Get-MailboxData function searches each mailbox in a tenant and records anything that has data in the ForwardingSMTPAddress property or if the WhenCreated date is within the last 90 days.

MailboxData.png

Get-RecentTransportRules, as the name implies, looks over the global Exchange rules and records any rule that has been altered within the last 90 days. Since there can be so much variety to a global rule, I voted to take the entire rule configuration and save it to a text file for review later.

TransportRule.png

Finally, Get-RecentMobileDevices records any recent, well.. mobile devices!

Mobile.png

Get-MSOnlineData #

This one has two nested functions, Get-RecentMSOLUsers and Get-AlllMSOLRoleMemberships.

Get-RecentMSOLUsers simply records any MSOnline users that were created in the last 90 days.
And, as you may have deduced, Get-AllMSOLRoleMemberships records all users with administrative role in an Office 365 tenant (Global Admin, Exchange Admin, SharePoint Admin, etc.)

MSOL.png

MSOLRoles.png

Get-InterestingInboxRules #

This guy was quite the booger, but also the main motivation behind the creation of this tool. With nearly every business email compromise I’ve handled, there was some sort of malicious inbox rule created by the attacker.

The meat of this function is Get-InboxRule, which can give you a lot of information. Let’s look at all of the rules on Taylor Swift’s mailbox:

TayRulez.png

Now, she named these appropriately for this demonstration, but let’s just pretend that the rules ‘Bad - Delete’ and ‘Bad - Forward’ look interesting. Lets look at the delete first:

TayRulez_Del_desc.png

Now, I’m only showing the description since there are tons of properties that come with this command (see for yourself with Get-InboxRule -Mailbox FLast@Domain.com -Identity #### | gm), but this should be a good indication that this rule is intended to delete anything that may be a NDR (non-deliverable), which would tip off a user that their mailbox is probably compromised. It’s a pretty common way for an attacker to cover their tracks.

Alright, let’s look at the forward rule:
TayRulez_For_desc.png

Looking this one over, it should be easy to deduce what its intention is. Anything that has something to do with billing or invoices or, basically money, gets forwarded to an outside email.
It’s commonplace for attackers to intercept these, alter them a bit so they would be the recipient of the funds, then send that doctored invoice to someone internally in an attempt to get the funds sent to them.

Sneaky
Sneaky sneaky!

Using these rules as examples/baselines, the following checks were made in the Get-InterestingInboxRules function:

If ($InboxRule.DeleteMessage -eq $true -and $InboxRule.SubjectOrBodyContainsWords -like "*Mail Delivery*" -or $InboxRule.SubjectOrBodyContainsWords -like "*could not be delivered*")
                {

                    Write-Warning "$ID was flagged for a questionable delete action"
                    IR-Logwrite " "
                    IR-Logwrite "---------------------------------------------------------------------------"
                    IR-Logwrite "The Inbox Rule from $ID deletes a message when processed:"
                    IR-Logwrite "---------------------------------------------------------------------------"
                    IR-Logwrite " "

                    $String = $InboxRule.Description | Format-List | Out-String

                    IR-Logwrite $String

                }

                elseIf ($InboxRule.DeleteMessage -eq $true -and $InboxRule.SubjectContainsWords -like "*Mail Delivery*" -or $InboxRule.SubjectContainsWords -like "*could not be delivered*")
                {

                    Write-Warning "$ID was flagged for a questionable delete action"
                    IR-Logwrite " "
                    IR-Logwrite "---------------------------------------------------------------------------"
                    IR-Logwrite "The Inbox Rule from $ID deletes a message when processed:"
                    IR-Logwrite "---------------------------------------------------------------------------"
                    IR-Logwrite " "

                    $String = $InboxRule.Description | Format-List | Out-String

                    IR-Logwrite $String

                }

                # Forward to an outside email with questionable keywords
                elseIf ($InboxRule.ForwardTo -like "*@*" -and $InboxRule.SubjectOrBodyContainsWords -like "*pay*" -or $InboxRule.SubjectOrBodyContainsWords -like "*invoice*" -or $InboxRule.SubjectOrBodyContainsWords -like "*wire*")
                {

                    Write-Warning "$ID was flagged for a questionable forward action"
                    IR-Logwrite " "
                    IR-Logwrite "---------------------------------------------------------------------------"
                    IR-Logwrite "The Inbox Rule from $ID forwards a message when processed:"
                    IR-Logwrite "---------------------------------------------------------------------------"
                    IR-Logwrite " "

                    $String = $InboxRule.Description | Format-List | Out-String

                    IR-Logwrite $String

                }

                # Forward to an outside email with questionable keywords
                elseIf ($InboxRule.ForwardTo -like "*@*" -and $InboxRule.SubjectContainsWords -like "*pay*" -or $InboxRule.SubjectContainsWords -like "*invoice*" -or $InboxRule.SubjectContainsWords -like "*wire*")
                {

                    Write-Warning "$ID was flagged for a questionable forward action"
                    IR-Logwrite " "
                    IR-Logwrite "---------------------------------------------------------------------------"
                    IR-Logwrite "The Inbox Rule from $ID forwards a message when processed:"
                    IR-Logwrite "---------------------------------------------------------------------------"
                    IR-Logwrite " "

                    $String = $InboxRule.Description | Format-List | Out-String

                    IR-Logwrite $String

                }

                # Forward to an outside email with questionable keywords
                elseIf ($InboxRule.ForwardAsAttachmentTo -like "*@*" -and $InboxRule.SubjectOrBodyContainsWords -like "*pay*" -or $InboxRule.SubjectOrBodyContainsWords -like "*invoice*" -or $InboxRule.SubjectOrBodyContainsWords -like "*wire*")
                {

                    Write-Warning "$ID was flagged for a questionable forward action"
                    IR-Logwrite " "
                    IR-Logwrite "---------------------------------------------------------------------------"
                    IR-Logwrite "The Inbox Rule from $ID forwards a message as an attachment when processed:"
                    IR-Logwrite "---------------------------------------------------------------------------"
                    IR-Logwrite " "

                    $String = $InboxRule.Description | Format-List | Out-String

                    IR-Logwrite $String

                }

                # Forward to an outside email with questionable keywords
                elseIf ($InboxRule.ForwardAsAttachmentTo -like "*@*" -and $InboxRule.SubjectContainsWords -like "*pay*" -or $InboxRule.SubjectContainsWords -like "*invoice*" -or $InboxRule.SubjectContainsWords -like "*wire*")
                {

                    Write-Warning "$ID was flagged for a questionable forward action"
                    IR-Logwrite " "
                    IR-Logwrite "---------------------------------------------------------------------------"
                    IR-Logwrite "The Inbox Rule from $ID forwards a message as an attachment when processed:"
                    IR-Logwrite "---------------------------------------------------------------------------"
                    IR-Logwrite " "

                    $String = $InboxRule.Description | Format-List | Out-String

                    IR-Logwrite $String

                }

                else
                {

                    $null

                }

Basically, anything that looks questionable gets logged to a text file for further analysis.

One hurdle that I had to get over was how slow Get-InboxRule takes to run. If you’re running too many commands within a period of time, you’ll get kicked out of your session by Exchange Online.
To get over this hurdle, I have the script function close its session and create a new one at every 150 mailboxes it checks:

InboxFunct_top.png


InboxFunct_logic.png

Someday I’m going to go down the rabbit hole of Office 365 APIs in hopes to get around this bottleneck. Or hopefully the new Exchange Online Module, v2 will improve this cmdlet.


Show-Menu #

Finally, the Show-Menu function wraps everything together and gives the user running the script options to run. Rather than using Read-Host, I though it would be fun, and look cleaner, if .NET was leveraged:

Menu_logic.png

FinalResult.png

Depending on what the user selects to run will determine what functions are called:

Selection_logic.png


In Closing #

Overall, this was a lot of fun to make and I plan on adding more functionality in the future.

Got more blogs coming down the pipeline. Until next time <3

l8er

 
1
Kudos
 
1
Kudos

Now read this

Import BIND zones to Azure DNS

One of my customers was using BIND to handle their public facing DNS. In a effort to remove technical debt, minimize their infrastructure footprint, and to make it easier for staff, I was tasked to look for a cloud alternative to BIND... Continue →