External guest invitation followed by Azure AD PowerShell signin
Id | acc4c247-aaf7-494b-b5da-17f18863878a |
Rulename | External guest invitation followed by Azure AD PowerShell signin |
Description | By default guests have capability to invite more external guest users, guests also can do suspicious Azure AD enumeration. This detection look at guests users, who have been invited or have invited recently, who also are logging via various PowerShell CLI. Ref : ‘https://danielchronlund.com/2021/11/18/scary-azure-ad-tenant-enumeration-using-regular-b2b-guest-accounts/ |
Severity | Medium |
Tactics | InitialAccess Persistence Discovery |
Techniques | T1078.004 T1136.003 T1087.004 |
Required data connectors | AzureActiveDirectory |
Kind | Scheduled |
Query frequency | 1h |
Query period | 1d |
Trigger threshold | 0 |
Trigger operator | gt |
Source Uri | https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Azure Active Directory/Analytic Rules/UnusualGuestActivity.yaml |
Version | 1.0.7 |
Arm template | acc4c247-aaf7-494b-b5da-17f18863878a.json |
let queryfrequency = 1h;
let queryperiod = 1d;
AuditLogs
| where TimeGenerated > ago(queryperiod)
| where OperationName in ("Invite external user", "Bulk invite users - started (bulk)", "Invite external user with reset invitation status")
| extend InitiatedBy = iff(isnotempty(InitiatedBy.user.userPrincipalName), InitiatedBy.user.userPrincipalName, InitiatedBy.app.displayName)
// Uncomment the following line to filter events where the inviting user was a guest user
//| where InitiatedBy has_any ("live.com#", "#EXT#")
| mv-apply TargetResource = TargetResources on
(
where TargetResource.type =~ "User"
| extend InvitedUser = tostring(TargetResource.userPrincipalName)
)
| mv-expand UserToCompare = pack_array(InitiatedBy, InvitedUser) to typeof(string)
| where UserToCompare has_any ("live.com#", "#EXT#")
| extend
parsedUser = replace_string(tolower(iff(UserToCompare startswith "live.com#", tostring(split(UserToCompare, "#")[1]), tostring(split(UserToCompare, "#EXT#")[0]))), "@", "_"),
InvitationTime = TimeGenerated
| join (
(union isfuzzy=true SigninLogs, AADNonInteractiveUserSignInLogs)
| where TimeGenerated > ago(queryfrequency)
| where UserType != "Member"
| where AppId has_any // This web may contain a list of these apps: https://msshells.net/
("1b730954-1685-4b74-9bfd-dac224a7b894",// Azure Active Directory PowerShell
"04b07795-8ddb-461a-bbee-02f9e1bf7b46",// Microsoft Azure CLI
"1950a258-227b-4e31-a9cf-717495945fc2",// Microsoft Azure PowerShell
"a0c73c16-a7e3-4564-9a95-2bdf47383716",// Microsoft Exchange Online Remote PowerShell
"fb78d390-0c51-40cd-8e17-fdbfab77341b",// Microsoft Exchange REST API Based Powershell
"d1ddf0e4-d672-4dae-b554-9d5bdfd93547",// Microsoft Intune PowerShell
"9bc3ab49-b65d-410a-85ad-de819febfddc",// Microsoft SharePoint Online Management Shell
"12128f48-ec9e-42f0-b203-ea49fb6af367",// MS Teams Powershell Cmdlets
"23d8f6bd-1eb0-4cc2-a08c-7bf525c67bcd",// Power BI PowerShell
"31359c7f-bd7e-475c-86db-fdb8c937548e",// PnP Management Shell
"90f610bf-206d-4950-b61d-37fa6fd1b224",// Aadrm Admin Powershell
"14d82eec-204b-4c2f-b7e8-296a70dab67e" // Microsoft Graph PowerShell
)
| summarize arg_min(TimeGenerated, *) by UserPrincipalName
| extend
parsedUser = replace_string(UserPrincipalName, "@", "_"),
SigninTime = TimeGenerated
)
on parsedUser
| project InvitationTime, InitiatedBy, OperationName, InvitedUser, SigninTime, SigninCategory = Category1, SigninUserPrincipalName = UserPrincipalName, IPAddress, AppDisplayName, ResourceDisplayName, UserAgent, InvitationAdditionalDetails = AdditionalDetails, InvitationTargetResources = TargetResources
| extend InvitedUserName = tostring(split(InvitedUser,'@',0)[0]), InvitedUserUPNSuffix = tostring(split(InvitedUser,'@',1)[0]),
InitiatedByName = tostring(split(InitiatedBy,'@',0)[0]), InitiatedByUPNSuffix = tostring(split(InitiatedBy,'@',1)[0])
requiredDataConnectors:
- connectorId: AzureActiveDirectory
dataTypes:
- AuditLogs
- connectorId: AzureActiveDirectory
dataTypes:
- SigninLogs
triggerOperator: gt
queryFrequency: 1h
name: External guest invitation followed by Azure AD PowerShell signin
queryPeriod: 1d
id: acc4c247-aaf7-494b-b5da-17f18863878a
description: |
'By default guests have capability to invite more external guest users, guests also can do suspicious Azure AD enumeration. This detection look at guests
users, who have been invited or have invited recently, who also are logging via various PowerShell CLI.
Ref : 'https://danielchronlund.com/2021/11/18/scary-azure-ad-tenant-enumeration-using-regular-b2b-guest-accounts/'
severity: Medium
query: |
let queryfrequency = 1h;
let queryperiod = 1d;
AuditLogs
| where TimeGenerated > ago(queryperiod)
| where OperationName in ("Invite external user", "Bulk invite users - started (bulk)", "Invite external user with reset invitation status")
| extend InitiatedBy = iff(isnotempty(InitiatedBy.user.userPrincipalName), InitiatedBy.user.userPrincipalName, InitiatedBy.app.displayName)
// Uncomment the following line to filter events where the inviting user was a guest user
//| where InitiatedBy has_any ("live.com#", "#EXT#")
| mv-apply TargetResource = TargetResources on
(
where TargetResource.type =~ "User"
| extend InvitedUser = tostring(TargetResource.userPrincipalName)
)
| mv-expand UserToCompare = pack_array(InitiatedBy, InvitedUser) to typeof(string)
| where UserToCompare has_any ("live.com#", "#EXT#")
| extend
parsedUser = replace_string(tolower(iff(UserToCompare startswith "live.com#", tostring(split(UserToCompare, "#")[1]), tostring(split(UserToCompare, "#EXT#")[0]))), "@", "_"),
InvitationTime = TimeGenerated
| join (
(union isfuzzy=true SigninLogs, AADNonInteractiveUserSignInLogs)
| where TimeGenerated > ago(queryfrequency)
| where UserType != "Member"
| where AppId has_any // This web may contain a list of these apps: https://msshells.net/
("1b730954-1685-4b74-9bfd-dac224a7b894",// Azure Active Directory PowerShell
"04b07795-8ddb-461a-bbee-02f9e1bf7b46",// Microsoft Azure CLI
"1950a258-227b-4e31-a9cf-717495945fc2",// Microsoft Azure PowerShell
"a0c73c16-a7e3-4564-9a95-2bdf47383716",// Microsoft Exchange Online Remote PowerShell
"fb78d390-0c51-40cd-8e17-fdbfab77341b",// Microsoft Exchange REST API Based Powershell
"d1ddf0e4-d672-4dae-b554-9d5bdfd93547",// Microsoft Intune PowerShell
"9bc3ab49-b65d-410a-85ad-de819febfddc",// Microsoft SharePoint Online Management Shell
"12128f48-ec9e-42f0-b203-ea49fb6af367",// MS Teams Powershell Cmdlets
"23d8f6bd-1eb0-4cc2-a08c-7bf525c67bcd",// Power BI PowerShell
"31359c7f-bd7e-475c-86db-fdb8c937548e",// PnP Management Shell
"90f610bf-206d-4950-b61d-37fa6fd1b224",// Aadrm Admin Powershell
"14d82eec-204b-4c2f-b7e8-296a70dab67e" // Microsoft Graph PowerShell
)
| summarize arg_min(TimeGenerated, *) by UserPrincipalName
| extend
parsedUser = replace_string(UserPrincipalName, "@", "_"),
SigninTime = TimeGenerated
)
on parsedUser
| project InvitationTime, InitiatedBy, OperationName, InvitedUser, SigninTime, SigninCategory = Category1, SigninUserPrincipalName = UserPrincipalName, IPAddress, AppDisplayName, ResourceDisplayName, UserAgent, InvitationAdditionalDetails = AdditionalDetails, InvitationTargetResources = TargetResources
| extend InvitedUserName = tostring(split(InvitedUser,'@',0)[0]), InvitedUserUPNSuffix = tostring(split(InvitedUser,'@',1)[0]),
InitiatedByName = tostring(split(InitiatedBy,'@',0)[0]), InitiatedByUPNSuffix = tostring(split(InitiatedBy,'@',1)[0])
triggerThreshold: 0
version: 1.0.7
kind: Scheduled
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Azure Active Directory/Analytic Rules/UnusualGuestActivity.yaml
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: InvitedUserName
- identifier: UPNSuffix
columnName: InvitedUserUPNSuffix
- entityType: Account
fieldMappings:
- identifier: Name
columnName: InitiatedByName
- identifier: UPNSuffix
columnName: InitiatedByUPNSuffix
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPAddress
relevantTechniques:
- T1078.004
- T1136.003
- T1087.004
tactics:
- InitialAccess
- Persistence
- Discovery
status: Available
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"workspace": {
"type": "String"
}
},
"resources": [
{
"id": "[concat(resourceId('Microsoft.OperationalInsights/workspaces/providers', parameters('workspace'), 'Microsoft.SecurityInsights'),'/alertRules/acc4c247-aaf7-494b-b5da-17f18863878a')]",
"name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/acc4c247-aaf7-494b-b5da-17f18863878a')]",
"type": "Microsoft.OperationalInsights/workspaces/providers/alertRules",
"kind": "Scheduled",
"apiVersion": "2022-11-01-preview",
"properties": {
"displayName": "External guest invitation followed by Azure AD PowerShell signin",
"description": "'By default guests have capability to invite more external guest users, guests also can do suspicious Azure AD enumeration. This detection look at guests\nusers, who have been invited or have invited recently, who also are logging via various PowerShell CLI.\nRef : 'https://danielchronlund.com/2021/11/18/scary-azure-ad-tenant-enumeration-using-regular-b2b-guest-accounts/'\n",
"severity": "Medium",
"enabled": true,
"query": "let queryfrequency = 1h;\nlet queryperiod = 1d;\nAuditLogs\n| where TimeGenerated > ago(queryperiod)\n| where OperationName in (\"Invite external user\", \"Bulk invite users - started (bulk)\", \"Invite external user with reset invitation status\")\n| extend InitiatedBy = iff(isnotempty(InitiatedBy.user.userPrincipalName), InitiatedBy.user.userPrincipalName, InitiatedBy.app.displayName)\n// Uncomment the following line to filter events where the inviting user was a guest user\n//| where InitiatedBy has_any (\"live.com#\", \"#EXT#\")\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"User\"\n | extend InvitedUser = tostring(TargetResource.userPrincipalName)\n )\n| mv-expand UserToCompare = pack_array(InitiatedBy, InvitedUser) to typeof(string)\n| where UserToCompare has_any (\"live.com#\", \"#EXT#\")\n| extend\n parsedUser = replace_string(tolower(iff(UserToCompare startswith \"live.com#\", tostring(split(UserToCompare, \"#\")[1]), tostring(split(UserToCompare, \"#EXT#\")[0]))), \"@\", \"_\"),\n InvitationTime = TimeGenerated\n| join (\n (union isfuzzy=true SigninLogs, AADNonInteractiveUserSignInLogs)\n | where TimeGenerated > ago(queryfrequency)\n | where UserType != \"Member\"\n | where AppId has_any // This web may contain a list of these apps: https://msshells.net/\n (\"1b730954-1685-4b74-9bfd-dac224a7b894\",// Azure Active Directory PowerShell\n \"04b07795-8ddb-461a-bbee-02f9e1bf7b46\",// Microsoft Azure CLI\n \"1950a258-227b-4e31-a9cf-717495945fc2\",// Microsoft Azure PowerShell\n \"a0c73c16-a7e3-4564-9a95-2bdf47383716\",// Microsoft Exchange Online Remote PowerShell\n \"fb78d390-0c51-40cd-8e17-fdbfab77341b\",// Microsoft Exchange REST API Based Powershell\n \"d1ddf0e4-d672-4dae-b554-9d5bdfd93547\",// Microsoft Intune PowerShell\n \"9bc3ab49-b65d-410a-85ad-de819febfddc\",// Microsoft SharePoint Online Management Shell\n \"12128f48-ec9e-42f0-b203-ea49fb6af367\",// MS Teams Powershell Cmdlets\n \"23d8f6bd-1eb0-4cc2-a08c-7bf525c67bcd\",// Power BI PowerShell\n \"31359c7f-bd7e-475c-86db-fdb8c937548e\",// PnP Management Shell\n \"90f610bf-206d-4950-b61d-37fa6fd1b224\",// Aadrm Admin Powershell\n \"14d82eec-204b-4c2f-b7e8-296a70dab67e\" // Microsoft Graph PowerShell\n )\n | summarize arg_min(TimeGenerated, *) by UserPrincipalName\n | extend\n parsedUser = replace_string(UserPrincipalName, \"@\", \"_\"),\n SigninTime = TimeGenerated\n )\n on parsedUser\n| project InvitationTime, InitiatedBy, OperationName, InvitedUser, SigninTime, SigninCategory = Category1, SigninUserPrincipalName = UserPrincipalName, IPAddress, AppDisplayName, ResourceDisplayName, UserAgent, InvitationAdditionalDetails = AdditionalDetails, InvitationTargetResources = TargetResources\n| extend InvitedUserName = tostring(split(InvitedUser,'@',0)[0]), InvitedUserUPNSuffix = tostring(split(InvitedUser,'@',1)[0]), \n InitiatedByName = tostring(split(InitiatedBy,'@',0)[0]), InitiatedByUPNSuffix = tostring(split(InitiatedBy,'@',1)[0])\n",
"queryFrequency": "PT1H",
"queryPeriod": "P1D",
"triggerOperator": "GreaterThan",
"triggerThreshold": 0,
"suppressionDuration": "PT1H",
"suppressionEnabled": false,
"tactics": [
"InitialAccess",
"Persistence",
"Discovery"
],
"techniques": [
"T1078.004",
"T1136.003",
"T1087.004"
],
"alertRuleTemplateName": "acc4c247-aaf7-494b-b5da-17f18863878a",
"customDetails": null,
"entityMappings": [
{
"fieldMappings": [
{
"identifier": "Name",
"columnName": "InvitedUserName"
},
{
"identifier": "UPNSuffix",
"columnName": "InvitedUserUPNSuffix"
}
],
"entityType": "Account"
},
{
"fieldMappings": [
{
"identifier": "Name",
"columnName": "InitiatedByName"
},
{
"identifier": "UPNSuffix",
"columnName": "InitiatedByUPNSuffix"
}
],
"entityType": "Account"
},
{
"fieldMappings": [
{
"identifier": "Address",
"columnName": "IPAddress"
}
],
"entityType": "IP"
}
],
"status": "Available",
"templateVersion": "1.0.7",
"OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Azure Active Directory/Analytic Rules/UnusualGuestActivity.yaml"
}
}
]
}