Microsoft Office 365 Incident Response using the Microsoft Graph Security API

During an incident, you want to do your analysis as quickly and as precisely as possible. Although there are many scripts available to do proper research within Microsoft 365, if you are working with Exchange Online, OneDrive, SharePoint, they all need separate modules. Not to mention that Exchange Online sometimes need multiple modules depending on what data you want to extract. Using numerous modules can be a pain due to numerous logins that are required.

I wanted to create a ‘One ring to rule them all’ for any incident response within Microsoft 365, which is Operating System independent, runs natively on Windows, and works with or without Multi-Factor Authentication. PowerShell runs on Linux, macOS, natively on Windows, and it happens to be a language I somewhat understand.

Since many Microsoft security products and services connect to the Microsoft Graph Security API, I have chosen to use PowerShell in combination with the Microsoft Graph Security API.

App Registration

To communicate to the Microsoft Graph Security API, you need an app registration. If you create an app registration, be sure you select the Microsoft graph and Application Permissions.

Note: During the application registration, write down the application ID, the client secret, and the tenant name.

Figure 1: Azure AD API Permissions Microsoft Graph
Figure 2: Azure AD Permissions Applications Permissions

Add the following API permissions.

    Directory.Read.All
    Directory.ReadWrite.All
    IdentityRiskyUser.Read.All
    Policy.Read.All
    SecurityEvents.Read.All
    DelegatedPermissionGrant.ReadWrite.All
    AuditLog.Read.All
    Mail.Read
    MailboxSettings.Read

Research Questions

The idea of answering a research question is to run a function, export the outcome to a JSON file, and filter the JSON file if needed. The sign-in logs, for example, contain a lot of information. Using your favorite tool, you can extract what research question you would like to answer. The export includes the location of the login. A simple query makes it possible to filter all logins outside the company’s country to get an overview of potential malicious logins.

RR-GetAccessToken

The first thing you need to do is getting a token using the app registration you created previously.

RR-GetAccessToken -appId 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX' -appSecret 'XXXXXXXX' -tenantName "thalpius.onmicrosoft.com"

Once you have a token, you can use the functions described below.

Note: The token expires in one hour. I have not had this issue myself that a function runs more than an hour, but I am looking to add a refresh token to the script. You can always request a new token described above, which is valid for another hour.

RR-GetSkus

The first thing to look for is licenses. If the tenant contains an Office 365 Advanced Threat Protection license, it helps during the investigation. Or if the tenant contains an Azure AD Premium license, you know the logs in Azure AD go back one month instead of seven days.

I recommend starting with an output of the licenses to see what tools can help during the investigation.

RR-GetSkus

RR-GetAcceptedDomains

Accepted domains are used in the tenant to sent and receive e-mail. The function RR-GetAcceptedDomains can extract all accepted domains within the tenant.

Getting all accepted domains is helpful to validate which domain names accept e-mail within the tenant.

RR-GetAcceptedDomains

RR-GetInboxRules

Many attackers create inbox rules for persistence or hiding footprints. With the function RR-GetInboxRules you can export all inbox rules within the tenant or for a particular user.

RR-GetInboxRules
RR-GetInboxRules -userPrincipalName user@thalpius.com

RR-GetSignins

The RR-GetSignins functions export all Azure AD sign-ins within the tenant or for a particular user. The sign-in logs contain a lot of information like the user-agent, location of the sign-in, etc.

RR-GetSignins
RR-GetSignins -userPrincipalName user@thalpius.com

RR-GetAuditLogs

The RR-GetAuditLogs functions export all Azure AD audit logs within the tenant or for a particular user.

RR-GetAuditLogs
RR-GetAuditLogs -userPrincipalName user@thalpius.com

RR-GetEmailBySubject

The function RR-GetEmailBySubject searches for any e-mail with a given subject.

RR-GetEmailBySubject -subject "thalpius"

RR-GetEmailByBody

The function RR-GetEmailByBody searches for any e-mail with a given keyword in the body of the e-mail.

RR-GetEmailByBody -bodyKeyword "thalpius"

RR-GetAttachment

This function gives you the ability to extract all usernames with a given attachment filename in their mailbox.

RR-GetAttachment -fileName "thalpius.zip"

RR-GetAttachments

This function gives you the ability to extract attachments to check if it is malicious. It exports all attachments from a user’s mailbox or extracts the attachment itself if you use the attachmentId. The attachment is Base64 encoded. Decode the encoded string in the output to get the binary.

RR-GetAttachments -userPrincipalName user@thalpius.com
RR-GetAttachments -userPrincipalName user@thalpius.com -extension ".zip"
RR-GetAttachments -userPrincipalName user@thalpius.com -attachmentId XXXX-XXXXXX-XXXX

RR-GetAllAppRegistrations

In an illicit consent grant attack, the attacker creates an Azure-registered application that requests access to data such as contact information and e-mail. This function exports all app registrations within the tenant, including the owner.

RR-GetAllAppRegistrations

RR-OutputArray

Every function adds the data to an array. Once you are done running all functions you think you need, RR-OutputArray creates a JSON file with all data. You can filter the data if needed using your favorite scripting language.

RR-OutputArray -outputLocation 'c:\users\thalpius\incidentResponse\output.json'

Conclusion

Check out the script on my GitHub page. If you are missing any research questions, please let me know or add a GitHub issue and I will do my best to add it to the script.

Note: Do not forget to remove the Microsoft Graph Security API permissions once the investigation is completed.