Finding the Master Keys: How to Hunt Malicious Client Secrets in M365
文章探讨了微软365中客户端密钥的安全风险及其被滥用的可能性。通过发现、调查和影响评估三个阶段的方法,结合PowerShell脚本和KQL查询工具,帮助识别和应对恶意活动。强调了定期审计、权限最小化和持续监控的重要性。 2025-10-30 23:0:6 Author: www.guidepointsecurity.com(查看原文) 阅读量:5 收藏

The biggest risk to a secure building isn’t the burglar with a crowbar, it’s the locksmith who quietly makes an extra copy of the master key. In Microsoft 365, client secrets are those keys. They are confidential credentials issued to applications that allow those apps to authenticate as themselves via OAuth (an open-standard authorization protocol) and request access tokens. This method of authentication unlocks powerful application and service principal access, and when mishandled, it can silently grant attackers the same privileges you give to your most trusted employees and systems.

This post will build upon research conducted by Proofpoint, which provides insight into malicious OAuth apps and how they get abused.

We’ll explore a technical approach to identifying and investigating malicious client secrets in Microsoft 365 environments. This guide will walk you through a step-by-step methodology, utilized by GuidePoint Security’s DFIR (Digital Forensics and Incident Response) team in real-world incidents. 

We provide working PowerShell scripts and Kusto Query Language (KQL) queries that will aid the investigation process; however, the query logic can be easily understood and adapted to other security solutions or languages available in your environment. 

The Hunting Methodology: A Three-phase Approach

Our methodology consists of three main phases:

  • Discovery: Identifying all client secrets across applications and service principals
  • Investigation: Analyzing suspicious credentials and their associated activities
  • Impact Assessment: Determining what data was accessed and by whom

Phase 1: Discovering Client Secrets in Your Environment

The first step in hunting for malicious activity is knowing what client secrets exist in your environment. You can’t protect what you can’t see, so comprehensive visibility is essential.

Setting Up Your Hunting Environment

Before you begin the discovery process, you’ll need to prepare your PowerShell environment with the appropriate tools. Microsoft Graph SDK for PowerShell provides the necessary cmdlets to interact with your Microsoft 365 tenant programmatically. The following commands will ensure that the Microsoft Graph PowerShell module is installed for you, and the appropriate permissions needed to enumerate application and service principal configurations are assigned to the Microsoft Graph connection.

Install-Module Microsoft.Graph -Scope CurrentUser -Force
Connect-MgGraph -Scopes "Application.Read.All"

Discovering Service Principal Credentials

Service principals represent applications within your specific Entra ID tenant. They define what an application can do, who can access it, and what resources it can access. Each service principal can have multiple credentials associated with it.

Retrieving All Service Principal Credentials:

$allSpCreds = Get-MgServicePrincipal -All | ForEach-Object {
    $sp = $_
    ForEach ($cred in $sp.PasswordCredentials) {
        [PSCustomObject]@{
            SPname = $sp.DisplayName
            AppId = $sp.AppId
            SPObjectId = $sp.Id
            KeyId = $cred.KeyId
            Hint = $cred.Hint
            DisplayName = $cred.DisplayName
            StartDateTime = $cred.StartDateTime
            EndDateTime = $cred.EndDateTime
        }
    }
}
$allSpCreds | Export-Csv -Path "ServicePrincipalCredentials.csv" -NoTypeInformation

NOTE: All the queries provided in this post may need additional fine-tuning for each unique environment.

What’s Happening Here?

This script retrieves every service principal in your tenant, then loops through each one’s credentials. For each item found, it creates a structured record containing key information:

  • SPname: The human-readable name of the service principal
  • AppId: The unique application identifier
  • SPObjectId: The object ID of the service principal in your directory
  • KeyId: A unique identifier for this specific credential
  • Hint: A partial view of the credential (for identification purposes only)
  • DisplayName: A descriptive name for the credential
  • StartDateTime: When the credential becomes valid
  • EndDateTime: When the credential expires

The results are exported to a CSV file for further analysis.

Discovering Application Credentials

While service principals represent applications within your tenant, application objects are the global representation of applications across all tenants where they’re used. It’s important to check both, as threat actors might create credentials at either level.

Retrieving All Application Credentials:

$allAppCreds = Get-MgApplication -All | ForEach-Object {
    $app = $_
    ForEach ($cred in $app.PasswordCredentials) {
        [PSCustomObject]@{
            AppName = $app.DisplayName
            AppId = $app.AppId
            AppObjectId = $app.Id
            KeyId = $cred.KeyId
            Hint = $cred.Hint
            DisplayName = $cred.DisplayName
            StartDateTime = $cred.StartDateTime
            EndDateTime = $cred.EndDateTime
        }
    }
}
$allAppCreds | Export-Csv -Path "ApplicationCredentials.csv" -NoTypeInformation

NOTE: All the queries provided in this post may need additional fine-tuning for each unique environment.

This script follows the same pattern as the service principal discovery but focuses on application objects instead. By running both scripts, you create a comprehensive inventory of all credentials that could potentially be used for authentication.

Why Check Both?

Applications and service principals serve different purposes in the identity architecture. An application object is the template, while service principals are the local instances. Attackers might create malicious credentials at either level, depending on their objectives and the permissions they’ve obtained.

Phase 2: Investigating Suspicious Activity

Once you’ve identified potential malicious client secrets, the next step is understanding what they’ve been used for. In many real-world incidents, threat actors leverage compromised or malicious client secrets to access sensitive data, particularly email messages, which often contain valuable intellectual property, financial information, and confidential communications.

The Attack Pattern: Graph API Mail Access

Microsoft Graph API provides a powerful interface for accessing Microsoft 365 resources programmatically. While this is invaluable for legitimate automation and integration scenarios, it’s also a prime target for attackers. When threat actors gain access through malicious client secrets, they often use Graph API to export email messages from multiple accounts. This is why monitoring Graph API usage is crucial for security operations.

Leveraging the GraphAPIAuditEvents Table

The table GraphAPIAuditEvents captures detailed telemetry for API requests made via Microsoft Graph API for resources in your Entra ID tenant. These events provide visibility into which applications accessed what resources, when, and from where.

Identifying Mail Access by Suspicious Applications:

GraphAPIAuditEvents
| where AccountObjectId in ("AppID 1", "AppID 2")

NOTE: All the queries provided in this post may need additional fine-tuning for each unique environment.

Understanding the Query:

This KQL statement filters the GraphAPIAuditEvents table to show only those activities performed by specific applications. To utilize this query, replace the placeholder AppIDs with the actual application identifiers you discovered in Phase 1 that appear suspicious.

When this query returns results, pay close attention to the RequestUri field. For mail access operations, you’ll see URLs following this pattern:

https://graph.microsoft.com/v1.0/users/<userId>/messages/<messageId>

Two important things to note in this URL pattern is the <userId> value, identifying the account whose mailbox was accessed, and the <messageId> value, identifying the specific email message that was retrieved.

The <messageId> value can later be utilized to correlate the identified accessed messages with Message Trace logs in Microsoft 365 to obtain additional details about the accessed email messages in order to identify patterns of interest.

Each of these URIs represents a single email message that was accessed by the application. If you see hundreds or thousands of these events, it’s a strong indicator of large-scale data exfiltration.

To understand the scope of the compromise, you need to identify all user accounts whose mailboxes were accessed. This enhanced query extracts the email addresses from the request URIs and provides a timeline of access:

GraphAPIAuditEvents
| where AccountObjectId in ("AppID 1", "AppID 2")
| extend EmailAddress = extract(@"/users/([^/]+)/", 1, RequestUri)
| summarize FirstSeen = min(Timestamp), LastSeen = max(Timestamp) by EmailAddress, IPAddress
| project FirstSeen, LastSeen, IPAddress, EmailAddress

NOTE: All the queries provided in this post may need additional fine-tuning for each unique environment.

This information is crucial for your incident response efforts, enabling you to notify affected users, assess the sensitivity of potentially compromised data, and take appropriate containment actions.

Identify Multiple Mailboxes Accessed by the Same Session Token

Another option is to analyze Microsoft 365 OfficeActivity logs in order to identify potential cases where the same access token (client secret) is being used to access multiple users, a behavior that can indicate a potential compromise or misuse of the application identity.

OfficeActivity
| where isnotempty(AppAccessContext)
| extend UniqueTokenId = tostring(AppAccessContext.UniqueTokenId)
| extend AppId = tostring(AppAccessContext.ClientAppId)
| where isnotempty(UniqueTokenId) and isnotempty(AppId)
| where Operation == "MailItemsAccessed"
| summarize UniqueUsers = dcount(UserId), Users = make_set(UserId) by UniqueTokenId, AppId | where UniqueUsers > 1
| project TimeGenerated, AppId, UniqueTokenId, UniqueUsers, Users

NOTE: All the queries provided in this post may need additional fine-tuning for each unique environment.

The above query focuses solely on MailItemsAccess operation and focuses on tokens used to access more than one user account.

Further fine-tuning of this query can be made by excluding cases where users legitimately access multiple mailboxes in the environment, for instance, their personal account and a shared mailbox.

Hunting for New Service Principal Credentials

Identifying when and where new credentials were added is crucial during the investigation process. While that can be answered by triaging credentials for all Service Principals and Applications in the environment through the scripts provided in this article, you can also hunt and should regularly monitor for the creation of new service principal credentials.

This data exists in two separate tables, AuditLogs and CloudAppEvents. The relevant KQL queries are shown below:

CloudAppEvents
| where ActionType == "Add service principal credentials."
AuditLogs
| where OperationName == "Add service principal credentials"
| where Identity != "Managed Service Identity"

NOTE: All the queries provided in this post may need additional fine-tuning for each unique environment.

In the case of the AuditLogs we have excluded newly created credentials for service principals that are automatically managed by the system.

Phase 3: Impact Assessment and Response

Armed with the data from your investigation, you can now assess the full impact of the incident and formulate an appropriate response strategy.

Questions to Answer

During your assessment, focus on these critical questions:

Scope of Compromise:

  • How many user accounts were affected?
  • Which departments or roles do these users belong to?
  • What types of data were potentially accessed?

Timeline Analysis:

  • When did malicious access begin?
  • How long did it continue undetected?
  • Were there patterns or specific time windows when access occurred?

Threat Actor Indicators:

  • What IP addresses were used?
  • Are there patterns in the accessed messages (specific senders, subjects, or time periods)? Some of these items may need additional correlation with Message Trace logs as mentioned above.
  • Does the activity align with known threat actor techniques?

Building Your Response Plan

Based on your findings, your response should include:

  1. Immediate Containment: Disable or remove identified malicious client secrets
  2. Credential Rotation: Reset credentials for affected applications and potentially compromised accounts
  3. Access Review: Audit and potentially revoke granted permissions for suspicious applications
  4. Enhanced Monitoring: Implement additional detection rules based on observed tactics, techniques, and procedures (TTPs)

Best Practices for Proactive Defense

Prevention is always better than cure. Here are key practices to minimize your exposure to malicious client secret attacks:

Perform Regular Credential Audits:

  • Credentials created outside of your change management process
  • Secrets with unusually long validity periods
  • Applications with excessive permissions relative to their stated purpose

Implement Conditional Access: Use Entra ID Conditional Access policies to restrict application access based on risk factors.

Enable Privileged Identity Management (PIM): For applications requiring high-privilege permissions, use PIM to ensure just-in-time access rather than standing privileges.

Monitor Graph API Activity: Don’t wait for an incident. Establish baseline behavior for Graph API usage in your environment and set up alerts for anomalies.

Principle of Least Privilege: When granting permissions to applications, provide only the minimum necessary scopes.

Stay Ahead of the Threat

The methodology outlined in this post provides a structured approach to hunting for malicious client secrets in your Microsoft 365 environment. By combining proactive discovery with detailed investigation techniques, you can identify threats that might otherwise remain hidden in the noise of normal application activity.

Remember, security is not a one-time effort but an ongoing process. Threat actors continually evolve their techniques, and your defensive measures must evolve as well. The scripts and queries provided here are starting points, adapt them to your specific environment, integrate them into your security operations workflow, and continuously refine your detection capabilities based on the threats you observe.

Learn more about how GuidePoint Security can help you with threat hunting and incident response.

Stay vigilant, stay informed, and happy hunting!


文章来源: https://www.guidepointsecurity.com/blog/finding-the-master-keys-how-to-hunt-malicious-client-secrets-in-m365/
如有侵权请联系:admin#unsafe.sh