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

Power Apps - Bulk sharing of Power Apps to newly created guest users

Back
Id943acfa0-9285-4eb0-a9c0-42e36177ef19
RulenamePower Apps - Bulk sharing of Power Apps to newly created guest users
DescriptionIdentifies unusual bulk sharing, based on a predefined threshold in the query, of Power Apps to newly created Microsoft Entra guest users.
SeverityMedium
TacticsResourceDevelopment
InitialAccess
LateralMovement
TechniquesT1587
T1566
T1534
Required data connectorsAzureActiveDirectory
PowerPlatformAdmin
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 - Bulk sharing of Power Apps to newly created guest users.yaml
Version3.2.0
Arm template943acfa0-9285-4eb0-a9c0-42e36177ef19.json
Deploy To Azure
////////////
// threshold = If the number of unique accounts that a power app is shared with is greater than
// threshold than it'll trigger an alert. A threshold of 5 is good to start with.
// However, if this is giving too many false positives, please adjust the threshold.
////////////
let threshold = 5;
////////////
// Please replace the allowed_domains with a list of domains of your partners/sibling orgs
// with whom you generally share power apps with. This will allow us to filter
// legitimate bulk sharing attempts. Avoid using domains such as gmail, outlook, etc.
///////////
let allowed_domains = pack_array("contoso.com");
let query_frequency = 1h;
let query_lookback = 14d;
PowerPlatformAdminActivity
| where TimeGenerated >= ago(query_frequency)
| where EventOriginalType == "PowerAppPermissionEdited"
| extend Properties = tostring(PropertyCollection)
| extend AppId = extract(@'"powerplatform.analytics.resource.power_app.id","Value":"([^"]+)"', 1, Properties)
| extend AppId = tolower(replace_string(AppId, '/providers/Microsoft.PowerApps/apps/', ''))
| extend TargetPrincipalId = extract(@'"targetuser.id","Value":"([^"]+)"', 1, Properties)
| join kind=leftouter (
    AuditLogs
    | where ActivityDateTime >= ago(query_lookback)
    | where SourceSystem =~ "Azure AD" and OperationName == "Invite external user"
    | where Result =~ "success"
    | extend InvitedOrgEmail = tostring(parse_json(AdditionalDetails[5])['value'])
    | extend InvitedOrgDomain = tostring(split(InvitedOrgEmail, "@")[1])
    | where not(InvitedOrgDomain has_any(allowed_domains))
    | extend
        InvitedById = tostring(parse_json(InitiatedBy)['user']['id']),
        InvitedByUPN = tostring(parse_json(InitiatedBy)['user']['userPrincipalName']),
        InvitedEmail = tostring(parse_json(TargetResources[0])['userPrincipalName']),
        InvitedId = tostring(parse_json(TargetResources[0])['id'])
    | summarize by InvitedById, InvitedByUPN, InvitedEmail, InvitedId, InvitedOrgDomain)
    on $left.TargetPrincipalId == $right.InvitedId
| where isnotempty(InvitedId)
| summarize
    StartTime = min(TimeGenerated),
    EndTime = max(TimeGenerated),
    TargetedUsersCount=dcount(TargetPrincipalId),
    TargetedObjectIds = make_set(TargetPrincipalId, 1000),
    InvitedDomains = make_set(InvitedOrgDomain, 1000),
    InvitedEmailAddresses = make_set(InvitedEmail, 1000)
    by AppId, InvitedById, InvitedByUPN
| extend
    PowerAppsEntityId = 27593,
    AccountName = tostring(split(InvitedByUPN, '@')[0]),
    UPNSuffix = tostring(split(InvitedByUPN, '@')[1])
| project
    StartTime,
    EndTime,
    InvitedByUPN,
    InvitedById,
    InvitedDomains,
    InvitedEmailAddresses,
    TargetedUsersCount,
    TargetedObjectIds,
    AppId,
    PowerAppsEntityId,
    AccountName,
    UPNSuffix
entityMappings:
- entityType: Account
  fieldMappings:
  - identifier: Name
    columnName: AccountName
  - identifier: UPNSuffix
    columnName: UPNSuffix
- entityType: CloudApplication
  fieldMappings:
  - identifier: AppId
    columnName: PowerAppsEntityId
  - identifier: InstanceName
    columnName: AppId
queryFrequency: 1h
name: Power Apps - Bulk sharing of Power Apps to newly created guest users
alertDetailsOverride:
  alertDisplayNameFormat: Power Apps - app shared with recently created external guest accounts
  alertDescriptionFormat: '{{InvitedByUPN}}  shared an app with {{TargetedUsersCount}} recently added guest user accounts that are not on the list of allowed partner domains. List of domain s {{InvitedDomains}}'
kind: Scheduled
tactics:
- ResourceDevelopment
- InitialAccess
- LateralMovement
triggerThreshold: 0
query: |
  ////////////
  // threshold = If the number of unique accounts that a power app is shared with is greater than
  // threshold than it'll trigger an alert. A threshold of 5 is good to start with.
  // However, if this is giving too many false positives, please adjust the threshold.
  ////////////
  let threshold = 5;
  ////////////
  // Please replace the allowed_domains with a list of domains of your partners/sibling orgs
  // with whom you generally share power apps with. This will allow us to filter
  // legitimate bulk sharing attempts. Avoid using domains such as gmail, outlook, etc.
  ///////////
  let allowed_domains = pack_array("contoso.com");
  let query_frequency = 1h;
  let query_lookback = 14d;
  PowerPlatformAdminActivity
  | where TimeGenerated >= ago(query_frequency)
  | where EventOriginalType == "PowerAppPermissionEdited"
  | extend Properties = tostring(PropertyCollection)
  | extend AppId = extract(@'"powerplatform.analytics.resource.power_app.id","Value":"([^"]+)"', 1, Properties)
  | extend AppId = tolower(replace_string(AppId, '/providers/Microsoft.PowerApps/apps/', ''))
  | extend TargetPrincipalId = extract(@'"targetuser.id","Value":"([^"]+)"', 1, Properties)
  | join kind=leftouter (
      AuditLogs
      | where ActivityDateTime >= ago(query_lookback)
      | where SourceSystem =~ "Azure AD" and OperationName == "Invite external user"
      | where Result =~ "success"
      | extend InvitedOrgEmail = tostring(parse_json(AdditionalDetails[5])['value'])
      | extend InvitedOrgDomain = tostring(split(InvitedOrgEmail, "@")[1])
      | where not(InvitedOrgDomain has_any(allowed_domains))
      | extend
          InvitedById = tostring(parse_json(InitiatedBy)['user']['id']),
          InvitedByUPN = tostring(parse_json(InitiatedBy)['user']['userPrincipalName']),
          InvitedEmail = tostring(parse_json(TargetResources[0])['userPrincipalName']),
          InvitedId = tostring(parse_json(TargetResources[0])['id'])
      | summarize by InvitedById, InvitedByUPN, InvitedEmail, InvitedId, InvitedOrgDomain)
      on $left.TargetPrincipalId == $right.InvitedId
  | where isnotempty(InvitedId)
  | summarize
      StartTime = min(TimeGenerated),
      EndTime = max(TimeGenerated),
      TargetedUsersCount=dcount(TargetPrincipalId),
      TargetedObjectIds = make_set(TargetPrincipalId, 1000),
      InvitedDomains = make_set(InvitedOrgDomain, 1000),
      InvitedEmailAddresses = make_set(InvitedEmail, 1000)
      by AppId, InvitedById, InvitedByUPN
  | extend
      PowerAppsEntityId = 27593,
      AccountName = tostring(split(InvitedByUPN, '@')[0]),
      UPNSuffix = tostring(split(InvitedByUPN, '@')[1])
  | project
      StartTime,
      EndTime,
      InvitedByUPN,
      InvitedById,
      InvitedDomains,
      InvitedEmailAddresses,
      TargetedUsersCount,
      TargetedObjectIds,
      AppId,
      PowerAppsEntityId,
      AccountName,
      UPNSuffix  
relevantTechniques:
- T1587
- T1566
- T1534
triggerOperator: gt
customDetails:
  PowerAppsApp: AppId
queryPeriod: 14d
eventGroupingSettings:
  aggregationKind: SingleAlert
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Microsoft Business Applications/Analytic Rules/Power Apps - Bulk sharing of Power Apps to newly created guest users.yaml
severity: Medium
status: Available
id: 943acfa0-9285-4eb0-a9c0-42e36177ef19
requiredDataConnectors:
- connectorId: PowerPlatformAdmin
  dataTypes:
  - PowerPlatformAdminActivity
- connectorId: AzureActiveDirectory
  dataTypes:
  - AuditLogs
version: 3.2.0
description: Identifies unusual bulk sharing, based on a predefined threshold in the query, of Power Apps to newly created Microsoft Entra guest users.
{
  "$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/943acfa0-9285-4eb0-a9c0-42e36177ef19')]",
      "kind": "Scheduled",
      "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/943acfa0-9285-4eb0-a9c0-42e36177ef19')]",
      "properties": {
        "alertDetailsOverride": {
          "alertDescriptionFormat": "{{InvitedByUPN}}  shared an app with {{TargetedUsersCount}} recently added guest user accounts that are not on the list of allowed partner domains. List of domain s {{InvitedDomains}}",
          "alertDisplayNameFormat": "Power Apps - app shared with recently created external guest accounts"
        },
        "alertRuleTemplateName": "943acfa0-9285-4eb0-a9c0-42e36177ef19",
        "customDetails": {
          "PowerAppsApp": "AppId"
        },
        "description": "Identifies unusual bulk sharing, based on a predefined threshold in the query, of Power Apps to newly created Microsoft Entra guest users.",
        "displayName": "Power Apps - Bulk sharing of Power Apps to newly created guest users",
        "enabled": true,
        "entityMappings": [
          {
            "entityType": "Account",
            "fieldMappings": [
              {
                "columnName": "AccountName",
                "identifier": "Name"
              },
              {
                "columnName": "UPNSuffix",
                "identifier": "UPNSuffix"
              }
            ]
          },
          {
            "entityType": "CloudApplication",
            "fieldMappings": [
              {
                "columnName": "PowerAppsEntityId",
                "identifier": "AppId"
              },
              {
                "columnName": "AppId",
                "identifier": "InstanceName"
              }
            ]
          }
        ],
        "eventGroupingSettings": {
          "aggregationKind": "SingleAlert"
        },
        "OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Microsoft Business Applications/Analytic Rules/Power Apps - Bulk sharing of Power Apps to newly created guest users.yaml",
        "query": "////////////\n// threshold = If the number of unique accounts that a power app is shared with is greater than\n// threshold than it'll trigger an alert. A threshold of 5 is good to start with.\n// However, if this is giving too many false positives, please adjust the threshold.\n////////////\nlet threshold = 5;\n////////////\n// Please replace the allowed_domains with a list of domains of your partners/sibling orgs\n// with whom you generally share power apps with. This will allow us to filter\n// legitimate bulk sharing attempts. Avoid using domains such as gmail, outlook, etc.\n///////////\nlet allowed_domains = pack_array(\"contoso.com\");\nlet query_frequency = 1h;\nlet query_lookback = 14d;\nPowerPlatformAdminActivity\n| where TimeGenerated >= ago(query_frequency)\n| where EventOriginalType == \"PowerAppPermissionEdited\"\n| extend Properties = tostring(PropertyCollection)\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 TargetPrincipalId = extract(@'\"targetuser.id\",\"Value\":\"([^\"]+)\"', 1, Properties)\n| join kind=leftouter (\n    AuditLogs\n    | where ActivityDateTime >= ago(query_lookback)\n    | where SourceSystem =~ \"Azure AD\" and OperationName == \"Invite external user\"\n    | where Result =~ \"success\"\n    | extend InvitedOrgEmail = tostring(parse_json(AdditionalDetails[5])['value'])\n    | extend InvitedOrgDomain = tostring(split(InvitedOrgEmail, \"@\")[1])\n    | where not(InvitedOrgDomain has_any(allowed_domains))\n    | extend\n        InvitedById = tostring(parse_json(InitiatedBy)['user']['id']),\n        InvitedByUPN = tostring(parse_json(InitiatedBy)['user']['userPrincipalName']),\n        InvitedEmail = tostring(parse_json(TargetResources[0])['userPrincipalName']),\n        InvitedId = tostring(parse_json(TargetResources[0])['id'])\n    | summarize by InvitedById, InvitedByUPN, InvitedEmail, InvitedId, InvitedOrgDomain)\n    on $left.TargetPrincipalId == $right.InvitedId\n| where isnotempty(InvitedId)\n| summarize\n    StartTime = min(TimeGenerated),\n    EndTime = max(TimeGenerated),\n    TargetedUsersCount=dcount(TargetPrincipalId),\n    TargetedObjectIds = make_set(TargetPrincipalId, 1000),\n    InvitedDomains = make_set(InvitedOrgDomain, 1000),\n    InvitedEmailAddresses = make_set(InvitedEmail, 1000)\n    by AppId, InvitedById, InvitedByUPN\n| extend\n    PowerAppsEntityId = 27593,\n    AccountName = tostring(split(InvitedByUPN, '@')[0]),\n    UPNSuffix = tostring(split(InvitedByUPN, '@')[1])\n| project\n    StartTime,\n    EndTime,\n    InvitedByUPN,\n    InvitedById,\n    InvitedDomains,\n    InvitedEmailAddresses,\n    TargetedUsersCount,\n    TargetedObjectIds,\n    AppId,\n    PowerAppsEntityId,\n    AccountName,\n    UPNSuffix\n",
        "queryFrequency": "PT1H",
        "queryPeriod": "P14D",
        "severity": "Medium",
        "status": "Available",
        "subTechniques": [],
        "suppressionDuration": "PT1H",
        "suppressionEnabled": false,
        "tactics": [
          "InitialAccess",
          "LateralMovement",
          "ResourceDevelopment"
        ],
        "techniques": [
          "T1534",
          "T1566",
          "T1587"
        ],
        "templateVersion": "3.2.0",
        "triggerOperator": "GreaterThan",
        "triggerThreshold": 0
      },
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
    }
  ]
}