Home NewsX Threat hunting with Microsoft Graph activity logs

Threat hunting with Microsoft Graph activity logs

by info.odysseyx@gmail.com
0 comment 15 views


Introduction

Microsoft Graph is a unified REST API endpoint that allows you to query data from various sources, including data stored in Microsoft 365. Microsoft Graph provides access to a suite of services including Microsoft 365, Enterprise Mobility + Security, and Windows. In the wrong hands, access to Microsoft Graph API can be misused by threat actors to compromise users; for example, by reading emails or files on SharePoint.

 

Responding to and detecting these cloud-based attacks is of utmost priority. Multiple products and logs are available to help with threat investigation and detection. In this blog, we’ll explore the recent addition of Microsoft Graph activity logs, which has been made generally available.

 

Microsoft Graph activity logs provides a history of all Microsoft Graph API requests. In this blog, we’ll go over collection and analysis of these logs and share a few detection/hunting ideas. The goal is to create general awareness of this log source and show how it can be used effectively.

 

How to get Microsoft Graph activity logs

Microsoft Graph activity logs are not collected by default and are not available via an UI. You must collect the logs for storage and analysis via Log Analytics, Sentinel, or other SIEMs. Use the following steps to get these logs.

 

Note: You must have a Microsoft Entra ID P1 or P2 tenant license to collect the Microsoft Graph activity logs.

 

On the Azure portal, go to Microsoft Entra ID, and on the left pane, go to to Diagnostic Settings

  1. Choose the + Add diagnostic setting link.
  2. Enter a Diagnostic setting name.
  3. Select MicrosoftGraphActivityLogs.

  4. Under Destination details, configure one of the following locations to store the logs, and then choose Save.

  • Send to Log Analytics workspace
  • Archive to a storage account
  • Stream to an event hub
  • Send to partner solution

 

ShivaP_4-1725377820547.png

 

 

Figure 1: Screenshot showing the MicrosoftGraphActivityLogs Diagnostic setting.

 

Note: We recommend that you estimate the cost before you collect the logs. Depending on your tenant, there might be a high volume of logs generated.

 

Notable activity log fields

The output log contains many fields (for a full list, see what data is available in the activity logs). The following table lists the fields that are relevant to threat investigations.

 

Fields

Details

TenantId

The Log Analytics workspace ID.

TimeGenerated [UTC]

The date and time the request was received.

AppId

The identifier of the application.

IPAddress

The IP address of the client from where the request occurred.

ServicePrincipalId

The identifier of the service principal making the request.

RequestId

The identifier that represents the request.

RequestMethod

The HTTP method of the event.

ResponseStatusCode

The HTTP response status code for the event.

RequestUri

The URI of the request.

ResponseSizeBytes

The size of the response in bytes.

Roles

The roles in token claims.

 

Correlatable fields and functions

To enrich these logs, joining some of these fields with those from other tables can offer additional context.

 

User details: MicrosoftGraphActivityLogs can be joined with IdentityInfo logs by a common field (for example, UserID and AccountObjectId) to get further information about the user; however, this does not include information about service principals.

 

 

MicrosoftGraphActivityLogs
| where isnotempty(UserId)
| join kind=leftouter IdentityInfo on $left.UserId == $right.AccountObjectId
| where isnotempty(AccountUPN)
| project-reorder TimeGenerated, AppId, IPAddress, AccountUPN, AccountCreationTime, AssignedRoles, ServicePrincipalId, RequestId, RequestMethod, ResponseStatusCode, RequestUri, ResponseSizeBytes, Roles

 

 

Note: For data to appear in IdentityInfo, enable User and Entity Behavior Analytics (UEBA). For more information, see How to enable User and Entity Behavior Analytics.

 

RiskyUsers: Combining MicrosoftGraphActivityLogs with the table AadRiskyUser provides context on user risk details and risk levels.

 

 

MicrosoftGraphActivityLogs
| join AADRiskyUsers on $left.UserId == $right.Id

 

 

Geo IP information: You can get context on geo-location of the IP by using the function geo_info_from_ip_address.

 

 

MicrosoftGraphActivityLogs
| extend GeoIPInfo = geo_info_from_ip_address(IPAddress)
| extend country = tostring(parse_json(GeoIPInfo).country)
| extend state = tostring(parse_json(GeoIPInfo).state)
| extend city = tostring(parse_json(GeoIPInfo).city)

 

 

You can also derive the latitude and longitude of the IP addresses and plot them into a map on Azure Data Explorer. For more information, see Query data in Azure Monitor using Azure Data Explorer.

 

 

MicrosoftGraphActivityLogs
| where not (ipv4_is_private( IPAddress))
| extend GeoLocation = geo_info_from_ip_address(IPAddress)
| extend Latitude = toreal(['GeoLocation']['latitude'])
| extend Longitude = toreal(['GeoLocation']['longitude'])
| where isnotempty(Latitude) and isnotempty(Longitude)
| project  Longitude, Latitude
| render scatterchart with (kind = map)

 

 

Function: One of the important fields in MicrosoftGraphActivityLogs is the ResourceURI field. Although this field is long and difficult to analyze, the parse_url() function can be used to divide the data to show an easily readable version of the Path field, making it easier to query and analyze.

 

 

MicrosoftGraphActivityLogs
| extend ParsedURI = parse_url(RequestUri)
| extend Path = tostring(ParsedURI.Path)

 

 

With this function, the path is clear, but it still includes API information, such as v1.0 or beta. During analysis or summarization, this might not add value. You can use the replace_string() function to remove that information.

 

 

MicrosoftGraphActivityLogs
| extend ParsedURI = parse_url(RequestUri)
| extend Path = tostring(ParsedURI.Path)
| extend FinalPath = replace_string(replace_string(Path ,'v1.0/',''),'beta/','')

 

 

Delegated vs. Application permissions

Before we run through scenarios to show how valuable these logs can be during an investigation of Microsoft Graph API misuse, it is important to understand the permissions used. Applications that use the Microsoft Graph API require either a Delegated or an Application permission.

  

 

Delegated permissions

Application permissions

User context

Requires a signed-in user

No user context needed

Consent

User consent (or admin on behalf of user)

Admin consent required

Scope

Limited to user’s permissions

Broader, organization-wide scope

Typical use cases

Interactive applications (web, mobile, desktop)

Background services, daemons, administrative tools

Examples

Reading user email, updating user calendar

Reading all user emails, managing directory data

 

To learn more about delegated and application permissions, see Permissions and consent overview.

 

Additionally, registering an Entra application generates an application object and an associated service principal. The service principal defines the permissions the app has, specifying whether they are application permissions or delegated permissions, or both. 

 

Attack patterns and hunting/detection opportunities

The Microsoft Graph API offers many functions that enable a wide range of activities across multiple operations and applications. Let’s explore a few scenarios over the MITRE Attack matrix to understand how a benign API function can be misused if compromised. We’ll examine parts of logs that might be significant during an investigation and identify opportunities for detecting and/or hunting such activities.

 

The purpose of this blog is not to provide a comprehensive list of all possible attacks and their respective detection/hunting opportunities. Instead, we’ll showcase a few examples to help you understand how to use the logs and to offer insights into building your own hunting strategy or use cases based on your organization.

 

The following examples require specific types of user permissions, which are specified as delegated, application, or both. The response codes in the queries are based on sample data. Please note that the queries are provided for reference purposes only.

 

Reconnaissance/Discovery

If a bad actor gains access to the tenant, the Microsoft Graph API can be misused to enable reconnaissance scenarios, such as enumerating users, groups, and roles, collecting metadata and configuration details, discovering misconfigured mailboxes, and retrieving app registrations, consents, and scopes. Numerous open-source tools are available to facilitate these activities.

 

Real world scenario: Microsoft Incident Response often assists external customers where tools for reconnaissance are used to collect data of a tenant to determine ways to elevate privileges.

Mitre technique: T1087

Attack: Reconnaissance

Permissions required: Various

RequestURI: Various

 

In this example scenario, we explored open-source reconnaissance tools, such as GraphRunner and AzureHound.

 

Query: The purpose of this query is to identify a surge in standard calls within a brief period that are characteristics of reconnaissance tools.

 

 

let calls = dynamic(["https://graph.microsoft.com/v1.0/users/","https://graph.microsoft.com/v1.0/search/query","https://graph.microsoft.com/beta/policies/authorizationPolicy","https://graph.microsoft.com/v1.0/users","https://graph.microsoft.com/v1.0/groups","https://graph.microsoft.com/v1.0/groups//members","https://graph.microsoft.com/v1.0/servicePrincipals","https://graph.microsoft.com/v1.0/servicePrincipals/","https://graph.microsoft.com/v1.0/applications","https://graph.microsoft.com/v1.0/servicePrincipals(appId='')/appRoleAssignedTo","https://graph.microsoft.com/v1.0/organization","https://graph.microsoft.com/beta/servicePrincipals","https://graph.microsoft.com/beta/servicePrincipals//owners","https://graph.microsoft.com/beta/groups//owners","https://graph.microsoft.com/beta/groups//members","https://graph.microsoft.com/v1.0/servicePrincipals//appRoleAssignedTo","https://graph.microsoft.com/beta/applications//owners","https://graph.microsoft.com/beta/devices//registeredOwners","https://graph.microsoft.com/v1.0/roleManagement/directory/roleAssignments","https://graph.microsoft.com/v1.0/roleManagement/directory/roleDefinitions","https://graph.microsoft.com/v1.0/devices","https://graph.microsoft.com/beta/users//roleManagement/directorytransitiveRoleAssignments","https://graph.microsoft.com/v1.0/roleManagement/directory/roleDefinitions/","https://graph.microsoft.com/beta/roleManagement/directory/estimateAccess","https://graph.microsoft.com/beta/users"]);
MicrosoftGraphActivityLogs
| where ResponseStatusCode == '200' 
| extend GeneralizedUri = replace_regex(RequestUri, @'\b[0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}\b-[0-9a-fA-F]{12}', @'')
| extend GeneralizedUri = replace_string(GeneralizedUri, @"//", @"https://techcommunity.microsoft.com/")
| extend GeneralizedUri = replace_string(GeneralizedUri, @"https:/", @"https://")
| extend GeneralizedUri = replace_regex(GeneralizedUri, @'\?.*$', @"")
| extend GeneralizedUri = replace_regex(GeneralizedUri, @'/$', @"")
| where GeneralizedUri in (calls)
| extend Id = iff(isempty(UserId), ServicePrincipalId, UserId)
| extend ObjectType = iff(isempty(UserId), "ServicePrincipal", "User")
| summarize MinTime=min(TimeGenerated), MaxTime=max(TimeGenerated), UniqueCalls=dcount(GeneralizedUri), CallsMade=count(), UserAgents=make_set(UserAgent) by IPAddress, bin(TimeGenerated, 2m), Id, ObjectType
| where datetime_diff('second', MaxTime, MinTime) < 100 and ((UniqueCalls >= 3 and CallsMade >= 40) or CallsMade > 100)

 

 

Note: Adjust the filter attributes as needed. You can also add more Microsoft Graph API requests to the calls array.

 

ShivaP_17-1725268194065.png

Figure 2: Reconnaissance results showing AzureHound and PowerShell usage.

 

Privilege escalation

Microsoft Graph provides several methods to escalate account privileges. These include assigning directory roles to users, adding users to privileged groups, creating service principals, and assigning roles.

 

Real world scenario: In an example of a customer engagement Microsoft IR was engaged on, a threat actor compromised a Service Principal of an Entra application that had the “RoleManagement.ReadWrite.Directory” role. Using these permissions, they granted a Global Administrator role to another compromised user identity.

Mitre technique: T1098.003

Application Compromised: Entra

Attack: Account manipulation: additional cloud roles

Permissions required: RoleManagement.ReadWrite.Directory (Delegated/Application)

ReqestURI: https://graph.microsoft.com/{v1.0  | beta}/{directoryRoles/{role-id}/members/$ref

For more details, see Add directory role member.

 

After an initial compromise, having specific privileges in an environment can allow for the assignment of higher privileges to other compromised accounts. In this example, an application with the “RoleManagement.ReadWrite.Directory” role was used to grant the Global Admin role to a user account under the actor’s control.

 

The following screenshot shows the roles assigned to the identity before the new role was added:

ShivaP_18-1725268194066.png

Figure 3: Screenshot showing a user with no role assigned.

 

The following screenshot shows that the identity has been granted Global Admin through Graph API:

ShivaP_19-1725268194067.png

Figure 4: Screenshot showing the Global Administrator role granted to the user.

 

Query: The following query detects role changes in Microsoft Graph activity logs, which also show when a role is added. Investigators should examine the result using audit logs or other available logs to provide further context and to distinguish between legitimate and unauthorized activity.

 

 

MicrosoftGraphActivityLogs
| where RequestUri has_all ("https://graph.microsoft.com/", "/directoryRoles/", "members/$ref")
| where RequestMethod == "POST"
| where ResponseStatusCode in ("204")
| extend Role = tostring(split(RequestUri, "https://techcommunity.microsoft.com/")[-3]) //Role can be looked up in Auditlogs
| project  TimeGenerated, IPAddress, RequestUri, ResponseStatusCode, Role, UserAgent, AppId

 

 

ShivaP_0-1725377309551.png

Figure 5: Screenshot showing a successful response code (204).

 

Lateral movement

After compromising a user identity or a service principal, an actor can send phishing emails to users within the organization. This can potentially lead to the compromise of further identities and facilitate lateral movement.

 

Microsoft Threat Intelligence outlined a similar attack in their blog post on how threat actors misuse OAuth applications to automate financially driven attacks.

 

Mitre technique: T1534

Application misused: Exchange Online

Attack: Internal phishing

Permissions required: Mail.Send (Delegated/Application)

ReqestURI: https://graph.microsoft.com/{v1.0  | beta}/{me | users}/{id | userPrincipalName}/sendMail.

For more details, see user: sendMail.

 

In our scenario, a rogue application was created, and a phishing link was sent to a user. After the user’s token was captured through the phish, the actor used delegated permissions to send emails to another user by using the sendMail API function.

 

ShivaP_21-1725268194071.png

Figure 6: Delegated permission abuse.

 

Query: This query detects the use of sendMail in the URI and lists every email sent using Microsoft Graph API. It distinguishes between delegated and application-based permissions and provides user information by combining it with the IdentityInfo table.

 

 

MicrosoftGraphActivityLogs 
| where ResponseStatusCode == "202"
| where RequestUri endswith "/sendMail"
| extend EmailSentFrom = tostring(parse_url(RequestUri).Path).substring(1).split("https://techcommunity.microsoft.com/")[-2]
| extend Id = iff(isempty(UserId), ServicePrincipalId, UserId)
| extend Type = iff(isempty(UserId), "ServicePrincipal", "User")
| extend JoinKey = case(Type == "ServicePrincipal", EmailSentFrom, Type == "User", UserId, "")
| join kind=leftouter (IdentityInfo | extend JoinKey = AccountObjectId | summarize arg_max(TimeGenerated, *) by JoinKey ) on  JoinKey
| extend AccountUPN = coalesce(AccountUPN, EmailSentFrom)
| project-reorder TimeGenerated, Type, AppId, MailAddress, RequestUri, ResponseStatusCode, UserAgent, AccountUPN

 

 

Note that the query retrieves details of successful mail submission requests to the server, but it doesn’t verify that the actual mail was delivered.

 

ShivaP_22-1725268194073.png

Figure 7: SendMail operations request URI.

 

Query: Reviewing the app ID and service principal can help verify that the applications are allowed to send emails. The following query summarizes the emails sent by service principals in the past 30 days.

 

 

MicrosoftGraphActivityLogs 
| where ResponseStatusCode == "202"
| where RequestUri endswith "/sendMail" and RequestUri has "/users/"  //Looking for the user's API in terms of ServicePrincipal access
| extend EmailSentFrom =  tostring(split(RequestUri, "https://techcommunity.microsoft.com/")[-2])
| extend Id = iff(isempty(UserId), ServicePrincipalId, UserId)
| extend Type = iff(isempty(UserId), "ServicePrincipal", "User")
| where Type == "ServicePrincipal"
| join kind=leftouter (IdentityInfo | summarize arg_max(TimeGenerated, *) by AccountObjectId ) on $left.EmailSentFrom == $right.AccountObjectId
| extend AccountUPN = coalesce(AccountUPN, EmailSentFrom)
| summarize EmailsSentCount=count(), SentFromUsers=make_set(AccountUPN), UserAgents=make_set(UserAgent) by AppId 

 

 

ShivaP_1-1725377526796.png

 

Figure 8: SendMail operations count using ServicePrincipal.

 

Collection

The Microsoft Graph API includes functions that can be misused by a threat actor to access and read emails from users’ mailboxes.

 

Real world scenario: In one customer engagement, a threat actor targeted a specific user’s mailbox by using delegated permissions and accessed multiple users’ emails through an Entra application with broad permissions. 

Mitre technique: T1114

Application misused: Exchange Online

Attack: Email collection

Permissions required: Mail.ReadBasic.All (Application), Mail.Read (Delegated/Application)

ReqestURI: https://graph.microsoft.com/{v1.0  | beta} /users/{user-id}/mailFolders/{folder-id}/messages 

For more details, see List messages.

https://graph.microsoft.com/{v1.0  | beta} /users/UserID/messages

For more details, see Send Outlook messages from another user.

 

In our scenario, the threat actor abused an application with excessive permissions, which allowed them to gain unauthorized access to the mailboxes of users.

 

Query: The following query can be used to hunt for Microsoft Graph API calls which are used to read mail from a users’ mailbox. The application ID (AppId) represents the application that Microsoft Graph uses to access the emails.

 

 

MicrosoftGraphActivityLogs
| where RequestMethod == "GET"
| where RequestUri has_all ("https://graph.microsoft.com", "/users/", "/messages")
| where ResponseStatusCode in ("200")
| project AppId, UserAgent, RequestUri

 

 

ShivaP_2-1725377621320.png

 

Figure 9: Example of successful mail access.

 

Query: The query below reveals statistics about the applications or users used for reading emails, along with the number of unique mailboxes accessed and their respective timeframes. Note that this query also uses the IdentityInfo table.

 

 

MicrosoftGraphActivityLogs
| where RequestMethod == "GET"
| where RequestUri has_all ("https://graph.microsoft.com", "/users/", "/messages")
| where ResponseStatusCode == "200"
| extend Id = iff(isempty(UserId), ServicePrincipalId, UserId)
| extend ObjectType = iff(isempty(UserId), "ServicePrincipal", "User")
| extend MailboxTargetUPN = tostring(extract_all( @'https://graph.microsoft.com/v.../users/([^/]*)/', RequestUri)[0]) //Parses the AccountUPN
| extend UserGuid= tostring(extract_all( @'*.(\b[0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}\b-[0-9a-fA-F]{12}).*', RequestUri)[0]) //Parses the object-ID of an targeted identity
| join kind=leftouter (IdentityInfo |  where TimeGenerated > ago(30d) | summarize arg_max(TimeGenerated, *) by AccountObjectId | project TargetUPN=AccountUPN, AccountObjectId) on $left.UserGuid==$right.AccountObjectId
| extend TargetUPN = coalesce(TargetUPN, MailboxTargetUPN)
| summarize MinTime=min(TimeGenerated), MaxTime=max(TimeGenerated), MailBoxAccessCount=dcount(TargetUPN), Targets=make_set(TargetUPN) by AppId, ObjectType, Id 

 

 

 

ShivaP_3-1725377741699.png

 

Figure 10: Results showing total unique Mailbox count.

 

Exfiltration

Actors can use Microsoft Graph to download sensitive files or data from any user’s OneDrive accounts or SharePoint. By illegitimately using file capabilities in Microsoft Graph, a bad actor can access and download confidential documents even without direct access to those files.

 

Real world scenario: In one of our customer engagements, Microsoft Incident Response observed compromised identities accessing files on SharePoint Online and OneDrive through Microsoft Graph API.

Mitre technique: T1567

Application misused: OneDrive/SharePoint

Attack: Download data

Permissions required: Files.ReadWrite (Delegated), Files.ReadWrite.All (Delegated/Application), Sites.ReadWrite.All (Delegated/Application)

ReqestURI:

https://graph.microsoft.com/{v1.0  | beta} /drives/{drive-id}/items/{item-id}/content

https://graph.microsoft.com/{v1.0  | beta} /groups/{group-id}/drive/items/{item-id}/content

https://graph.microsoft.com/{v1.0  | beta} /me/drive/root:/{item-path}:/content

https://graph.microsoft.com/{v1.0  | beta} /me/drive/items/{item-id}/content

https://graph.microsoft.com/{v1.0  | beta} /sites/{siteId}/drive/items/{item-id}/content

https://graph.microsoft.com/{v1.0  | beta} /sites/{siteId}/drives/{drive-id}/items/{item-id}/content

https://graph.microsoft.com/{v1.0  | beta} /users/{userId}/drive/items/{item-id}/content

For more details, see Download driveItem content.

 

In this scenario, the bad actor abused an application with Files Read/Write and Sites Read/Write permissions. These excessive permissions allow them to search through users’ OneDrive and SharePoint files to download confidential documents.

 

Query: The following query is a good starting point for investigating Microsoft Graph API calls related to download activities. Analyze the UserAgent and AppID to determine whether these activities are expected in your environment. Note that the Item ID cannot be resolved to identify the downloaded item, but CloudApp events can be correlated to provide further context for this download activity.

 

 

MicrosoftGraphActivityLogs
| where RequestMethod == "GET" 
| where ResponseStatusCode in ("302", "200")       // https://learn.microsoft.com/en-us/graph/api/driveitem-get-content?view=graph-rest-1.0&tabs=http#response, normal response code returns a "302 Found" response redirecting to a preauthenticated download URL. 
| where RequestUri matches regex @"https://graph\.microsoft\.com/.*/items/.*/content" and RequestUri matches regex @"/drives?/.*" and RequestUri !has "/thumbnails/"
| project  TimeGenerated, ResponseStatusCode, RequestMethod, IPAddress, UserAgent, RequestUri, AppId 

 

 

ShivaP_26-1725268194085.png

 Figure 11: SharePoint access.

Impact

When it comes to impact, Microsoft Graph API includes multiple functions that can be misused to allow unauthorized access to sensitive data and resources. This could lead to account access removals, data destruction, and/or resource hijacking. Such activities can significantly disrupt business operations, result in financial losses, and damage an organization’s reputation.

 

Mitre technique: T1531

Application misused: Entra

Attack: Account access removal

Permissions required: User.ReadWrite.All (Delegated/Application)

Request URI: https://graph.microsoft.com/v1.0/users/{user-id}  

For more details, see User Delete

 

In this scenario, the bad actor abuses an application with the “User.ReadWrite.All” role to delete a user, disrupting business operations.

 

Query: The following query identifies delete requests and the associated User ID. AppID and UserAgent can be used for further investigation to determine if this behavior is expected.

 

 

MicrosoftGraphActivityLogs
| where RequestMethod == "DELETE"
| where RequestUri matches regex @"/users/[0-9a-fA-F-]{36}$"
| where ResponseStatusCode == "204"
| extend DeletedUserID =  tostring(split(RequestUri, "https://techcommunity.microsoft.com/")[-1])
| join kind=leftouter (IdentityInfo | summarize arg_max(TimeGenerated, *) by AccountObjectId ) on $left.DeletedUserID == $right.AccountObjectId 
| project-reorder  TimeGenerated, ResponseStatusCode, RequestMethod, IPAddress, UserAgent, RequestUri, AppId, AccountDisplayName, AccountUPN 

 

 

ShivaP_27-1725268194087.png

Figure 12: Account access removed.

 

Auditing the Microsoft Graph usage

Conducting regular audits of Entra applications that use the Microsoft Graph API can reveal whether an application has excessive permissions or if an application is accessing Microsoft Graph API unexpectedly or inappropriately. This can indicate a possible service principal compromise.

 

Auditing helps to create a safe list of approved applications with excessive permissions. Using this information, you can apply continuous monitoring to identify any new applications with high privileges, ensuring timely detection of potential security threats.

 

Query: The following query helps to identify the types of Entra applications that have accesses with high-impact permissions.

 

 


let PrivilegeAbuse = datatable (Type: string, Permission: string, Privilege: string, Reason: string) [
    "Application","Mail.ReadWrite","High","BroadImpact",
    "Application","Mail.Read","High","Collection",
    "Application","Contacts","High","Phishing",
    "Application","MailboxSettings","High","Phishing",
    "Application","People","High","Phishing",
    "Application","Files","High","Collection",
    "Application","Notes","High","Collection",
    "Application","Directory.AccessAsUser.All","High","Phishing",
    "Application","user_impersonation","High","Phishing",
    "Application","Application.ReadWrite.All","High","BroadImpact",
    "Application","Directory.ReadWrite.All","High","BroadImpact",
    "Application","Domain.ReadWrite.All","High","BroadImpact",
    "Application","EduRoster.ReadWrite.All","High","BroadImpact",
    "Application","Group.ReadWrite.All","High","BroadImpact",
    "Application","Member.Read.Hidden","High","BroadImpact",
    "Application","RoleManagement.ReadWrite.Directory","High","BroadImpact",
    "Application","User.ReadWrite.All","High","BroadImpact",
    "Application","User.ManageCreds.All","High","BroadImpact",
    "Application","AppRoleAssignment.ReadWrite.All","High","PrivEscalation"
];
MicrosoftGraphActivityLogs
| where TimeGenerated between (ago(7d) .. now())
| extend ObjectType = iff(isempty(UserId), "ServicePrincipal", "User")
| where ObjectType == 'ServicePrincipal'
| extend RolesTemp = split(Roles, " ")
| mv-expand RolesTemp
| where RolesTemp has_any (( PrivilegeAbuse | distinct Permission ))
| extend Role = tostring(RolesTemp)
| summarize Calls=count(), MinTime=min(TimeGenerated), MaxTime=max(TimeGenerated) by AppId, Role

 

 

The final step is to evaluate the results of this query, compile a list of authorized Entra applications, and identify any unauthorized or recent usage. This can be done as a part of an ongoing monitoring and auditing process.

 

Conclusion

The Microsoft Graph API provides a unified endpoint to access a wide range of Microsoft 365 services, including Azure Active Directory, Outlook, Teams, OneDrive, and more. The potential misuse of the Microsoft Graph API poses a significant security risk to organizations. As described in this blog, malicious actors can and have used these APIs to gain access to sensitive data, disrupt operations, and exfiltrate information.

 

To counter these threats, it is crucial to collect and monitor Microsoft Graph API logs to identify suspicious activities, detect anomalies, and establish baseline usage patterns. Conduct regular audits of applications that use Microsoft Graph API to ensure that they strictly adhere to the principle of least privilege. By establishing a safe list of trusted applications and continuously monitoring high privileged accesses, organizations can swiftly detect and respond to threats and anomalies.

 

Proactive measures like these, combined with vigilant monitoring, are essential to safeguarding your organization against sophisticated cyber threats. As we always say: stay proactive, stay secure.





Source link

You may also like

Leave a Comment

Our Company

Welcome to OdysseyX, your one-stop destination for the latest news and opportunities across various domains.

Newsletter

Subscribe my Newsletter for new blog posts, tips & new photos. Let's stay updated!

Laest News

@2024 – All Right Reserved. Designed and Developed by OdysseyX