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
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  
version: 3.2.0
triggerOperator: gt
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
status: Available
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.
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'
customDetails:
  Environment: EnvironmentId
  PowerAppsApp: AppId
  PowerAppsAppName: AppName
  AppCreator: AppCreator
queryFrequency: 1h
triggerThreshold: 0
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
eventGroupingSettings:
  aggregationKind: AlertPerResult
severity: High
queryPeriod: 14d
relevantTechniques:
- T1189
- T1566
kind: Scheduled
name: Power Apps - Multiple users access a malicious link after launching new app
entityMappings:
- fieldMappings:
  - columnName: PowerAppsEntityId
    identifier: AppId
  - columnName: AppName
    identifier: InstanceName
  entityType: CloudApplication
- fieldMappings:
  - columnName: Url
    identifier: Url
  entityType: URL
- fieldMappings:
  - columnName: AppCreator
    identifier: FullName
  entityType: Account
- fieldMappings:
  - columnName: UPNSuffix
    identifier: UPNSuffix
  - columnName: AccountName
    identifier: Name
  entityType: Account
tactics:
- InitialAccess