Microsoft Sentinel Analytic Rules
cloudbrothers.infoAzure Sentinel RepoToggle Dark/Light/Auto modeToggle Dark/Light/Auto modeToggle Dark/Light/Auto modeBack to homepage

Power Apps - Multiple users access a malicious link after launching new app

Back
Id4bd7e93a-0646-4e02-8dcb-aa16d16618f4
RulenamePower Apps - Multiple users access a malicious link after launching new app
DescriptionIdentifies a chain of events, where a new Power App is created, followed by mulitple users launching the app within the detection window and clicking on the same malicious URL.
SeverityHigh
TacticsInitialAccess
TechniquesT1189
T1566
Required data connectorsAzureActiveDirectoryIdentityProtection
MicrosoftDefenderThreatIntelligence
MicrosoftThreatProtection
PowerPlatformAdmin
ThreatIntelligence
ThreatIntelligenceTaxii
KindScheduled
Query frequency1h
Query period14d
Trigger threshold0
Trigger operatorgt
Source Urihttps://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Microsoft Business Applications/Analytic Rules/Power Apps - Multiple users access a malicious link after launching new app.yaml
Version3.2.0
Arm template4bd7e93a-0646-4e02-8dcb-aa16d16618f4.json
Deploy To Azure
// Define a threshold (distinct_user_launch_threshold) for
// the minimum number of users who launched an app
// to be in scope of this detection
let distinct_user_launch_threshold = 2;
// Define a threshold for the minumum number of users
// who clicked the same malicious link after launching the app
// to be in scope of this detection
let distinct_user_url_click_threshold = 2;
let query_frequency = 1h;
let query_lookback = 14d;
let new_app_creation_activity = materialize(
    PowerPlatformAdminActivity
    | where TimeGenerated >= ago (query_lookback)
    | where EventOriginalType == "CreatePowerApp"
    | extend Properties = tostring(PropertyCollection)
    | extend SrcIpAddr = extract(@'"enduser.ip_address","Value":"([^"]+)"', 1, Properties)
    | extend SrcIpAddr = iif(SrcIpAddr startswith '::ffff:', replace_string(SrcIpAddr, '::ffff:', ''), SrcIpAddr)
    | extend AppId = extract(@'"powerplatform.analytics.resource.power_app.id","Value":"([^"]+)"', 1, Properties)
    | extend AppId = tolower(replace_string(AppId, '/providers/Microsoft.PowerApps/apps/', ''))
    | extend
        AppName = extract(@'"powerplatform.analytics.resource.power_app.display_name","Value":"([^"]+)"', 1, Properties),
        EnvironmentId = extract(@'"powerplatform.analytics.resource.environment.id","Value":"([^"]+)"', 1, Properties)
    | project-rename
        AppCreatedTime = TimeGenerated,
        AppCreator = ActorName,
        AppCreatorIpAddr = SrcIpAddr
    );
let distinct_apps = new_app_creation_activity
    | distinct AppName;
let new_app_launch_activity = materialize(
    new_app_creation_activity
    | join kind=inner (
        PowerPlatformAdminActivity
        | where TimeGenerated >= ago (query_lookback)
        | where EventOriginalType == "LaunchPowerApp"
        | where PropertyCollection has_any (distinct_apps)
        | extend Properties = tostring(PropertyCollection)
        | extend AppName = extract(@'"powerplatform.analytics.resource.power_app.display_name","Value":"([^"]+)"', 1, Properties)
        | summarize FirstAppLaunchTime = min(TimeGenerated) by ActorName, AppName)
        on AppName
    | where FirstAppLaunchTime > AppCreatedTime
    );
let new_app_launch_users = new_app_launch_activity
    | summarize LaunchCount = dcount(ActorName) by AppName
    | where LaunchCount > distinct_user_launch_threshold
    | join kind=inner new_app_launch_activity on AppName
    | summarize
        by
        ActorName,
        FirstAppLaunchTime,
        AppName,
        AppId,
        EnvironmentId,
        AppCreator,
        AppCreatorIpAddr;
let detected_urls = union isfuzzy=true
        (
        SecurityAlert
        | where TimeGenerated >= ago (query_lookback)
        | where Entities has_cs '"Type":"url"'
        | mv-expand todynamic(Entities)
        | where tostring(Entities.Type) == "url"
        | project Url = tostring(Entities.Url), Source = "SecurityAlert"
        ),
        (
        ThreatIntelligenceIndicator
        | where TimeGenerated >= ago(query_lookback)
        | summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by IndicatorId
        | where Active == true and ExpirationDateTime > now()
        | where isnotempty(isnotempty(Url))
        | project Url, Source = "ThreatIntelligence"
        )
    | summarize by Url, Source;
let url_click_events = materialize(
    union isfuzzy=true
        (
        UrlClickEvents
        | where TimeGenerated >= ago(query_frequency)
        | where isnotempty(ThreatTypes)
        | join kind=inner (new_app_launch_users) on $left.AccountUpn == $right.ActorName
        | where TimeGenerated between (FirstAppLaunchTime .. (FirstAppLaunchTime + 1h))
        | summarize by ActorName, Url, Source = "MicrosoftDefender"
        ),
        (
        _Im_WebSession
        | where TimeGenerated >= ago(query_frequency)
        | join kind=inner (new_app_launch_users) on $left.SrcUsername == $right.ActorName
        | join kind=inner (detected_urls) on Url
        | where TimeGenerated between (FirstAppLaunchTime .. (FirstAppLaunchTime + 1h))
        | summarize by ActorName, Url, Source
        )
    );
let distinct_url_click_events_count = toscalar(
    url_click_events
    | summarize DistinctUserCount = dcount(ActorName) by Url
    | where DistinctUserCount > distinct_user_url_click_threshold
    | summarize sum(DistinctUserCount)
    );
url_click_events
| summarize DistinctUserCount = dcount(ActorName) by Url
| where DistinctUserCount >= distinct_user_url_click_threshold
| join kind=inner url_click_events on Url
| join kind=inner (new_app_launch_users) on ActorName
| extend
    PowerAppsEntityId = 27593,
    DataverseId = 32780,
    AccountName = tostring(split(ActorName, '@')[0]),
    UPNSuffix = tostring(split(ActorName, '@')[1])
| project
    FirstAppLaunchTime,
    AppCreator,
    AppName,
    AppId,
    ImpactedUser = ActorName,
    AccountName,
    UPNSuffix,
    EnvironmentId,
    Url,
    Source,
    PowerAppsEntityId
entityMappings:
- entityType: CloudApplication
  fieldMappings:
  - identifier: AppId
    columnName: PowerAppsEntityId
  - identifier: InstanceName
    columnName: AppName
- entityType: URL
  fieldMappings:
  - identifier: Url
    columnName: Url
- entityType: Account
  fieldMappings:
  - identifier: FullName
    columnName: AppCreator
- entityType: Account
  fieldMappings:
  - identifier: UPNSuffix
    columnName: UPNSuffix
  - identifier: Name
    columnName: AccountName
queryFrequency: 1h
name: Power Apps - Multiple users access a malicious link after launching new app
alertDetailsOverride:
  alertDisplayNameFormat: 'Possible malicious app detected - {{AppName}} '
  alertDescriptionFormat: 'Multiple users opened a malicious link after launching app {{AppName}}.  Click here to navigate to the Power Apps Portal to examine the app: https://make.powerapps.com/environments/{{EnvironmentId}}/apps'
kind: Scheduled
tactics:
- InitialAccess
triggerThreshold: 0
query: |
  // Define a threshold (distinct_user_launch_threshold) for
  // the minimum number of users who launched an app
  // to be in scope of this detection
  let distinct_user_launch_threshold = 2;
  // Define a threshold for the minumum number of users
  // who clicked the same malicious link after launching the app
  // to be in scope of this detection
  let distinct_user_url_click_threshold = 2;
  let query_frequency = 1h;
  let query_lookback = 14d;
  let new_app_creation_activity = materialize(
      PowerPlatformAdminActivity
      | where TimeGenerated >= ago (query_lookback)
      | where EventOriginalType == "CreatePowerApp"
      | extend Properties = tostring(PropertyCollection)
      | extend SrcIpAddr = extract(@'"enduser.ip_address","Value":"([^"]+)"', 1, Properties)
      | extend SrcIpAddr = iif(SrcIpAddr startswith '::ffff:', replace_string(SrcIpAddr, '::ffff:', ''), SrcIpAddr)
      | extend AppId = extract(@'"powerplatform.analytics.resource.power_app.id","Value":"([^"]+)"', 1, Properties)
      | extend AppId = tolower(replace_string(AppId, '/providers/Microsoft.PowerApps/apps/', ''))
      | extend
          AppName = extract(@'"powerplatform.analytics.resource.power_app.display_name","Value":"([^"]+)"', 1, Properties),
          EnvironmentId = extract(@'"powerplatform.analytics.resource.environment.id","Value":"([^"]+)"', 1, Properties)
      | project-rename
          AppCreatedTime = TimeGenerated,
          AppCreator = ActorName,
          AppCreatorIpAddr = SrcIpAddr
      );
  let distinct_apps = new_app_creation_activity
      | distinct AppName;
  let new_app_launch_activity = materialize(
      new_app_creation_activity
      | join kind=inner (
          PowerPlatformAdminActivity
          | where TimeGenerated >= ago (query_lookback)
          | where EventOriginalType == "LaunchPowerApp"
          | where PropertyCollection has_any (distinct_apps)
          | extend Properties = tostring(PropertyCollection)
          | extend AppName = extract(@'"powerplatform.analytics.resource.power_app.display_name","Value":"([^"]+)"', 1, Properties)
          | summarize FirstAppLaunchTime = min(TimeGenerated) by ActorName, AppName)
          on AppName
      | where FirstAppLaunchTime > AppCreatedTime
      );
  let new_app_launch_users = new_app_launch_activity
      | summarize LaunchCount = dcount(ActorName) by AppName
      | where LaunchCount > distinct_user_launch_threshold
      | join kind=inner new_app_launch_activity on AppName
      | summarize
          by
          ActorName,
          FirstAppLaunchTime,
          AppName,
          AppId,
          EnvironmentId,
          AppCreator,
          AppCreatorIpAddr;
  let detected_urls = union isfuzzy=true
          (
          SecurityAlert
          | where TimeGenerated >= ago (query_lookback)
          | where Entities has_cs '"Type":"url"'
          | mv-expand todynamic(Entities)
          | where tostring(Entities.Type) == "url"
          | project Url = tostring(Entities.Url), Source = "SecurityAlert"
          ),
          (
          ThreatIntelligenceIndicator
          | where TimeGenerated >= ago(query_lookback)
          | summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by IndicatorId
          | where Active == true and ExpirationDateTime > now()
          | where isnotempty(isnotempty(Url))
          | project Url, Source = "ThreatIntelligence"
          )
      | summarize by Url, Source;
  let url_click_events = materialize(
      union isfuzzy=true
          (
          UrlClickEvents
          | where TimeGenerated >= ago(query_frequency)
          | where isnotempty(ThreatTypes)
          | join kind=inner (new_app_launch_users) on $left.AccountUpn == $right.ActorName
          | where TimeGenerated between (FirstAppLaunchTime .. (FirstAppLaunchTime + 1h))
          | summarize by ActorName, Url, Source = "MicrosoftDefender"
          ),
          (
          _Im_WebSession
          | where TimeGenerated >= ago(query_frequency)
          | join kind=inner (new_app_launch_users) on $left.SrcUsername == $right.ActorName
          | join kind=inner (detected_urls) on Url
          | where TimeGenerated between (FirstAppLaunchTime .. (FirstAppLaunchTime + 1h))
          | summarize by ActorName, Url, Source
          )
      );
  let distinct_url_click_events_count = toscalar(
      url_click_events
      | summarize DistinctUserCount = dcount(ActorName) by Url
      | where DistinctUserCount > distinct_user_url_click_threshold
      | summarize sum(DistinctUserCount)
      );
  url_click_events
  | summarize DistinctUserCount = dcount(ActorName) by Url
  | where DistinctUserCount >= distinct_user_url_click_threshold
  | join kind=inner url_click_events on Url
  | join kind=inner (new_app_launch_users) on ActorName
  | extend
      PowerAppsEntityId = 27593,
      DataverseId = 32780,
      AccountName = tostring(split(ActorName, '@')[0]),
      UPNSuffix = tostring(split(ActorName, '@')[1])
  | project
      FirstAppLaunchTime,
      AppCreator,
      AppName,
      AppId,
      ImpactedUser = ActorName,
      AccountName,
      UPNSuffix,
      EnvironmentId,
      Url,
      Source,
      PowerAppsEntityId  
relevantTechniques:
- T1189
- T1566
triggerOperator: gt
customDetails:
  PowerAppsApp: AppId
  AppCreator: AppCreator
  Environment: EnvironmentId
  PowerAppsAppName: AppName
queryPeriod: 14d
eventGroupingSettings:
  aggregationKind: AlertPerResult
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Microsoft Business Applications/Analytic Rules/Power Apps - Multiple users access a malicious link after launching new app.yaml
severity: High
status: Available
id: 4bd7e93a-0646-4e02-8dcb-aa16d16618f4
requiredDataConnectors:
- connectorId: PowerPlatformAdmin
  dataTypes:
  - PowerPlatformAdminActivity
- connectorId: MicrosoftThreatProtection
  dataTypes:
  - UrlClickEvents
- connectorId: ThreatIntelligence
  dataTypes:
  - ThreatIntelligenceIndicator
- connectorId: ThreatIntelligenceTaxii
  dataTypes:
  - ThreatIntelligenceIndicator
- connectorId: MicrosoftDefenderThreatIntelligence
  dataTypes:
  - ThreatIntelligenceIndicator
- connectorId: ThreatIntelligence
  dataTypes:
  - ThreatIntelligenceIndicator
- connectorId: ThreatIntelligenceTaxii
  dataTypes:
  - ThreatIntelligenceIndicator
- connectorId: MicrosoftDefenderThreatIntelligence
  dataTypes:
  - ThreatIntelligenceIndicator
- connectorId: MicrosoftThreatProtection
  dataTypes:
  - UrlClickEvents
- connectorId: AzureActiveDirectoryIdentityProtection
  dataTypes:
  - SecurityAlert
version: 3.2.0
description: Identifies a chain of events, where a new Power App is created, followed by mulitple users launching the app within the detection window and clicking on the same malicious URL.
{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "workspace": {
      "type": "String"
    }
  },
  "resources": [
    {
      "apiVersion": "2024-01-01-preview",
      "id": "[concat(resourceId('Microsoft.OperationalInsights/workspaces/providers', parameters('workspace'), 'Microsoft.SecurityInsights'),'/alertRules/4bd7e93a-0646-4e02-8dcb-aa16d16618f4')]",
      "kind": "Scheduled",
      "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/4bd7e93a-0646-4e02-8dcb-aa16d16618f4')]",
      "properties": {
        "alertDetailsOverride": {
          "alertDescriptionFormat": "Multiple users opened a malicious link after launching app {{AppName}}.  Click here to navigate to the Power Apps Portal to examine the app: https://make.powerapps.com/environments/{{EnvironmentId}}/apps",
          "alertDisplayNameFormat": "Possible malicious app detected - {{AppName}} "
        },
        "alertRuleTemplateName": "4bd7e93a-0646-4e02-8dcb-aa16d16618f4",
        "customDetails": {
          "AppCreator": "AppCreator",
          "Environment": "EnvironmentId",
          "PowerAppsApp": "AppId",
          "PowerAppsAppName": "AppName"
        },
        "description": "Identifies a chain of events, where a new Power App is created, followed by mulitple users launching the app within the detection window and clicking on the same malicious URL.",
        "displayName": "Power Apps - Multiple users access a malicious link after launching new app",
        "enabled": true,
        "entityMappings": [
          {
            "entityType": "CloudApplication",
            "fieldMappings": [
              {
                "columnName": "PowerAppsEntityId",
                "identifier": "AppId"
              },
              {
                "columnName": "AppName",
                "identifier": "InstanceName"
              }
            ]
          },
          {
            "entityType": "URL",
            "fieldMappings": [
              {
                "columnName": "Url",
                "identifier": "Url"
              }
            ]
          },
          {
            "entityType": "Account",
            "fieldMappings": [
              {
                "columnName": "AppCreator",
                "identifier": "FullName"
              }
            ]
          },
          {
            "entityType": "Account",
            "fieldMappings": [
              {
                "columnName": "UPNSuffix",
                "identifier": "UPNSuffix"
              },
              {
                "columnName": "AccountName",
                "identifier": "Name"
              }
            ]
          }
        ],
        "eventGroupingSettings": {
          "aggregationKind": "AlertPerResult"
        },
        "OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Microsoft Business Applications/Analytic Rules/Power Apps - Multiple users access a malicious link after launching new app.yaml",
        "query": "// Define a threshold (distinct_user_launch_threshold) for\n// the minimum number of users who launched an app\n// to be in scope of this detection\nlet distinct_user_launch_threshold = 2;\n// Define a threshold for the minumum number of users\n// who clicked the same malicious link after launching the app\n// to be in scope of this detection\nlet distinct_user_url_click_threshold = 2;\nlet query_frequency = 1h;\nlet query_lookback = 14d;\nlet new_app_creation_activity = materialize(\n    PowerPlatformAdminActivity\n    | where TimeGenerated >= ago (query_lookback)\n    | where EventOriginalType == \"CreatePowerApp\"\n    | extend Properties = tostring(PropertyCollection)\n    | extend SrcIpAddr = extract(@'\"enduser.ip_address\",\"Value\":\"([^\"]+)\"', 1, Properties)\n    | extend SrcIpAddr = iif(SrcIpAddr startswith '::ffff:', replace_string(SrcIpAddr, '::ffff:', ''), SrcIpAddr)\n    | extend AppId = extract(@'\"powerplatform.analytics.resource.power_app.id\",\"Value\":\"([^\"]+)\"', 1, Properties)\n    | extend AppId = tolower(replace_string(AppId, '/providers/Microsoft.PowerApps/apps/', ''))\n    | extend\n        AppName = extract(@'\"powerplatform.analytics.resource.power_app.display_name\",\"Value\":\"([^\"]+)\"', 1, Properties),\n        EnvironmentId = extract(@'\"powerplatform.analytics.resource.environment.id\",\"Value\":\"([^\"]+)\"', 1, Properties)\n    | project-rename\n        AppCreatedTime = TimeGenerated,\n        AppCreator = ActorName,\n        AppCreatorIpAddr = SrcIpAddr\n    );\nlet distinct_apps = new_app_creation_activity\n    | distinct AppName;\nlet new_app_launch_activity = materialize(\n    new_app_creation_activity\n    | join kind=inner (\n        PowerPlatformAdminActivity\n        | where TimeGenerated >= ago (query_lookback)\n        | where EventOriginalType == \"LaunchPowerApp\"\n        | where PropertyCollection has_any (distinct_apps)\n        | extend Properties = tostring(PropertyCollection)\n        | extend AppName = extract(@'\"powerplatform.analytics.resource.power_app.display_name\",\"Value\":\"([^\"]+)\"', 1, Properties)\n        | summarize FirstAppLaunchTime = min(TimeGenerated) by ActorName, AppName)\n        on AppName\n    | where FirstAppLaunchTime > AppCreatedTime\n    );\nlet new_app_launch_users = new_app_launch_activity\n    | summarize LaunchCount = dcount(ActorName) by AppName\n    | where LaunchCount > distinct_user_launch_threshold\n    | join kind=inner new_app_launch_activity on AppName\n    | summarize\n        by\n        ActorName,\n        FirstAppLaunchTime,\n        AppName,\n        AppId,\n        EnvironmentId,\n        AppCreator,\n        AppCreatorIpAddr;\nlet detected_urls = union isfuzzy=true\n        (\n        SecurityAlert\n        | where TimeGenerated >= ago (query_lookback)\n        | where Entities has_cs '\"Type\":\"url\"'\n        | mv-expand todynamic(Entities)\n        | where tostring(Entities.Type) == \"url\"\n        | project Url = tostring(Entities.Url), Source = \"SecurityAlert\"\n        ),\n        (\n        ThreatIntelligenceIndicator\n        | where TimeGenerated >= ago(query_lookback)\n        | summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by IndicatorId\n        | where Active == true and ExpirationDateTime > now()\n        | where isnotempty(isnotempty(Url))\n        | project Url, Source = \"ThreatIntelligence\"\n        )\n    | summarize by Url, Source;\nlet url_click_events = materialize(\n    union isfuzzy=true\n        (\n        UrlClickEvents\n        | where TimeGenerated >= ago(query_frequency)\n        | where isnotempty(ThreatTypes)\n        | join kind=inner (new_app_launch_users) on $left.AccountUpn == $right.ActorName\n        | where TimeGenerated between (FirstAppLaunchTime .. (FirstAppLaunchTime + 1h))\n        | summarize by ActorName, Url, Source = \"MicrosoftDefender\"\n        ),\n        (\n        _Im_WebSession\n        | where TimeGenerated >= ago(query_frequency)\n        | join kind=inner (new_app_launch_users) on $left.SrcUsername == $right.ActorName\n        | join kind=inner (detected_urls) on Url\n        | where TimeGenerated between (FirstAppLaunchTime .. (FirstAppLaunchTime + 1h))\n        | summarize by ActorName, Url, Source\n        )\n    );\nlet distinct_url_click_events_count = toscalar(\n    url_click_events\n    | summarize DistinctUserCount = dcount(ActorName) by Url\n    | where DistinctUserCount > distinct_user_url_click_threshold\n    | summarize sum(DistinctUserCount)\n    );\nurl_click_events\n| summarize DistinctUserCount = dcount(ActorName) by Url\n| where DistinctUserCount >= distinct_user_url_click_threshold\n| join kind=inner url_click_events on Url\n| join kind=inner (new_app_launch_users) on ActorName\n| extend\n    PowerAppsEntityId = 27593,\n    DataverseId = 32780,\n    AccountName = tostring(split(ActorName, '@')[0]),\n    UPNSuffix = tostring(split(ActorName, '@')[1])\n| project\n    FirstAppLaunchTime,\n    AppCreator,\n    AppName,\n    AppId,\n    ImpactedUser = ActorName,\n    AccountName,\n    UPNSuffix,\n    EnvironmentId,\n    Url,\n    Source,\n    PowerAppsEntityId\n",
        "queryFrequency": "PT1H",
        "queryPeriod": "P14D",
        "severity": "High",
        "status": "Available",
        "subTechniques": [],
        "suppressionDuration": "PT1H",
        "suppressionEnabled": false,
        "tactics": [
          "InitialAccess"
        ],
        "techniques": [
          "T1189",
          "T1566"
        ],
        "templateVersion": "3.2.0",
        "triggerOperator": "GreaterThan",
        "triggerThreshold": 0
      },
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
    }
  ]
}