Contributors:
Business Email Compromise (BEC) continues to evolve, and Triskele Labs’ Digital Forensics and Incident Response (DFIR) team has recently observed a concerning trend — threat actors using Python scripts to exploit Microsoft 365 environments. This blog explains how attackers are leveraging native Microsoft Graph functions to harvest emails, why this approach is so hard to detect, and the indicators analysts can use to spot it. It’s written for cybersecurity professionals, incident responders, and IT administrators seeking to strengthen detection and response against mailbox exfiltration attempts.
As Threat Actors persist in compromising Business Email accounts, Digital Forensic Incident Response (DFIR) analysts face a constant struggle to investigate the full scope of the intrusion.
Threat Actors are coming up with new and elusive ways to steal company data and leveraging python and native Microsoft 365 (M365) applications are just another way trying to avoid detection.
Unlike other common methods seen by Threat Actors, such as registering applications in the environment such as eM Client or PERFECTDATA, leveraging python to harvest emails can make use of native Microsoft applications which are typically already installed within the tenancy, resulting in a much smaller footprint and tying IP addresses to Microsoft, rather than the Threat Actors own.
The attack involves the Theat Actor gaining access to a user’s mailbox, likely through compromised credentials or phishing emails. This allows for the Threat Actor to steal a session token for a specific mailbox. For more information on this, see our other blog post https://www.triskelelabs.com/business-email-compromise-mailbox-synchronisation-malicious-oauth-applications.
Once a session token has been stolen by the Threat Actor, the next step is ensuring the account has appropriate permissions. The permissions needed are Mail.Read with Microsoft Graph. This can be done through Azure Entra ID or Graph Explorer.
Once the Threat Actor has set these permissions, a simple python script is able to leverage this application and the session token in order to collect the compromised user’s mailbox.
This method of exfiltration is effective as Microsoft Graph is a common application seen in many M365 environments.
This means the application being present in the environment does not raise suspicions like eM Client or PERFECTDATA does and may have been present in the environment from before the time of compromise. Also, performing mailbox exfiltration this way leverages Microsoft Graph to conduct the action, meaning that actions performed are recorded in the Unified Audit Log (UAL) with a Microsoft IP address.
This makes it easy to filter these actions out of the UAL when looking for actions conducted by the Threat Actor’s IP addresses.
If permissions were not correct on the account that was compromised, the Threat Actor would need to add the Mail.Read permissions. This action would show up in Audit Logs for the impacted accounts.
But the main Indicator of Compromise (IOC) for this type of collection is in the UAL. If this type of mailbox harvesting has occurred, there will be “MailItemsAccessed” Operations with something similar to the following located in the “ActorInfoString” column:
Client=REST;python-requests/<Version_Number>[AppId=<APPIDNUMBER>];
The Message IDs (MIDs) of the collected can also be seen in the UAL under the column “Folders.FolderItems.InternetMessageId”.
Seeing this ActorInfoString detail is the most obvious sign that python script was used to leverage an application, which is not standard behaviour for a typical user account.
Filtering on this column for “python” is a good way to ensure nothing is missed. The script is using the “requests” library for python, which allows for HTTP requests to be sent via python.
As seen in the photo above, each MailItemsAccessed operation seen is an email that was collected. This method is able to extract multiple emails within the same second and does not use an IP address that would be an IOC for the Threat Actor.
During an investigation, Triskele Labs observed this action linked to a different application ID. This suggests there are various methods to leverage python scripts to collect mailboxes, but the common IOC is the “python-requests” seen in the UAL. This makes the UAL the ideal place to search for exfiltration.
Along with these MailItemsAccessed action, a value should be present in the SessionID column. If it is confirmed the python script was conducted by the Threat Actor, this session ID can be used to filter for other malicious actions conducted during the same session.
1. Implement phishing resistant Multifactor Authentication (MFA) policies to the tenancy to prevent unauthorised initial access.
2. Configure geo-blocking conditional access policies to prevent Threat Actors from initially signing into the environment and stealing a session token.
3. Enforce admin consent for users to give high-risk permissions (such as Mail.Read) to applications within the environment.