Detecting Suspicious Entra ID Activity Using Office 365 Logs

jstoner
Staff

entra-o365-title.png

Throughout 2023, I spent some time digging into the logging that Microsoft Azure Active Directory (AAD), now called Entra ID, generates. My specific focus was to better understand the logging available to defenders that could be used to detect suspicious cloud activity following an attack like the infamous Golden SAML attack from October 2020.

I was fortunate enough to present what I learned about the logging that Entra ID provides through both Office 365 and Azure Active Directory and shared some ideas on how to hunt and detect these suspicious activities once the adversary has access to the tenant. In fact, here is a 30-minute video of my talk at the SANS DFIR Summit.

Based on the ideas I presented on detecting suspicious behavior within a Microsoft cloud tenant, I developed a set of detection rules for Chronicle Security Operations. Chronicle users who use Entra ID as well as those who leverage a federated environment using Active Directory Federation Services (ADFS) and Entra ID may find these rules helpful.

These YARA-L rules are posted to our community site and are primarily focused on the Office 365 log type. Chronicle ingests this log source natively through Feed Management. Office 365 provides the ability to log Entra ID (Azure Active Directory) events in addition to Exchange and SharePoint events. There is also the ability to log general audit type and Data Loss Prevention (DLP) events. This flexibility provides users the ability to monitor login and audit events for Entra ID as well as events like mail items accessed or anonymous file links created in OneDrive.

The final two rules in the list below are focused on ADFS. Because they are monitoring the endpoint for named pipe connections and file access, they utilize Microsoft Sysmon and Windows Event Logs, respectively. If you aren’t using Sysmon, EDR solutions that detect named pipe connections may work as well.

 

Rule Name
MITRE ATT&CK Technique

Azure Active Directory PowerShell Login with Subsequent Admin Actions in Entra ID

Account Manipulation: Additional Cloud Credentials (T1098.001)

Add user to administrator roles in Entra ID

Account Manipulation: Additional Cloud Credentials (T1098.001)

Admin users login activity to Non First Party Microsoft Cloud applications

Valid Accounts: Cloud Accounts (T1078.004)

Modify Entra ID application permissions that match watchlist permissions of interest

 

Entra ID application permission modifications exceed a percentage threshold

 

Entra ID application modifications exceed a threshold

 

Entra ID application created

 

Entra ID Client Secret Added, Updated or Deleted in application

Account Manipulation: Additional Cloud Credentials (T1098.001)

Login activity to the Azure Active Directory PowerShell application

Valid Accounts: Cloud Accounts (T1078.004)

User login activity to Non First Party Microsoft Cloud applications

Valid Accounts: Cloud Accounts (T1078.004)

File download from Office365 OneDrive using an anonymous link

Exfiltration Over Alternative Protocol: Exfiltration Over Asymmetric Encrypted Non-C2 Protocol (T104...

File accessed from Office 365 OneDrive using an anonymous link

Exfiltration Over Alternative Protocol: Exfiltration Over Asymmetric Encrypted Non-C2 Protocol (T104...

Anonymous link created or updated in Office 365 OneDrive

 

Persistent login activity to the Azure Active Directory PowerShell application

Remote Services: Cloud Services (T1021.007)

New user creation within Entra ID and assignment to a role on the watchlist within a short period of...

Account Manipulation: Additional Cloud Roles (T1098.003)

Suspicious Named Pipe Connection to Active Directory Federation Services

 

Access to Active Directory Federation Services Distributed Key Manager master value key

Unsecured Credentials: Private Keys (T1552.004)

 

Monitoring for Client Secrets in Entra ID Applications

The first rule we are going to highlight is a single event rule focused on the application of certificates and secrets in an Entra ID application. While we aren’t going to go deep into all the nuances around applications in Entra ID, suffice to say that an application with permissions provides access to different data sets within the Microsoft Graph API. In fact, when ingesting data into Chronicle, we set up an application, assign specific API permissions and create a secret that is used in feed management to access the logs!

Creating, modifying, and deleting secrets within an Entra ID application are generally normal behavior. However, one method to maintain persistence would be for an adversary to add their own secret to an application. Because of this, it’s a wise idea to monitor the creation or modification of these secrets, the applications they are being applied to and the user making these changes.

 

 

 

rule o365_entra_id_client_secret_add_update_delete_in_app {

 meta:
   author = "Google Cloud Security"
   description = "Secrets added to applications have legitimate purposes, but can also be a method of persistence. This alert will trigger on creation, modification or delete of a client secret"
   mitre_attack_tactic = "Persistence"
   mitre_attack_technique = "Account Manipulation: Additional Cloud Credentials"
   mitre_attack_url = "https://attack.mitre.org/techniques/T1098/001/"
   mitre_attack_version = "v14.1"
   type = "alert"
   platform = "azure"
   data_source = "o365"  
   severity = "Medium"
   priority = "Medium"

 events:
   $app.metadata.event_type = "USER_RESOURCE_UPDATE_CONTENT"
   $app.metadata.product_name = "Office 365"
   $app.metadata.product_event_type = /Update application.*Certificates and secrets management/
   $app.metadata.vendor_name = "Microsoft"
   $app.security_result.action = "ALLOW"
   $app.principal.user.userid = $userid
  
 match:
   $userid over 5m

 outcome:
   $risk_score = 65
   $mitre_attack_tactic = "Persistence"
   $mitre_attack_technique = "Account Manipulation: Additional Cloud Credentials"
   $mitre_attack_technique_id = "T1098.001"
   $event_count = count_distinct($app.metadata.id)
   $security_summary = array_distinct($app.security_result.summary)
   $user_agent = array_distinct($app.network.http.user_agent)
   $target_entra_id_application = array_distinct(re.capture($app.network.http.user_agent,`\"AppId\":\"(.*)`))
   //added to populate alert graph with additional context
   //$principal_user_userid = array_distinct($app.principal.user.userid)

 condition:
   $app 
}

 

 

 

Our rule gathers Office 365 logs that reference the certificates and secrets management event type and aggregates them by the principal.user.userid over a 5 minute window. It’s worth noting these particular Office 365 events do not contain the IP address of the requestor.

jstoner_0-1707245115046.png

In our test rule output, we can see that the userid tim.smith_admin added a secret to the application GUID ccbc3dcb-5c0e-4d85-aa7a-1c313ec4588b.

Monitoring for Subsequent Activity after a AD PowerShell Application Login

The second rule we are going to highlight is looking for a login and then subsequent activity that may be deemed suspicious. Initial access into a tenant may leverage the Azure application, Azure AD PowerShell, followed by a series of actions where an adversary may create their own application, add new permissions to access portions of the Graph API as well as create their own certificates and secrets for persistence. For additional strategies on remediation and hardening around this style of attack, this whitepaper by Mandiant has some great tips in it. 

Our rule detects login events to the Azure AD PowerShell application. This is represented in the target.resource.product_object_id field and its value is universal for all Entra ID tenants. From there, we are identifying subsequent activity by the same user who either adds or modifies an application, or its permissions, or its secrets within a 90 minute window. Because an access token can range from 60-90 minutes in length, I decided to use the outer boundary of that time range.

 

 

 

rule o365_ADPowerShell_app_login_subsequent_activity {

 meta:
   author = "Google Cloud Security"
   description = "Once a user authenticates to the Azure AD PowerShell application, if they take multiple admin actions indicative of establishing their own persistence with an Entra ID application within a portion of the access token time, alert for additional investigation"
   assumption = "This does not take into account attempts that were blocked, just any logging of attempts for any of these actions"
   mitre_attack_tactic = "Persistence"
   mitre_attack_technique = "Account Manipulation: Additional Cloud Credentials"
   mitre_attack_url = "https://attack.mitre.org/techniques/T1098/001/"
   mitre_attack_version = "v14.1"
   type = "alert"
   platform = "azure"
   data_source = "o365"
   severity = "Medium"
   priority = "Medium"

 events:
   (
       $login.metadata.event_type = "USER_LOGIN" and
       $login.metadata.product_event_type = "UserLoggedIn" and
       $login.metadata.product_name = "Office 365" and
       $login.metadata.vendor_name = "Microsoft" and
       $login.target.resource.product_object_id = "1b730954-1685-4b74-9bfd-dac224a7b894" and
       $login.security_result.action = "ALLOW"
   )
   $login.target.user.userid = $userid
   $login.metadata.event_timestamp.seconds < $other.metadata.event_timestamp.seconds
   (
       (
           $other.metadata.event_type = "USER_RESOURCE_CREATION" and
           $other.metadata.product_event_type = "Add application." and

           $other.metadata.product_name = "Office 365" and
           $other.metadata.vendor_name = "Microsoft"
       )
       or
       (
           $other.metadata.event_type = "USER_RESOURCE_UPDATE_CONTENT" and
           $other.metadata.product_event_type = "Update application." and
           $other.metadata.product_name = "Office 365" and
           $other.metadata.vendor_name = "Microsoft"
       )
       or
       (
           $other.metadata.event_type = "USER_RESOURCE_UPDATE_PERMISSIONS" and
           $other.metadata.product_event_type = "Add delegated permission grant." and
           $other.metadata.product_name = "Office 365" and
           $other.metadata.vendor_name = "Microsoft"
       )
       or
       (
           $other.metadata.event_type = "USER_RESOURCE_UPDATE_CONTENT" and
           $other.metadata.product_event_type = /Update application.*Certificates and secrets management/ nocase and
           $other.metadata.product_name = "Office 365" and
           $other.metadata.vendor_name = "Microsoft"
       )     
   )
   $other.principal.user.userid = $userid
   $other.metadata.product_event_type = $other_event

 match:
   $userid over 90m

 outcome:
   $risk_score = max(if($other.metadata.product_event_type = "Add application.", 10, 0) +
                       if($other.metadata.product_event_type = "Update application.", 10, 0) +
                       if($other.metadata.product_event_type = "Add delegated permission grant.", 10, 0) +
                       if($other.metadata.product_event_type = /Update application.*Certificates and secrets management/ nocase, 55, 0))
   $mitre_attack_tactic = "Persistence"
   $mitre_attack_technique = "Account Manipulation: Additional Cloud Credentials"
   $mitre_attack_technique_id = "T1098.001"
   $subsequent_action_threshold = 1
   $product_event_type = array_distinct($other.metadata.product_event_type)
   $country_region_login_attempt = array_distinct($login.principal.ip_geo_artifact.location.country_or_region)
   //added to populate alert graph with additional context
   $principal_ip = array_distinct($login.principal.ip)
   //$principal_user_userid = array_distinct($other.principal.user.userid)
   $target_resource_name = array_distinct($other.target.resource.name)

 condition:
   $login and #other_event > 0
}

 

 

 

All of the subsequent metadata.product_event_type values are grouped into the placeholder variable of $other_event and in the sample rule here, we are alerting if we have at least one other event because our condition states #other_event > 0. Depending on your business processes and risk appetite, I will leave it to you to adjust this value to look for N number of subsequent events types occurring. Also notice we are incrementing our risk_score in outcome using these events. There are additional activities that you might want to look for as well and those could also be added into the event section of the rule if desired using the format I’ve created above. Always test and adjust the community rules to ensure they align to your needs before deploying them. 

jstoner_1-1707245115354.png

Here is our detection. In this case, we have an IP address because login events in Office 365 contain the IP address. We can also see that an application called NewYear was added and it appears that permissions were modified, a secret was added and more.

There are more detections in the list above that focus on permissions, role assignment, administrator access and more. If you have Entra ID and Office 365, consider some of these rules as a good place to start looking for suspicious activities with Chronicle Security Operations.

While we only covered Office 365 logs and detection, there are also Azure AD and Azure Sign-in logs available as well. In a future post, I hope to share more rules and how these events can be used for detections, too.

2 0 5,717
Authors