Power Apps - Bulk sharing of Power Apps to newly created guest users
Id | 943acfa0-9285-4eb0-a9c0-42e36177ef19 |
Rulename | Power Apps - Bulk sharing of Power Apps to newly created guest users |
Description | Identifies unusual bulk sharing, based on a predefined threshold in the query, of Power Apps to newly created Microsoft Entra guest users. |
Severity | Medium |
Tactics | ResourceDevelopment InitialAccess LateralMovement |
Techniques | T1587 T1566 T1534 |
Required data connectors | AzureActiveDirectory PowerPlatformAdmin |
Kind | Scheduled |
Query frequency | 1h |
Query period | 14d |
Trigger threshold | 0 |
Trigger operator | gt |
Source Uri | 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 |
Version | 3.2.0 |
Arm template | 943acfa0-9285-4eb0-a9c0-42e36177ef19.json |
////////////
// 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
customDetails:
PowerAppsApp: AppId
queryPeriod: 14d
id: 943acfa0-9285-4eb0-a9c0-42e36177ef19
relevantTechniques:
- T1587
- T1566
- T1534
triggerOperator: gt
entityMappings:
- fieldMappings:
- columnName: AccountName
identifier: Name
- columnName: UPNSuffix
identifier: UPNSuffix
entityType: Account
- fieldMappings:
- columnName: PowerAppsEntityId
identifier: AppId
- columnName: AppId
identifier: InstanceName
entityType: CloudApplication
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
kind: Scheduled
triggerThreshold: 0
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
queryFrequency: 1h
requiredDataConnectors:
- dataTypes:
- PowerPlatformAdminActivity
connectorId: PowerPlatformAdmin
- dataTypes:
- AuditLogs
connectorId: AzureActiveDirectory
eventGroupingSettings:
aggregationKind: SingleAlert
name: Power Apps - Bulk sharing of Power Apps to newly created guest users
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.
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}}'
tactics:
- ResourceDevelopment
- InitialAccess
- LateralMovement
severity: Medium
status: Available
{
"$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"
}
]
}