From b9a157b1b68dc1b18e80dc1c90bca5c0379fd22a Mon Sep 17 00:00:00 2001 From: v-rbajaj Date: Tue, 17 Oct 2023 15:08:38 +0530 Subject: [PATCH 1/6] Update PIMElevationRequestRejected.yaml --- .../Analytic Rules/PIMElevationRequestRejected.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Solutions/Azure Active Directory/Analytic Rules/PIMElevationRequestRejected.yaml b/Solutions/Azure Active Directory/Analytic Rules/PIMElevationRequestRejected.yaml index 80483912104..a3f611e59d0 100644 --- a/Solutions/Azure Active Directory/Analytic Rules/PIMElevationRequestRejected.yaml +++ b/Solutions/Azure Active Directory/Analytic Rules/PIMElevationRequestRejected.yaml @@ -21,7 +21,7 @@ tags: - AADSecOpsGuide query: | AuditLogs - | where (ActivityDisplayName =~'Add member to role completed (PIM activation)' and Result =~ "failure") or ActivityDisplayName =~'Add member to role request denied (PIM activation)' + | ActivityDisplayName =~'Add member to role request denied (PIM activation)' | mv-apply ResourceItem = TargetResources on ( where ResourceItem.type =~ "Role" @@ -54,5 +54,5 @@ entityMappings: fieldMappings: - identifier: Address columnName: InitiatingIpAddress -version: 1.0.6 +version: 1.0.7 kind: Scheduled From 2331649bd10f70f4ed553206e632e6fba63c077a Mon Sep 17 00:00:00 2001 From: v-rbajaj Date: Tue, 17 Oct 2023 15:48:45 +0530 Subject: [PATCH 2/6] Update PIMElevationRequestRejected.yaml --- .../Analytic Rules/PIMElevationRequestRejected.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Solutions/Azure Active Directory/Analytic Rules/PIMElevationRequestRejected.yaml b/Solutions/Azure Active Directory/Analytic Rules/PIMElevationRequestRejected.yaml index a3f611e59d0..81123db02a5 100644 --- a/Solutions/Azure Active Directory/Analytic Rules/PIMElevationRequestRejected.yaml +++ b/Solutions/Azure Active Directory/Analytic Rules/PIMElevationRequestRejected.yaml @@ -21,7 +21,7 @@ tags: - AADSecOpsGuide query: | AuditLogs - | ActivityDisplayName =~'Add member to role request denied (PIM activation)' + | where ActivityDisplayName =~'Add member to role request denied (PIM activation)' | mv-apply ResourceItem = TargetResources on ( where ResourceItem.type =~ "Role" From 4d654c3ca4e2d453c5356d24ba790686f4d30a9d Mon Sep 17 00:00:00 2001 From: Github Bot Date: Tue, 17 Oct 2023 10:38:23 +0000 Subject: [PATCH 3/6] [skip ci] Github Bot Added package to Pull Request! --- .../Data/system_generated_metadata.json | 4 +- .../Azure Active Directory/Package/3.0.5.zip | Bin 0 -> 83601 bytes .../Package/createUiDefinition.json | 28 +- .../Package/mainTemplate.json | 18289 ++++++++-------- 4 files changed, 8952 insertions(+), 9369 deletions(-) create mode 100644 Solutions/Azure Active Directory/Package/3.0.5.zip diff --git a/Solutions/Azure Active Directory/Data/system_generated_metadata.json b/Solutions/Azure Active Directory/Data/system_generated_metadata.json index 742829c3911..a145fa873ef 100644 --- a/Solutions/Azure Active Directory/Data/system_generated_metadata.json +++ b/Solutions/Azure Active Directory/Data/system_generated_metadata.json @@ -7,7 +7,7 @@ "Metadata": "SolutionMetadata.json", "TemplateSpec": true, "Is1PConnector": true, - "Version": "3.0.4", + "Version": "3.0.5", "publisherId": "azuresentinel", "offerId": "azure-sentinel-solution-azureactivedirectory", "providers": [ @@ -41,5 +41,5 @@ "Playbooks/Revoke-AADSignInSessions/incident-trigger/azuredeploy.json" ], "Workbooks": "[\n \"AzureActiveDirectoryAuditLogs.json\",\n \"AzureActiveDirectorySignins.json\"\n]", - "Analytic Rules": "[\n \"AccountCreatedandDeletedinShortTimeframe.yaml\",\n \"AccountCreatedDeletedByNonApprovedUser.yaml\",\n \"ADFSDomainTrustMods.yaml\",\n \"ADFSSignInLogsPasswordSpray.yaml\",\n \"AdminPromoAfterRoleMgmtAppPermissionGrant.yaml\",\n \"AnomalousUserAppSigninLocationIncrease-detection.yaml\",\n \"AuthenticationMethodsChangedforPrivilegedAccount.yaml\",\n \"AzureAADPowerShellAnomaly.yaml\",\n \"AzureADRoleManagementPermissionGrant.yaml\",\n \"AzurePortalSigninfromanotherAzureTenant.yaml\",\n \"Brute Force Attack against GitHub Account.yaml\",\n \"BruteForceCloudPC.yaml\",\n \"BulkChangestoPrivilegedAccountPermissions.yaml\",\n \"BypassCondAccessRule.yaml\",\n \"CredentialAddedAfterAdminConsent.yaml\",\n \"Cross-tenantAccessSettingsOrganizationAdded.yaml\",\n \"Cross-tenantAccessSettingsOrganizationDeleted.yaml\",\n \"Cross-tenantAccessSettingsOrganizationInboundCollaborationSettingsChanged.yaml\",\n \"Cross-tenantAccessSettingsOrganizationInboundDirectSettingsChanged.yaml\",\n \"Cross-tenantAccessSettingsOrganizationOutboundCollaborationSettingsChanged.yaml\",\n \"Cross-tenantAccessSettingsOrganizationOutboundDirectSettingsChanged.yaml\",\n \"DisabledAccountSigninsAcrossManyApplications.yaml\",\n \"DistribPassCrackAttempt.yaml\",\n \"ExplicitMFADeny.yaml\",\n \"ExchangeFullAccessGrantedToApp.yaml\",\n \"FailedLogonToAzurePortal.yaml\",\n \"FirstAppOrServicePrincipalCredential.yaml\",\n \"GuestAccountsAddedinAADGroupsOtherThanTheOnesSpecified.yaml\",\n \"MailPermissionsAddedToApplication.yaml\",\n \"MaliciousOAuthApp_O365AttackToolkit.yaml\",\n \"MaliciousOAuthApp_PwnAuth.yaml\",\n \"MFARejectedbyUser.yaml\",\n \"MultipleAdmin_membership_removals_from_NewAdmin.yaml\",\n \"NewAppOrServicePrincipalCredential.yaml\",\n \"NRT_ADFSDomainTrustMods.yaml\",\n \"NRT_AuthenticationMethodsChangedforVIPUsers.yaml\",\n \"nrt_FirstAppOrServicePrincipalCredential.yaml\",\n \"NRT_NewAppOrServicePrincipalCredential.yaml\",\n \"NRT_PIMElevationRequestRejected.yaml\",\n \"NRT_PrivlegedRoleAssignedOutsidePIM.yaml\",\n \"NRT_UseraddedtoPrivilgedGroups.yaml\",\n \"PIMElevationRequestRejected.yaml\",\n \"PrivilegedAccountsSigninFailureSpikes.yaml\",\n \"PrivlegedRoleAssignedOutsidePIM.yaml\",\n \"RareApplicationConsent.yaml\",\n \"SeamlessSSOPasswordSpray.yaml\",\n \"Sign-in Burst from Multiple Locations.yaml\",\n \"SigninAttemptsByIPviaDisabledAccounts.yaml\",\n \"SigninBruteForce-AzurePortal.yaml\",\n \"SigninPasswordSpray.yaml\",\n \"SuccessThenFail_DiffIP_SameUserandApp.yaml\",\n \"SuspiciousAADJoinedDeviceUpdate.yaml\",\n \"SuspiciousOAuthApp_OfflineAccess.yaml\",\n \"SuspiciousServicePrincipalcreationactivity.yaml\",\n \"UnusualGuestActivity.yaml\",\n \"UserAccounts-CABlockedSigninSpikes.yaml\",\n \"UseraddedtoPrivilgedGroups.yaml\",\n \"UserAssignedPrivilegedRole.yaml\",\n \"NewOnmicrosoftDomainAdded.yaml\"\n]" + "Analytic Rules": "[\n \"AccountCreatedandDeletedinShortTimeframe.yaml\",\n \"AccountCreatedDeletedByNonApprovedUser.yaml\",\n \"ADFSDomainTrustMods.yaml\",\n \"ADFSSignInLogsPasswordSpray.yaml\",\n \"AdminPromoAfterRoleMgmtAppPermissionGrant.yaml\",\n \"AnomalousUserAppSigninLocationIncrease-detection.yaml\",\n \"AuthenticationMethodsChangedforPrivilegedAccount.yaml\",\n \"AzureAADPowerShellAnomaly.yaml\",\n \"AzureADRoleManagementPermissionGrant.yaml\",\n \"AzurePortalSigninfromanotherAzureTenant.yaml\",\n \"Brute Force Attack against GitHub Account.yaml\",\n \"BruteForceCloudPC.yaml\",\n \"BulkChangestoPrivilegedAccountPermissions.yaml\",\n \"BypassCondAccessRule.yaml\",\n \"CredentialAddedAfterAdminConsent.yaml\",\n \"Cross-tenantAccessSettingsOrganizationAdded.yaml\",\n \"Cross-tenantAccessSettingsOrganizationDeleted.yaml\",\n \"Cross-tenantAccessSettingsOrganizationInboundCollaborationSettingsChanged.yaml\",\n \"Cross-tenantAccessSettingsOrganizationInboundDirectSettingsChanged.yaml\",\n \"Cross-tenantAccessSettingsOrganizationOutboundCollaborationSettingsChanged.yaml\",\n \"Cross-tenantAccessSettingsOrganizationOutboundDirectSettingsChanged.yaml\",\n \"DisabledAccountSigninsAcrossManyApplications.yaml\",\n \"DistribPassCrackAttempt.yaml\",\n \"ExplicitMFADeny.yaml\",\n \"ExchangeFullAccessGrantedToApp.yaml\",\n \"FailedLogonToAzurePortal.yaml\",\n \"FirstAppOrServicePrincipalCredential.yaml\",\n \"GuestAccountsAddedinAADGroupsOtherThanTheOnesSpecified.yaml\",\n \"MailPermissionsAddedToApplication.yaml\",\n \"MaliciousOAuthApp_O365AttackToolkit.yaml\",\n \"MaliciousOAuthApp_PwnAuth.yaml\",\n \"MFARejectedbyUser.yaml\",\n \"MultipleAdmin_membership_removals_from_NewAdmin.yaml\",\n \"NewAppOrServicePrincipalCredential.yaml\",\n \"NRT_ADFSDomainTrustMods.yaml\",\n \"NRT_AuthenticationMethodsChangedforVIPUsers.yaml\",\n \"nrt_FirstAppOrServicePrincipalCredential.yaml\",\n \"NRT_NewAppOrServicePrincipalCredential.yaml\",\n \"NRT_PIMElevationRequestRejected.yaml\",\n \"NRT_PrivlegedRoleAssignedOutsidePIM.yaml\",\n \"NRT_UseraddedtoPrivilgedGroups.yaml\",\n \"PIMElevationRequestRejected.yaml\",\n \"PrivilegedAccountsSigninFailureSpikes.yaml\",\n \"PrivlegedRoleAssignedOutsidePIM.yaml\",\n \"RareApplicationConsent.yaml\",\n \"SeamlessSSOPasswordSpray.yaml\",\n \"Sign-in Burst from Multiple Locations.yaml\",\n \"SigninAttemptsByIPviaDisabledAccounts.yaml\",\n \"SigninBruteForce-AzurePortal.yaml\",\n \"SigninPasswordSpray.yaml\",\n \"SuccessThenFail_DiffIP_SameUserandApp.yaml\",\n \"SuspiciousAADJoinedDeviceUpdate.yaml\",\n \"SuspiciousOAuthApp_OfflineAccess.yaml\",\n \"SuspiciousServicePrincipalcreationactivity.yaml\",\n \"UnusualGuestActivity.yaml\",\n \"UserAccounts-CABlockedSigninSpikes.yaml\",\n \"UseraddedtoPrivilgedGroups.yaml\",\n \"UserAssignedPrivilegedRole.yaml\",\n \"NewOnmicrosoftDomainAdded.yaml\",\n \"SuspiciousSignInFollowedByMFAModification.yaml\"\n]" } diff --git a/Solutions/Azure Active Directory/Package/3.0.5.zip b/Solutions/Azure Active Directory/Package/3.0.5.zip new file mode 100644 index 0000000000000000000000000000000000000000..a26b39064a232a1725a87171ed47a9a41e05aa27 GIT binary patch literal 83601 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

odj({hBf=Guy?8< zaKXD-hI^riw18T1aSVIPM1X~~+F&j{z848x>{0x1aAs6sO=9Xqi4Tp;O0(c7yv~$$ zStX}Gh;g{8re?&`6sVD}>9M>9`>UdIB(G-kx}(GVZq)fV9PhW-vi2f}CPfQ6JNd=P z3EvAD14G^2(FEBA*&g@0gL(@L+d&<}Z^_g~S`JOkUK}VVk_Ho#YRaZR9Zd#72IC|) zMRm+X-BQUap-3>^*aGr^c}D1vc7hH`=wW;Oc~VAeNqHZ%E-EC{dbFtBY=6b^NXy%) z#$*q((%29kb>c%Ti?y&9a2fb-!IKgP5kvb)pG*^u3=_qaAK_QgAlH@3i=~fSA(ZFx zyp7#P@}4pNO)(RR4?0!(4Ai!b%dg~WDlrWygtKi`wAU?Zus4|fVfVnEEPLo=61XVP zSj5rbHd`wT@mZEpk0qBV>~#%`NVlyyqo2=^?~vZ2@oH*J;(NDB;ytNsD?HDQKc% zX6X9(bV;_4>nw?Y;QVCt!jTg!k#0!-Gb!IW@tw((|)8+M%Y&QHwCg&m%m| z(?h5-K`N>&u#U}PT9g)~&JZ9M6&Fky)UVxGbWZ*ah&WlX!k$#BB>PW+S4ad{8nvJ> zo}6>>F~SF+REc9B1$#qO_v;WreEhBFw6ANqfI#}gzsn^%U)NCx4w0y;>NG7pA2&71 zdZ~T5%hxMOysIDrYy4$XT78Vfo;HaIm2f_6Xq6`{zGMqC>*mKqoqF)kIE5RK0rC2v zax_t09({K{p2etl5_qvApJ`y3!K=5Cfi!jiVx2ZLE6R&%wkwSi!Ox{%kutO{!BjaL zKxGWYfSVNBhBXo*<&n8S7&=B`bJxQ_5)3Fv2OMEM0hkw*~<3z*X1b=M#2xiTdc z7YoHSV(E%WxLZM=G9H*re#E|Zfl5r)x*3TuoGVhRsJn_m!Pbl>+lqCX%*-Ojfz5nJ+?Fg)dV8%Outa3z`AV}Aq9JJY=K!>u{Y^70GV zxc+{NZ71@eyYZ+HuyI`2eyKp!Cirm$2dny?Tb+SXQCf!T>cUEM;Kkbq(k69&)a5#@ zC~sx`rAS(@glwsI-YBE=dmGbzW>8Mn`njM~VbF+P^$8LQ6lQHJT z8zl}zYJXJQ4g4=0?p?(>oakty>YIEb0O^61OCKsUgWGX?Y1N*6jb?4AEWHqZOY}H3 zbCqsvfTmUr)px(!5dYa0=ue)qzn?yDZx8rXn%a!cE#mz}#VaI{#xQ@`E2POjzBAhl zzdGU^r34>CCSW{LAK(O$0XRVnhsp7ssU8Il90k1`dhoo2_V%gWT(uQoMZ4sqT-125uw&~x4mekT)Lm*4sr*KiOcMQTQSGePXx-={!E;uz7C z&%$u}Jr7TX9r7DLPq7&FB|mhf|lHC%5Yfa2~YPP5DGpl3O90 zX>$FNwC{g!97S!kL2tc3K2E_7dRfd1s%0D$EMs~E;@Wt3Cu3^A63-0_EQiV)&lGVA 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 h3@mK_nAq4`162K=?cfmqkpcm{g8|\n\n**Note:** Please refer to the following before installing the solution: \r \n • Review the solution [Release Notes](https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Azure%20Active%20Directory/ReleaseNotes.md)\r \n • There may be [known issues](https://aka.ms/sentinelsolutionsknownissues) pertaining to this Solution, please refer to them before installing.\n\nThe [ Azure Active Directory](https://docs.microsoft.com/azure/active-directory/fundamentals/active-directory-whatis) solution for Microsoft Sentinel enables you to ingest Azure Active Directory [Audit](https://docs.microsoft.com/azure/active-directory/reports-monitoring/concept-audit-logs), [Sign-in](https://docs.microsoft.com/azure/active-directory/reports-monitoring/concept-sign-ins), [Provisioning](https://docs.microsoft.com/azure/active-directory/reports-monitoring/concept-provisioning-logs), [Risk Events and Risky User/Service Principal](https://docs.microsoft.com/azure/active-directory/identity-protection/howto-identity-protection-investigate-risk#risky-users) logs using Diagnostic Settings into Microsoft Sentinel.\n\n**Data Connectors:** 1, **Workbooks:** 2, **Analytic Rules:** 60, **Playbooks:** 11\n\n[Learn more about Microsoft Sentinel](https://aka.ms/azuresentinel) | [Learn more about Solutions](https://aka.ms/azuresentinelsolutionsdoc)", + "description": "\n\n**Note:** _There may be [known issues](https://aka.ms/sentinelsolutionsknownissues) pertaining to this Solution, please refer to them before installing._\n\nThe [ Azure Active Directory](https://docs.microsoft.com/azure/active-directory/fundamentals/active-directory-whatis) solution for Microsoft Sentinel enables you to ingest Azure Active Directory [Audit](https://docs.microsoft.com/azure/active-directory/reports-monitoring/concept-audit-logs), [Sign-in](https://docs.microsoft.com/azure/active-directory/reports-monitoring/concept-sign-ins), [Provisioning](https://docs.microsoft.com/azure/active-directory/reports-monitoring/concept-provisioning-logs), [Risk Events and Risky User/Service Principal](https://docs.microsoft.com/azure/active-directory/identity-protection/howto-identity-protection-investigate-risk#risky-users) logs using Diagnostic Settings into Microsoft Sentinel.\n\n**Workbooks:** 2, **Analytic Rules:** 60, **Playbooks:** 11\n\n[Learn more about Microsoft Sentinel](https://aka.ms/azuresentinel) | [Learn more about Solutions](https://aka.ms/azuresentinelsolutionsdoc)", "subscription": { "resourceProviders": [ "Microsoft.OperationsManagement/solutions", @@ -51,30 +51,6 @@ } ], "steps": [ - { - "name": "dataconnectors", - "label": "Data Connectors", - "bladeTitle": "Data Connectors", - "elements": [ - { - "name": "dataconnectors1-text", - "type": "Microsoft.Common.TextBlock", - "options": { - "text": "This Solution installs the data connector for Azure Active Directory. You can get Azure Active Directory custom log data in your Microsoft Sentinel workspace. After installing the solution, configure and enable this data connector by following guidance in Manage solution view." - } - }, - { - "name": "dataconnectors-link2", - "type": "Microsoft.Common.TextBlock", - "options": { - "link": { - "label": "Learn more about connecting data sources", - "uri": "https://docs.microsoft.com/azure/sentinel/connect-data-sources" - } - } - } - ] - }, { "name": "workbooks", "label": "Workbooks", @@ -1034,4 +1010,4 @@ "workspace": "[basics('workspace')]" } } -} \ No newline at end of file +} diff --git a/Solutions/Azure Active Directory/Package/mainTemplate.json b/Solutions/Azure Active Directory/Package/mainTemplate.json index 9ced27c37ec..9d8146d6e7b 100644 --- a/Solutions/Azure Active Directory/Package/mainTemplate.json +++ b/Solutions/Azure Active Directory/Package/mainTemplate.json @@ -46,27 +46,107 @@ } }, "variables": { + "solutionId": "azuresentinel.azure-sentinel-solution-azureactivedirectory", + "_solutionId": "[variables('solutionId')]", "email": "support@microsoft.com", "_email": "[variables('email')]", "_solutionName": "Azure Active Directory", - "_solutionVersion": "3.0.4", - "solutionId": "azuresentinel.azure-sentinel-solution-azureactivedirectory", - "_solutionId": "[variables('solutionId')]", - "uiConfigId1": "AzureActiveDirectory", - "_uiConfigId1": "[variables('uiConfigId1')]", - "dataConnectorContentId1": "AzureActiveDirectory", - "_dataConnectorContentId1": "[variables('dataConnectorContentId1')]", - "dataConnectorId1": "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/dataConnectors', variables('_dataConnectorContentId1'))]", - "_dataConnectorId1": "[variables('dataConnectorId1')]", - "dataConnectorTemplateSpecName1": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-dc-',uniquestring(variables('_dataConnectorContentId1'))))]", - "dataConnectorVersion1": "1.0.0", - "_dataConnectorcontentProductId1": "[concat(take(variables('_solutionId'),50),'-','dc','-', uniqueString(concat(variables('_solutionId'),'-','DataConnector','-',variables('_dataConnectorContentId1'),'-', variables('dataConnectorVersion1'))))]", + "_solutionVersion": "3.0.5", + "Block-AADUser-alert-trigger": "Block-AADUser-alert-trigger", + "_Block-AADUser-alert-trigger": "[variables('Block-AADUser-alert-trigger')]", + "playbookVersion1": "1.1", + "playbookContentId1": "Block-AADUser-alert-trigger", + "_playbookContentId1": "[variables('playbookContentId1')]", + "playbookId1": "[resourceId('Microsoft.Logic/workflows', variables('playbookContentId1'))]", + "playbookTemplateSpecName1": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-pl-',uniquestring(variables('_playbookContentId1'))))]", + "workspaceResourceId": "[resourceId('microsoft.OperationalInsights/Workspaces', parameters('workspace'))]", + "_playbookcontentProductId1": "[concat(take(variables('_solutionId'),50),'-','pl','-', uniqueString(concat(variables('_solutionId'),'-','Playbook','-',variables('_playbookContentId1'),'-', variables('playbookVersion1'))))]", + "Block-AADUser-entity-trigger": "Block-AADUser-entity-trigger", + "_Block-AADUser-entity-trigger": "[variables('Block-AADUser-entity-trigger')]", + "playbookVersion2": "1.1", + "playbookContentId2": "Block-AADUser-entity-trigger", + "_playbookContentId2": "[variables('playbookContentId2')]", + "playbookId2": "[resourceId('Microsoft.Logic/workflows', variables('playbookContentId2'))]", + "playbookTemplateSpecName2": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-pl-',uniquestring(variables('_playbookContentId2'))))]", + "_playbookcontentProductId2": "[concat(take(variables('_solutionId'),50),'-','pl','-', uniqueString(concat(variables('_solutionId'),'-','Playbook','-',variables('_playbookContentId2'),'-', variables('playbookVersion2'))))]", + "Block-AADUser-incident-trigger": "Block-AADUser-incident-trigger", + "_Block-AADUser-incident-trigger": "[variables('Block-AADUser-incident-trigger')]", + "playbookVersion3": "1.1", + "playbookContentId3": "Block-AADUser-incident-trigger", + "_playbookContentId3": "[variables('playbookContentId3')]", + "playbookId3": "[resourceId('Microsoft.Logic/workflows', variables('playbookContentId3'))]", + "playbookTemplateSpecName3": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-pl-',uniquestring(variables('_playbookContentId3'))))]", + "_playbookcontentProductId3": "[concat(take(variables('_solutionId'),50),'-','pl','-', uniqueString(concat(variables('_solutionId'),'-','Playbook','-',variables('_playbookContentId3'),'-', variables('playbookVersion3'))))]", + "Prompt-User-alert-trigger": "Prompt-User-alert-trigger", + "_Prompt-User-alert-trigger": "[variables('Prompt-User-alert-trigger')]", + "playbookVersion4": "1.1", + "playbookContentId4": "Prompt-User-alert-trigger", + "_playbookContentId4": "[variables('playbookContentId4')]", + "playbookId4": "[resourceId('Microsoft.Logic/workflows', variables('playbookContentId4'))]", + "playbookTemplateSpecName4": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-pl-',uniquestring(variables('_playbookContentId4'))))]", + "_playbookcontentProductId4": "[concat(take(variables('_solutionId'),50),'-','pl','-', uniqueString(concat(variables('_solutionId'),'-','Playbook','-',variables('_playbookContentId4'),'-', variables('playbookVersion4'))))]", + "Prompt-User-incident-trigger": "Prompt-User-incident-trigger", + "_Prompt-User-incident-trigger": "[variables('Prompt-User-incident-trigger')]", + "playbookVersion5": "1.1", + "playbookContentId5": "Prompt-User-incident-trigger", + "_playbookContentId5": "[variables('playbookContentId5')]", + "playbookId5": "[resourceId('Microsoft.Logic/workflows', variables('playbookContentId5'))]", + "playbookTemplateSpecName5": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-pl-',uniquestring(variables('_playbookContentId5'))))]", + "_playbookcontentProductId5": "[concat(take(variables('_solutionId'),50),'-','pl','-', uniqueString(concat(variables('_solutionId'),'-','Playbook','-',variables('_playbookContentId5'),'-', variables('playbookVersion5'))))]", + "Reset-AADUserPassword-alert-trigger": "Reset-AADUserPassword-alert-trigger", + "_Reset-AADUserPassword-alert-trigger": "[variables('Reset-AADUserPassword-alert-trigger')]", + "playbookVersion6": "1.1", + "playbookContentId6": "Reset-AADUserPassword-alert-trigger", + "_playbookContentId6": "[variables('playbookContentId6')]", + "playbookId6": "[resourceId('Microsoft.Logic/workflows', variables('playbookContentId6'))]", + "playbookTemplateSpecName6": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-pl-',uniquestring(variables('_playbookContentId6'))))]", + "_playbookcontentProductId6": "[concat(take(variables('_solutionId'),50),'-','pl','-', uniqueString(concat(variables('_solutionId'),'-','Playbook','-',variables('_playbookContentId6'),'-', variables('playbookVersion6'))))]", + "Reset-AADUserPassword-entity-trigger": "Reset-AADUserPassword-entity-trigger", + "_Reset-AADUserPassword-entity-trigger": "[variables('Reset-AADUserPassword-entity-trigger')]", + "playbookVersion7": "1.1", + "playbookContentId7": "Reset-AADUserPassword-entity-trigger", + "_playbookContentId7": "[variables('playbookContentId7')]", + "playbookId7": "[resourceId('Microsoft.Logic/workflows', variables('playbookContentId7'))]", + "playbookTemplateSpecName7": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-pl-',uniquestring(variables('_playbookContentId7'))))]", + "_playbookcontentProductId7": "[concat(take(variables('_solutionId'),50),'-','pl','-', uniqueString(concat(variables('_solutionId'),'-','Playbook','-',variables('_playbookContentId7'),'-', variables('playbookVersion7'))))]", + "blanks": "[replace('b', 'b', '')]", + "Reset-AADUserPassword-incident-trigger": "Reset-AADUserPassword-incident-trigger", + "_Reset-AADUserPassword-incident-trigger": "[variables('Reset-AADUserPassword-incident-trigger')]", + "playbookVersion8": "1.1", + "playbookContentId8": "Reset-AADUserPassword-incident-trigger", + "_playbookContentId8": "[variables('playbookContentId8')]", + "playbookId8": "[resourceId('Microsoft.Logic/workflows', variables('playbookContentId8'))]", + "playbookTemplateSpecName8": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-pl-',uniquestring(variables('_playbookContentId8'))))]", + "_playbookcontentProductId8": "[concat(take(variables('_solutionId'),50),'-','pl','-', uniqueString(concat(variables('_solutionId'),'-','Playbook','-',variables('_playbookContentId8'),'-', variables('playbookVersion8'))))]", + "Revoke-AADSignInSessions-alert-trigger": "Revoke-AADSignInSessions-alert-trigger", + "_Revoke-AADSignInSessions-alert-trigger": "[variables('Revoke-AADSignInSessions-alert-trigger')]", + "playbookVersion9": "1.0", + "playbookContentId9": "Revoke-AADSignInSessions-alert-trigger", + "_playbookContentId9": "[variables('playbookContentId9')]", + "playbookId9": "[resourceId('Microsoft.Logic/workflows', variables('playbookContentId9'))]", + "playbookTemplateSpecName9": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-pl-',uniquestring(variables('_playbookContentId9'))))]", + "_playbookcontentProductId9": "[concat(take(variables('_solutionId'),50),'-','pl','-', uniqueString(concat(variables('_solutionId'),'-','Playbook','-',variables('_playbookContentId9'),'-', variables('playbookVersion9'))))]", + "Revoke-AADSignInSessions-entity-trigger": "Revoke-AADSignInSessions-entity-trigger", + "_Revoke-AADSignInSessions-entity-trigger": "[variables('Revoke-AADSignInSessions-entity-trigger')]", + "playbookVersion10": "1.0", + "playbookContentId10": "Revoke-AADSignInSessions-entity-trigger", + "_playbookContentId10": "[variables('playbookContentId10')]", + "playbookId10": "[resourceId('Microsoft.Logic/workflows', variables('playbookContentId10'))]", + "playbookTemplateSpecName10": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-pl-',uniquestring(variables('_playbookContentId10'))))]", + "_playbookcontentProductId10": "[concat(take(variables('_solutionId'),50),'-','pl','-', uniqueString(concat(variables('_solutionId'),'-','Playbook','-',variables('_playbookContentId10'),'-', variables('playbookVersion10'))))]", + "Revoke-AADSignInSessions-incident-trigger": "Revoke-AADSignInSessions-incident-trigger", + "_Revoke-AADSignInSessions-incident-trigger": "[variables('Revoke-AADSignInSessions-incident-trigger')]", + "playbookVersion11": "1.0", + "playbookContentId11": "Revoke-AADSignInSessions-incident-trigger", + "_playbookContentId11": "[variables('playbookContentId11')]", + "playbookId11": "[resourceId('Microsoft.Logic/workflows', variables('playbookContentId11'))]", + "playbookTemplateSpecName11": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-pl-',uniquestring(variables('_playbookContentId11'))))]", + "_playbookcontentProductId11": "[concat(take(variables('_solutionId'),50),'-','pl','-', uniqueString(concat(variables('_solutionId'),'-','Playbook','-',variables('_playbookContentId11'),'-', variables('playbookVersion11'))))]", "workbookVersion1": "1.2.0", "workbookContentId1": "AzureActiveDirectoryAuditLogsWorkbook", "workbookId1": "[resourceId('Microsoft.Insights/workbooks', variables('workbookContentId1'))]", "workbookTemplateSpecName1": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-wb-',uniquestring(variables('_workbookContentId1'))))]", "_workbookContentId1": "[variables('workbookContentId1')]", - "workspaceResourceId": "[resourceId('microsoft.OperationalInsights/Workspaces', parameters('workspace'))]", "_workbookcontentProductId1": "[concat(take(variables('_solutionId'),50),'-','wb','-', uniqueString(concat(variables('_solutionId'),'-','Workbook','-',variables('_workbookContentId1'),'-', variables('workbookVersion1'))))]", "workbookVersion2": "2.4.0", "workbookContentId2": "AzureActiveDirectorySigninLogsWorkbook", @@ -320,7 +400,7 @@ "analyticRuleId41": "[resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', variables('analyticRulecontentId41'))]", "analyticRuleTemplateSpecName41": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-ar-',uniquestring(variables('_analyticRulecontentId41'))))]", "_analyticRulecontentProductId41": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-',variables('_analyticRulecontentId41'),'-', variables('analyticRuleVersion41'))))]", - "analyticRuleVersion42": "1.0.6", + "analyticRuleVersion42": "1.0.7", "analyticRulecontentId42": "7d7e20f8-3384-4b71-811c-f5e950e8306c", "_analyticRulecontentId42": "[variables('analyticRulecontentId42')]", "analyticRuleId42": "[resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', variables('analyticRulecontentId42'))]", @@ -434,855 +514,392 @@ "analyticRuleId60": "[resourceId('Microsoft.SecurityInsights/AlertRuleTemplates', variables('analyticRulecontentId60'))]", "analyticRuleTemplateSpecName60": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-ar-',uniquestring(variables('_analyticRulecontentId60'))))]", "_analyticRulecontentProductId60": "[concat(take(variables('_solutionId'),50),'-','ar','-', uniqueString(concat(variables('_solutionId'),'-','AnalyticsRule','-',variables('_analyticRulecontentId60'),'-', variables('analyticRuleVersion60'))))]", - "Block-AADUser-alert-trigger": "Block-AADUser-alert-trigger", - "_Block-AADUser-alert-trigger": "[variables('Block-AADUser-alert-trigger')]", - "playbookVersion1": "1.1", - "playbookContentId1": "Block-AADUser-alert-trigger", - "_playbookContentId1": "[variables('playbookContentId1')]", - "playbookId1": "[resourceId('Microsoft.Logic/workflows', variables('playbookContentId1'))]", - "playbookTemplateSpecName1": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-pl-',uniquestring(variables('_playbookContentId1'))))]", - "_playbookcontentProductId1": "[concat(take(variables('_solutionId'),50),'-','pl','-', uniqueString(concat(variables('_solutionId'),'-','Playbook','-',variables('_playbookContentId1'),'-', variables('playbookVersion1'))))]", - "Block-AADUser-incident-trigger": "Block-AADUser-incident-trigger", - "_Block-AADUser-incident-trigger": "[variables('Block-AADUser-incident-trigger')]", - "playbookVersion2": "1.1", - "playbookContentId2": "Block-AADUser-incident-trigger", - "_playbookContentId2": "[variables('playbookContentId2')]", - "playbookId2": "[resourceId('Microsoft.Logic/workflows', variables('playbookContentId2'))]", - "playbookTemplateSpecName2": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-pl-',uniquestring(variables('_playbookContentId2'))))]", - "_playbookcontentProductId2": "[concat(take(variables('_solutionId'),50),'-','pl','-', uniqueString(concat(variables('_solutionId'),'-','Playbook','-',variables('_playbookContentId2'),'-', variables('playbookVersion2'))))]", - "Prompt-User-alert-trigger": "Prompt-User-alert-trigger", - "_Prompt-User-alert-trigger": "[variables('Prompt-User-alert-trigger')]", - "playbookVersion3": "1.1", - "playbookContentId3": "Prompt-User-alert-trigger", - "_playbookContentId3": "[variables('playbookContentId3')]", - "playbookId3": "[resourceId('Microsoft.Logic/workflows', variables('playbookContentId3'))]", - "playbookTemplateSpecName3": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-pl-',uniquestring(variables('_playbookContentId3'))))]", - "_playbookcontentProductId3": "[concat(take(variables('_solutionId'),50),'-','pl','-', uniqueString(concat(variables('_solutionId'),'-','Playbook','-',variables('_playbookContentId3'),'-', variables('playbookVersion3'))))]", - "Prompt-User-incident-trigger": "Prompt-User-incident-trigger", - "_Prompt-User-incident-trigger": "[variables('Prompt-User-incident-trigger')]", - "playbookVersion4": "1.1", - "playbookContentId4": "Prompt-User-incident-trigger", - "_playbookContentId4": "[variables('playbookContentId4')]", - "playbookId4": "[resourceId('Microsoft.Logic/workflows', variables('playbookContentId4'))]", - "playbookTemplateSpecName4": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-pl-',uniquestring(variables('_playbookContentId4'))))]", - "_playbookcontentProductId4": "[concat(take(variables('_solutionId'),50),'-','pl','-', uniqueString(concat(variables('_solutionId'),'-','Playbook','-',variables('_playbookContentId4'),'-', variables('playbookVersion4'))))]", - "Reset-AADUserPassword-alert-trigger": "Reset-AADUserPassword-alert-trigger", - "_Reset-AADUserPassword-alert-trigger": "[variables('Reset-AADUserPassword-alert-trigger')]", - "playbookVersion5": "1.1", - "playbookContentId5": "Reset-AADUserPassword-alert-trigger", - "_playbookContentId5": "[variables('playbookContentId5')]", - "playbookId5": "[resourceId('Microsoft.Logic/workflows', variables('playbookContentId5'))]", - "playbookTemplateSpecName5": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-pl-',uniquestring(variables('_playbookContentId5'))))]", - "_playbookcontentProductId5": "[concat(take(variables('_solutionId'),50),'-','pl','-', uniqueString(concat(variables('_solutionId'),'-','Playbook','-',variables('_playbookContentId5'),'-', variables('playbookVersion5'))))]", - "Reset-AADUserPassword-incident-trigger": "Reset-AADUserPassword-incident-trigger", - "_Reset-AADUserPassword-incident-trigger": "[variables('Reset-AADUserPassword-incident-trigger')]", - "playbookVersion6": "1.1", - "playbookContentId6": "Reset-AADUserPassword-incident-trigger", - "_playbookContentId6": "[variables('playbookContentId6')]", - "playbookId6": "[resourceId('Microsoft.Logic/workflows', variables('playbookContentId6'))]", - "playbookTemplateSpecName6": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-pl-',uniquestring(variables('_playbookContentId6'))))]", - "_playbookcontentProductId6": "[concat(take(variables('_solutionId'),50),'-','pl','-', uniqueString(concat(variables('_solutionId'),'-','Playbook','-',variables('_playbookContentId6'),'-', variables('playbookVersion6'))))]", - "Block-AADUser-entity-trigger": "Block-AADUser-entity-trigger", - "_Block-AADUser-entity-trigger": "[variables('Block-AADUser-entity-trigger')]", - "playbookVersion7": "1.1", - "playbookContentId7": "Block-AADUser-entity-trigger", - "_playbookContentId7": "[variables('playbookContentId7')]", - "playbookId7": "[resourceId('Microsoft.Logic/workflows', variables('playbookContentId7'))]", - "playbookTemplateSpecName7": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-pl-',uniquestring(variables('_playbookContentId7'))))]", - "_playbookcontentProductId7": "[concat(take(variables('_solutionId'),50),'-','pl','-', uniqueString(concat(variables('_solutionId'),'-','Playbook','-',variables('_playbookContentId7'),'-', variables('playbookVersion7'))))]", - "Reset-AADUserPassword-entity-trigger": "Reset-AADUserPassword-entity-trigger", - "_Reset-AADUserPassword-entity-trigger": "[variables('Reset-AADUserPassword-entity-trigger')]", - "playbookVersion8": "1.1", - "playbookContentId8": "Reset-AADUserPassword-entity-trigger", - "_playbookContentId8": "[variables('playbookContentId8')]", - "playbookId8": "[resourceId('Microsoft.Logic/workflows', variables('playbookContentId8'))]", - "playbookTemplateSpecName8": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-pl-',uniquestring(variables('_playbookContentId8'))))]", - "_playbookcontentProductId8": "[concat(take(variables('_solutionId'),50),'-','pl','-', uniqueString(concat(variables('_solutionId'),'-','Playbook','-',variables('_playbookContentId8'),'-', variables('playbookVersion8'))))]", - "blanks": "[replace('b', 'b', '')]", - "Revoke-AADSignInSessions-alert-trigger": "Revoke-AADSignInSessions-alert-trigger", - "_Revoke-AADSignInSessions-alert-trigger": "[variables('Revoke-AADSignInSessions-alert-trigger')]", - "playbookVersion9": "1.0", - "playbookContentId9": "Revoke-AADSignInSessions-alert-trigger", - "_playbookContentId9": "[variables('playbookContentId9')]", - "playbookId9": "[resourceId('Microsoft.Logic/workflows', variables('playbookContentId9'))]", - "playbookTemplateSpecName9": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-pl-',uniquestring(variables('_playbookContentId9'))))]", - "_playbookcontentProductId9": "[concat(take(variables('_solutionId'),50),'-','pl','-', uniqueString(concat(variables('_solutionId'),'-','Playbook','-',variables('_playbookContentId9'),'-', variables('playbookVersion9'))))]", - "Revoke-AADSignInSessions-incident-trigger": "Revoke-AADSignInSessions-incident-trigger", - "_Revoke-AADSignInSessions-incident-trigger": "[variables('Revoke-AADSignInSessions-incident-trigger')]", - "playbookVersion10": "1.0", - "playbookContentId10": "Revoke-AADSignInSessions-incident-trigger", - "_playbookContentId10": "[variables('playbookContentId10')]", - "playbookId10": "[resourceId('Microsoft.Logic/workflows', variables('playbookContentId10'))]", - "playbookTemplateSpecName10": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-pl-',uniquestring(variables('_playbookContentId10'))))]", - "_playbookcontentProductId10": "[concat(take(variables('_solutionId'),50),'-','pl','-', uniqueString(concat(variables('_solutionId'),'-','Playbook','-',variables('_playbookContentId10'),'-', variables('playbookVersion10'))))]", - "Revoke-AADSignInSessions-entity-trigger": "Revoke-AADSignInSessions-entity-trigger", - "_Revoke-AADSignInSessions-entity-trigger": "[variables('Revoke-AADSignInSessions-entity-trigger')]", - "playbookVersion11": "1.0", - "playbookContentId11": "Revoke-AADSignInSessions-entity-trigger", - "_playbookContentId11": "[variables('playbookContentId11')]", - "playbookId11": "[resourceId('Microsoft.Logic/workflows', variables('playbookContentId11'))]", - "playbookTemplateSpecName11": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat(parameters('workspace'),'-pl-',uniquestring(variables('_playbookContentId11'))))]", - "_playbookcontentProductId11": "[concat(take(variables('_solutionId'),50),'-','pl','-', uniqueString(concat(variables('_solutionId'),'-','Playbook','-',variables('_playbookContentId11'),'-', variables('playbookVersion11'))))]", "_solutioncontentProductId": "[concat(take(variables('_solutionId'),50),'-','sl','-', uniqueString(concat(variables('_solutionId'),'-','Solution','-',variables('_solutionId'),'-', variables('_solutionVersion'))))]" }, "resources": [ { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('dataConnectorTemplateSpecName1')]", + "name": "[variables('playbookTemplateSpecName1')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "Azure Active Directory data connector with template version 3.0.4", + "description": "Block-AADUser-Alert Playbook with template version 3.0.5", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('dataConnectorVersion1')]", - "parameters": {}, - "variables": {}, + "contentVersion": "[variables('playbookVersion1')]", + "parameters": { + "PlaybookName": { + "defaultValue": "Block-AADUser-Alert", + "type": "string" + } + }, + "variables": { + "AzureADConnectionName": "[[concat('azuread-', parameters('PlaybookName'))]", + "MicrosoftSentinelConnectionName": "[[concat('microsoftsentinel-', parameters('PlaybookName'))]", + "Office365ConnectionName": "[[concat('office365-', parameters('PlaybookName'))]", + "connection-1": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuread')]", + "_connection-1": "[[variables('connection-1')]", + "connection-2": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", + "_connection-2": "[[variables('connection-2')]", + "connection-3": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]", + "_connection-3": "[[variables('connection-3')]", + "workspace-location-inline": "[concat('[resourceGroup().locatio', 'n]')]", + "workspace-name": "[parameters('workspace')]", + "workspaceResourceId": "[[resourceId('microsoft.OperationalInsights/Workspaces', variables('workspace-name'))]" + }, "resources": [ { - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',variables('_dataConnectorContentId1'))]", - "apiVersion": "2021-03-01-preview", - "type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectors", - "location": "[parameters('workspace-location')]", - "kind": "StaticUI", - "properties": { - "connectorUiConfig": { - "id": "[variables('_uiConfigId1')]", - "title": "Azure Active Directory", - "publisher": "Microsoft", - "descriptionMarkdown": "Gain insights into Azure Active Directory by connecting Audit and Sign-in logs to Microsoft Sentinel to gather insights around Azure Active Directory scenarios. You can learn about app usage, conditional access policies, legacy auth relate details using our Sign-in logs. You can get information on your Self Service Password Reset (SSPR) usage, Azure Active Directory Management activities like user, group, role, app management using our Audit logs table. For more information, see the [Microsoft Sentinel documentation](https://go.microsoft.com/fwlink/?linkid=2219715&wt.mc_id=sentinel_dataconnectordocs_content_cnl_csasci).", - "graphQueries": [ - { - "metricName": "Total data received", - "legend": "SigninLogs", - "baseQuery": "SigninLogs" - }, - { - "metricName": "Total data received", - "legend": "AuditLogs", - "baseQuery": "AuditLogs" - }, - { - "metricName": "Total data received", - "legend": "AADNonInteractiveUserSignInLogs", - "baseQuery": "AADNonInteractiveUserSignInLogs" - }, - { - "metricName": "Total data received", - "legend": "AADServicePrincipalSignInLogs", - "baseQuery": "AADServicePrincipalSignInLogs" - }, - { - "metricName": "Total data received", - "legend": "AADManagedIdentitySignInLogs", - "baseQuery": "AADManagedIdentitySignInLogs" - }, - { - "metricName": "Total data received", - "legend": "AADProvisioningLogs", - "baseQuery": "AADProvisioningLogs" - }, - { - "metricName": "Total data received", - "legend": "ADFSSignInLogs", - "baseQuery": "ADFSSignInLogs" - }, - { - "metricName": "Total data received", - "legend": "AADUserRiskEvents", - "baseQuery": "AADUserRiskEvents" - }, - { - "metricName": "Total data received", - "legend": "AADRiskyUsers", - "baseQuery": "AADRiskyUsers" - }, - { - "metricName": "Total data received", - "legend": "NetworkAccessTraffic", - "baseQuery": "NetworkAccessTraffic" - }, - { - "metricName": "Total data received", - "legend": "AADRiskyServicePrincipals", - "baseQuery": "AADRiskyServicePrincipals" - }, - { - "metricName": "Total data received", - "legend": "AADServicePrincipalRiskEvents", - "baseQuery": "AADServicePrincipalRiskEvents" - } - ], - "connectivityCriterias": [ - { - "type": "IsConnectedQuery", - "value": [ - "SigninLogs\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(7d)", - "AuditLogs\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(7d)", - "AADNonInteractiveUserSignInLogs\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(7d)", - "AADServicePrincipalSignInLogs\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(7d)", - "AADManagedIdentitySignInLogs\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(7d)", - "AADProvisioningLogs\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(7d)", - "ADFSSignInLogs\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(7d)", - "AADUserRiskEvents\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(7d)", - "AADRiskyUsers\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(7d)", - "NetworkAccessTraffic\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(7d)", - "AADRiskyServicePrincipals\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(7d)", - "AADServicePrincipalRiskEvents\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(7d)" - ] - } - ], - "dataTypes": [ - { - "name": "SigninLogs", - "lastDataReceivedQuery": "SigninLogs\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" - }, - { - "name": "AuditLogs", - "lastDataReceivedQuery": "AuditLogs\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" - }, - { - "name": "AADNonInteractiveUserSignInLogs", - "lastDataReceivedQuery": "AADNonInteractiveUserSignInLogs\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" - }, - { - "name": "AADServicePrincipalSignInLogs", - "lastDataReceivedQuery": "AADServicePrincipalSignInLogs\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" - }, - { - "name": "AADManagedIdentitySignInLogs", - "lastDataReceivedQuery": "AADManagedIdentitySignInLogs\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" - }, - { - "name": "AADProvisioningLogs", - "lastDataReceivedQuery": "AADProvisioningLogs\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" - }, - { - "name": "ADFSSignInLogs", - "lastDataReceivedQuery": "ADFSSignInLogs\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" - }, - { - "name": "AADUserRiskEvents", - "lastDataReceivedQuery": "AADUserRiskEvents\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" - }, - { - "name": "AADRiskyUsers", - "lastDataReceivedQuery": "AADRiskyUsers\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" - }, - { - "name": "NetworkAccessTraffic", - "lastDataReceivedQuery": "NetworkAccessTraffic\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" - }, - { - "name": "AADRiskyServicePrincipals", - "lastDataReceivedQuery": "AADRiskyServicePrincipals\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" - }, - { - "name": "AADServicePrincipalRiskEvents", - "lastDataReceivedQuery": "AADServicePrincipalRiskEvents\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" - } - ] + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[[variables('AzureADConnectionName')]", + "location": "[[variables('workspace-location-inline')]", + "properties": { + "displayName": "[[variables('AzureADConnectionName')]", + "api": { + "id": "[[variables('_connection-1')]" } } }, { - "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", - "apiVersion": "2023-04-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('DataConnector-', last(split(variables('_dataConnectorId1'),'/'))))]", + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[[variables('MicrosoftSentinelConnectionName')]", + "location": "[[variables('workspace-location-inline')]", + "kind": "V1", "properties": { - "parentId": "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/dataConnectors', variables('_dataConnectorContentId1'))]", - "contentId": "[variables('_dataConnectorContentId1')]", - "kind": "DataConnector", - "version": "[variables('dataConnectorVersion1')]", - "source": { - "kind": "Solution", - "name": "Azure Active Directory", - "sourceId": "[variables('_solutionId')]" - }, - "author": { - "name": "Microsoft", - "email": "[variables('_email')]" - }, - "support": { - "tier": "Microsoft", - "name": "Microsoft Corporation", - "email": "support@microsoft.com", - "link": "https://support.microsoft.com/" + "displayName": "[[variables('MicrosoftSentinelConnectionName')]", + "parameterValueType": "Alternative", + "api": { + "id": "[[variables('_connection-2')]" } } - } - ] - }, - "packageKind": "Solution", - "packageVersion": "[variables('_solutionVersion')]", - "packageName": "[variables('_solutionName')]", - "packageId": "[variables('_solutionId')]", - "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_dataConnectorContentId1')]", - "contentKind": "DataConnector", - "displayName": "Azure Active Directory", - "contentProductId": "[variables('_dataConnectorcontentProductId1')]", - "id": "[variables('_dataConnectorcontentProductId1')]", - "version": "[variables('dataConnectorVersion1')]" - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", - "apiVersion": "2023-04-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('DataConnector-', last(split(variables('_dataConnectorId1'),'/'))))]", - "dependsOn": [ - "[variables('_dataConnectorId1')]" - ], - "location": "[parameters('workspace-location')]", - "properties": { - "parentId": "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/dataConnectors', variables('_dataConnectorContentId1'))]", - "contentId": "[variables('_dataConnectorContentId1')]", - "kind": "DataConnector", - "version": "[variables('dataConnectorVersion1')]", - "source": { - "kind": "Solution", - "name": "Azure Active Directory", - "sourceId": "[variables('_solutionId')]" - }, - "author": { - "name": "Microsoft", - "email": "[variables('_email')]" - }, - "support": { - "tier": "Microsoft", - "name": "Microsoft Corporation", - "email": "support@microsoft.com", - "link": "https://support.microsoft.com/" - } - } - }, - { - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',variables('_dataConnectorContentId1'))]", - "apiVersion": "2021-03-01-preview", - "type": "Microsoft.OperationalInsights/workspaces/providers/dataConnectors", - "location": "[parameters('workspace-location')]", - "kind": "StaticUI", - "properties": { - "connectorUiConfig": { - "title": "Azure Active Directory", - "publisher": "Microsoft", - "descriptionMarkdown": "Gain insights into Azure Active Directory by connecting Audit and Sign-in logs to Microsoft Sentinel to gather insights around Azure Active Directory scenarios. You can learn about app usage, conditional access policies, legacy auth relate details using our Sign-in logs. You can get information on your Self Service Password Reset (SSPR) usage, Azure Active Directory Management activities like user, group, role, app management using our Audit logs table. For more information, see the [Microsoft Sentinel documentation](https://go.microsoft.com/fwlink/?linkid=2219715&wt.mc_id=sentinel_dataconnectordocs_content_cnl_csasci).", - "graphQueries": [ - { - "metricName": "Total data received", - "legend": "SigninLogs", - "baseQuery": "SigninLogs" - }, - { - "metricName": "Total data received", - "legend": "AuditLogs", - "baseQuery": "AuditLogs" - }, - { - "metricName": "Total data received", - "legend": "AADNonInteractiveUserSignInLogs", - "baseQuery": "AADNonInteractiveUserSignInLogs" - }, - { - "metricName": "Total data received", - "legend": "AADServicePrincipalSignInLogs", - "baseQuery": "AADServicePrincipalSignInLogs" - }, - { - "metricName": "Total data received", - "legend": "AADManagedIdentitySignInLogs", - "baseQuery": "AADManagedIdentitySignInLogs" - }, - { - "metricName": "Total data received", - "legend": "AADProvisioningLogs", - "baseQuery": "AADProvisioningLogs" - }, - { - "metricName": "Total data received", - "legend": "ADFSSignInLogs", - "baseQuery": "ADFSSignInLogs" - }, - { - "metricName": "Total data received", - "legend": "AADUserRiskEvents", - "baseQuery": "AADUserRiskEvents" - }, - { - "metricName": "Total data received", - "legend": "AADRiskyUsers", - "baseQuery": "AADRiskyUsers" - }, - { - "metricName": "Total data received", - "legend": "NetworkAccessTraffic", - "baseQuery": "NetworkAccessTraffic" - }, - { - "metricName": "Total data received", - "legend": "AADRiskyServicePrincipals", - "baseQuery": "AADRiskyServicePrincipals" - }, - { - "metricName": "Total data received", - "legend": "AADServicePrincipalRiskEvents", - "baseQuery": "AADServicePrincipalRiskEvents" - } - ], - "dataTypes": [ - { - "name": "SigninLogs", - "lastDataReceivedQuery": "SigninLogs\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" - }, - { - "name": "AuditLogs", - "lastDataReceivedQuery": "AuditLogs\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" - }, - { - "name": "AADNonInteractiveUserSignInLogs", - "lastDataReceivedQuery": "AADNonInteractiveUserSignInLogs\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" - }, - { - "name": "AADServicePrincipalSignInLogs", - "lastDataReceivedQuery": "AADServicePrincipalSignInLogs\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" - }, - { - "name": "AADManagedIdentitySignInLogs", - "lastDataReceivedQuery": "AADManagedIdentitySignInLogs\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" - }, - { - "name": "AADProvisioningLogs", - "lastDataReceivedQuery": "AADProvisioningLogs\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" - }, - { - "name": "ADFSSignInLogs", - "lastDataReceivedQuery": "ADFSSignInLogs\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" - }, - { - "name": "AADUserRiskEvents", - "lastDataReceivedQuery": "AADUserRiskEvents\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" - }, - { - "name": "AADRiskyUsers", - "lastDataReceivedQuery": "AADRiskyUsers\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" - }, - { - "name": "NetworkAccessTraffic", - "lastDataReceivedQuery": "NetworkAccessTraffic\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" - }, - { - "name": "AADRiskyServicePrincipals", - "lastDataReceivedQuery": "AADRiskyServicePrincipals\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" - }, - { - "name": "AADServicePrincipalRiskEvents", - "lastDataReceivedQuery": "AADServicePrincipalRiskEvents\n | summarize Time = max(TimeGenerated)\n | where isnotempty(Time)" - } - ], - "connectivityCriterias": [ - { - "type": "IsConnectedQuery", - "value": [ - "SigninLogs\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(7d)", - "AuditLogs\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(7d)", - "AADNonInteractiveUserSignInLogs\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(7d)", - "AADServicePrincipalSignInLogs\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(7d)", - "AADManagedIdentitySignInLogs\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(7d)", - "AADProvisioningLogs\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(7d)", - "ADFSSignInLogs\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(7d)", - "AADUserRiskEvents\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(7d)", - "AADRiskyUsers\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(7d)", - "NetworkAccessTraffic\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(7d)", - "AADRiskyServicePrincipals\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(7d)", - "AADServicePrincipalRiskEvents\n | summarize LastLogReceived = max(TimeGenerated)\n | project IsConnected = LastLogReceived > ago(7d)" - ] - } - ], - "id": "[variables('_uiConfigId1')]" - } - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", - "apiVersion": "2023-04-01-preview", - "name": "[variables('workbookTemplateSpecName1')]", - "location": "[parameters('workspace-location')]", - "dependsOn": [ - "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" - ], - "properties": { - "description": "AzureActiveDirectoryAuditLogsWorkbook Workbook with template version 3.0.4", - "mainTemplate": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('workbookVersion1')]", - "parameters": {}, - "variables": {}, - "resources": [ - { - "type": "Microsoft.Insights/workbooks", - "name": "[variables('workbookContentId1')]", - "location": "[parameters('workspace-location')]", - "kind": "shared", - "apiVersion": "2021-08-01", - "metadata": { - "description": "Gain insights into Azure Active Directory by connecting Microsoft Sentinel and using the audit logs to gather insights around Azure AD scenarios. \nYou can learn about user operations, including password and group management, device activities, and top active users and apps." - }, - "properties": { - "displayName": "[parameters('workbook1-name')]", - "serializedData": "{\"version\":\"Notebook/1.0\",\"items\":[{\"type\":1,\"content\":{\"json\":\"## Azure AD audit logs\"},\"name\":\"text - 1\"},{\"type\":9,\"content\":{\"version\":\"KqlParameterItem/1.0\",\"parameters\":[{\"id\":\"bc372bf5-2dcd-4efa-aa85-94b6e6fafe14\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"TimeRange\",\"type\":4,\"isRequired\":true,\"value\":{\"durationMs\":7776000000},\"typeSettings\":{\"selectableValues\":[{\"durationMs\":300000},{\"durationMs\":900000},{\"durationMs\":1800000},{\"durationMs\":3600000},{\"durationMs\":14400000},{\"durationMs\":43200000},{\"durationMs\":86400000},{\"durationMs\":172800000},{\"durationMs\":259200000},{\"durationMs\":604800000},{\"durationMs\":1209600000},{\"durationMs\":2419200000},{\"durationMs\":2592000000},{\"durationMs\":5184000000},{\"durationMs\":7776000000}],\"allowCustom\":true}},{\"id\":\"e032b9f7-5449-4180-9c20-75760afa96f6\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"User\",\"type\":2,\"isRequired\":true,\"multiSelect\":true,\"quote\":\"'\",\"delimiter\":\",\",\"query\":\"AuditLogs\\r\\n| where SourceSystem == \\\"Azure AD\\\"\\r\\n| extend initiator = iif (tostring(InitiatedBy.user.userPrincipalName) != \\\"\\\", tostring(InitiatedBy.user.userPrincipalName), \\\"unknown\\\")\\r\\n//| where initiator!= \\\"\\\"\\r\\n| summarize Count = count() by initiator\\r\\n| order by Count desc, initiator asc\\r\\n| project Value = initiator, Label = strcat(initiator, ' - ', Count), Selected = false\",\"value\":[\"value::all\"],\"typeSettings\":{\"additionalResourceOptions\":[\"value::all\"],\"selectAllValue\":\"All\"},\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},{\"id\":\"0a59a0b3-6d93-4fee-bdbe-147383c510c6\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"Category\",\"type\":2,\"isRequired\":true,\"multiSelect\":true,\"quote\":\"'\",\"delimiter\":\",\",\"query\":\"AuditLogs\\r\\n| extend initiator = iif (tostring(InitiatedBy.user.userPrincipalName) != \\\"\\\", tostring(InitiatedBy.user.userPrincipalName), \\\"unknown\\\")\\r\\n| where \\\"{User:lable}\\\" == \\\"All\\\" or initiator in ({User})\\r\\n| summarize Count = count() by Category\\r\\n| order by Count desc, Category asc\\r\\n| project Value = Category, Label = strcat(Category, ' - ', Count)\",\"value\":[\"value::all\"],\"typeSettings\":{\"additionalResourceOptions\":[\"value::all\"],\"selectAllValue\":\"All\"},\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},{\"id\":\"4d2b245b-5e59-4eb6-9f51-ba926581ab47\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"Result\",\"type\":2,\"isRequired\":true,\"multiSelect\":true,\"quote\":\"'\",\"delimiter\":\",\",\"query\":\"AuditLogs\\r\\n| extend initiator = iif (tostring(InitiatedBy.user.userPrincipalName) != \\\"\\\", tostring(InitiatedBy.user.userPrincipalName), \\\"unknown\\\")\\r\\n| where \\\"{User:lable}\\\" == \\\"All\\\" or initiator in ({User})\\r\\n| summarize Count = count() by Result\\r\\n| order by Count desc, Result asc\\r\\n| project Value = Result, Label = strcat(Result, ' - ', Count, ' sign-ins')\",\"value\":[\"value::all\"],\"typeSettings\":{\"additionalResourceOptions\":[\"value::all\"],\"selectAllValue\":\"All\"},\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"}],\"style\":\"pills\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},\"name\":\"parameters - 1\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let data = AuditLogs\\r\\n| where \\\"{Category:lable}\\\" == \\\"All\\\" or Category in ({Category})\\r\\n| where \\\"{Result:lable}\\\" == \\\"All\\\" or Result in ({Result})\\r\\n| extend initiatingUserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)\\r\\n| where initiatingUserPrincipalName != \\\"\\\" \\r\\n| where \\\"{User:lable}\\\" == \\\"All\\\" or initiatingUserPrincipalName in ({User});\\r\\ndata\\r\\n| summarize Count = count() by Category\\r\\n| join kind = fullouter (datatable(Category:string)['Medium', 'high', 'low']) on Category\\r\\n| project Category = iff(Category == '', Category1, Category), Count = iff(Category == '', 0, Count)\\r\\n| join kind = inner (data\\r\\n | make-series Trend = count() default = 0 on TimeGenerated from {TimeRange:start} to {TimeRange:end} step {TimeRange:grain} by Category)\\r\\n on Category\\r\\n| project-away Category1, TimeGenerated\\r\\n| extend Category = Category\\r\\n| union (\\r\\n data \\r\\n | summarize Count = count() \\r\\n | extend jkey = 1\\r\\n | join kind=inner (data\\r\\n | make-series Trend = count() default = 0 on TimeGenerated from {TimeRange:start} to {TimeRange:end} step {TimeRange:grain}\\r\\n | extend jkey = 1) on jkey\\r\\n | extend Category = 'All', Categorys = '*' \\r\\n)\\r\\n| order by Count desc\\r\\n| take 10\",\"size\":4,\"title\":\"Categories volume\",\"timeContext\":{\"durationMs\":7776000000},\"timeContextFromParameter\":\"TimeRange\",\"exportFieldName\":\"Category\",\"exportParameterName\":\"CategoryFIlter\",\"exportDefaultValue\":\"All\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"tiles\",\"tileSettings\":{\"titleContent\":{\"columnMatch\":\"Category\",\"formatter\":1,\"formatOptions\":{\"showIcon\":true}},\"leftContent\":{\"columnMatch\":\"Count\",\"formatter\":12,\"formatOptions\":{\"palette\":\"auto\",\"showIcon\":true},\"numberFormat\":{\"unit\":17,\"options\":{\"style\":\"decimal\",\"maximumFractionDigits\":2,\"maximumSignificantDigits\":3}}},\"secondaryContent\":{\"columnMatch\":\"Trend\",\"formatter\":21,\"formatOptions\":{\"palette\":\"purple\",\"showIcon\":true}},\"showBorder\":false}},\"name\":\"query - 4\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let data = AuditLogs\\r\\n| where \\\"{Result:lable}\\\" == \\\"All\\\" or Result in ({Result})\\r\\n| extend initiator = iif (tostring(InitiatedBy.user.userPrincipalName) != \\\"\\\", tostring(InitiatedBy.user.userPrincipalName), \\\"unknown\\\")\\r\\n| where \\\"{User:lable}\\\" == \\\"All\\\" or initiator in ({User})\\r\\n| where \\\"{Category:lable}\\\" == \\\"All\\\" or Category in ({Category})\\r\\n| where Category == '{CategoryFIlter}' or '{CategoryFIlter}' == \\\"All\\\";\\r\\nlet appData = data\\r\\n| summarize TotalCount = count() by OperationName, Category\\r\\n| join kind=inner (data\\r\\n | make-series Trend = count() default = 0 on TimeGenerated in range({TimeRange:start}, {TimeRange:end}, {TimeRange:grain}) by OperationName\\r\\n | project-away TimeGenerated) on OperationName\\r\\n| order by TotalCount desc, OperationName asc\\r\\n| project OperationName, TotalCount, Trend, Category\\r\\n| serialize Id = row_number();\\r\\ndata\\r\\n| summarize TotalCount = count() by initiator = iif (tostring(InitiatedBy.user.userPrincipalName) != \\\"\\\", tostring(InitiatedBy.user.userPrincipalName), \\\"unknown\\\"), Category, OperationName\\r\\n| join kind=inner (data\\r\\n | make-series Trend = count() default = 0 on TimeGenerated in range({TimeRange:start}, {TimeRange:end}, {TimeRange:grain}) by OperationName, initiator = iif (tostring(InitiatedBy.user.userPrincipalName) != \\\"\\\", tostring(InitiatedBy.user.userPrincipalName), \\\"unknown\\\")\\r\\n | project-away TimeGenerated) on OperationName, initiator\\r\\n| order by TotalCount desc, OperationName asc\\r\\n| project OperationName, initiator, TotalCount, Category, Trend\\r\\n| serialize Id = row_number(1000000)\\r\\n| join kind=inner (appData) on OperationName\\r\\n| project Id, Name = initiator, Type = 'initiator', ['Operations Count'] = TotalCount, Trend, Category, ParentId = Id1\\r\\n| union (appData \\r\\n | project Id, Name = OperationName, Type = 'Operation', ['Operations Count'] = TotalCount, Category, Trend)\\r\\n| order by ['Operations Count'] desc, Name asc\",\"size\":0,\"showAnalytics\":true,\"title\":\"User activities\",\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"exportParameterName\":\"UserInfo\",\"exportDefaultValue\":\"{ \\\"Name\\\":\\\"\\\", \\\"Type\\\":\\\"*\\\"}\",\"showExportToExcel\":true,\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"gridSettings\":{\"formatters\":[{\"columnMatch\":\"Id\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Type\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Operations Count\",\"formatter\":8,\"formatOptions\":{\"min\":0,\"palette\":\"blue\",\"showIcon\":true},\"numberFormat\":{\"unit\":0,\"options\":{\"style\":\"decimal\"}}},{\"columnMatch\":\"Trend\",\"formatter\":9,\"formatOptions\":{\"min\":0,\"palette\":\"turquoise\",\"showIcon\":true},\"numberFormat\":{\"unit\":0,\"options\":{\"style\":\"decimal\"}}},{\"columnMatch\":\"ParentId\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}}],\"rowLimit\":1000,\"filter\":true,\"hierarchySettings\":{\"idColumn\":\"Id\",\"parentColumn\":\"ParentId\",\"treeType\":0,\"expanderColumn\":\"Name\"}}},\"customWidth\":\"70\",\"showPin\":true,\"name\":\"query - 2\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let details = dynamic({UserInfo});\\r\\nAuditLogs\\r\\n| where \\\"{Category:lable}\\\" == \\\"All\\\" or Category in ({Category})\\r\\n| where \\\"{Result:lable}\\\" == \\\"All\\\" or Result in ({Result})\\r\\n| extend initiatingUserPrincipalName = iif (tostring(InitiatedBy.user.userPrincipalName) != \\\"\\\", tostring(InitiatedBy.user.userPrincipalName), \\\"unknown\\\")\\r\\n//| where initiatingUserPrincipalName != \\\"\\\" \\r\\n| where \\\"{User:lable}\\\" == \\\"All\\\" or initiatingUserPrincipalName in ({User})\\r\\n| where details.Type == '*' or (details.Type == 'initiator' and initiatingUserPrincipalName == details.Name) or (details.Type == 'Operation' and OperationName == details.Name)\\r\\n| summarize Activities = count() by initiatingUserPrincipalName\\r\\n| sort by Activities desc nulls last \",\"size\":0,\"title\":\"Top active users\",\"timeContext\":{\"durationMs\":7776000000},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"piechart\"},\"customWidth\":\"30\",\"name\":\"query - 3\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let details = dynamic({UserInfo});\\r\\nlet data = AuditLogs\\r\\n| extend initiator = iif (tostring(InitiatedBy.user.userPrincipalName) != \\\"\\\", tostring(InitiatedBy.user.userPrincipalName), \\\"unknown\\\")\\r\\n| where details.Type == '*' or (details.Type == 'initiator' and initiator == details.Name) or (details.Type == 'Operation' and OperationName == details.Name)\\r\\n| where \\\"{Category:lable}\\\" == \\\"All\\\" or Category in ({Category})\\r\\n| where \\\"{Result:lable}\\\" == \\\"All\\\" or Result in ({Result})\\r\\n| where \\\"{User:lable}\\\" == \\\"All\\\" or initiator in ({User});\\r\\nlet appData = data\\r\\n| summarize TotalCount = count() by Result\\r\\n| join kind=inner (data\\r\\n | make-series Trend = count() default = 0 on TimeGenerated in range({TimeRange:start}, {TimeRange:end}, {TimeRange:grain}) by Result\\r\\n | project-away TimeGenerated) on Result\\r\\n| order by TotalCount desc, Result asc\\r\\n| project Result, TotalCount, Trend\\r\\n| serialize Id = row_number();\\r\\ndata\\r\\n| summarize TotalCount = count() by OperationName, Result\\r\\n| join kind=inner (data\\r\\n | make-series Trend = count() default = 0 on TimeGenerated in range({TimeRange:start}, {TimeRange:end}, {TimeRange:grain}) by Result, OperationName\\r\\n | project-away TimeGenerated) on Result, OperationName\\r\\n| order by TotalCount desc, Result asc\\r\\n| project Result, OperationName, TotalCount, Trend\\r\\n| serialize Id = row_number(1000000)\\r\\n| join kind=inner (appData) on Result\\r\\n| project Id, Name = OperationName, Type = 'Operation', ['Results Count'] = TotalCount, Trend, ParentId = Id1\\r\\n| union (appData \\r\\n | project Id, Name = Result, Type = 'Result', ['Results Count'] = TotalCount, Trend)\\r\\n| order by ['Results Count'] desc, Name asc\",\"size\":0,\"title\":\"Result status\",\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"exportParameterName\":\"ResultInfo\",\"exportDefaultValue\":\"{ \\\"Name\\\":\\\"\\\", \\\"Type\\\":\\\"*\\\"}\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"gridSettings\":{\"formatters\":[{\"columnMatch\":\"Id\",\"formatter\":5},{\"columnMatch\":\"Type\",\"formatter\":5},{\"columnMatch\":\"Results Count\",\"formatter\":8,\"formatOptions\":{\"min\":0,\"palette\":\"grayBlue\"}},{\"columnMatch\":\"Trend\",\"formatter\":9,\"formatOptions\":{\"palette\":\"greenDark\"}},{\"columnMatch\":\"ParentId\",\"formatter\":5}],\"hierarchySettings\":{\"idColumn\":\"Id\",\"parentColumn\":\"ParentId\",\"treeType\":0,\"expanderColumn\":\"Name\"}}},\"customWidth\":\"70\",\"name\":\"query - 5\"}],\"fallbackResourceIds\":[\"\"],\"fromTemplateId\":\"sentinel-AzureActiveDirectoryAuditLogs\",\"$schema\":\"https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json\"}\r\n", - "version": "1.0", - "sourceId": "[variables('workspaceResourceId')]", - "category": "sentinel" - } }, { - "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", - "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('Workbook-', last(split(variables('workbookId1'),'/'))))]", + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[[variables('Office365ConnectionName')]", + "location": "[[variables('workspace-location-inline')]", "properties": { - "description": "@{workbookKey=AzureActiveDirectoryAuditLogsWorkbook; logoFileName=azureactivedirectory_logo.svg; description=Gain insights into Azure Active Directory by connecting Microsoft Sentinel and using the audit logs to gather insights around Azure AD scenarios. \nYou can learn about user operations, including password and group management, device activities, and top active users and apps.; dataTypesDependencies=System.Object[]; dataConnectorsDependencies=System.Object[]; previewImagesFileNames=System.Object[]; version=1.2.0; title=Azure AD Audit logs; templateRelativePath=AzureActiveDirectoryAuditLogs.json; subtitle=; provider=Microsoft}.description", - "parentId": "[variables('workbookId1')]", - "contentId": "[variables('_workbookContentId1')]", - "kind": "Workbook", - "version": "[variables('workbookVersion1')]", - "source": { - "kind": "Solution", - "name": "Azure Active Directory", - "sourceId": "[variables('_solutionId')]" - }, - "author": { - "name": "Microsoft", - "email": "[variables('_email')]" - }, - "support": { - "tier": "Microsoft", - "name": "Microsoft Corporation", - "email": "support@microsoft.com", - "link": "https://support.microsoft.com/" - }, - "dependencies": { - "operator": "AND", - "criteria": [ - { - "contentId": "AuditLogs", - "kind": "DataType" - }, - { - "contentId": "AzureActiveDirectory", - "kind": "DataConnector" - } - ] + "displayName": "[[variables('Office365ConnectionName')]", + "api": { + "id": "[[variables('_connection-3')]" } } - } - ] - }, - "packageKind": "Solution", - "packageVersion": "[variables('_solutionVersion')]", - "packageName": "[variables('_solutionName')]", - "packageId": "[variables('_solutionId')]", - "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_workbookContentId1')]", - "contentKind": "Workbook", - "displayName": "[parameters('workbook1-name')]", - "contentProductId": "[variables('_workbookcontentProductId1')]", - "id": "[variables('_workbookcontentProductId1')]", - "version": "[variables('workbookVersion1')]" - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", - "apiVersion": "2023-04-01-preview", - "name": "[variables('workbookTemplateSpecName2')]", - "location": "[parameters('workspace-location')]", - "dependsOn": [ - "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" - ], - "properties": { - "description": "AzureActiveDirectorySigninsWorkbook Workbook with template version 3.0.4", - "mainTemplate": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('workbookVersion2')]", - "parameters": {}, - "variables": {}, - "resources": [ - { - "type": "Microsoft.Insights/workbooks", - "name": "[variables('workbookContentId2')]", - "location": "[parameters('workspace-location')]", - "kind": "shared", - "apiVersion": "2021-08-01", - "metadata": { - "description": "Gain insights into Azure Active Directory by connecting Microsoft Sentinel and using the sign-in logs to gather insights around Azure AD scenarios. \nYou can learn about sign-in operations, such as user sign-ins and locations, email addresses, and IP addresses of your users, as well as failed activities and the errors that triggered the failures." - }, - "properties": { - "displayName": "[parameters('workbook2-name')]", - "serializedData": "{\"version\":\"Notebook/1.0\",\"items\":[{\"type\":1,\"content\":{\"json\":\"## Sign-in Analysis\"},\"name\":\"text - 0\"},{\"type\":9,\"content\":{\"version\":\"KqlParameterItem/1.0\",\"parameters\":[{\"id\":\"13f56671-7604-4427-a4d8-663f3da0cbc5\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"TimeRange\",\"type\":4,\"isRequired\":true,\"value\":{\"durationMs\":1209600000},\"typeSettings\":{\"selectableValues\":[{\"durationMs\":300000,\"createdTime\":\"2018-11-13T19:33:10.162Z\",\"isInitialTime\":false,\"grain\":1,\"useDashboardTimeRange\":false},{\"durationMs\":900000,\"createdTime\":\"2018-11-13T19:33:10.164Z\",\"isInitialTime\":false,\"grain\":1,\"useDashboardTimeRange\":false},{\"durationMs\":1800000,\"createdTime\":\"2018-11-13T19:33:10.164Z\",\"isInitialTime\":false,\"grain\":1,\"useDashboardTimeRange\":false},{\"durationMs\":3600000,\"createdTime\":\"2018-11-13T19:33:10.164Z\",\"isInitialTime\":false,\"grain\":1,\"useDashboardTimeRange\":false},{\"durationMs\":14400000,\"createdTime\":\"2018-11-13T19:33:10.164Z\",\"isInitialTime\":false,\"grain\":1,\"useDashboardTimeRange\":false},{\"durationMs\":43200000,\"createdTime\":\"2018-11-13T19:33:10.164Z\",\"isInitialTime\":false,\"grain\":1,\"useDashboardTimeRange\":false},{\"durationMs\":86400000,\"createdTime\":\"2018-11-13T19:33:10.165Z\",\"isInitialTime\":false,\"grain\":1,\"useDashboardTimeRange\":false},{\"durationMs\":172800000,\"createdTime\":\"2018-11-13T19:33:10.166Z\",\"isInitialTime\":false,\"grain\":1,\"useDashboardTimeRange\":false},{\"durationMs\":259200000,\"createdTime\":\"2018-11-13T19:33:10.166Z\",\"isInitialTime\":false,\"grain\":1,\"useDashboardTimeRange\":false},{\"durationMs\":604800000,\"createdTime\":\"2018-11-13T19:33:10.166Z\",\"isInitialTime\":false,\"grain\":1,\"useDashboardTimeRange\":false},{\"durationMs\":1209600000,\"createdTime\":\"2018-11-13T19:33:10.166Z\",\"isInitialTime\":false,\"grain\":1,\"useDashboardTimeRange\":false},{\"durationMs\":2592000000,\"createdTime\":\"2018-11-13T19:33:10.167Z\",\"isInitialTime\":false,\"grain\":1,\"useDashboardTimeRange\":false}],\"allowCustom\":true}},{\"id\":\"3b5cc420-8ad8-4523-ba28-a54910756794\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"Apps\",\"type\":2,\"isRequired\":true,\"multiSelect\":true,\"quote\":\"'\",\"delimiter\":\",\",\"query\":\"SigninLogs\\r\\n| summarize Count = count() by AppDisplayName\\r\\n| order by Count desc, AppDisplayName asc\\r\\n| project Value = AppDisplayName, Label = strcat(AppDisplayName, ' - ', Count, ' sign-ins'), Selected = false\\r\\n\",\"value\":[\"value::all\"],\"typeSettings\":{\"limitSelectTo\":10,\"additionalResourceOptions\":[\"value::all\"],\"selectAllValue\":\"*\"},\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},{\"id\":\"0611ecce-d6a0-4a6f-a1bc-6be314ae36a7\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"UserNamePrefix\",\"type\":2,\"isRequired\":true,\"multiSelect\":true,\"quote\":\"'\",\"delimiter\":\",\",\"query\":\"SigninLogs\\r\\n|where AppDisplayName in ({Apps}) or '*' in ({Apps})\\r\\n| summarize Count = count() by UserDisplayName\\r\\n| order by Count desc, UserDisplayName asc\\r\\n| project Value = UserDisplayName, Label = strcat(UserDisplayName, ' - ', Count, ' sign-ins'), Selected = false\\r\\n| extend prefix = substring(Value, 0, 1)\\r\\n| distinct prefix\\r\\n| sort by prefix asc\",\"value\":[\"value::all\"],\"typeSettings\":{\"additionalResourceOptions\":[\"value::all\"],\"selectAllValue\":\"*\",\"showDefault\":false},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},{\"id\":\"f7f7970b-58c1-474f-9043-62243d2d4edd\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"Users\",\"label\":\"UserName\",\"type\":2,\"isRequired\":true,\"multiSelect\":true,\"quote\":\"'\",\"delimiter\":\",\",\"query\":\"SigninLogs\\r\\n|where AppDisplayName in ({Apps}) or '*' in ({Apps})\\r\\n| summarize Count = count() by UserDisplayName\\r\\n| order by Count desc, UserDisplayName asc\\r\\n| project Value = UserDisplayName, Label = strcat(UserDisplayName, ' - ', Count, ' sign-ins'), Selected = false\\r\\n| where (substring(Value, 0, 1) in ({UserNamePrefix})) or ('*' in ({UserNamePrefix}))\\r\\n| sort by Value asc\\r\\n\",\"value\":[\"value::all\"],\"typeSettings\":{\"limitSelectTo\":10000000,\"additionalResourceOptions\":[\"value::all\"],\"selectAllValue\":\"\",\"showDefault\":false},\"timeContext\":{\"durationMs\":1209600000},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},{\"id\":\"85568f4e-9ad4-46c5-91d4-0ee1b2c8f3aa\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"Category\",\"type\":2,\"isRequired\":true,\"multiSelect\":true,\"quote\":\"'\",\"delimiter\":\",\",\"value\":[\"value::all\"],\"typeSettings\":{\"additionalResourceOptions\":[\"value::all\"],\"selectAllValue\":\"\"},\"jsonData\":\"[\\\"SignInLogs\\\", \\\"NonInteractiveUserSignInLogs\\\"]\"}],\"style\":\"pills\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},\"name\":\"parameters - 1\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let data = \\r\\nunion SigninLogs,AADNonInteractiveUserSignInLogs\\r\\n| where Category in ({Category})\\r\\n|where AppDisplayName in ({Apps}) or '*' in ({Apps})\\r\\n|where UserDisplayName in ({Users});\\r\\ndata\\r\\n| summarize count() by UserPrincipalName, bin (TimeGenerated,5m)\\r\\n\",\"size\":0,\"title\":\"Sign-in Trend over Time\",\"timeContext\":{\"durationMs\":86400000},\"timeContextFromParameter\":\"TimeRange\",\"timeBrushParameterName\":\"TimeBrush\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"timechart\"},\"name\":\"query - 19\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let nonInteractive = AADNonInteractiveUserSignInLogs\\r\\n| extend LocationDetails = parse_json(LocationDetails)\\r\\n| extend Status = parse_json(Status);\\r\\nlet data = \\r\\nunion SigninLogs,nonInteractive\\r\\n| where Category in ({Category})\\r\\n|where AppDisplayName in ({Apps}) or '*' in ({Apps})\\r\\n|where UserDisplayName in ({Users}) \\r\\n|extend errorCode = Status.errorCode\\r\\n|extend SigninStatus = case(errorCode == 0, \\\"Success\\\", errorCode == 50058, \\\"Pending user action\\\",errorCode == 50140, \\\"Pending user action\\\", errorCode == 51006, \\\"Pending user action\\\", errorCode == 50059, \\\"Pending user action\\\",errorCode == 65001, \\\"Pending user action\\\", errorCode == 52004, \\\"Pending user action\\\", errorCode == 50055, \\\"Pending user action\\\", errorCode == 50144, \\\"Pending user action\\\", errorCode == 50072, \\\"Pending user action\\\", errorCode == 50074, \\\"Pending user action\\\", errorCode == 16000, \\\"Pending user action\\\", errorCode == 16001, \\\"Pending user action\\\", errorCode == 16003, \\\"Pending user action\\\", errorCode == 50127, \\\"Pending user action\\\", errorCode == 50125, \\\"Pending user action\\\", errorCode == 50129, \\\"Pending user action\\\", errorCode == 50143, \\\"Pending user action\\\", errorCode == 81010, \\\"Pending user action\\\", errorCode == 81014, \\\"Pending user action\\\", errorCode == 81012 ,\\\"Pending user action\\\", \\\"Failure\\\");\\r\\ndata\\r\\n| summarize Count = count() by SigninStatus\\r\\n| join kind = fullouter (datatable(SigninStatus:string)['Success', 'Pending action (Interrupts)', 'Failure']) on SigninStatus\\r\\n| project SigninStatus = iff(SigninStatus == '', SigninStatus1, SigninStatus), Count = iff(SigninStatus == '', 0, Count)\\r\\n| join kind = inner (data\\r\\n | make-series Trend = count() default = 0 on TimeGenerated from {TimeRange:start} to {TimeRange:end} step {TimeRange:grain} by SigninStatus)\\r\\n on SigninStatus\\r\\n| project-away SigninStatus1, TimeGenerated\\r\\n| extend Status = SigninStatus\\r\\n| union (\\r\\n data \\r\\n | summarize Count = count()\\r\\n | extend jkey = 1\\r\\n | join kind=inner (data\\r\\n | make-series Trend = count() default = 0 on TimeGenerated from {TimeRange:start} to {TimeRange:end} step {TimeRange:grain}\\r\\n | extend jkey = 1) on jkey\\r\\n | extend SigninStatus = 'All Sign-ins', Status = '*' \\r\\n)\\r\\n| order by Count desc\\r\\n\\r\\n\\r\\n\\r\\n\",\"size\":3,\"timeContext\":{\"durationMs\":1209600000},\"timeContextFromParameter\":\"TimeBrush\",\"exportFieldName\":\"Status\",\"exportParameterName\":\"SigninStatus\",\"exportDefaultValue\":\"*\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"tiles\",\"tileSettings\":{\"titleContent\":{\"columnMatch\":\"SigninStatus\",\"formatter\":1,\"formatOptions\":{\"showIcon\":true}},\"leftContent\":{\"columnMatch\":\"Count\",\"formatter\":12,\"formatOptions\":{\"palette\":\"blue\",\"showIcon\":true},\"numberFormat\":{\"unit\":17,\"options\":{\"style\":\"decimal\",\"maximumFractionDigits\":2,\"maximumSignificantDigits\":3}}},\"secondaryContent\":{\"columnMatch\":\"Trend\",\"formatter\":9,\"formatOptions\":{\"min\":0,\"palette\":\"blue\",\"showIcon\":true}},\"showBorder\":false}},\"name\":\"query - 5\"},{\"type\":1,\"content\":{\"json\":\"
\\r\\n💡 _Click on a tile or a row in the grid to drill-in further_\"},\"name\":\"text - 6 - Copy\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let nonInteractive = AADNonInteractiveUserSignInLogs\\r\\n| extend LocationDetails = parse_json(LocationDetails)\\r\\n| extend Status = parse_json(Status);\\r\\nlet data = \\r\\nunion SigninLogs,nonInteractive\\r\\n| extend AppDisplayName = iff(AppDisplayName == '', 'Unknown', AppDisplayName)\\r\\n|where AppDisplayName in ({Apps}) or '*' in ({Apps})\\r\\n|where UserDisplayName in ({Users}) \\r\\n| extend Country = iff(LocationDetails.countryOrRegion == '', 'Unknown country', tostring(LocationDetails.countryOrRegion))\\r\\n| extend City = iff(LocationDetails.city == '', 'Unknown city', tostring(LocationDetails.city))\\r\\n| extend errorCode = Status.errorCode\\r\\n| extend SigninStatus = case(errorCode == 0, \\\"Success\\\", errorCode == 50058, \\\"Pending user action\\\",errorCode == 50140, \\\"Pending user action\\\", errorCode == 51006, \\\"Pending user action\\\", errorCode == 50059, \\\"Pending user action\\\",errorCode == 65001, \\\"Pending user action\\\", errorCode == 52004, \\\"Pending user action\\\", errorCode == 50055, \\\"Pending user action\\\", errorCode == 50144, \\\"Pending user action\\\", errorCode == 50072, \\\"Pending user action\\\", errorCode == 50074, \\\"Pending user action\\\", errorCode == 16000, \\\"Pending user action\\\", errorCode == 16001, \\\"Pending user action\\\", errorCode == 16003, \\\"Pending user action\\\", errorCode == 50127, \\\"Pending user action\\\", errorCode == 50125, \\\"Pending user action\\\", errorCode == 50129, \\\"Pending user action\\\", errorCode == 50143, \\\"Pending user action\\\", errorCode == 81010, \\\"Pending user action\\\", errorCode == 81014, \\\"Pending user action\\\", errorCode == 81012 ,\\\"Pending user action\\\", \\\"Failure\\\")\\r\\n| where SigninStatus == '{SigninStatus}' or '{SigninStatus}' == '*' or '{SigninStatus}' == 'All Sign-ins';\\r\\nlet countryData = data\\r\\n| summarize TotalCount = count(), SuccessCount = countif(SigninStatus == \\\"Success\\\"), FailureCount = countif(SigninStatus == \\\"Failure\\\"), InterruptCount = countif(SigninStatus == \\\"Pending user action\\\") by Country,Category\\r\\n| join kind=inner\\r\\n(\\r\\n data\\r\\n| make-series Trend = count() default = 0 on TimeGenerated in range({TimeRange:start}, {TimeRange:end}, {TimeRange:grain}) by Country\\r\\n| project-away TimeGenerated\\r\\n)\\r\\non Country\\r\\n| project Country, TotalCount, SuccessCount,FailureCount,InterruptCount,Trend,Category\\r\\n| order by TotalCount desc, Country asc;\\r\\ndata\\r\\n| summarize TotalCount = count(), SuccessCount = countif(SigninStatus == \\\"Success\\\"), FailureCount = countif(SigninStatus == \\\"Failure\\\"), InterruptCount = countif(SigninStatus == \\\"Pending user action\\\") by Country, City,Category\\r\\n| join kind=inner\\r\\n(\\r\\n data \\r\\n| make-series Trend = count() default = 0 on TimeGenerated in range({TimeRange:start}, {TimeRange:end}, {TimeRange:grain}) by Country, City\\r\\n| project-away TimeGenerated\\r\\n)\\r\\non Country, City\\r\\n| order by TotalCount desc, Country asc\\r\\n| project Country, City,TotalCount, SuccessCount,FailureCount,InterruptCount, Trend,Category\\r\\n| join kind=inner\\r\\n(\\r\\n countryData\\r\\n)\\r\\non Country\\r\\n| summarize arg_max(TotalCount, SuccessCount, FailureCount, InterruptCount) by Country, City, Category, tostring(Trend)\\r\\n| project Id = strcat(City, '-', Category), Name = City, Type = 'City', ['Sign-in Count'] = TotalCount, Trend, ['Failure Count'] = FailureCount, ['Interrupt Count'] = InterruptCount, ['Success Rate'] = 1.0 * SuccessCount / TotalCount, ParentId = strcat(Country, '-', Category),Category\\r\\n| union (countryData\\r\\n| summarize arg_max(TotalCount, SuccessCount, FailureCount, InterruptCount) by Country, Category, tostring(Trend)\\r\\n| project Id = strcat(Country, '-', Category), Name = Country, Type = 'Country', ['Sign-in Count'] = TotalCount, Trend, ['Failure Count'] = FailureCount, ['Interrupt Count'] = InterruptCount, ['Success Rate'] = 1.0 * SuccessCount / TotalCount, ParentId = 'root',Category)\\r\\n| where Category in ({Category})\\r\\n| order by ['Sign-in Count'] desc, Name asc\\r\\n\",\"size\":1,\"showAnalytics\":true,\"title\":\"Sign-ins by Location\",\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeBrush\",\"showRefreshButton\":true,\"exportMultipleValues\":true,\"exportedParameters\":[{\"fieldName\":\"Name\",\"parameterName\":\"LocationDetail\",\"parameterType\":1}],\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"table\",\"gridSettings\":{\"formatters\":[{\"columnMatch\":\"Id\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Type\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Sign-in Count\",\"formatter\":8,\"formatOptions\":{\"min\":0,\"palette\":\"blue\",\"showIcon\":true},\"numberFormat\":{\"unit\":17,\"options\":{\"style\":\"decimal\"}}},{\"columnMatch\":\"Trend\",\"formatter\":9,\"formatOptions\":{\"min\":0,\"palette\":\"blue\",\"showIcon\":true}},{\"columnMatch\":\"Failure Count|Interrupt Count\",\"formatter\":8,\"formatOptions\":{\"min\":0,\"palette\":\"orange\",\"showIcon\":true},\"numberFormat\":{\"unit\":17,\"options\":{\"style\":\"decimal\"}}},{\"columnMatch\":\"Success Rate\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true},\"numberFormat\":{\"unit\":0,\"options\":{\"style\":\"percent\"}}},{\"columnMatch\":\"ParentId\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}}],\"filter\":true,\"hierarchySettings\":{\"idColumn\":\"Id\",\"parentColumn\":\"ParentId\",\"treeType\":0,\"expanderColumn\":\"Name\",\"expandTopLevel\":false}}},\"customWidth\":\"67\",\"showPin\":true,\"name\":\"query - 8\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let selectedCountry = dynamic([{LocationDetail}]);\\r\\nlet nonInteractive = AADNonInteractiveUserSignInLogs\\r\\n| extend LocationDetails = parse_json(LocationDetails),Status = parse_json(Status),ConditionalAccessPolicies = parse_json(ConditionalAccessPolicies),DeviceDetail =parse_json(DeviceDetail);\\r\\nlet details = dynamic({ \\\"Name\\\":\\\"\\\", \\\"Type\\\":\\\"*\\\"});\\r\\nlet data = union SigninLogs,nonInteractive\\r\\n| extend AppDisplayName = iff(AppDisplayName == '', 'Unknown', AppDisplayName)\\r\\n|where AppDisplayName in ({Apps}) or '*' in ({Apps})\\r\\n|where UserDisplayName in ({Users}) \\r\\n| extend Country = tostring(LocationDetails.countryOrRegion)\\r\\n| extend City = tostring(LocationDetails.city) \\r\\n| where array_length(selectedCountry) == 0 or \\\"*\\\" in (selectedCountry) or Country in (selectedCountry) or City in (selectedCountry) \\r\\n| extend errorCode = Status.errorCode\\r\\n| extend SigninStatus = case(errorCode == 0, \\\"Success\\\", errorCode == 50058, \\\"Pending user action\\\",errorCode == 50140, \\\"Pending user action\\\", errorCode == 51006, \\\"Pending user action\\\", errorCode == 50059, \\\"Pending user action\\\",errorCode == 65001, \\\"Pending user action\\\", errorCode == 52004, \\\"Pending user action\\\", errorCode == 50055, \\\"Pending user action\\\", errorCode == 50144, \\\"Pending user action\\\", errorCode == 50072, \\\"Pending user action\\\", errorCode == 50074, \\\"Pending user action\\\", errorCode == 16000, \\\"Pending user action\\\", errorCode == 16001, \\\"Pending user action\\\", errorCode == 16003, \\\"Pending user action\\\", errorCode == 50127, \\\"Pending user action\\\", errorCode == 50125, \\\"Pending user action\\\", errorCode == 50129, \\\"Pending user action\\\", errorCode == 50143, \\\"Pending user action\\\", errorCode == 81010, \\\"Pending user action\\\", errorCode == 81014, \\\"Pending user action\\\", errorCode == 81012 ,\\\"Pending user action\\\", \\\"Failure\\\")\\r\\n| where SigninStatus == '{SigninStatus}' or '{SigninStatus}' == '*' or '{SigninStatus}' == 'All Sign-ins'\\r\\n| where details.Type == '*' or (details.Type == 'Country' and Country == details.Name) or (details.Type == 'City' and City == details.Name);\\r\\ndata\\r\\n| top 200 by TimeGenerated desc\\r\\n| extend TimeFromNow = now() - TimeGenerated\\r\\n| extend TimeAgo = strcat(case(TimeFromNow < 2m, strcat(toint(TimeFromNow / 1m), ' seconds'), TimeFromNow < 2h, strcat(toint(TimeFromNow / 1m), ' minutes'), TimeFromNow < 2d, strcat(toint(TimeFromNow / 1h), ' hours'), strcat(toint(TimeFromNow / 1d), ' days')), ' ago')\\r\\n| project User = UserDisplayName, ['Sign-in Status'] = strcat(iff(SigninStatus == 'Success', '✔️', '❌'), ' ', SigninStatus), ['Sign-in Time'] = TimeAgo, App = AppDisplayName, ['Error code'] = errorCode, ['Result type'] = ResultType, ['Result signature'] = ResultSignature, ['Result description'] = ResultDescription, ['Conditional access policies'] = ConditionalAccessPolicies, ['Conditional access status'] = ConditionalAccessStatus, ['Operating system'] = DeviceDetail.operatingSystem, Browser = DeviceDetail.browser, ['Country or region'] = LocationDetails.countryOrRegion, ['State'] = LocationDetails.state, ['City'] = LocationDetails.city, ['Time generated'] = TimeGenerated, Status, ['User principal name'] = UserPrincipalName, Category\\r\\n| where Category in ({Category})\\r\\n\\r\\n\\r\\n\",\"size\":1,\"showAnalytics\":true,\"title\":\"Location Sign-in details\",\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeBrush\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"gridSettings\":{\"formatters\":[{\"columnMatch\":\"Sign-in Status\",\"formatter\":7,\"formatOptions\":{\"linkTarget\":\"CellDetails\",\"showIcon\":true}},{\"columnMatch\":\"App\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Error code\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Result type\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Result signature\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Result description\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Conditional access policies\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Conditional access status\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Operating system\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Browser\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Time generated\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Status\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"User principal name\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"TimeGenerated\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}}],\"filter\":true}},\"customWidth\":\"33\",\"name\":\"query - 8\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let nonInteractive = AADNonInteractiveUserSignInLogs | extend LocationDetails = parse_json(LocationDetails), Status = parse_json(Status), DeviceDetail = parse_json(DeviceDetail);\\r\\nlet data = \\r\\nunion SigninLogs,nonInteractive\\r\\n|where AppDisplayName in ({Apps}) or '*' in ({Apps})\\r\\n|where UserDisplayName in ({Users}) \\r\\n | extend errorCode = Status.errorCode\\r\\n | extend SigninStatus = case(errorCode == 0, \\\"Success\\\", errorCode == 50058, \\\"Pending user action\\\", errorCode == 50140, \\\"Pending user action\\\", errorCode == 51006, \\\"Pending user action\\\", errorCode == 50059, \\\"Pending user action\\\", errorCode == 65001, \\\"Pending user action\\\", errorCode == 52004, \\\"Pending user action\\\", errorCode == 50055, \\\"Pending user action\\\", errorCode == 50144, \\\"Pending user action\\\", errorCode == 50072, \\\"Pending user action\\\", errorCode == 50074, \\\"Pending user action\\\", errorCode == 16000, \\\"Pending user action\\\", errorCode == 16001, \\\"Pending user action\\\", errorCode == 16003, \\\"Pending user action\\\", errorCode == 50127, \\\"Pending user action\\\", errorCode == 50125, \\\"Pending user action\\\", errorCode == 50129, \\\"Pending user action\\\", errorCode == 50143, \\\"Pending user action\\\", errorCode == 81010, \\\"Pending user action\\\", errorCode == 81014, \\\"Pending user action\\\", errorCode == 81012, \\\"Pending user action\\\", \\\"Failure\\\")\\r\\n| where SigninStatus == '{SigninStatus}' or '{SigninStatus}' == '*' or '{SigninStatus}' == 'All Sign-ins';\\r\\nlet appData = data\\r\\n | summarize TotalCount = count(), SuccessCount = countif(SigninStatus == \\\"Success\\\"), FailureCount = countif(SigninStatus == \\\"Failure\\\"), InterruptCount = countif(SigninStatus == \\\"Pending user action\\\") by Os = tostring(DeviceDetail.operatingSystem) ,Category\\r\\n | where Os != ''\\r\\n | join kind=inner (data\\r\\n | make-series Trend = count() default = 0 on TimeGenerated in range({TimeRange:start}, {TimeRange:end}, {TimeRange:grain}) by Os = tostring(DeviceDetail.operatingSystem)\\r\\n | project-away TimeGenerated)\\r\\n on Os\\r\\n | order by TotalCount desc, Os asc\\r\\n | project Os, TotalCount, SuccessCount, FailureCount, InterruptCount, Trend,Category\\r\\n | serialize Id = row_number();\\r\\ndata\\r\\n| summarize TotalCount = count(), SuccessCount = countif(SigninStatus == \\\"Success\\\"), FailureCount = countif(SigninStatus == \\\"Failure\\\"), InterruptCount = countif(SigninStatus == \\\"Pending user action\\\") by Os = tostring(DeviceDetail.operatingSystem), Browser = tostring(DeviceDetail.browser),Category\\r\\n| join kind=inner (data\\r\\n | make-series Trend = count() default = 0 on TimeGenerated in range({TimeRange:start}, {TimeRange:end}, {TimeRange:grain})by Os = tostring(DeviceDetail.operatingSystem), Browser = tostring(DeviceDetail.browser)\\r\\n | project-away TimeGenerated)\\r\\n on Os, Browser\\r\\n| order by TotalCount desc, Os asc\\r\\n| project Os, Browser, TotalCount, SuccessCount, FailureCount, InterruptCount, Trend,Category\\r\\n| serialize Id = row_number(1000000)\\r\\n| join kind=inner (appData) on Os\\r\\n| project Id, Name = Browser, Type = 'Browser', ['Sign-in Count'] = TotalCount, Trend, ['Failure Count'] = FailureCount, ['Interrupt Count'] = InterruptCount, ['Success Rate'] = 1.0 * SuccessCount / TotalCount, ParentId = Id1,Category\\r\\n| union (appData \\r\\n | project Id, Name = Os, Type = 'Operating System', ['Sign-in Count'] = TotalCount, Trend, ['Failure Count'] = FailureCount, ['Interrupt Count'] = InterruptCount, ['Success Rate'] = 1.0 * SuccessCount / TotalCount, ParentId = -1,Category)\\r\\n| where Category in ({Category})\\r\\n| order by ['Sign-in Count'] desc, Name asc\\r\\n\",\"size\":1,\"showAnalytics\":true,\"title\":\"Sign-ins by Device\",\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeBrush\",\"exportedParameters\":[{\"parameterName\":\"DeviceDetail\",\"defaultValue\":\"{ \\\"Name\\\":\\\"\\\", \\\"Type\\\":\\\"*\\\"}\"},{\"fieldName\":\"Category\",\"parameterName\":\"exportCategory\",\"parameterType\":1,\"defaultValue\":\"*\"},{\"fieldName\":\"Name\",\"parameterName\":\"exportName\",\"parameterType\":1,\"defaultValue\":\"*\"}],\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"table\",\"gridSettings\":{\"formatters\":[{\"columnMatch\":\"Id\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Type\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Sign-in Count\",\"formatter\":8,\"formatOptions\":{\"min\":0,\"palette\":\"blue\",\"showIcon\":true},\"numberFormat\":{\"unit\":17,\"options\":{\"style\":\"decimal\"}}},{\"columnMatch\":\"Trend\",\"formatter\":9,\"formatOptions\":{\"min\":0,\"palette\":\"blue\",\"showIcon\":true},\"numberFormat\":{\"unit\":17,\"options\":{\"style\":\"decimal\"}}},{\"columnMatch\":\"Failure Count|Interrupt Count\",\"formatter\":8,\"formatOptions\":{\"min\":0,\"palette\":\"orange\",\"showIcon\":true},\"numberFormat\":{\"unit\":17,\"options\":{\"style\":\"decimal\"}}},{\"columnMatch\":\"Success Rate\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true},\"numberFormat\":{\"unit\":0,\"options\":{\"style\":\"percent\"}}},{\"columnMatch\":\"ParentId\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}}],\"filter\":true,\"hierarchySettings\":{\"idColumn\":\"Id\",\"parentColumn\":\"ParentId\",\"treeType\":0,\"expanderColumn\":\"Name\",\"expandTopLevel\":false}}},\"customWidth\":\"67\",\"showPin\":true,\"name\":\"query - 9\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let nonInteractive = AADNonInteractiveUserSignInLogs\\r\\n| extend LocationDetails = parse_json(LocationDetails),Status = parse_json(Status),ConditionalAccessPolicies = parse_json(ConditionalAccessPolicies),DeviceDetail =parse_json(DeviceDetail);\\r\\nlet details = dynamic({ \\\"Name\\\":\\\"\\\", \\\"Type\\\":\\\"*\\\"});\\r\\nlet data = union SigninLogs,nonInteractive\\r\\n| extend AppDisplayName = iff(AppDisplayName == '', 'Unknown', AppDisplayName)\\r\\n|where AppDisplayName in ({Apps}) or '*' in ({Apps})\\r\\n|where UserDisplayName in ({Users}) \\r\\n| extend Country = tostring(LocationDetails.countryOrRegion)\\r\\n| extend City = tostring(LocationDetails.city)\\r\\n| extend errorCode = Status.errorCode\\r\\n| extend SigninStatus = case(errorCode == 0, \\\"Success\\\", errorCode == 50058, \\\"Pending user action\\\",errorCode == 50140, \\\"Pending user action\\\", errorCode == 51006, \\\"Pending user action\\\", errorCode == 50059, \\\"Pending user action\\\",errorCode == 65001, \\\"Pending user action\\\", errorCode == 52004, \\\"Pending user action\\\", errorCode == 50055, \\\"Pending user action\\\", errorCode == 50144, \\\"Pending user action\\\", errorCode == 50072, \\\"Pending user action\\\", errorCode == 50074, \\\"Pending user action\\\", errorCode == 16000, \\\"Pending user action\\\", errorCode == 16001, \\\"Pending user action\\\", errorCode == 16003, \\\"Pending user action\\\", errorCode == 50127, \\\"Pending user action\\\", errorCode == 50125, \\\"Pending user action\\\", errorCode == 50129, \\\"Pending user action\\\", errorCode == 50143, \\\"Pending user action\\\", errorCode == 81010, \\\"Pending user action\\\", errorCode == 81014, \\\"Pending user action\\\", errorCode == 81012 ,\\\"Pending user action\\\", \\\"Failure\\\")\\r\\n| where SigninStatus == '{SigninStatus}' or '{SigninStatus}' == '*' or '{SigninStatus}' == 'All Sign-ins'\\r\\n| where details.Type == '*' or (details.Type == 'Country' and Country == details.Name) or (details.Type == 'City' and City == details.Name);\\r\\ndata\\r\\n| top 200 by TimeGenerated desc\\r\\n| extend TimeFromNow = now() - TimeGenerated\\r\\n| extend TimeAgo = strcat(case(TimeFromNow < 2m, strcat(toint(TimeFromNow / 1m), ' seconds'), TimeFromNow < 2h, strcat(toint(TimeFromNow / 1m), ' minutes'), TimeFromNow < 2d, strcat(toint(TimeFromNow / 1h), ' hours'), strcat(toint(TimeFromNow / 1d), ' days')), ' ago')\\r\\n| project User = UserDisplayName, ['Sign-in Status'] = strcat(iff(SigninStatus == 'Success', '✔️', '❌'), ' ', SigninStatus), ['Sign-in Time'] = TimeAgo, App = AppDisplayName, ['Error code'] = errorCode, ['Result type'] = ResultType, ['Result signature'] = ResultSignature, ['Result description'] = ResultDescription, ['Conditional access policies'] = ConditionalAccessPolicies, ['Conditional access status'] = ConditionalAccessStatus, ['Operating system'] = DeviceDetail.operatingSystem, Browser = DeviceDetail.browser, ['Country or region'] = LocationDetails.countryOrRegion, ['State'] = LocationDetails.state, ['City'] = LocationDetails.city, ['Time generated'] = TimeGenerated, Status, ['User principal name'] = UserPrincipalName, Category, Name = tostring(DeviceDetail.operatingSystem)\\r\\n| where Category in ('{exportCategory}') or \\\"*\\\" in ('{exportCategory}')\\r\\n| where Name in ('{exportName}') or \\\"*\\\" in ('{exportName}')\",\"size\":1,\"showAnalytics\":true,\"title\":\"Device Sign-in details\",\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"gridSettings\":{\"formatters\":[{\"columnMatch\":\"Sign-in Status\",\"formatter\":7,\"formatOptions\":{\"linkTarget\":\"CellDetails\"}},{\"columnMatch\":\"App\",\"formatter\":5},{\"columnMatch\":\"Error code\",\"formatter\":5},{\"columnMatch\":\"Result type\",\"formatter\":5},{\"columnMatch\":\"Result signature\",\"formatter\":5},{\"columnMatch\":\"Result description\",\"formatter\":5},{\"columnMatch\":\"Conditional access policies\",\"formatter\":5},{\"columnMatch\":\"Conditional access status\",\"formatter\":5},{\"columnMatch\":\"Operating system\",\"formatter\":5},{\"columnMatch\":\"Browser\",\"formatter\":5},{\"columnMatch\":\"Country or region\",\"formatter\":5},{\"columnMatch\":\"State\",\"formatter\":5},{\"columnMatch\":\"City\",\"formatter\":5},{\"columnMatch\":\"Time generated\",\"formatter\":5},{\"columnMatch\":\"Status\",\"formatter\":5},{\"columnMatch\":\"User principal name\",\"formatter\":5},{\"columnMatch\":\"Category\",\"formatter\":5},{\"columnMatch\":\"Name\",\"formatter\":5}],\"filter\":true}},\"customWidth\":\"33\",\"name\":\"query - 8 - Copy\"},{\"type\":1,\"content\":{\"json\":\"## Sign-ins using Conditional Access\"},\"name\":\"text - 12\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let nonInteractive = AADNonInteractiveUserSignInLogs\\r\\n| extend LocationDetails = parse_json(LocationDetails)\\r\\n| extend Status = parse_json(Status)\\r\\n| extend ConditionalAccessPolicies = parse_json(ConditionalAccessPolicies);\\r\\nlet data = \\r\\nunion SigninLogs,nonInteractive\\r\\n|where AppDisplayName in ({Apps}) or '*' in ({Apps})\\r\\n|where UserDisplayName in ({Users}) \\r\\n|extend CAStatus = case(ConditionalAccessStatus ==\\\"success\\\",\\\"Successful\\\",\\r\\n ConditionalAccessStatus == \\\"failure\\\", \\\"Failed\\\", \\r\\n ConditionalAccessStatus == \\\"notApplied\\\", \\\"Not applied\\\", \\r\\n isempty(ConditionalAccessStatus), \\\"Not applied\\\", \\r\\n \\\"Disabled\\\")\\r\\n|mvexpand ConditionalAccessPolicies\\r\\n|extend CAGrantControlName = tostring(ConditionalAccessPolicies.enforcedGrantControls[0])\\r\\n|extend CAGrantControl = case(CAGrantControlName contains \\\"MFA\\\", \\\"Require MFA\\\", \\r\\n CAGrantControlName contains \\\"Terms of Use\\\", \\\"Require Terms of Use\\\", \\r\\n CAGrantControlName contains \\\"Privacy\\\", \\\"Require Privacy Statement\\\", \\r\\n CAGrantControlName contains \\\"Device\\\", \\\"Require Device Compliant\\\", \\r\\n CAGrantControlName contains \\\"Azure AD Joined\\\", \\\"Require Hybird Azure AD Joined Device\\\", \\r\\n CAGrantControlName contains \\\"Apps\\\", \\\"Require Approved Apps\\\",\\r\\n \\\"Other\\\");\\r\\ndata\\r\\n| where Category in ({Category})\\r\\n| summarize Count = dcount(Id) by CAStatus\\r\\n| join kind = inner (data\\r\\n | make-series Trend = dcount(Id) default = 0 on TimeGenerated in range({TimeRange:start}, {TimeRange:end}, {TimeRange:grain}) by CAStatus\\r\\n ) on CAStatus\\r\\n| project-away CAStatus1, TimeGenerated\\r\\n| order by Count desc\",\"size\":4,\"title\":\"Conditional access status\",\"timeContext\":{\"durationMs\":1209600000},\"timeContextFromParameter\":\"TimeBrush\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"tiles\",\"tileSettings\":{\"titleContent\":{\"columnMatch\":\"CAStatus\",\"formatter\":1},\"subtitleContent\":{\"columnMatch\":\"Category\"},\"leftContent\":{\"columnMatch\":\"Count\",\"formatter\":12,\"formatOptions\":{\"palette\":\"auto\"},\"numberFormat\":{\"unit\":17,\"options\":{\"maximumSignificantDigits\":3,\"maximumFractionDigits\":2}}},\"showBorder\":false}},\"name\":\"query - 9\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let nonInteractive = AADNonInteractiveUserSignInLogs\\r\\n| extend LocationDetails = parse_json(LocationDetails)\\r\\n| extend Status = parse_json(Status)\\r\\n| extend ConditionalAccessPolicies = parse_json(ConditionalAccessPolicies);\\r\\nlet data = \\r\\nunion SigninLogs,nonInteractive|where AppDisplayName in ({Apps}) or '*' in ({Apps})\\r\\n|where UserDisplayName in ({Users}) \\r\\n|extend errorCode = toint(Status.errorCode)\\r\\n|extend Reason = tostring(Status.failureReason)\\r\\n|extend CAStatus = case(ConditionalAccessStatus ==0,\\\"✔️ Success\\\", \\r\\n ConditionalAccessStatus == 1, \\\"❌ Failure\\\", \\r\\n ConditionalAccessStatus == 2, \\\"⚠️ Not Applied\\\", \\r\\n ConditionalAccessStatus == \\\"\\\", \\\"⚠️ Not Applied\\\", \\r\\n \\\"🚫 Disabled\\\")\\r\\n|mvexpand ConditionalAccessPolicies\\r\\n|extend CAGrantControlName = tostring(ConditionalAccessPolicies.enforcedGrantControls[0])\\r\\n|extend CAGrantControl = case(CAGrantControlName contains \\\"MFA\\\", \\\"Require MFA\\\", \\r\\n CAGrantControlName contains \\\"Terms of Use\\\", \\\"Require Terms of Use\\\", \\r\\n CAGrantControlName contains \\\"Privacy\\\", \\\"Require Privacy Statement\\\", \\r\\n CAGrantControlName contains \\\"Device\\\", \\\"Require Device Compliant\\\", \\r\\n CAGrantControlName contains \\\"Azure AD Joined\\\", \\\"Require Hybird Azure AD Joined Device\\\", \\r\\n CAGrantControlName contains \\\"Apps\\\", \\\"Require Approved Apps\\\",\\\"Other\\\");\\r\\ndata\\r\\n| summarize Count = dcount(Id) by CAStatus, CAGrantControl\\r\\n| project Id = strcat(CAStatus, '/', CAGrantControl), Name = CAGrantControl, Parent = CAStatus, Count, Type = 'CAGrantControl'\\r\\n| join kind = inner (data\\r\\n | make-series Trend = dcount(Id) default = 0 on TimeGenerated in range({TimeRange:start}, {TimeRange:end}, {TimeRange:grain}) by CAStatus, CAGrantControl\\r\\n | project Id = strcat(CAStatus, '/', CAGrantControl), Trend\\r\\n ) on Id\\r\\n| project-away Id1\\r\\n| union (data\\r\\n | where Category in ({Category})\\r\\n | summarize Count = dcount(Id) by CAStatus\\r\\n | project Id = CAStatus, Name = CAStatus, Parent = '', Count, Type = 'CAStatus'\\r\\n | join kind = inner (data\\r\\n | make-series Trend = dcount(Id) default = 0 on TimeGenerated in range({TimeRange:start}, {TimeRange:end}, {TimeRange:grain}) by CAStatus\\r\\n | project Id = CAStatus, Trend\\r\\n ) on Id\\r\\n | project-away Id1)\\r\\n| order by Count desc\",\"size\":0,\"title\":\"Conditional access status\",\"timeContext\":{\"durationMs\":1209600000},\"timeContextFromParameter\":\"TimeBrush\",\"exportParameterName\":\"Detail\",\"exportDefaultValue\":\"{ \\\"Name\\\":\\\"\\\", \\\"Type\\\":\\\"*\\\", \\\"Parent\\\":\\\"*\\\"}\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"table\",\"gridSettings\":{\"formatters\":[{\"columnMatch\":\"Id\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Parent\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Count\",\"formatter\":8,\"formatOptions\":{\"min\":0,\"palette\":\"blue\",\"showIcon\":true},\"numberFormat\":{\"unit\":0,\"options\":{\"style\":\"decimal\"}}},{\"columnMatch\":\"Type\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Trend\",\"formatter\":9,\"formatOptions\":{\"min\":0,\"palette\":\"blue\",\"showIcon\":true}}],\"hierarchySettings\":{\"idColumn\":\"Id\",\"parentColumn\":\"Parent\",\"treeType\":0,\"expanderColumn\":\"Name\",\"expandTopLevel\":true}}},\"customWidth\":\"50\",\"name\":\"query - 10\",\"styleSettings\":{\"margin\":\"50\"}},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let details = dynamic({Detail});\\r\\nlet nonInteractive = AADNonInteractiveUserSignInLogs\\r\\n| extend LocationDetails = parse_json(LocationDetails)\\r\\n| extend Status = parse_json(Status)\\r\\n| extend ConditionalAccessPolicies = parse_json(ConditionalAccessPolicies);\\r\\nlet data = \\r\\nunion SigninLogs,nonInteractive\\r\\n|where AppDisplayName in ({Apps}) or '*' in ({Apps})\\r\\n|where UserDisplayName in ({Users}) \\r\\n|extend errorCode = toint(Status.errorCode)\\r\\n|extend Reason = tostring(Status.failureReason)\\r\\n|extend CAStatus = case(ConditionalAccessStatus ==\\\"success\\\",\\\"✔️ Success\\\", \\r\\n ConditionalAccessStatus == \\\"failure\\\", \\\"❌ Failure\\\", \\r\\n ConditionalAccessStatus == \\\"notApplied\\\", \\\"⚠️ Not Applied\\\", \\r\\n ConditionalAccessStatus == \\\"\\\", \\\"⚠️ Not Applied\\\", \\r\\n \\\"🚫 Disabled\\\")\\r\\n|mvexpand ConditionalAccessPolicies\\r\\n|extend CAGrantControlName = tostring(ConditionalAccessPolicies.enforcedGrantControls[0])\\r\\n|extend CAGrantControl = case(CAGrantControlName contains \\\"MFA\\\", \\\"Require MFA\\\", \\r\\n CAGrantControlName contains \\\"Terms of Use\\\", \\\"Require Terms of Use\\\", \\r\\n CAGrantControlName contains \\\"Privacy\\\", \\\"Require Privacy Statement\\\", \\r\\n CAGrantControlName contains \\\"Device\\\", \\\"Require Device Compliant\\\", \\r\\n CAGrantControlName contains \\\"Azure AD Joined\\\", \\\"Require Hybird Azure AD Joined Device\\\", \\r\\n CAGrantControlName contains \\\"Apps\\\", \\\"Require Approved Apps\\\",\\r\\n \\\"Other\\\")\\r\\n|extend CAGrantControlRank = case(CAGrantControlName contains \\\"MFA\\\", 1, \\r\\n CAGrantControlName contains \\\"Terms of Use\\\", 2, \\r\\n CAGrantControlName contains \\\"Privacy\\\", 3, \\r\\n CAGrantControlName contains \\\"Device\\\", 4, \\r\\n CAGrantControlName contains \\\"Azure AD Joined\\\", 5, \\r\\n CAGrantControlName contains \\\"Apps\\\", 6,\\r\\n 7)\\r\\n| where details.Type == '*' or (details.Type == 'CAStatus' and CAStatus == details.Name) or (details.Type == 'CAGrantControl' and CAGrantControl == details.Name and CAStatus == details.Parent);\\r\\ndata\\r\\n| order by CAGrantControlRank desc\\r\\n| summarize CAGrantControls = make_set(CAGrantControl) by AppDisplayName, CAStatus, TimeGenerated, UserDisplayName, Category\\r\\n| extend CAGrantControlText = replace(@\\\",\\\", \\\", \\\", replace(@'\\\"', @'', replace(@\\\"\\\\]\\\", @\\\"\\\", replace(@\\\"\\\\[\\\", @\\\"\\\", tostring(CAGrantControls)))))\\r\\n| extend CAGrantControlSummary = case(array_length(CAGrantControls) > 1, strcat(CAGrantControls[0], ' + ', array_length(CAGrantControls) - 1, ' more'), array_length(CAGrantControls) == 1, tostring(CAGrantControls[0]), 'None')\\r\\n| top 200 by TimeGenerated desc\\r\\n| extend TimeFromNow = now() - TimeGenerated\\r\\n| extend TimeAgo = strcat(case(TimeFromNow < 2m, strcat(toint(TimeFromNow / 1m), ' seconds'), TimeFromNow < 2h, strcat(toint(TimeFromNow / 1m), ' minutes'), TimeFromNow < 2d, strcat(toint(TimeFromNow / 1h), ' hours'), strcat(toint(TimeFromNow / 1d), ' days')), ' ago')\\r\\n| project Application = AppDisplayName, ['CA Status'] = CAStatus, ['CA Grant Controls'] = CAGrantControlSummary, ['All CA Grant Controls'] = CAGrantControlText, ['Sign-in Time'] = TimeAgo, ['User'] = UserDisplayName, Category\\r\\n| where Category in ({Category})\",\"size\":0,\"showAnalytics\":true,\"title\":\"Recent sign-ins\",\"timeContext\":{\"durationMs\":1209600000},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"table\",\"gridSettings\":{\"formatters\":[{\"columnMatch\":\"CA Grant Controls\",\"formatter\":1,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"All CA Grant Controls\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"User\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}}]}},\"customWidth\":\"50\",\"showPin\":true,\"name\":\"query - 7 - Copy\"},{\"type\":1,\"content\":{\"json\":\"## Troubleshooting Sign-ins\"},\"name\":\"text - 13\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let nonInteractive = AADNonInteractiveUserSignInLogs\\r\\n| extend LocationDetails = parse_json(LocationDetails)\\r\\n| extend Status = parse_json(Status);\\r\\nlet data = \\r\\nunion SigninLogs,nonInteractive|where AppDisplayName in ({Apps}) or '*' in ({Apps})\\r\\n|where UserDisplayName in ({Users}) \\r\\n|extend errorCode = Status.errorCode\\r\\n|extend SigninStatus = case(errorCode == 0, \\\"Success\\\", errorCode == 50058, \\\"Pending action (Interrupts)\\\",errorCode == 50140, \\\"Pending action (Interrupts)\\\", errorCode == 51006, \\\"Pending action (Interrupts)\\\", errorCode == 50059, \\\"Pending action (Interrupts)\\\",errorCode == 65001, \\\"Pending action (Interrupts)\\\", errorCode == 52004, \\\"Pending action (Interrupts)\\\", errorCode == 50055, \\\"Pending action (Interrupts)\\\", errorCode == 50144, \\\"Pending action (Interrupts)\\\", errorCode == 50072, \\\"Pending action (Interrupts)\\\", errorCode == 50074, \\\"Pending action (Interrupts)\\\", errorCode == 16000, \\\"Pending action (Interrupts)\\\", errorCode == 16001, \\\"Pending action (Interrupts)\\\", errorCode == 16003, \\\"Pending action (Interrupts)\\\", errorCode == 50127, \\\"Pending action (Interrupts)\\\", errorCode == 50125, \\\"Pending action (Interrupts)\\\", errorCode == 50129, \\\"Pending action (Interrupts)\\\", errorCode == 50143, \\\"Pending action (Interrupts)\\\", errorCode == 81010, \\\"Pending action (Interrupts)\\\", errorCode == 81014, \\\"Pending action (Interrupts)\\\", errorCode == 81012 ,\\\"Pending action (Interrupts)\\\", \\\"Failure\\\");\\r\\ndata\\r\\n| summarize Count = count() by SigninStatus, Category\\r\\n| join kind = fullouter (datatable(SigninStatus:string)['Success', 'Pending action (Interrupts)', 'Failure']) on SigninStatus\\r\\n| project SigninStatus = iff(SigninStatus == '', SigninStatus1, SigninStatus), Count = iff(SigninStatus == '', 0, Count), Category\\r\\n| join kind = inner (data\\r\\n | make-series Trend = count() default = 0 on TimeGenerated from {TimeRange:start} to {TimeRange:end} step {TimeRange:grain} by SigninStatus)\\r\\n on SigninStatus\\r\\n| project-away SigninStatus1, TimeGenerated\\r\\n| extend Status = SigninStatus\\r\\n| union (\\r\\n data \\r\\n | summarize Count = count() \\r\\n | extend jkey = 1\\r\\n | join kind=inner (data\\r\\n | make-series Trend = count() default = 0 on TimeGenerated from {TimeRange:start} to {TimeRange:end} step {TimeRange:grain}\\r\\n | extend jkey = 1) on jkey\\r\\n | extend SigninStatus = 'All Sign-ins', Status = '*' \\r\\n)\\r\\n| where Category in ({Category})\\r\\n| order by Count desc\\r\\n\\r\\n\\r\\n\\r\\n\",\"size\":3,\"timeContext\":{\"durationMs\":1209600000},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"tiles\",\"tileSettings\":{\"titleContent\":{\"columnMatch\":\"SigninStatus\",\"formatter\":1,\"formatOptions\":{\"showIcon\":true}},\"leftContent\":{\"columnMatch\":\"Count\",\"formatter\":12,\"formatOptions\":{\"palette\":\"blue\",\"showIcon\":true},\"numberFormat\":{\"unit\":17,\"options\":{\"style\":\"decimal\",\"maximumFractionDigits\":2,\"maximumSignificantDigits\":3}}},\"secondaryContent\":{\"columnMatch\":\"Trend\",\"formatter\":9,\"formatOptions\":{\"min\":0,\"palette\":\"blue\",\"showIcon\":true}},\"showBorder\":false}},\"name\":\"query - 5\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let nonInteractive = AADNonInteractiveUserSignInLogs\\r\\n| extend LocationDetails = parse_json(LocationDetails)\\r\\n| extend Status = parse_json(Status);\\r\\nlet data = \\r\\nunion SigninLogs,nonInteractive|where AppDisplayName in ({Apps}) or '*' in ({Apps})\\r\\n|where UserDisplayName in ({Users}) \\r\\n| extend ErrorCode = tostring(Status.errorCode) \\r\\n| extend FailureReason = tostring(Status.failureReason) \\r\\n| where ErrorCode !in (\\\"0\\\",\\\"50058\\\",\\\"50148\\\",\\\"50140\\\", \\\"51006\\\", \\\"50059\\\", \\\"65001\\\", \\\"52004\\\", \\\"50055\\\", \\\"50144\\\",\\\"50072\\\", \\\"50074\\\", \\\"16000\\\",\\\"16001\\\", \\\"16003\\\", \\\"50127\\\", \\\"50125\\\", \\\"50129\\\",\\\"50143\\\", \\\"81010\\\", \\\"81014\\\", \\\"81012\\\") \\r\\n|summarize errCount = count() by ErrorCode, tostring(FailureReason), Category| sort by errCount, Category\\r\\n|project ['❌ Error Code'] = ErrorCode, ['Reason']= FailureReason, ['Error Count'] = toint(errCount), Category\\r\\n|where Category in ({Category});\\r\\ndata\",\"size\":1,\"showAnalytics\":true,\"title\":\"Summary of top errors\",\"timeContext\":{\"durationMs\":1209600000},\"timeContextFromParameter\":\"TimeBrush\",\"exportFieldName\":\"❌ Error Code\",\"exportParameterName\":\"ErrorCode\",\"exportDefaultValue\":\"*\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"table\",\"gridSettings\":{\"formatters\":[{\"columnMatch\":\"Error Count\",\"formatter\":8,\"formatOptions\":{\"min\":0,\"palette\":\"orange\",\"showIcon\":true}}],\"filter\":true}},\"customWidth\":\"67\",\"showPin\":true,\"name\":\"query - 5\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let nonInteractive = AADNonInteractiveUserSignInLogs\\r\\n| extend LocationDetails = parse_json(LocationDetails)\\r\\n| extend Status = parse_json(Status)\\r\\n| extend DeviceDetail = parse_json(DeviceDetail)\\r\\n| extend ConditionalAccessPolicies = parse_json(ConditionalAccessPolicies);\\r\\nlet data=\\r\\nunion SigninLogs,nonInteractive\\r\\n|where AppDisplayName in ({Apps}) or '*' in ({Apps})\\r\\n|where UserDisplayName in ({Users}) \\r\\n| extend ErrorCode = tostring(Status.errorCode) \\r\\n| extend FailureReason = tostring(Status.failureReason) \\r\\n| where ErrorCode !in (\\\"0\\\",\\\"50058\\\",\\\"50148\\\",\\\"50140\\\", \\\"51006\\\", \\\"50059\\\", \\\"65001\\\", \\\"52004\\\", \\\"50055\\\", \\\"50144\\\",\\\"50072\\\", \\\"50074\\\", \\\"16000\\\",\\\"16001\\\", \\\"16003\\\", \\\"50127\\\", \\\"50125\\\", \\\"50129\\\",\\\"50143\\\", \\\"81010\\\", \\\"81014\\\", \\\"81012\\\") \\r\\n| where '{ErrorCode}' == '*' or '{ErrorCode}' == ErrorCode\\r\\n| top 200 by TimeGenerated desc\\r\\n| extend TimeFromNow = now() - TimeGenerated\\r\\n| extend TimeAgo = strcat(case(TimeFromNow < 2m, strcat(toint(TimeFromNow / 1m), ' seconds'), TimeFromNow < 2h, strcat(toint(TimeFromNow / 1m), ' minutes'), TimeFromNow < 2d, strcat(toint(TimeFromNow / 1h), ' hours'), strcat(toint(TimeFromNow / 1d), ' days')), ' ago')\\r\\n| project User = UserDisplayName, IPAddress, ['❌ Error Code'] = ErrorCode, ['Sign-in Time'] = TimeAgo, App = AppDisplayName, ['Error code'] = ErrorCode, ['Result type'] = ResultType, ['Result signature'] = ResultSignature, ['Result description'] = ResultDescription, ['Conditional access policies'] = ConditionalAccessPolicies, ['Conditional access status'] = ConditionalAccessStatus, ['Operating system'] = DeviceDetail.operatingSystem, Browser = DeviceDetail.browser, ['Country or region'] = LocationDetails.countryOrRegion, ['State'] = LocationDetails.state, ['City'] = LocationDetails.city, ['Time generated'] = TimeGenerated, Status, ['User principal name'] = UserPrincipalName, Category\\r\\n| where Category in ({Category});\\r\\ndata\\r\\n\\r\\n\\r\\n\",\"size\":1,\"showAnalytics\":true,\"title\":\"Sign-ins with errors\",\"timeContext\":{\"durationMs\":1209600000},\"timeContextFromParameter\":\"TimeBrush\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"table\",\"gridSettings\":{\"formatters\":[{\"columnMatch\":\"❌ Error Code\",\"formatter\":7,\"formatOptions\":{\"linkTarget\":\"GenericDetails\",\"showIcon\":true}},{\"columnMatch\":\"App\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Error code\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Result type\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Result signature\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Result description\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Conditional access policies\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Conditional access status\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Operating system\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Browser\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Country or region\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"State\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"City\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Time generated\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Status\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"User principal name\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}}],\"filter\":true}},\"customWidth\":\"33\",\"name\":\"query - 5 - Copy\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let nonInteractive = AADNonInteractiveUserSignInLogs\\r\\n| extend LocationDetails = parse_json(LocationDetails)\\r\\n| extend Status = parse_json(Status);\\r\\nlet data = \\r\\nunion SigninLogs,nonInteractive|where AppDisplayName in ({Apps}) or '*' in ({Apps})\\r\\n|where UserDisplayName in ({Users}) \\r\\n| extend ErrorCode = tostring(Status.errorCode) \\r\\n| extend FailureReason = Status.failureReason \\r\\n| where ErrorCode in (\\\"50058\\\",\\\"50140\\\", \\\"51006\\\", \\\"50059\\\", \\\"65001\\\", \\\"52004\\\", \\\"50055\\\", \\\"50144\\\",\\\"50072\\\", \\\"50074\\\", \\\"16000\\\",\\\"16001\\\", \\\"16003\\\", \\\"50127\\\", \\\"50125\\\", \\\"50129\\\",\\\"50143\\\", \\\"81010\\\", \\\"81014\\\", \\\"81012\\\") \\r\\n|summarize errCount = count() by ErrorCode, tostring(FailureReason), Category\\r\\n| sort by errCount\\r\\n|project ['❌ Error Code'] = ErrorCode, ['Reason'] = FailureReason, ['Interrupt Count'] = toint(errCount), Category\\r\\n| where Category in ({Category});\\r\\ndata\",\"size\":1,\"showAnalytics\":true,\"title\":\"Summary of sign-ins waiting on user action\",\"timeContext\":{\"durationMs\":1209600000},\"timeContextFromParameter\":\"TimeBrush\",\"exportFieldName\":\"❌ Error Code\",\"exportParameterName\":\"InterruptErrorCode\",\"exportDefaultValue\":\"*\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"gridSettings\":{\"formatters\":[{\"columnMatch\":\"Interrupt Count\",\"formatter\":8,\"formatOptions\":{\"min\":0,\"palette\":\"orange\"}}],\"filter\":true}},\"customWidth\":\"67\",\"showPin\":true,\"name\":\"query - 7\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let nonInteractive = AADNonInteractiveUserSignInLogs\\r\\n| extend LocationDetails = parse_json(LocationDetails)\\r\\n| extend ConditionalAccessPolicies = parse_json(ConditionalAccessPolicies)\\r\\n| extend DeviceDetail = parse_json(DeviceDetail)\\r\\n| extend Status = parse_json(Status);\\r\\nlet data = \\r\\nunion SigninLogs,nonInteractive \\r\\n|where AppDisplayName in ({Apps}) or '*' in ({Apps})\\r\\n|where UserDisplayName in ({Users}) \\r\\n| extend ErrorCode = tostring(Status.errorCode) \\r\\n| extend FailureReason = Status.failureReason \\r\\n| where ErrorCode in (\\\"50058\\\",\\\"50140\\\", \\\"51006\\\", \\\"50059\\\", \\\"65001\\\", \\\"52004\\\", \\\"50055\\\", \\\"50144\\\",\\\"50072\\\", \\\"50074\\\", \\\"16000\\\",\\\"16001\\\", \\\"16003\\\", \\\"50127\\\", \\\"50125\\\", \\\"50129\\\",\\\"50143\\\", \\\"81010\\\", \\\"81014\\\", \\\"81012\\\") \\r\\n| where '{InterruptErrorCode}' == '*' or '{InterruptErrorCode}' == ErrorCode\\r\\n| top 200 by TimeGenerated desc\\r\\n| extend TimeFromNow = now() - TimeGenerated\\r\\n| extend TimeAgo = strcat(case(TimeFromNow < 2m, strcat(toint(TimeFromNow / 1m), ' seconds'), TimeFromNow < 2h, strcat(toint(TimeFromNow / 1m), ' minutes'), TimeFromNow < 2d, strcat(toint(TimeFromNow / 1h), ' hours'), strcat(toint(TimeFromNow / 1d), ' days')), ' ago')\\r\\n| project User = UserDisplayName, IPAddress, ['❌ Error Code'] = ErrorCode, ['Sign-in Time'] = TimeAgo, App = AppDisplayName, ['Error code'] = ErrorCode, ['Result type'] = ResultType, ['Result signature'] = ResultSignature, ['Result description'] = ResultDescription, ['Conditional access policies'] = ConditionalAccessPolicies, ['Conditional access status'] = ConditionalAccessStatus, ['Operating system'] = DeviceDetail.operatingSystem, Browser = DeviceDetail.browser, ['Country or region'] = LocationDetails.countryOrRegion, ['State'] = LocationDetails.state, ['City'] = LocationDetails.city, ['Time generated'] = TimeGenerated, Status, ['User principal name'] = UserPrincipalName, Category\\r\\n| where Category in ({Category});\\r\\ndata\\r\\n\\r\\n\",\"size\":1,\"showAnalytics\":true,\"title\":\"Sign-ins waiting on user action\",\"timeContext\":{\"durationMs\":1209600000},\"timeContextFromParameter\":\"TimeBrush\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"gridSettings\":{\"formatters\":[{\"columnMatch\":\"❌ Error Code\",\"formatter\":7,\"formatOptions\":{\"linkTarget\":\"GenericDetails\",\"showIcon\":true}},{\"columnMatch\":\"App\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Error code\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Result type\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Result signature\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Result description\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Conditional access policies\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Conditional access status\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Operating system\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Browser\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Country or region\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"State\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"City\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Time generated\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Status\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"User principal name\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}}],\"filter\":true}},\"customWidth\":\"33\",\"showPin\":true,\"name\":\"query - 7 - Copy\"}],\"fromTemplateId\":\"sentinel-AzureActiveDirectorySigninLogs\",\"$schema\":\"https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json\"}\r\n", - "version": "1.0", - "sourceId": "[variables('workspaceResourceId')]", - "category": "sentinel" - } }, { - "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", - "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('Workbook-', last(split(variables('workbookId2'),'/'))))]", + "type": "Microsoft.Logic/workflows", + "apiVersion": "2017-07-01", + "name": "[[parameters('PlaybookName')]", + "location": "[[variables('workspace-location-inline')]", + "tags": { + "LogicAppsCategory": "security", + "hidden-SentinelTemplateName": "Block-AADUser_alert", + "hidden-SentinelTemplateVersion": "1.1", + "hidden-SentinelWorkspaceId": "[[variables('workspaceResourceId')]" + }, + "identity": { + "type": "SystemAssigned" + }, + "dependsOn": [ + "[[resourceId('Microsoft.Web/connections', variables('AzureADConnectionName'))]", + "[[resourceId('Microsoft.Web/connections', variables('MicrosoftSentinelConnectionName'))]", + "[[resourceId('Microsoft.Web/connections', variables('Office365ConnectionName'))]" + ], "properties": { - "description": "@{workbookKey=AzureActiveDirectorySigninLogsWorkbook; logoFileName=azureactivedirectory_logo.svg; description=Gain insights into Azure Active Directory by connecting Microsoft Sentinel and using the sign-in logs to gather insights around Azure AD scenarios. \nYou can learn about sign-in operations, such as user sign-ins and locations, email addresses, and IP addresses of your users, as well as failed activities and the errors that triggered the failures.; dataTypesDependencies=System.Object[]; dataConnectorsDependencies=System.Object[]; previewImagesFileNames=System.Object[]; version=2.4.0; title=Azure AD Sign-in logs; templateRelativePath=AzureActiveDirectorySignins.json; subtitle=; provider=Microsoft}.description", - "parentId": "[variables('workbookId2')]", - "contentId": "[variables('_workbookContentId2')]", - "kind": "Workbook", - "version": "[variables('workbookVersion2')]", - "source": { - "kind": "Solution", - "name": "Azure Active Directory", - "sourceId": "[variables('_solutionId')]" - }, - "author": { - "name": "Microsoft", - "email": "[variables('_email')]" - }, - "support": { - "tier": "Microsoft", - "name": "Microsoft Corporation", - "email": "support@microsoft.com", - "link": "https://support.microsoft.com/" - }, - "dependencies": { - "operator": "AND", - "criteria": [ - { - "contentId": "SigninLogs", - "kind": "DataType" - }, - { - "contentId": "AzureActiveDirectory", - "kind": "DataConnector" + "state": "Enabled", + "definition": { + "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "$connections": { + "type": "Object" } - ] - } - } - } - ] - }, - "packageKind": "Solution", - "packageVersion": "[variables('_solutionVersion')]", - "packageName": "[variables('_solutionName')]", - "packageId": "[variables('_solutionId')]", - "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_workbookContentId2')]", - "contentKind": "Workbook", - "displayName": "[parameters('workbook2-name')]", - "contentProductId": "[variables('_workbookcontentProductId2')]", - "id": "[variables('_workbookcontentProductId2')]", - "version": "[variables('workbookVersion2')]" - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", - "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName1')]", - "location": "[parameters('workspace-location')]", - "dependsOn": [ - "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" - ], - "properties": { - "description": "AccountCreatedandDeletedinShortTimeframe_AnalyticalRules Analytics Rule with template version 3.0.4", - "mainTemplate": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion1')]", - "parameters": {}, - "variables": {}, - "resources": [ - { - "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId1')]", - "apiVersion": "2022-04-01-preview", - "kind": "Scheduled", - "location": "[parameters('workspace-location')]", - "properties": { - "description": "Search for user principal name (UPN) events. Look for accounts created and then deleted in under 24 hours. Attackers may create an account for their use, and then remove the account when no longer needed.\nRef : https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-user-accounts#short-lived-account", - "displayName": "Account Created and Deleted in Short Timeframe", - "enabled": false, - "query": "let queryfrequency = 1h;\nlet queryperiod = 1d;\nAuditLogs\n| where TimeGenerated > ago(queryfrequency)\n| where OperationName =~ \"Delete user\"\n//extend UserPrincipalName = tostring(TargetResources[0].userPrincipalName)\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type == \"User\"\n | extend UserPrincipalName = extract(@'([a-f0-9]{32})?(.*)', 2, tostring(TargetResource.userPrincipalName))\n )\n| extend DeletedByUser = tostring(InitiatedBy.user.userPrincipalName), DeletedByIPAddress = tostring(InitiatedBy.user.ipAddress)\n| extend DeletedByApp = tostring(InitiatedBy.app.displayName)\n| project Deletion_TimeGenerated = TimeGenerated, UserPrincipalName, DeletedByUser, DeletedByIPAddress, DeletedByApp, Deletion_AdditionalDetails = AdditionalDetails, Deletion_InitiatedBy = InitiatedBy, Deletion_TargetResources = TargetResources\n| join kind=inner (\n AuditLogs\n | where TimeGenerated > ago(queryperiod)\n | where OperationName =~ \"Add user\" \n | mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type == \"User\"\n | extend UserPrincipalName = trim(@'\"',tostring(TargetResource.userPrincipalName))\n )\n | project-rename Creation_TimeGenerated = TimeGenerated\n) on UserPrincipalName\n| extend TimeDelta = Deletion_TimeGenerated - Creation_TimeGenerated\n| where TimeDelta between (time(0s) .. queryperiod)\n| extend CreatedByUser = tostring(InitiatedBy.user.userPrincipalName), CreatedByIPAddress = tostring(InitiatedBy.user.ipAddress)\n| extend CreatedByApp = tostring(InitiatedBy.app.displayName)\n| project Creation_TimeGenerated, Deletion_TimeGenerated, TimeDelta, UserPrincipalName, DeletedByUser, DeletedByIPAddress, DeletedByApp, CreatedByUser, CreatedByIPAddress, CreatedByApp, Creation_AdditionalDetails = AdditionalDetails, Creation_InitiatedBy = InitiatedBy, Creation_TargetResources = TargetResources, Deletion_AdditionalDetails, Deletion_InitiatedBy, Deletion_TargetResources\n| extend timestamp = Deletion_TimeGenerated, Name = tostring(split(UserPrincipalName,'@',0)[0]), UPNSuffix = tostring(split(UserPrincipalName,'@',1)[0])\n", - "queryFrequency": "PT1H", - "queryPeriod": "P1D", - "severity": "High", - "suppressionDuration": "PT1H", - "suppressionEnabled": false, - "triggerOperator": "GreaterThan", - "triggerThreshold": 0, - "status": "Available", - "requiredDataConnectors": [ - { - "dataTypes": [ - "SigninLogs" - ], - "connectorId": "AzureActiveDirectory" - } - ], - "tactics": [ - "InitialAccess" - ], - "techniques": [ - "T1078" - ], - "entityMappings": [ - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "Name" - }, - { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" + }, + "triggers": { + "Microsoft_Sentinel_alert": { + "type": "ApiConnectionWebhook", + "inputs": { + "body": { + "callback_url": "@{listCallbackUrl()}" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" + } + }, + "path": "/subscribe" } - ] + } }, - { - "entityType": "IP", - "fieldMappings": [ - { - "identifier": "Address", - "columnName": "DeletedByIPAddress" + "actions": { + "Alert_-_Get_incident": { + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" + } + }, + "method": "get", + "path": "/Incidents/subscriptions/@{encodeURIComponent(triggerBody()?['WorkspaceSubscriptionId'])}/resourceGroups/@{encodeURIComponent(triggerBody()?['WorkspaceResourceGroup'])}/workspaces/@{encodeURIComponent(triggerBody()?['WorkspaceId'])}/alerts/@{encodeURIComponent(triggerBody()?['SystemAlertId'])}" } - ] - } - ] - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", - "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId1'),'/'))))]", - "properties": { - "description": "Azure Active Directory Analytics Rule 1", - "parentId": "[variables('analyticRuleId1')]", - "contentId": "[variables('_analyticRulecontentId1')]", - "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion1')]", - "source": { - "kind": "Solution", - "name": "Azure Active Directory", - "sourceId": "[variables('_solutionId')]" - }, - "author": { - "name": "Microsoft", - "email": "[variables('_email')]" - }, - "support": { - "tier": "Microsoft", - "name": "Microsoft Corporation", - "email": "support@microsoft.com", - "link": "https://support.microsoft.com/" - } - } - } - ] - }, - "packageKind": "Solution", - "packageVersion": "[variables('_solutionVersion')]", - "packageName": "[variables('_solutionName')]", - "packageId": "[variables('_solutionId')]", - "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId1')]", - "contentKind": "AnalyticsRule", - "displayName": "Account Created and Deleted in Short Timeframe", - "contentProductId": "[variables('_analyticRulecontentProductId1')]", - "id": "[variables('_analyticRulecontentProductId1')]", - "version": "[variables('analyticRuleVersion1')]" - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", - "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName2')]", - "location": "[parameters('workspace-location')]", - "dependsOn": [ - "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" - ], - "properties": { - "description": "AccountCreatedDeletedByNonApprovedUser_AnalyticalRules Analytics Rule with template version 3.0.4", - "mainTemplate": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion2')]", - "parameters": {}, - "variables": {}, - "resources": [ - { - "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId2')]", - "apiVersion": "2022-04-01-preview", - "kind": "Scheduled", - "location": "[parameters('workspace-location')]", - "properties": { - "description": "Identifies accounts that were created or deleted by a defined list of non-approved user principal names. Add to this list before running the query for accurate results.\nRef : https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-user-accounts", - "displayName": "Account created or deleted by non-approved user", - "enabled": false, - "query": "// Add non-approved user principal names to the list below to search for their account creation/deletion activity\n// ex: dynamic([\"UPN1\", \"upn123\"])\nlet nonapproved_users = dynamic([]);\nAuditLogs\n| where OperationName =~ \"Add user\" or OperationName =~ \"Delete user\"\n| where Result =~ \"success\"\n| extend InitiatingUser = tostring(InitiatedBy.user.userPrincipalName)\n| where InitiatingUser has_any (nonapproved_users)\n| project-reorder TimeGenerated, ResourceId, OperationName, InitiatingUser, TargetResources\n| extend InitiatedUserIpAddress = tostring(InitiatedBy.user.ipAddress)\n| extend Name = tostring(split(InitiatingUser,'@',0)[0]), UPNSuffix = tostring(split(InitiatingUser,'@',1)[0])\n", - "queryFrequency": "P1D", - "queryPeriod": "P1D", - "severity": "Medium", - "suppressionDuration": "PT1H", - "suppressionEnabled": false, - "triggerOperator": "GreaterThan", - "triggerThreshold": 0, - "status": "Available", - "requiredDataConnectors": [ - { - "dataTypes": [ - "AuditLogs" - ], - "connectorId": "AzureActiveDirectory" - } - ], - "tactics": [ - "InitialAccess" - ], - "techniques": [ - "T1078" - ], - "entityMappings": [ - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "Name" + }, + "Entities_-_Get_Accounts": { + "runAfter": { + "Alert_-_Get_incident": [ + "Succeeded" + ] }, - { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" - } - ] - }, - { - "entityType": "IP", - "fieldMappings": [ - { - "identifier": "Address", - "columnName": "InitiatedUserIpAddress" + "type": "ApiConnection", + "inputs": { + "body": "@triggerBody()?['Entities']", + "host": { + "connection": { + "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" + } + }, + "method": "post", + "path": "/entities/account" } - ] - } - ] + }, + "For_each": { + "foreach": "@body('Entities_-_Get_Accounts')?['Accounts']", + "actions": { + "Condition": { + "actions": { + "Condition_-_if_user_have_manager": { + "actions": { + "Add_comment_to_incident_-_with_manager_-_no_admin": { + "runAfter": { + "Get_user_-_details": [ + "Succeeded" + ] + }, + "type": "ApiConnection", + "inputs": { + "body": { + "incidentArmId": "@body('Alert_-_Get_incident')?['id']", + "message": "

User @{items('For_each')?['Name']} (UPN - @{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])}) was disabled in AAD via playbook Block-AADUser. Manager (@{body('Parse_JSON_-_get_user_manager')?['userPrincipalName']}) is notified.

" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" + } + }, + "method": "post", + "path": "/Incidents/Comment" + } + }, + "Get_user_-_details": { + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['azuread']['connectionId']" + } + }, + "method": "get", + "path": "/v1.0/users/@{encodeURIComponent(concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix']))}" + } + }, + "Send_an_email_-_to_manager_-_no_admin": { + "runAfter": { + "Add_comment_to_incident_-_with_manager_-_no_admin": [ + "Succeeded" + ] + }, + "type": "ApiConnection", + "inputs": { + "body": { + "Body": "

Security notification! This is automated email sent by Microsoft Sentinel Automation!
\n
\nYour direct report @{items('For_each')?['Name']} has been disabled in Azure AD due to the security incident. Can you please notify the user and work with him to reach our support.
\n
\nDirect report details:
\nFirst name: @{body('Get_user_-_details')?['displayName']}
\nSurname: @{body('Get_user_-_details')?['surname']}
\nJob title: @{body('Get_user_-_details')?['jobTitle']}
\nOffice location: @{body('Get_user_-_details')?['officeLocation']}
\nBusiness phone: @{body('Get_user_-_details')?['businessPhones']}
\nMobile phone: @{body('Get_user_-_details')?['mobilePhone']}
\nMail: @{body('Get_user_-_details')?['mail']}
\n
\nThank you!

", + "Importance": "High", + "Subject": "@{items('For_each')?['Name']} has been disabled in Azure AD due to the security risk!", + "To": "@body('Parse_JSON_-_get_user_manager')?['userPrincipalName']" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['office365']['connectionId']" + } + }, + "method": "post", + "path": "/v2/Mail" + } + } + }, + "runAfter": { + "Parse_JSON_-_get_user_manager": [ + "Succeeded" + ] + }, + "else": { + "actions": { + "Add_comment_to_incident_-_no_manager_-_no_admin": { + "type": "ApiConnection", + "inputs": { + "body": { + "incidentArmId": "@body('Alert_-_Get_incident')?['id']", + "message": "

User @{items('For_each')?['Name']} (UPN - @{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])}) was disabled in AAD via playbook Block-AADUser. Manager has not been notified, since it is not found for this user!

" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" + } + }, + "method": "post", + "path": "/Incidents/Comment" + } + } + } + }, + "expression": { + "and": [ + { + "not": { + "equals": [ + "@body('Parse_JSON_-_get_user_manager')?['userPrincipalName']", + "@null" + ] + } + } + ] + }, + "type": "If" + }, + "HTTP_-_get_user_manager": { + "type": "Http", + "inputs": { + "authentication": { + "audience": "https://graph.microsoft.com/", + "type": "ManagedServiceIdentity" + }, + "method": "GET", + "uri": "https://graph.microsoft.com/v1.0/users/@{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])}/manager" + } + }, + "Parse_JSON_-_get_user_manager": { + "runAfter": { + "HTTP_-_get_user_manager": [ + "Succeeded", + "Failed" + ] + }, + "type": "ParseJson", + "inputs": { + "content": "@body('HTTP_-_get_user_manager')", + "schema": { + "properties": { + "userPrincipalName": { + "type": "string" + } + }, + "type": "object" + } + } + } + }, + "runAfter": { + "Update_user_-_disable_user": [ + "Succeeded", + "Failed" + ] + }, + "else": { + "actions": { + "Add_comment_to_incident_-_error_details": { + "type": "ApiConnection", + "inputs": { + "body": { + "incidentArmId": "@body('Alert_-_Get_incident')?['id']", + "message": "

Block-AADUser playbook could not disable user @{items('For_each')?['Name']}.
\nError message: @{body('Update_user_-_disable_user')['error']['message']}
\nNote: If user is admin, this playbook don't have privilages to block admin users!

" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" + } + }, + "method": "post", + "path": "/Incidents/Comment" + } + } + } + }, + "expression": { + "and": [ + { + "equals": [ + "@body('Update_user_-_disable_user')", + "@null" + ] + } + ] + }, + "type": "If" + }, + "Update_user_-_disable_user": { + "type": "ApiConnection", + "inputs": { + "body": { + "accountEnabled": false + }, + "host": { + "connection": { + "name": "@parameters('$connections')['azuread']['connectionId']" + } + }, + "method": "patch", + "path": "/v1.0/users/@{encodeURIComponent(concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix']))}" + } + } + }, + "runAfter": { + "Entities_-_Get_Accounts": [ + "Succeeded" + ] + }, + "type": "Foreach" + } + } + }, + "parameters": { + "$connections": { + "value": { + "azuread": { + "connectionId": "[[resourceId('Microsoft.Web/connections', variables('AzureADConnectionName'))]", + "connectionName": "[[variables('AzureADConnectionName')]", + "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuread')]" + }, + "microsoftsentinel": { + "connectionId": "[[resourceId('Microsoft.Web/connections', variables('MicrosoftSentinelConnectionName'))]", + "connectionName": "[[variables('MicrosoftSentinelConnectionName')]", + "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", + "connectionProperties": { + "authentication": { + "type": "ManagedServiceIdentity" + } + } + }, + "office365": { + "connectionId": "[[resourceId('Microsoft.Web/connections', variables('Office365ConnectionName'))]", + "connectionName": "[[variables('Office365ConnectionName')]", + "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]" + } + } + } + } } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId2'),'/'))))]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('Playbook-', last(split(variables('playbookId1'),'/'))))]", "properties": { - "description": "Azure Active Directory Analytics Rule 2", - "parentId": "[variables('analyticRuleId2')]", - "contentId": "[variables('_analyticRulecontentId2')]", - "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion2')]", + "parentId": "[variables('playbookId1')]", + "contentId": "[variables('_playbookContentId1')]", + "kind": "Playbook", + "version": "[variables('playbookVersion1')]", "source": { "kind": "Solution", "name": "Azure Active Directory", @@ -1300,711 +917,453 @@ } } } - ] - }, - "packageKind": "Solution", - "packageVersion": "[variables('_solutionVersion')]", - "packageName": "[variables('_solutionName')]", - "packageId": "[variables('_solutionId')]", - "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId2')]", - "contentKind": "AnalyticsRule", - "displayName": "Account created or deleted by non-approved user", - "contentProductId": "[variables('_analyticRulecontentProductId2')]", - "id": "[variables('_analyticRulecontentProductId2')]", - "version": "[variables('analyticRuleVersion2')]" - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", - "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName3')]", - "location": "[parameters('workspace-location')]", - "dependsOn": [ - "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" - ], - "properties": { - "description": "ADFSDomainTrustMods_AnalyticalRules Analytics Rule with template version 3.0.4", - "mainTemplate": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion3')]", - "parameters": {}, - "variables": {}, - "resources": [ - { - "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId3')]", - "apiVersion": "2022-04-01-preview", - "kind": "Scheduled", - "location": "[parameters('workspace-location')]", - "properties": { - "description": "This will alert when a user or application modifies the federation settings on the domain or Update domain authentication from Managed to Federated.\nFor example, this alert will trigger when a new Active Directory Federated Service (ADFS) TrustedRealm object, such as a signing certificate, is added to the domain.\nModification to domain federation settings should be rare. Confirm the added or modified target domain/URL is legitimate administrator behavior.\nTo understand why an authorized user may update settings for a federated domain in Office 365, Azure, or Intune, see: https://docs.microsoft.com/office365/troubleshoot/active-directory/update-federated-domain-office-365.\nFor details on security realms that accept security tokens, see the ADFS Proxy Protocol (MS-ADFSPP) specification: https://docs.microsoft.com/openspecs/windows_protocols/ms-adfspp/e7b9ea73-1980-4318-96a6-da559486664b.\nFor further information on AuditLogs please see https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-audit-activities.", - "displayName": "Modified domain federation trust settings", - "enabled": false, - "query": "(union isfuzzy=true\n(\nAuditLogs\n| where OperationName =~ \"Set federation settings on domain\"\n//| where Result =~ \"success\" // commenting out, as it may be interesting to capture failed attempts\n| mv-expand TargetResources\n| extend modifiedProperties = parse_json(TargetResources).modifiedProperties\n| mv-expand modifiedProperties\n| extend targetDisplayName = tostring(parse_json(modifiedProperties).displayName)\n),\n(\nAuditLogs\n| where OperationName =~ \"Set domain authentication\"\n//| where Result =~ \"success\" // commenting out, as it may be interesting to capture failed attempts\n| mv-expand TargetResources\n| extend modifiedProperties = parse_json(TargetResources).modifiedProperties\n| mv-expand modifiedProperties\n| mv-apply Property = modifiedProperties on \n (\n where Property.displayName =~ \"LiveType\"\n | extend targetDisplayName = tostring(Property.displayName),\n NewDomainValue = tostring(Property.newValue)\n )\n| where NewDomainValue has \"Federated\"\n)\n)\n| mv-apply AdditionalDetail = AdditionalDetails on \n (\n where AdditionalDetail.key =~ \"User-Agent\"\n | extend UserAgent = tostring(AdditionalDetail.value)\n )\n| extend InitiatingUserOrApp = iff(isnotempty(InitiatedBy.user.userPrincipalName),tostring(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.app.displayName))\n| extend InitiatingIpAddress = iff(isnotempty(InitiatedBy.user.ipAddress), tostring(InitiatedBy.user.ipAddress), tostring(InitiatedBy.app.ipAddress))\n| project-reorder TimeGenerated, OperationName, InitiatingUserOrApp, AADOperationType, targetDisplayName, Result, InitiatingIpAddress, UserAgent, CorrelationId, TenantId, AADTenantId\n| extend timestamp = TimeGenerated, Name = tostring(split(InitiatingUserOrApp,'@',0)[0]), UPNSuffix = tostring(split(InitiatingUserOrApp,'@',1)[0])\n", - "queryFrequency": "P1D", - "queryPeriod": "P1D", - "severity": "High", - "suppressionDuration": "PT1H", - "suppressionEnabled": false, - "triggerOperator": "GreaterThan", - "triggerThreshold": 0, - "status": "Available", - "requiredDataConnectors": [ - { - "dataTypes": [ - "AuditLogs" - ], - "connectorId": "AzureActiveDirectory" - } - ], - "tactics": [ - "CredentialAccess" - ], - "entityMappings": [ - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "Name" - }, - { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" - } - ] - }, - { - "entityType": "IP", - "fieldMappings": [ - { - "identifier": "Address", - "columnName": "InitiatingIpAddress" - } - ] - } + ], + "metadata": { + "title": "Block AAD user - Alert", + "description": "For each account entity included in the alert, this playbook will disable the user in Azure Active Directoy, add a comment to the incident that contains this alert and notify manager if available. Note: This playbook will not disable admin user!", + "prerequisites": [ + "None" + ], + "postDeployment": [ + "1. Assign Microsoft Sentinel Responder role to the Playbook's managed identity.", + "2. Grant User.Read.All, User.ReadWrite.All, Directory.Read.All, Directory.ReadWrite.All permissions to the managed identity.", + "3. Authorize Azure AD and Office 365 Outlook Logic App connections." + ], + "lastUpdateTime": "2022-07-11T00:00:00Z", + "entities": [ + "Account" + ], + "tags": [ + "Remediation" + ], + "releaseNotes": [ + { + "version": "1.0.0", + "title": "Added manager notification action", + "notes": [ + "Initial version" ] } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", - "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId3'),'/'))))]", - "properties": { - "description": "Azure Active Directory Analytics Rule 3", - "parentId": "[variables('analyticRuleId3')]", - "contentId": "[variables('_analyticRulecontentId3')]", - "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion3')]", - "source": { - "kind": "Solution", - "name": "Azure Active Directory", - "sourceId": "[variables('_solutionId')]" - }, - "author": { - "name": "Microsoft", - "email": "[variables('_email')]" - }, - "support": { - "tier": "Microsoft", - "name": "Microsoft Corporation", - "email": "support@microsoft.com", - "link": "https://support.microsoft.com/" - } - } - } - ] + ] + } }, "packageKind": "Solution", "packageVersion": "[variables('_solutionVersion')]", "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId3')]", - "contentKind": "AnalyticsRule", - "displayName": "Modified domain federation trust settings", - "contentProductId": "[variables('_analyticRulecontentProductId3')]", - "id": "[variables('_analyticRulecontentProductId3')]", - "version": "[variables('analyticRuleVersion3')]" + "contentId": "[variables('_playbookContentId1')]", + "contentKind": "Playbook", + "displayName": "Block-AADUser-Alert", + "contentProductId": "[variables('_playbookcontentProductId1')]", + "id": "[variables('_playbookcontentProductId1')]", + "version": "[variables('playbookVersion1')]" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName4')]", + "name": "[variables('playbookTemplateSpecName2')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "ADFSSignInLogsPasswordSpray_AnalyticalRules Analytics Rule with template version 3.0.4", + "description": "Block-AADUser-EntityTrigger Playbook with template version 3.0.5", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion4')]", - "parameters": {}, - "variables": {}, + "contentVersion": "[variables('playbookVersion2')]", + "parameters": { + "PlaybookName": { + "defaultValue": "Block-AADUser-EntityTrigger", + "type": "string" + } + }, + "variables": { + "AzureADConnectionName": "[[concat('azuread-', parameters('PlaybookName'))]", + "MicrosoftSentinelConnectionName": "[[concat('microsoftsentinel-', parameters('PlaybookName'))]", + "Office365ConnectionName": "[[concat('office365-', parameters('PlaybookName'))]", + "connection-1": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuread')]", + "_connection-1": "[[variables('connection-1')]", + "connection-2": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", + "_connection-2": "[[variables('connection-2')]", + "connection-3": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]", + "_connection-3": "[[variables('connection-3')]", + "workspace-location-inline": "[concat('[resourceGroup().locatio', 'n]')]", + "workspace-name": "[parameters('workspace')]", + "workspaceResourceId": "[[resourceId('microsoft.OperationalInsights/Workspaces', variables('workspace-name'))]" + }, "resources": [ { - "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId4')]", - "apiVersion": "2022-04-01-preview", - "kind": "Scheduled", - "location": "[parameters('workspace-location')]", + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[[variables('AzureADConnectionName')]", + "location": "[[variables('workspace-location-inline')]", "properties": { - "description": "Identifies evidence of password spray activity against Connect Health for AD FS sign-in events by looking for failures from multiple accounts from the same IP address within a time window.\nReference: https://adfshelp.microsoft.com/References/ConnectHealthErrorCodeReference", - "displayName": "Password spray attack against ADFSSignInLogs", - "enabled": false, - "query": "let queryfrequency = 30m;\nlet accountthreshold = 10;\nlet successCodes = dynamic([0, 50144]);\nADFSSignInLogs\n| extend IngestionTime = ingestion_time()\n| where IngestionTime > ago(queryfrequency)\n| where not(todynamic(AuthenticationDetails)[0].authenticationMethod == \"Integrated Windows Authentication\")\n| summarize\n DistinctFailureCount = dcountif(UserPrincipalName, ResultType !in (successCodes)),\n DistinctSuccessCount = dcountif(UserPrincipalName, ResultType in (successCodes)),\n SuccessAccounts = make_set_if(UserPrincipalName, ResultType in (successCodes), 250),\n arg_min(TimeGenerated, *)\n by IPAddress\n| where DistinctFailureCount > DistinctSuccessCount and DistinctFailureCount >= accountthreshold\n//| extend SuccessAccounts = iff(array_length(SuccessAccounts) != 0, SuccessAccounts, dynamic([\"null\"]))\n//| mv-expand SuccessAccounts\n| project TimeGenerated, Category, OperationName, IPAddress, DistinctFailureCount, DistinctSuccessCount, SuccessAccounts, AuthenticationRequirement, ConditionalAccessStatus, IsInteractive, UserAgent, NetworkLocationDetails, DeviceDetail, TokenIssuerType, TokenIssuerName, ResourceIdentity\n", - "queryFrequency": "PT30M", - "queryPeriod": "PT1H", - "severity": "Medium", - "suppressionDuration": "PT1H", - "suppressionEnabled": false, - "triggerOperator": "GreaterThan", - "triggerThreshold": 0, - "status": "Available", - "requiredDataConnectors": [ - { - "dataTypes": [ - "ADFSSignInLogs" - ], - "connectorId": "AzureActiveDirectory" - } - ], - "tactics": [ - "CredentialAccess" - ], - "techniques": [ - "T1110" - ], - "entityMappings": [ - { - "entityType": "IP", - "fieldMappings": [ - { - "identifier": "Address", - "columnName": "IPAddress" - } - ] - } - ] + "displayName": "[[variables('AzureADConnectionName')]", + "api": { + "id": "[[variables('_connection-1')]" + } } }, { - "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", - "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId4'),'/'))))]", + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[[variables('MicrosoftSentinelConnectionName')]", + "location": "[[variables('workspace-location-inline')]", + "kind": "V1", "properties": { - "description": "Azure Active Directory Analytics Rule 4", - "parentId": "[variables('analyticRuleId4')]", - "contentId": "[variables('_analyticRulecontentId4')]", - "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion4')]", - "source": { - "kind": "Solution", - "name": "Azure Active Directory", - "sourceId": "[variables('_solutionId')]" - }, - "author": { - "name": "Microsoft", - "email": "[variables('_email')]" - }, - "support": { - "tier": "Microsoft", - "name": "Microsoft Corporation", - "email": "support@microsoft.com", - "link": "https://support.microsoft.com/" + "displayName": "[[variables('MicrosoftSentinelConnectionName')]", + "parameterValueType": "Alternative", + "api": { + "id": "[[variables('_connection-2')]" } } - } - ] - }, - "packageKind": "Solution", - "packageVersion": "[variables('_solutionVersion')]", - "packageName": "[variables('_solutionName')]", - "packageId": "[variables('_solutionId')]", - "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId4')]", - "contentKind": "AnalyticsRule", - "displayName": "Password spray attack against ADFSSignInLogs", - "contentProductId": "[variables('_analyticRulecontentProductId4')]", - "id": "[variables('_analyticRulecontentProductId4')]", - "version": "[variables('analyticRuleVersion4')]" - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", - "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName5')]", - "location": "[parameters('workspace-location')]", - "dependsOn": [ - "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" - ], - "properties": { - "description": "AdminPromoAfterRoleMgmtAppPermissionGrant_AnalyticalRules Analytics Rule with template version 3.0.4", - "mainTemplate": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion5')]", - "parameters": {}, - "variables": {}, - "resources": [ - { - "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId5')]", - "apiVersion": "2022-04-01-preview", - "kind": "Scheduled", - "location": "[parameters('workspace-location')]", - "properties": { - "description": "This rule looks for a service principal being granted the Microsoft Graph RoleManagement.ReadWrite.Directory (application) permission before being used to add an Azure AD object or user account to an Admin directory role (i.e. Global Administrators).\nThis is a known attack path that is usually abused when a service principal already has the AppRoleAssignment.ReadWrite.All permission granted. This permission allows an app to manage permission grants for application permissions to any API.\nA service principal can promote itself or other service principals to admin roles (i.e. Global Administrators). This would be considered a privilege escalation technique.\nRef : https://docs.microsoft.com/graph/permissions-reference#role-management-permissions, https://docs.microsoft.com/graph/api/directoryrole-post-members?view=graph-rest-1.0&tabs=http", - "displayName": "Admin promotion after Role Management Application Permission Grant", - "enabled": false, - "query": "let query_frequency = 1h;\nlet query_period = 2h;\nAuditLogs\n| where TimeGenerated > ago(query_period)\n| where Category =~ \"ApplicationManagement\" and LoggedByService =~ \"Core Directory\"\n| where OperationName =~ \"Add app role assignment to service principal\"\n| mv-expand TargetResource = TargetResources\n| mv-expand modifiedProperty = TargetResource[\"modifiedProperties\"]\n| where tostring(modifiedProperty[\"displayName\"]) == \"AppRole.Value\"\n| extend PermissionGrant = tostring(modifiedProperty[\"newValue\"])\n| where PermissionGrant has \"RoleManagement.ReadWrite.Directory\"\n| mv-apply modifiedProperty = TargetResource[\"modifiedProperties\"] on (\n summarize modifiedProperties = make_bag(\n bag_pack(tostring(modifiedProperty[\"displayName\"]),\n bag_pack(\"oldValue\", trim(@'[\\\"\\s]+', tostring(modifiedProperty[\"oldValue\"])),\n \"newValue\", trim(@'[\\\"\\s]+', tostring(modifiedProperty[\"newValue\"])))), 100)\n)\n| project\n PermissionGrant_TimeGenerated = TimeGenerated,\n PermissionGrant_OperationName = OperationName,\n PermissionGrant_Result = Result,\n PermissionGrant,\n AppDisplayName = tostring(modifiedProperties[\"ServicePrincipal.DisplayName\"][\"newValue\"]),\n AppServicePrincipalId = tostring(modifiedProperties[\"ServicePrincipal.ObjectID\"][\"newValue\"]),\n PermissionGrant_InitiatedBy = InitiatedBy,\n PermissionGrant_TargetResources = TargetResources,\n PermissionGrant_AdditionalDetails = AdditionalDetails,\n PermissionGrant_CorrelationId = CorrelationId\n| join kind=inner (\n AuditLogs\n | where TimeGenerated > ago(query_frequency)\n | where Category =~ \"RoleManagement\" and LoggedByService =~ \"Core Directory\" and AADOperationType =~ \"Assign\"\n | where isnotempty(InitiatedBy[\"app\"])\n | mv-expand TargetResource = TargetResources\n | mv-expand modifiedProperty = TargetResource[\"modifiedProperties\"]\n | where tostring(modifiedProperty[\"displayName\"]) in (\"Role.DisplayName\", \"RoleDefinition.DisplayName\")\n | extend RoleAssignment = tostring(modifiedProperty[\"newValue\"])\n | where RoleAssignment contains \"Admin\"\n | project\n RoleAssignment_TimeGenerated = TimeGenerated,\n RoleAssignment_OperationName = OperationName,\n RoleAssignment_Result = Result,\n RoleAssignment,\n TargetType = tostring(TargetResources[0][\"type\"]),\n Target = iff(isnotempty(TargetResources[0][\"displayName\"]), tostring(TargetResources[0][\"displayName\"]), tolower(TargetResources[0][\"userPrincipalName\"])),\n TargetId = tostring(TargetResources[0][\"id\"]),\n RoleAssignment_InitiatedBy = InitiatedBy,\n RoleAssignment_TargetResources = TargetResources,\n RoleAssignment_AdditionalDetails = AdditionalDetails,\n RoleAssignment_CorrelationId = CorrelationId,\n AppServicePrincipalId = tostring(InitiatedBy[\"app\"][\"servicePrincipalId\"])\n ) on AppServicePrincipalId\n| where PermissionGrant_TimeGenerated < RoleAssignment_TimeGenerated\n| extend\n TargetName = tostring(split(Target, \"@\")[0]),\n TargetUPNSuffix = tostring(split(Target, \"@\")[1])\n| project PermissionGrant_TimeGenerated, PermissionGrant_OperationName, PermissionGrant_Result, PermissionGrant, AppDisplayName, AppServicePrincipalId, PermissionGrant_InitiatedBy, PermissionGrant_TargetResources, PermissionGrant_AdditionalDetails, PermissionGrant_CorrelationId, RoleAssignment_TimeGenerated, RoleAssignment_OperationName, RoleAssignment_Result, RoleAssignment, TargetType, Target, TargetName, TargetUPNSuffix, TargetId, RoleAssignment_InitiatedBy, RoleAssignment_TargetResources, RoleAssignment_AdditionalDetails, RoleAssignment_CorrelationId\n", - "queryFrequency": "PT1H", - "queryPeriod": "PT2H", - "severity": "High", - "suppressionDuration": "PT1H", - "suppressionEnabled": false, - "triggerOperator": "GreaterThan", - "triggerThreshold": 0, - "status": "Available", - "requiredDataConnectors": [ - { - "dataTypes": [ - "AuditLogs" - ], - "connectorId": "AzureActiveDirectory" - } - ], - "tactics": [ - "PrivilegeEscalation", - "Persistence" - ], - "techniques": [ - "T1098", - "T1078" - ], - "entityMappings": [ - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "AppDisplayName" - } - ] - }, - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "TargetName" - }, - { - "identifier": "UPNSuffix", - "columnName": "TargetUPNSuffix" - } - ] - } - ] - } }, { - "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", - "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId5'),'/'))))]", + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[[variables('Office365ConnectionName')]", + "location": "[[variables('workspace-location-inline')]", "properties": { - "description": "Azure Active Directory Analytics Rule 5", - "parentId": "[variables('analyticRuleId5')]", - "contentId": "[variables('_analyticRulecontentId5')]", - "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion5')]", - "source": { - "kind": "Solution", - "name": "Azure Active Directory", - "sourceId": "[variables('_solutionId')]" - }, - "author": { - "name": "Microsoft", - "email": "[variables('_email')]" - }, - "support": { - "tier": "Microsoft", - "name": "Microsoft Corporation", - "email": "support@microsoft.com", - "link": "https://support.microsoft.com/" + "displayName": "[[variables('Office365ConnectionName')]", + "api": { + "id": "[[variables('_connection-3')]" } } - } - ] - }, - "packageKind": "Solution", - "packageVersion": "[variables('_solutionVersion')]", - "packageName": "[variables('_solutionName')]", - "packageId": "[variables('_solutionId')]", - "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId5')]", - "contentKind": "AnalyticsRule", - "displayName": "Admin promotion after Role Management Application Permission Grant", - "contentProductId": "[variables('_analyticRulecontentProductId5')]", - "id": "[variables('_analyticRulecontentProductId5')]", - "version": "[variables('analyticRuleVersion5')]" - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", - "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName6')]", - "location": "[parameters('workspace-location')]", - "dependsOn": [ - "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" - ], - "properties": { - "description": "AnomalousUserAppSigninLocationIncrease-detection_AnalyticalRules Analytics Rule with template version 3.0.4", - "mainTemplate": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion6')]", - "parameters": {}, - "variables": {}, - "resources": [ + }, { - "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId6')]", - "apiVersion": "2022-04-01-preview", - "kind": "Scheduled", - "location": "[parameters('workspace-location')]", + "type": "Microsoft.Logic/workflows", + "apiVersion": "2017-07-01", + "name": "[[parameters('PlaybookName')]", + "location": "[[variables('workspace-location-inline')]", + "tags": { + "LogicAppsCategory": "security", + "hidden-SentinelTemplateName": "Block-AADUser-EntityTrigger", + "hidden-SentinelTemplateVersion": "1.1", + "hidden-SentinelWorkspaceId": "[[variables('workspaceResourceId')]" + }, + "identity": { + "type": "SystemAssigned" + }, + "dependsOn": [ + "[[resourceId('Microsoft.Web/connections', variables('AzureADConnectionName'))]", + "[[resourceId('Microsoft.Web/connections', variables('MicrosoftSentinelConnectionName'))]", + "[[resourceId('Microsoft.Web/connections', variables('Office365ConnectionName'))]" + ], "properties": { - "description": "This query over Azure Active Directory sign-in considers all user sign-ins for each Azure Active\nDirectory application and picks out the most anomalous change in location profile for a user within an\nindividual application", - "displayName": "Anomalous sign-in location by user account and authenticating application", - "enabled": false, - "query": "// Adjust this figure to adjust how sensitive this detection is\nlet sensitivity = 2.5;\nlet AuthEvents = materialize(\nunion isfuzzy=True SigninLogs, AADNonInteractiveUserSignInLogs\n| where TimeGenerated > ago(7d)\n| where ResultType == 0\n| extend LocationDetails = LocationDetails_dynamic\n| extend Location = strcat(LocationDetails.countryOrRegion, \"-\", LocationDetails.state,\"-\", LocationDetails.city)\n| where Location != \"--\");\nAuthEvents\n| summarize dcount(Location) by AppDisplayName, AppId, UserPrincipalName, UserId, bin(startofday(TimeGenerated), 1d)\n| where dcount_Location > 2\n| summarize CountOfLocations = make_list(dcount_Location, 10000), TimeStamp = make_list(TimeGenerated, 10000) by AppId, UserId\n| extend (Anomalies, Score, Baseline) = series_decompose_anomalies(CountOfLocations, sensitivity, -1, 'linefit')\n| mv-expand CountOfLocations to typeof(double), TimeStamp to typeof(datetime), Anomalies to typeof(double), Score to typeof(double), Baseline to typeof(long)\n| where Anomalies > 0\n| join kind=inner( AuthEvents | extend TimeStamp = startofday(TimeGenerated)) on UserId, AppId\n| extend SignInDetails = bag_pack(\"TimeGenerated\", TimeGenerated, \"Location\", Location, \"Source\", IPAddress, \"Device\", DeviceDetail_dynamic)\n| summarize SignInDetailsSet=make_set(SignInDetails, 1000) by UserId, UserPrincipalName, CountOfLocations, TimeStamp, AppId, AppDisplayName\n| extend Name = split(UserPrincipalName, \"@\")[0], UPNSuffix = split(UserPrincipalName, \"@\")[1]\n", - "queryFrequency": "P1D", - "queryPeriod": "P7D", - "severity": "Medium", - "suppressionDuration": "PT1H", - "suppressionEnabled": false, - "triggerOperator": "GreaterThan", - "triggerThreshold": 0, - "status": "Available", - "requiredDataConnectors": [ - { - "dataTypes": [ - "SigninLogs" - ], - "connectorId": "AzureActiveDirectory" + "state": "Enabled", + "definition": { + "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "$connections": { + "type": "Object" + } }, - { - "dataTypes": [ - "AADNonInteractiveUserSignInLogs" - ], - "connectorId": "AzureActiveDirectory" - } - ], - "tactics": [ - "InitialAccess" - ], - "techniques": [ - "T1078" - ], - "entityMappings": [ - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "Name" - }, - { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" - }, - { - "identifier": "AadUserId", - "columnName": "UserId" + "triggers": { + "Microsoft_Sentinel_entity": { + "type": "ApiConnectionWebhook", + "inputs": { + "body": { + "callback_url": "@{listCallbackUrl()}" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" + } + }, + "path": "/entity/@{encodeURIComponent('Account')}" } - ] - } - ], - "eventGroupingSettings": { - "aggregationKind": "SingleAlert" - }, - "customDetails": { - "Application": "AppDisplayName" - }, - "alertDetailsOverride": { - "alertDescriptionFormat": "This query over Azure Active Directory sign-in considers all user sign-ins for each Azure Active\nDirectory application and picks out the most anomalous change in location profile for a user within an\nindividual application. This has detected {{UserPrincipalName}} signing into {{AppDisplayName}} from {{CountOfLocations}} \ndifferent locations.\n", - "alertDisplayNameFormat": "Anomalous sign-in location by {{UserPrincipalName}} to {{AppDisplayName}}" - } - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", - "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId6'),'/'))))]", - "properties": { - "description": "Azure Active Directory Analytics Rule 6", - "parentId": "[variables('analyticRuleId6')]", - "contentId": "[variables('_analyticRulecontentId6')]", - "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion6')]", - "source": { - "kind": "Solution", - "name": "Azure Active Directory", - "sourceId": "[variables('_solutionId')]" - }, - "author": { - "name": "Microsoft", - "email": "[variables('_email')]" - }, - "support": { - "tier": "Microsoft", - "name": "Microsoft Corporation", - "email": "support@microsoft.com", - "link": "https://support.microsoft.com/" - } - } - } - ] - }, - "packageKind": "Solution", - "packageVersion": "[variables('_solutionVersion')]", - "packageName": "[variables('_solutionName')]", - "packageId": "[variables('_solutionId')]", - "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId6')]", - "contentKind": "AnalyticsRule", - "displayName": "Anomalous sign-in location by user account and authenticating application", - "contentProductId": "[variables('_analyticRulecontentProductId6')]", - "id": "[variables('_analyticRulecontentProductId6')]", - "version": "[variables('analyticRuleVersion6')]" - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", - "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName7')]", - "location": "[parameters('workspace-location')]", - "dependsOn": [ - "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" - ], - "properties": { - "description": "AuthenticationMethodsChangedforPrivilegedAccount_AnalyticalRules Analytics Rule with template version 3.0.4", - "mainTemplate": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion7')]", - "parameters": {}, - "variables": {}, - "resources": [ - { - "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId7')]", - "apiVersion": "2022-04-01-preview", - "kind": "Scheduled", - "location": "[parameters('workspace-location')]", - "properties": { - "description": "Identifies authentication methods being changed for a privileged account. This could be an indication of an attacker adding an auth method to the account so they can have continued access.\nRef : https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-privileged-accounts#things-to-monitor-1", - "displayName": "Authentication Methods Changed for Privileged Account", - "enabled": false, - "query": "let queryperiod = 14d;\nlet queryfrequency = 2h;\nlet security_info_actions = dynamic([\"User registered security info\", \"User changed default security info\", \"User deleted security info\", \"Admin updated security info\", \"User reviewed security info\", \"Admin deleted security info\", \"Admin registered security info\"]);\nlet VIPUsers = (\n IdentityInfo\n | where TimeGenerated > ago(queryperiod)\n | mv-expand AssignedRoles\n | where AssignedRoles contains 'Admin'\n | summarize by AccountUPN);\nAuditLogs\n| where TimeGenerated > ago(queryfrequency)\n| where Category =~ \"UserManagement\"\n| where ActivityDisplayName in (security_info_actions)\n| extend Initiator = tostring(InitiatedBy.user.userPrincipalName)\n| extend IP = tostring(InitiatedBy.user.ipAddress)\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"User\"\n | extend Target = tostring(TargetResource.userPrincipalName)\n )\n| where Target in~ (VIPUsers)\n// Uncomment the line below if you are experiencing high volumes of Target entities. If this is uncommented, the Target column will not be mapped to an entity.\n//| summarize Start=min(TimeGenerated), End=max(TimeGenerated), Actions = make_set(ResultReason, MaxSize=8), Targets=make_set(Target, MaxSize=256) by Initiator, IP, Result\n// Comment out this line below, if line above is used.\n| summarize Start=min(TimeGenerated), End=max(TimeGenerated), Actions = make_set(ResultReason, MaxSize=8) by Initiator, IP, Result, Targets = Target\n| extend InitiatorName = tostring(split(Initiator,'@',0)[0]), \n InitiatorUPNSuffix = tostring(split(Initiator,'@',1)[0]),\n TargetName = iff(tostring(Targets) has \"[\", \"\", tostring(split(Targets,'@',0)[0])), \n TargetUPNSuffix = iff(tostring(Targets) has \"[\", \"\", tostring(split(Targets,'@',1)[0]))\n", - "queryFrequency": "PT2H", - "queryPeriod": "P14D", - "severity": "High", - "suppressionDuration": "PT1H", - "suppressionEnabled": false, - "triggerOperator": "GreaterThan", - "triggerThreshold": 0, - "status": "Available", - "requiredDataConnectors": [ - { - "dataTypes": [ - "AuditLogs" - ], - "connectorId": "AzureActiveDirectory" - } - ], - "tactics": [ - "Persistence" - ], - "techniques": [ - "T1098" - ], - "entityMappings": [ - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "InitiatorName" - }, - { - "identifier": "UPNSuffix", - "columnName": "InitiatorUPNSuffix" - } - ] + } }, - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "TargetName" + "actions": { + "Condition": { + "actions": { + "Condition_-_if_user_have_manager": { + "actions": { + "Condition_2": { + "actions": { + "Add_comment_to_incident_-_with_manager_-_no_admin": { + "type": "ApiConnection", + "inputs": { + "body": { + "incidentArmId": "@triggerBody()?['IncidentArmID']", + "message": "

User @{triggerBody()?['Entity']?['properties']?['Name']}  (UPN - @{variables('AccountDetails')}) was disabled in AAD via playbook Block-AADUser. Manager (@{body('Parse_JSON_-_get_user_manager')?['userPrincipalName']}) is notified.

" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" + } + }, + "method": "post", + "path": "/Incidents/Comment" + } + } + }, + "runAfter": { + "Get_user_-_details": [ + "Succeeded" + ] + }, + "expression": { + "and": [ + { + "not": { + "equals": [ + "@triggerBody()?['IncidentArmID']", + "@null" + ] + } + } + ] + }, + "type": "If" + }, + "Get_user_-_details": { + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['azuread']['connectionId']" + } + }, + "method": "get", + "path": "/v1.0/users/@{encodeURIComponent(variables('AccountDetails'))}" + } + }, + "Send_an_email_-_to_manager_-_no_admin": { + "runAfter": { + "Condition_2": [ + "Succeeded" + ] + }, + "type": "ApiConnection", + "inputs": { + "body": { + "Body": "

Security notification! This is automated email sent by Microsoft Sentinel Automation!
\n
\nYour direct report @{triggerBody()?['Entity']?['properties']?['Name']} has been disabled in Azure AD due to the security incident. Can you please notify the user and work with him to reach our support.
\n
\nDirect report details:
\nFirst name: @{body('Get_user_-_details')?['displayName']}
\nSurname: @{body('Get_user_-_details')?['surname']}
\nJob title: @{body('Get_user_-_details')?['jobTitle']}
\nOffice location: @{body('Get_user_-_details')?['officeLocation']}
\nBusiness phone: @{body('Get_user_-_details')?['businessPhones']}
\nMobile phone: @{body('Get_user_-_details')?['mobilePhone']}
\nMail: @{body('Get_user_-_details')?['mail']}
\n
\nThank you!

", + "Importance": "High", + "Subject": "@{triggerBody()?['Entity']?['properties']?['Name']} has been disabled in Azure AD due to the security risk!", + "To": "@body('Parse_JSON_-_get_user_manager')?['userPrincipalName']" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['office365']['connectionId']" + } + }, + "method": "post", + "path": "/v2/Mail" + } + } + }, + "runAfter": { + "Parse_JSON_-_get_user_manager": [ + "Succeeded" + ] + }, + "else": { + "actions": { + "Condition_3": { + "actions": { + "Add_comment_to_incident_-_no_manager_-_no_admin": { + "type": "ApiConnection", + "inputs": { + "body": { + "incidentArmId": "@triggerBody()?['IncidentArmID']", + "message": "

User @{triggerBody()?['Entity']?['properties']?['Name']} (UPN - @{variables('AccountDetails')}) was disabled in AAD via playbook Block-AADUser. Manager has not been notified, since it is not found for this user!

" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" + } + }, + "method": "post", + "path": "/Incidents/Comment" + } + } + }, + "expression": { + "and": [ + { + "not": { + "equals": [ + "@triggerBody()?['IncidentArmID']", + "@null" + ] + } + } + ] + }, + "type": "If" + } + } + }, + "expression": { + "and": [ + { + "not": { + "equals": [ + "@body('Parse_JSON_-_get_user_manager')?['userPrincipalName']", + "@null" + ] + } + } + ] + }, + "type": "If" + }, + "HTTP_-_get_user_manager": { + "type": "Http", + "inputs": { + "authentication": { + "audience": "https://graph.microsoft.com/", + "type": "ManagedServiceIdentity" + }, + "method": "GET", + "uri": "https://graph.microsoft.com/v1.0/users/@{variables('AccountDetails')}/manager" + } + }, + "Parse_JSON_-_get_user_manager": { + "runAfter": { + "HTTP_-_get_user_manager": [ + "Succeeded", + "Failed" + ] + }, + "type": "ParseJson", + "inputs": { + "content": "@body('HTTP_-_get_user_manager')", + "schema": { + "properties": { + "userPrincipalName": { + "type": "string" + } + }, + "type": "object" + } + } + } }, - { - "identifier": "UPNSuffix", - "columnName": "TargetUPNSuffix" - } - ] - }, - { - "entityType": "IP", - "fieldMappings": [ - { - "identifier": "Address", - "columnName": "IP" - } - ] - } - ] - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", - "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId7'),'/'))))]", - "properties": { - "description": "Azure Active Directory Analytics Rule 7", - "parentId": "[variables('analyticRuleId7')]", - "contentId": "[variables('_analyticRulecontentId7')]", - "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion7')]", - "source": { - "kind": "Solution", - "name": "Azure Active Directory", - "sourceId": "[variables('_solutionId')]" - }, - "author": { - "name": "Microsoft", - "email": "[variables('_email')]" - }, - "support": { - "tier": "Microsoft", - "name": "Microsoft Corporation", - "email": "support@microsoft.com", - "link": "https://support.microsoft.com/" - } - } - } - ] - }, - "packageKind": "Solution", - "packageVersion": "[variables('_solutionVersion')]", - "packageName": "[variables('_solutionName')]", - "packageId": "[variables('_solutionId')]", - "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId7')]", - "contentKind": "AnalyticsRule", - "displayName": "Authentication Methods Changed for Privileged Account", - "contentProductId": "[variables('_analyticRulecontentProductId7')]", - "id": "[variables('_analyticRulecontentProductId7')]", - "version": "[variables('analyticRuleVersion7')]" - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", - "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName8')]", - "location": "[parameters('workspace-location')]", - "dependsOn": [ - "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" - ], - "properties": { - "description": "AzureAADPowerShellAnomaly_AnalyticalRules Analytics Rule with template version 3.0.4", - "mainTemplate": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion8')]", - "parameters": {}, - "variables": {}, - "resources": [ - { - "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId8')]", - "apiVersion": "2022-04-01-preview", - "kind": "Scheduled", - "location": "[parameters('workspace-location')]", - "properties": { - "description": "This will alert when a user or application signs in using Azure Active Directory PowerShell to access non-Active Directory resources, such as the Azure Key Vault, which may be undesired or unauthorized behavior.\nFor capabilities and expected behavior of the Azure Active Directory PowerShell module, see: https://docs.microsoft.com/powershell/module/azuread/?view=azureadps-2.0.\nFor further information on Azure Active Directory Signin activity reports, see: https://docs.microsoft.com/azure/active-directory/reports-monitoring/concept-sign-ins.", - "displayName": "Azure Active Directory PowerShell accessing non-AAD resources", - "enabled": false, - "query": "let aadFunc = (tableName:string){\ntable(tableName)\n| where AppId =~ \"1b730954-1685-4b74-9bfd-dac224a7b894\" // AppDisplayName IS Azure Active Directory PowerShell\n| where TokenIssuerType =~ \"AzureAD\"\n| where ResourceIdentity !in (\"00000002-0000-0000-c000-000000000000\", \"00000003-0000-0000-c000-000000000000\") // ResourceDisplayName IS NOT Windows Azure Active Directory OR Microsoft Graph\n| extend Status = todynamic(Status)\n| where Status.errorCode == 0 // Success\n| project-reorder IPAddress, UserAgent, ResourceDisplayName, UserDisplayName, UserId, UserPrincipalName, Type\n| order by TimeGenerated desc\n// New entity mapping\n| extend timestamp = TimeGenerated, Name = tostring(split(UserPrincipalName,'@',0)[0]), UPNSuffix = tostring(split(UserPrincipalName,'@',1)[0])\n};\nlet aadSignin = aadFunc(\"SigninLogs\");\nlet aadNonInt = aadFunc(\"AADNonInteractiveUserSignInLogs\");\nunion isfuzzy=true aadSignin, aadNonInt\n", - "queryFrequency": "PT1H", - "queryPeriod": "PT1H", - "severity": "Low", - "suppressionDuration": "PT1H", - "suppressionEnabled": false, - "triggerOperator": "GreaterThan", - "triggerThreshold": 0, - "status": "Available", - "requiredDataConnectors": [ - { - "dataTypes": [ - "SigninLogs" - ], - "connectorId": "AzureActiveDirectory" - }, - { - "dataTypes": [ - "AADNonInteractiveUserSignInLogs" - ], - "connectorId": "AzureActiveDirectory" - } - ], - "tactics": [ - "InitialAccess" - ], - "techniques": [ - "T1078" - ], - "entityMappings": [ - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "Name" + "runAfter": { + "Update_user_-_disable_user": [ + "Succeeded", + "Failed" + ] }, - { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" + "else": { + "actions": { + "Add_comment_to_incident_-_error_details": { + "type": "ApiConnection", + "inputs": { + "body": { + "incidentArmId": "@triggerBody()?['IncidentArmID']", + "message": "

Block-AADUser playbook could not disable user @{triggerBody()?['Entity']?['properties']?['Name']}.
\nError message: @{body('Update_user_-_disable_user')['error']['message']}
\nNote: If user is admin, this playbook don't have privilages to block admin users!

" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" + } + }, + "method": "post", + "path": "/Incidents/Comment" + } + } + } }, - { - "identifier": "AadUserId", - "columnName": "UserId" + "expression": { + "and": [ + { + "equals": [ + "@body('Update_user_-_disable_user')", + "@null" + ] + } + ] + }, + "type": "If" + }, + "Initialize_variable_Account_Details": { + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "AccountDetails", + "type": "string" + } + ] } - ] - }, - { - "entityType": "IP", - "fieldMappings": [ - { - "identifier": "Address", - "columnName": "IPAddress" + }, + "Set_variable": { + "runAfter": { + "Initialize_variable_Account_Details": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "AccountDetails", + "value": "@{concat(triggerBody()?['Entity']?['properties']?['Name'],'@',triggerBody()?['Entity']?['properties']?['UPNSuffix'])}" } - ] + }, + "Update_user_-_disable_user": { + "runAfter": { + "Set_variable": [ + "Succeeded" + ] + }, + "type": "ApiConnection", + "inputs": { + "body": { + "accountEnabled": false + }, + "host": { + "connection": { + "name": "@parameters('$connections')['azuread']['connectionId']" + } + }, + "method": "patch", + "path": "/v1.0/users/@{encodeURIComponent(variables('AccountDetails'))}" + } + } } - ] + }, + "parameters": { + "$connections": { + "value": { + "azuread": { + "connectionId": "[[resourceId('Microsoft.Web/connections', variables('AzureADConnectionName'))]", + "connectionName": "[[variables('AzureADConnectionName')]", + "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuread')]" + }, + "microsoftsentinel": { + "connectionId": "[[resourceId('Microsoft.Web/connections', variables('MicrosoftSentinelConnectionName'))]", + "connectionName": "[[variables('MicrosoftSentinelConnectionName')]", + "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", + "connectionProperties": { + "authentication": { + "type": "ManagedServiceIdentity" + } + } + }, + "office365": { + "connectionId": "[[resourceId('Microsoft.Web/connections', variables('Office365ConnectionName'))]", + "connectionName": "[[variables('Office365ConnectionName')]", + "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]" + } + } + } + } } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId8'),'/'))))]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('Playbook-', last(split(variables('playbookId2'),'/'))))]", "properties": { - "description": "Azure Active Directory Analytics Rule 8", - "parentId": "[variables('analyticRuleId8')]", - "contentId": "[variables('_analyticRulecontentId8')]", - "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion8')]", + "parentId": "[variables('playbookId2')]", + "contentId": "[variables('_playbookContentId2')]", + "kind": "Playbook", + "version": "[variables('playbookVersion2')]", "source": { "kind": "Solution", "name": "Azure Active Directory", @@ -2022,589 +1381,412 @@ } } } - ] + ], + "metadata": { + "title": "Block AAD user - Entity trigger", + "description": "This playbook disables the selected user (account entity) in Azure Active Directoy. If this playbook triggered from an incident context, it will add a comment to the incident. This playbook will notify the disabled user manager if available. Note: This playbook will not disable admin user!", + "postDeployment": [ + "1. Assign Microsoft Sentinel Responder role to the Playbook's managed identity.", + "2. Grant User.Read.All, User.ReadWrite.All, Directory.Read.All, Directory.ReadWrite.All permissions to the managed identity.", + "3. Authorize Azure AD and Office 365 Outlook Logic App connections." + ], + "lastUpdateTime": "2022-12-08T00:00:00Z", + "entities": [ + "Account" + ], + "tags": [ + "Remediation" + ], + "releaseNotes": [ + { + "version": "1.0.0", + "title": "Added manager notification action", + "notes": [ + "Initial version" + ] + } + ] + } }, "packageKind": "Solution", "packageVersion": "[variables('_solutionVersion')]", "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId8')]", - "contentKind": "AnalyticsRule", - "displayName": "Azure Active Directory PowerShell accessing non-AAD resources", - "contentProductId": "[variables('_analyticRulecontentProductId8')]", - "id": "[variables('_analyticRulecontentProductId8')]", - "version": "[variables('analyticRuleVersion8')]" + "contentId": "[variables('_playbookContentId2')]", + "contentKind": "Playbook", + "displayName": "Block-AADUser-EntityTrigger", + "contentProductId": "[variables('_playbookcontentProductId2')]", + "id": "[variables('_playbookcontentProductId2')]", + "version": "[variables('playbookVersion2')]" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName9')]", + "name": "[variables('playbookTemplateSpecName3')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "AzureADRoleManagementPermissionGrant_AnalyticalRules Analytics Rule with template version 3.0.4", + "description": "Block-AADUser-Incident Playbook with template version 3.0.5", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion9')]", - "parameters": {}, - "variables": {}, - "resources": [ - { - "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId9')]", - "apiVersion": "2022-04-01-preview", - "kind": "Scheduled", - "location": "[parameters('workspace-location')]", - "properties": { - "description": "Identifies when the Microsoft Graph RoleManagement.ReadWrite.Directory (Delegated or Application) permission is granted to a service principal.\nThis permission allows an application to read and manage the role-based access control (RBAC) settings for your company's directory.\nAn adversary could use this permission to add an Azure AD object to an Admin directory role and escalate privileges.\nRef : https://docs.microsoft.com/graph/permissions-reference#role-management-permissions\nRef : https://docs.microsoft.com/graph/api/directoryrole-post-members?view=graph-rest-1.0&tabs=http", - "displayName": "Azure AD Role Management Permission Grant", - "enabled": false, - "query": "AuditLogs\n| where Category =~ \"ApplicationManagement\" and LoggedByService =~ \"Core Directory\" and OperationName in~ (\"Add delegated permission grant\", \"Add app role assignment to service principal\")\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"ServicePrincipal\" and array_length(TargetResource.modifiedProperties) > 0 and isnotnull(TargetResource.displayName)\n | extend props = TargetResource.modifiedProperties\n )\n| mv-apply Property = props on \n (\n where Property.displayName in~ (\"AppRole.Value\",\"DelegatedPermissionGrant.Scope\")\n | extend DisplayName = tostring(Property.displayName), PermissionGrant = trim('\"',tostring(Property.newValue))\n )\n| where PermissionGrant has \"RoleManagement.ReadWrite.Directory\"\n| mv-apply Property = props on \n (\n where Property.displayName =~ \"ServicePrincipal.DisplayName\"\n | extend AppDisplayName = trim('\"',tostring(Property.newValue))\n )\n| mv-apply Property = props on \n (\n where Property.displayName =~ \"ServicePrincipal.ObjectID\"\n | extend AppServicePrincipalId = trim('\"',tostring(Property.newValue))\n )\n| extend \n Initiator = iif(isnotempty(InitiatedBy.app), tostring(InitiatedBy.app.displayName), tostring(InitiatedBy.user.userPrincipalName)),\n InitiatorId = iif(isnotempty(InitiatedBy.app), tostring(InitiatedBy.app.servicePrincipalId), tostring(InitiatedBy.user.id))\n| project TimeGenerated, OperationName, Result, PermissionGrant, AppDisplayName, AppServicePrincipalId, Initiator, InitiatorId, InitiatedBy, TargetResources, AdditionalDetails, CorrelationId\n| extend Name = tostring(split(Initiator,'@',0)[0]), UPNSuffix = tostring(split(Initiator,'@',1)[0])\n", - "queryFrequency": "PT2H", - "queryPeriod": "PT2H", - "severity": "High", - "suppressionDuration": "PT1H", - "suppressionEnabled": false, - "triggerOperator": "GreaterThan", - "triggerThreshold": 0, - "status": "Available", - "requiredDataConnectors": [ - { - "dataTypes": [ - "AuditLogs" - ], - "connectorId": "AzureActiveDirectory" - } - ], - "tactics": [ - "Persistence", - "Impact" - ], - "techniques": [ - "T1098", - "T1078" - ], - "entityMappings": [ - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "Name" - }, - { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" - } - ] - }, - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "AppDisplayName" - } - ] - } - ] - } - }, + "contentVersion": "[variables('playbookVersion3')]", + "parameters": { + "PlaybookName": { + "defaultValue": "Block-AADUser-Incident", + "type": "string" + } + }, + "variables": { + "AzureADConnectionName": "[[concat('azuread-', parameters('PlaybookName'))]", + "MicrosoftSentinelConnectionName": "[[concat('microsoftsentinel-', parameters('PlaybookName'))]", + "Office365ConnectionName": "[[concat('office365-', parameters('PlaybookName'))]", + "connection-1": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuread')]", + "_connection-1": "[[variables('connection-1')]", + "connection-2": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", + "_connection-2": "[[variables('connection-2')]", + "connection-3": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]", + "_connection-3": "[[variables('connection-3')]", + "workspace-location-inline": "[concat('[resourceGroup().locatio', 'n]')]", + "workspace-name": "[parameters('workspace')]", + "workspaceResourceId": "[[resourceId('microsoft.OperationalInsights/Workspaces', variables('workspace-name'))]" + }, + "resources": [ { - "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", - "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId9'),'/'))))]", + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[[variables('AzureADConnectionName')]", + "location": "[[variables('workspace-location-inline')]", "properties": { - "description": "Azure Active Directory Analytics Rule 9", - "parentId": "[variables('analyticRuleId9')]", - "contentId": "[variables('_analyticRulecontentId9')]", - "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion9')]", - "source": { - "kind": "Solution", - "name": "Azure Active Directory", - "sourceId": "[variables('_solutionId')]" - }, - "author": { - "name": "Microsoft", - "email": "[variables('_email')]" - }, - "support": { - "tier": "Microsoft", - "name": "Microsoft Corporation", - "email": "support@microsoft.com", - "link": "https://support.microsoft.com/" + "displayName": "[[variables('AzureADConnectionName')]", + "api": { + "id": "[[variables('_connection-1')]" } } - } - ] - }, - "packageKind": "Solution", - "packageVersion": "[variables('_solutionVersion')]", - "packageName": "[variables('_solutionName')]", - "packageId": "[variables('_solutionId')]", - "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId9')]", - "contentKind": "AnalyticsRule", - "displayName": "Azure AD Role Management Permission Grant", - "contentProductId": "[variables('_analyticRulecontentProductId9')]", - "id": "[variables('_analyticRulecontentProductId9')]", - "version": "[variables('analyticRuleVersion9')]" - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", - "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName10')]", - "location": "[parameters('workspace-location')]", - "dependsOn": [ - "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" - ], - "properties": { - "description": "AzurePortalSigninfromanotherAzureTenant_AnalyticalRules Analytics Rule with template version 3.0.4", - "mainTemplate": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion10')]", - "parameters": {}, - "variables": {}, - "resources": [ + }, { - "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId10')]", - "apiVersion": "2022-04-01-preview", - "kind": "Scheduled", - "location": "[parameters('workspace-location')]", + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[[variables('MicrosoftSentinelConnectionName')]", + "location": "[[variables('workspace-location-inline')]", + "kind": "V1", "properties": { - "description": "This query looks for successful sign in attempts to the Azure Portal where the user who is signing in from another Azure tenant,\n and the IP address the login attempt is from is an Azure IP. A threat actor who compromises an Azure tenant may look\n to pivot to other tenants leveraging cross-tenant delegated access in this manner.", - "displayName": "Azure Portal sign in from another Azure Tenant", - "enabled": false, - "query": "// Get details of current Azure Ranges (note this URL updates regularly so will need to be manually updated over time)\n// You may find the name of the new JSON here: https://www.microsoft.com/download/details.aspx?id=56519\n// On the downloads page, click the 'details' button, and then replace just the filename in the URL below\nlet azure_ranges = externaldata(changeNumber: string, cloud: string, values: dynamic)\n[\"https://raw.githubusercontent.com/microsoft/mstic/master/PublicFeeds/MSFTIPRanges/ServiceTags_Public.json\"] with(format='multijson')\n| mv-expand values\n| mv-expand values.properties.addressPrefixes\n| mv-expand values_properties_addressPrefixes\n| summarize by tostring(values_properties_addressPrefixes)\n| extend isipv4 = parse_ipv4(values_properties_addressPrefixes)\n| extend isipv6 = parse_ipv6(values_properties_addressPrefixes)\n| extend ip_type = case(isnotnull(isipv4), \"v4\", \"v6\")\n| summarize make_list(values_properties_addressPrefixes) by ip_type\n;\nSigninLogs\n// Limiting to Azure Portal really reduces false positives and helps focus on potential admin activity\n| where ResultType == 0\n| where AppDisplayName =~ \"Azure Portal\"\n| extend isipv4 = parse_ipv4(IPAddress)\n| extend ip_type = case(isnotnull(isipv4), \"v4\", \"v6\")\n // Only get logons where the IP address is in an Azure range\n| join kind=fullouter (azure_ranges) on ip_type\n| extend ipv6_match = ipv6_is_in_any_range(IPAddress, list_values_properties_addressPrefixes)\n| extend ipv4_match = ipv4_is_in_any_range(IPAddress, list_values_properties_addressPrefixes)\n| where ipv4_match or ipv6_match \n// Limit to where the user is external to the tenant\n| where HomeTenantId != ResourceTenantId\n// Further limit it to just access to the current tenant (you can drop this if you wanted to look elsewhere as well but it helps reduce FPs)\n| where ResourceTenantId == AADTenantId\n| summarize FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated), make_set(ResourceDisplayName) by UserPrincipalName, IPAddress, UserAgent, Location, HomeTenantId, ResourceTenantId, UserId\n| extend AccountName = split(UserPrincipalName, \"@\")[0]\n| extend UPNSuffix = split(UserPrincipalName, \"@\")[1]\n", - "queryFrequency": "PT1H", - "queryPeriod": "PT1H", - "severity": "Medium", - "suppressionDuration": "PT1H", - "suppressionEnabled": false, - "triggerOperator": "GreaterThan", - "triggerThreshold": 0, - "status": "Available", - "requiredDataConnectors": [ - { - "dataTypes": [ - "SigninLogs" - ], - "connectorId": "AzureActiveDirectory" - } - ], - "tactics": [ - "InitialAccess" - ], - "techniques": [ - "T1199" - ], - "entityMappings": [ - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "AccountName" - }, - { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" - }, - { - "identifier": "AadUserId", - "columnName": "UserId" - } - ] - }, - { - "entityType": "IP", - "fieldMappings": [ - { - "identifier": "Address", - "columnName": "IPAddress" - } - ] - } - ], - "alertDetailsOverride": { - "alertDescriptionFormat": "This query looks for successful sign in attempts to the Azure Portal where the user who is signing in from another Azure tenant,\nand the IP address the login attempt is from is an Azure IP. A threat actor who compromises an Azure tenant may look\nto pivot to other tenants leveraging cross-tenant delegated access in this manner.\nIn this instance {{UserPrincipalName}} logged in at {{FirstSeen}} from IP Address {{IPAddress}}.\n", - "alertDisplayNameFormat": "Azure Portal sign in by {{UserPrincipalName}} from another Azure Tenant with IP Address {{IPAddress}}" + "displayName": "[[variables('MicrosoftSentinelConnectionName')]", + "parameterValueType": "Alternative", + "api": { + "id": "[[variables('_connection-2')]" } } }, { - "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", - "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId10'),'/'))))]", + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[[variables('Office365ConnectionName')]", + "location": "[[variables('workspace-location-inline')]", "properties": { - "description": "Azure Active Directory Analytics Rule 10", - "parentId": "[variables('analyticRuleId10')]", - "contentId": "[variables('_analyticRulecontentId10')]", - "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion10')]", - "source": { - "kind": "Solution", - "name": "Azure Active Directory", - "sourceId": "[variables('_solutionId')]" - }, - "author": { - "name": "Microsoft", - "email": "[variables('_email')]" - }, - "support": { - "tier": "Microsoft", - "name": "Microsoft Corporation", - "email": "support@microsoft.com", - "link": "https://support.microsoft.com/" + "displayName": "[[variables('Office365ConnectionName')]", + "api": { + "id": "[[variables('_connection-3')]" } } - } - ] - }, - "packageKind": "Solution", - "packageVersion": "[variables('_solutionVersion')]", - "packageName": "[variables('_solutionName')]", - "packageId": "[variables('_solutionId')]", - "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId10')]", - "contentKind": "AnalyticsRule", - "displayName": "Azure Portal sign in from another Azure Tenant", - "contentProductId": "[variables('_analyticRulecontentProductId10')]", - "id": "[variables('_analyticRulecontentProductId10')]", - "version": "[variables('analyticRuleVersion10')]" - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", - "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName11')]", - "location": "[parameters('workspace-location')]", - "dependsOn": [ - "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" - ], - "properties": { - "description": "Brute Force Attack against GitHub Account_AnalyticalRules Analytics Rule with template version 3.0.4", - "mainTemplate": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion11')]", - "parameters": {}, - "variables": {}, - "resources": [ + }, { - "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId11')]", - "apiVersion": "2022-04-01-preview", - "kind": "Scheduled", - "location": "[parameters('workspace-location')]", - "properties": { - "description": "Attackers who are trying to guess your users' passwords or use brute-force methods to get in. If your organization is using SSO with Azure Active Directory, authentication logs to GitHub.com will be generated. Using the following query can help you identify a sudden increase in failed logon attempt of users.", - "displayName": "Brute Force Attack against GitHub Account", - "enabled": false, - "query": "let LearningPeriod = 7d;\nlet BinTime = 1h;\nlet RunTime = 1h;\nlet StartTime = 1h; \nlet sensitivity = 2.5;\nlet EndRunTime = StartTime - RunTime;\nlet EndLearningTime = StartTime + LearningPeriod;\nlet aadFunc = (tableName:string){\ntable(tableName) \n| where TimeGenerated between (ago(EndLearningTime) .. ago(EndRunTime))\n| where AppDisplayName =~ \"GitHub.com\"\n| where ResultType != 0\n| make-series FailedLogins = count() on TimeGenerated from ago(LearningPeriod) to ago(EndRunTime) step BinTime by UserPrincipalName, Type\n| extend (Anomalies, Score, Baseline) = series_decompose_anomalies(FailedLogins, sensitivity, -1, 'linefit')\n| mv-expand FailedLogins to typeof(double), TimeGenerated to typeof(datetime), Anomalies to typeof(double), Score to typeof(double), Baseline to typeof(long) \n| where TimeGenerated >= ago(RunTime)\n| where Anomalies > 0 and Baseline > 0\n| join kind=inner (\n table(tableName) \n | where TimeGenerated between (ago(StartTime) .. ago(EndRunTime))\n | where AppDisplayName =~ \"GitHub.com\"\n | where ResultType != 0\n | summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), IPAddresses = make_set(IPAddress,100), Locations = make_set(LocationDetails,20), Devices = make_set(DeviceDetail,20) by UserPrincipalName \n ) on UserPrincipalName\n| extend timestamp = TimeGenerated, Name = tostring(split(UserPrincipalName,'@',0)[0]), UPNSuffix = tostring(split(UserPrincipalName,'@',1)[0])\n};\nlet aadSignin = aadFunc(\"SigninLogs\");\nlet aadNonInt = aadFunc(\"AADNonInteractiveUserSignInLogs\");\nunion isfuzzy=true aadSignin, aadNonInt\n", - "queryFrequency": "PT1H", - "queryPeriod": "P7D", - "severity": "Medium", - "suppressionDuration": "PT1H", - "suppressionEnabled": false, - "triggerOperator": "GreaterThan", - "triggerThreshold": 0, - "status": "Available", - "requiredDataConnectors": [ - { - "dataTypes": [ - "SigninLogs" - ], - "connectorId": "AzureActiveDirectory" - }, - { - "dataTypes": [ - "AADNonInteractiveUserSignInLogs" - ], - "connectorId": "AzureActiveDirectory" - } - ], - "tactics": [ - "CredentialAccess" - ], - "techniques": [ - "T1110" - ], - "entityMappings": [ - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "Name" - }, - { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" - } - ] - } - ] - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", - "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId11'),'/'))))]", - "properties": { - "description": "Azure Active Directory Analytics Rule 11", - "parentId": "[variables('analyticRuleId11')]", - "contentId": "[variables('_analyticRulecontentId11')]", - "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion11')]", - "source": { - "kind": "Solution", - "name": "Azure Active Directory", - "sourceId": "[variables('_solutionId')]" - }, - "author": { - "name": "Microsoft", - "email": "[variables('_email')]" - }, - "support": { - "tier": "Microsoft", - "name": "Microsoft Corporation", - "email": "support@microsoft.com", - "link": "https://support.microsoft.com/" - } - } - } - ] - }, - "packageKind": "Solution", - "packageVersion": "[variables('_solutionVersion')]", - "packageName": "[variables('_solutionName')]", - "packageId": "[variables('_solutionId')]", - "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId11')]", - "contentKind": "AnalyticsRule", - "displayName": "Brute Force Attack against GitHub Account", - "contentProductId": "[variables('_analyticRulecontentProductId11')]", - "id": "[variables('_analyticRulecontentProductId11')]", - "version": "[variables('analyticRuleVersion11')]" - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", - "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName12')]", - "location": "[parameters('workspace-location')]", - "dependsOn": [ - "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" - ], - "properties": { - "description": "BruteForceCloudPC_AnalyticalRules Analytics Rule with template version 3.0.4", - "mainTemplate": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion12')]", - "parameters": {}, - "variables": {}, - "resources": [ - { - "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId12')]", - "apiVersion": "2022-04-01-preview", - "kind": "Scheduled", - "location": "[parameters('workspace-location')]", + "type": "Microsoft.Logic/workflows", + "apiVersion": "2017-07-01", + "name": "[[parameters('PlaybookName')]", + "location": "[[variables('workspace-location-inline')]", + "tags": { + "LogicAppsCategory": "security", + "hidden-SentinelTemplateName": "Block-AADUser", + "hidden-SentinelTemplateVersion": "1.1", + "hidden-SentinelWorkspaceId": "[[variables('workspaceResourceId')]" + }, + "identity": { + "type": "SystemAssigned" + }, + "dependsOn": [ + "[[resourceId('Microsoft.Web/connections', variables('AzureADConnectionName'))]", + "[[resourceId('Microsoft.Web/connections', variables('MicrosoftSentinelConnectionName'))]", + "[[resourceId('Microsoft.Web/connections', variables('Office365ConnectionName'))]" + ], "properties": { - "description": "Identifies evidence of brute force activity against a Windows 365 Cloud PC by highlighting multiple authentication failures and by a successful authentication within a given time window.", - "displayName": "Brute force attack against a Cloud PC", - "enabled": false, - "query": "let authenticationWindow = 20m;\nlet sensitivity = 2.5;\nSigninLogs\n| where AppDisplayName =~ \"Windows Sign In\"\n| extend FailureOrSuccess = iff(ResultType in (\"0\", \"50125\", \"50140\", \"70043\", \"70044\"), \"Success\", \"Failure\")\n| summarize FailureCount = countif(FailureOrSuccess==\"Failure\"), SuccessCount = countif(FailureOrSuccess==\"Success\"), IPAddresses = make_set(IPAddress,1000)\n by bin(TimeGenerated, authenticationWindow), UserDisplayName, UserPrincipalName\n| extend FailureSuccessDiff = FailureCount - SuccessCount\n| where FailureSuccessDiff > 0\n| summarize Diff = make_list(FailureSuccessDiff, 10000), TimeStamp = make_list(TimeGenerated, 10000) by UserDisplayName, UserPrincipalName//, tostring(IPAddresses)\n| extend (Anomalies, Score, Baseline) = series_decompose_anomalies(Diff, sensitivity, -1, 'linefit') \n| mv-expand Diff to typeof(double), TimeStamp to typeof(datetime), Anomalies to typeof(double), Score to typeof(double), Baseline to typeof(long)\n| where Anomalies > 0\n| summarize by UserDisplayName, UserPrincipalName\n| join kind=leftouter (\n SigninLogs\n | where AppDisplayName =~ \"Windows Sign In\"\n | extend OS = DeviceDetail.operatingSystem, Browser = DeviceDetail.browser\n | extend StatusCode = tostring(Status.errorCode), StatusDetails = tostring(Status.additionalDetails)\n | extend State = tostring(LocationDetails.state), City = tostring(LocationDetails.city)\n | summarize StartTime = min(TimeGenerated), \n EndTime = max(TimeGenerated), \n IPAddress = make_set(IPAddress,100), \n OS = make_set(OS,20), \n Browser = make_set(Browser,20), \n City = make_set(City,100), \n ResultType = make_set(ResultType,100)\n by UserDisplayName, UserPrincipalName\n ) on UserDisplayName, UserPrincipalName\n| extend IPAddressFirst = IPAddress[0]\n| extend timestamp = StartTime, Name = tostring(split(UserPrincipalName,'@',0)[0]), UPNSuffix = tostring(split(UserPrincipalName,'@',1)[0])\n", - "queryFrequency": "P1D", - "queryPeriod": "P1D", - "severity": "Medium", - "suppressionDuration": "PT1H", - "suppressionEnabled": false, - "triggerOperator": "GreaterThan", - "triggerThreshold": 0, - "status": "Available", - "requiredDataConnectors": [ - { - "dataTypes": [ - "SigninLogs" - ], - "connectorId": "AzureActiveDirectory" - } - ], - "tactics": [ - "CredentialAccess" - ], - "techniques": [ - "T1110" - ], - "entityMappings": [ - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "Name" - }, - { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" + "state": "Enabled", + "definition": { + "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "$connections": { + "type": "Object" + } + }, + "triggers": { + "Microsoft_Sentinel_incident": { + "type": "ApiConnectionWebhook", + "inputs": { + "body": { + "callback_url": "@{listCallbackUrl()}" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" + } + }, + "path": "/incident-creation" } - ] + } }, - { - "entityType": "IP", - "fieldMappings": [ - { - "identifier": "Address", - "columnName": "IPAddressFirst" + "actions": { + "Entities_-_Get_Accounts": { + "type": "ApiConnection", + "inputs": { + "body": "@triggerBody()?['object']?['properties']?['relatedEntities']", + "host": { + "connection": { + "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" + } + }, + "method": "post", + "path": "/entities/account" } - ] - } - ] - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", - "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId12'),'/'))))]", - "properties": { - "description": "Azure Active Directory Analytics Rule 12", - "parentId": "[variables('analyticRuleId12')]", - "contentId": "[variables('_analyticRulecontentId12')]", - "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion12')]", - "source": { - "kind": "Solution", - "name": "Azure Active Directory", - "sourceId": "[variables('_solutionId')]" - }, - "author": { - "name": "Microsoft", - "email": "[variables('_email')]" - }, - "support": { - "tier": "Microsoft", - "name": "Microsoft Corporation", - "email": "support@microsoft.com", - "link": "https://support.microsoft.com/" - } - } - } - ] - }, - "packageKind": "Solution", - "packageVersion": "[variables('_solutionVersion')]", - "packageName": "[variables('_solutionName')]", - "packageId": "[variables('_solutionId')]", - "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId12')]", - "contentKind": "AnalyticsRule", - "displayName": "Brute force attack against a Cloud PC", - "contentProductId": "[variables('_analyticRulecontentProductId12')]", - "id": "[variables('_analyticRulecontentProductId12')]", - "version": "[variables('analyticRuleVersion12')]" - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", - "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName13')]", - "location": "[parameters('workspace-location')]", - "dependsOn": [ - "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" - ], - "properties": { - "description": "BulkChangestoPrivilegedAccountPermissions_AnalyticalRules Analytics Rule with template version 3.0.4", - "mainTemplate": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion13')]", - "parameters": {}, - "variables": {}, - "resources": [ - { - "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId13')]", - "apiVersion": "2022-04-01-preview", - "kind": "Scheduled", - "location": "[parameters('workspace-location')]", - "properties": { - "description": "Identifies when changes to multiple users permissions are changed at once. Investigate immediately if not a planned change. This setting could enable an attacker access to Azure subscriptions in your environment.\nRef : https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-privileged-identity-management", - "displayName": "Bulk Changes to Privileged Account Permissions", - "enabled": false, - "query": "let AdminRecords = AuditLogs\n| where Category =~ \"RoleManagement\"\n| where ActivityDisplayName has_any (\"Add eligible member to role\", \"Add member to role\")\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"User\"\n | extend Target = tostring(TargetResource.userPrincipalName),\n props = TargetResource.modifiedProperties\n )\n| mv-apply Property = props on \n (\n where Property.displayName =~ \"Role.DisplayName\"\n | extend RoleName = trim('\"',tostring(Property.newValue))\n )\n| where RoleName contains \"Admin\";\nAdminRecords\n| summarize dcount(Target) by bin(TimeGenerated, 1h)\n| where dcount_Target > 9\n| join kind=rightsemi (\n AdminRecords\n | extend TimeWindow = bin(TimeGenerated, 1h)\n) on $left.TimeGenerated == $right.TimeWindow\n| extend InitiatedByUser = iff(isnotempty(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.user.userPrincipalName), \"\")\n| extend TargetName = tostring(split(Target,'@',0)[0]), TargetUPNSuffix = tostring(split(Target,'@',1)[0]),\n InitiatedByUserName = tostring(split(InitiatedByUser,'@',0)[0]), InitiatedByUserUPNSuffix = tostring(split(InitiatedByUser,'@',1)[0])\n", - "queryFrequency": "PT2H", - "queryPeriod": "PT2H", - "severity": "High", - "suppressionDuration": "PT1H", - "suppressionEnabled": false, - "triggerOperator": "GreaterThan", - "triggerThreshold": 0, - "status": "Available", - "requiredDataConnectors": [ - { - "dataTypes": [ - "AuditLogs" - ], - "connectorId": "AzureActiveDirectory" + }, + "For_each": { + "foreach": "@body('Entities_-_Get_Accounts')?['Accounts']", + "actions": { + "Condition": { + "actions": { + "Condition_-_if_user_have_manager": { + "actions": { + "Add_comment_to_incident_-_with_manager_-_no_admin": { + "runAfter": { + "Get_user_-_details": [ + "Succeeded" + ] + }, + "type": "ApiConnection", + "inputs": { + "body": { + "incidentArmId": "@triggerBody()?['object']?['id']", + "message": "

User @{items('For_each')?['Name']} (UPN - @{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])}) was disabled in AAD via playbook Block-AADUser. Manager (@{body('Parse_JSON_-_get_user_manager')?['userPrincipalName']}) is notified.

" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" + } + }, + "method": "post", + "path": "/Incidents/Comment" + } + }, + "Get_user_-_details": { + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['azuread']['connectionId']" + } + }, + "method": "get", + "path": "/v1.0/users/@{encodeURIComponent(concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix']))}" + } + }, + "Send_an_email_-_to_manager_-_no_admin": { + "runAfter": { + "Add_comment_to_incident_-_with_manager_-_no_admin": [ + "Succeeded" + ] + }, + "type": "ApiConnection", + "inputs": { + "body": { + "Body": "

Security notification! This is automated email sent by Microsoft Sentinel Automation!
\n
\nYour direct report @{items('For_each')?['Name']} has been disabled in Azure AD due to the security incident. Can you please notify the user and work with him to reach our support.
\n
\nDirect report details:
\nFirst name: @{body('Get_user_-_details')?['displayName']}
\nSurname: @{body('Get_user_-_details')?['surname']}
\nJob title: @{body('Get_user_-_details')?['jobTitle']}
\nOffice location: @{body('Get_user_-_details')?['officeLocation']}
\nBusiness phone: @{body('Get_user_-_details')?['businessPhones']}
\nMobile phone: @{body('Get_user_-_details')?['mobilePhone']}
\nMail: @{body('Get_user_-_details')?['mail']}
\n
\nThank you!

", + "Importance": "High", + "Subject": "@{items('For_each')?['Name']} has been disabled in Azure AD due to the security risk!", + "To": "@body('Parse_JSON_-_get_user_manager')?['userPrincipalName']" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['office365']['connectionId']" + } + }, + "method": "post", + "path": "/v2/Mail" + } + } + }, + "runAfter": { + "Parse_JSON_-_get_user_manager": [ + "Succeeded" + ] + }, + "else": { + "actions": { + "Add_comment_to_incident_-_no_manager_-_no_admin": { + "type": "ApiConnection", + "inputs": { + "body": { + "incidentArmId": "@triggerBody()?['object']?['id']", + "message": "

User @{items('For_each')?['Name']} (UPN - @{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])}) was disabled in AAD via playbook Block-AADUser. Manager has not been notified, since it is not found for this user!

" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" + } + }, + "method": "post", + "path": "/Incidents/Comment" + } + } + } + }, + "expression": { + "and": [ + { + "not": { + "equals": [ + "@body('Parse_JSON_-_get_user_manager')?['userPrincipalName']", + "@null" + ] + } + } + ] + }, + "type": "If" + }, + "HTTP_-_get_user_manager": { + "type": "Http", + "inputs": { + "authentication": { + "audience": "https://graph.microsoft.com/", + "type": "ManagedServiceIdentity" + }, + "method": "GET", + "uri": "https://graph.microsoft.com/v1.0/users/@{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])}/manager" + } + }, + "Parse_JSON_-_get_user_manager": { + "runAfter": { + "HTTP_-_get_user_manager": [ + "Succeeded", + "Failed" + ] + }, + "type": "ParseJson", + "inputs": { + "content": "@body('HTTP_-_get_user_manager')", + "schema": { + "properties": { + "userPrincipalName": { + "type": "string" + } + }, + "type": "object" + } + } + } + }, + "runAfter": { + "Update_user_-_disable_user": [ + "Succeeded", + "Failed" + ] + }, + "else": { + "actions": { + "Add_comment_to_incident_-_error_details": { + "type": "ApiConnection", + "inputs": { + "body": { + "incidentArmId": "@triggerBody()?['object']?['id']", + "message": "

Block-AADUser playbook could not disable user @{items('For_each')?['Name']}.
\nError message: @{body('Update_user_-_disable_user')['error']['message']}
\nNote: If user is admin, this playbook don't have privilages to block admin users!

" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" + } + }, + "method": "post", + "path": "/Incidents/Comment" + } + } + } + }, + "expression": { + "and": [ + { + "equals": [ + "@body('Update_user_-_disable_user')", + "@null" + ] + } + ] + }, + "type": "If" + }, + "Update_user_-_disable_user": { + "type": "ApiConnection", + "inputs": { + "body": { + "accountEnabled": false + }, + "host": { + "connection": { + "name": "@parameters('$connections')['azuread']['connectionId']" + } + }, + "method": "patch", + "path": "/v1.0/users/@{encodeURIComponent(concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix']))}" + } + } + }, + "runAfter": { + "Entities_-_Get_Accounts": [ + "Succeeded" + ] + }, + "type": "Foreach" + } } - ], - "tactics": [ - "PrivilegeEscalation" - ], - "techniques": [ - "T1078" - ], - "entityMappings": [ - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "TargetName" + }, + "parameters": { + "$connections": { + "value": { + "azuread": { + "connectionId": "[[resourceId('Microsoft.Web/connections', variables('AzureADConnectionName'))]", + "connectionName": "[[variables('AzureADConnectionName')]", + "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuread')]" }, - { - "identifier": "UPNSuffix", - "columnName": "TargetUPNSuffix" - } - ] - }, - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "InitiatedByUserName" + "microsoftsentinel": { + "connectionId": "[[resourceId('Microsoft.Web/connections', variables('MicrosoftSentinelConnectionName'))]", + "connectionName": "[[variables('MicrosoftSentinelConnectionName')]", + "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", + "connectionProperties": { + "authentication": { + "type": "ManagedServiceIdentity" + } + } }, - { - "identifier": "UPNSuffix", - "columnName": "InitiatedByUserUPNSuffix" + "office365": { + "connectionId": "[[resourceId('Microsoft.Web/connections', variables('Office365ConnectionName'))]", + "connectionName": "[[variables('Office365ConnectionName')]", + "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]" } - ] + } } - ], - "customDetails": { - "TargetUser": "Target", - "InitiatedByUser": "InitiatedByUser" } } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId13'),'/'))))]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('Playbook-', last(split(variables('playbookId3'),'/'))))]", "properties": { - "description": "Azure Active Directory Analytics Rule 13", - "parentId": "[variables('analyticRuleId13')]", - "contentId": "[variables('_analyticRulecontentId13')]", - "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion13')]", + "parentId": "[variables('playbookId3')]", + "contentId": "[variables('_playbookContentId3')]", + "kind": "Playbook", + "version": "[variables('playbookVersion3')]", "source": { "kind": "Solution", "name": "Azure Active Directory", @@ -2622,719 +1804,433 @@ } } } - ] + ], + "metadata": { + "title": "Block AAD user - Incident", + "description": "For each account entity included in the incident, this playbook will disable the user in Azure Active Directoy, add a comment to the incident that contains this alert and notify manager if available. Note: This playbook will not disable admin user!", + "prerequisites": [ + "None" + ], + "postDeployment": [ + "1. Assign Microsoft Sentinel Responder role to the Playbook's managed identity.", + "2. Grant User.Read.All, User.ReadWrite.All, Directory.Read.All, Directory.ReadWrite.All permissions to the managed identity.", + "3. Authorize Azure AD and Office 365 Outlook Logic App connections." + ], + "lastUpdateTime": "2022-07-11T00:00:00Z", + "entities": [ + "Account" + ], + "tags": [ + "Remediation" + ], + "releaseNotes": [ + { + "version": "1.0.0", + "title": "Added manager notification action", + "notes": [ + "Initial version" + ] + } + ] + } }, "packageKind": "Solution", "packageVersion": "[variables('_solutionVersion')]", "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId13')]", - "contentKind": "AnalyticsRule", - "displayName": "Bulk Changes to Privileged Account Permissions", - "contentProductId": "[variables('_analyticRulecontentProductId13')]", - "id": "[variables('_analyticRulecontentProductId13')]", - "version": "[variables('analyticRuleVersion13')]" + "contentId": "[variables('_playbookContentId3')]", + "contentKind": "Playbook", + "displayName": "Block-AADUser-Incident", + "contentProductId": "[variables('_playbookcontentProductId3')]", + "id": "[variables('_playbookcontentProductId3')]", + "version": "[variables('playbookVersion3')]" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName14')]", + "name": "[variables('playbookTemplateSpecName4')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "BypassCondAccessRule_AnalyticalRules Analytics Rule with template version 3.0.4", + "description": "Prompt-User-Alert Playbook with template version 3.0.5", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion14')]", - "parameters": {}, - "variables": {}, + "contentVersion": "[variables('playbookVersion4')]", + "parameters": { + "PlaybookName": { + "defaultValue": "Prompt-User-Alert", + "type": "string" + }, + "TeamsId": { + "metadata": { + "description": "Enter the Teams Group ID" + }, + "type": "string" + }, + "TeamsChannelId": { + "metadata": { + "description": "Enter the Teams Channel ID" + }, + "type": "string" + } + }, + "variables": { + "AzureADConnectionName": "[[concat('azuread-', parameters('PlaybookName'))]", + "AzureSentinelConnectionName": "[[concat('azuresentinel-', parameters('PlaybookName'))]", + "Office365ConnectionName": "[[concat('office365-', parameters('PlaybookName'))]", + "TeamsConnectionName": "[[concat('teams-', parameters('PlaybookName'))]", + "connection-1": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuread')]", + "_connection-1": "[[variables('connection-1')]", + "connection-2": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", + "_connection-2": "[[variables('connection-2')]", + "connection-3": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]", + "_connection-3": "[[variables('connection-3')]", + "connection-4": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/teams')]", + "_connection-4": "[[variables('connection-4')]", + "workspace-location-inline": "[concat('[resourceGroup().locatio', 'n]')]", + "workspace-name": "[parameters('workspace')]", + "workspaceResourceId": "[[resourceId('microsoft.OperationalInsights/Workspaces', variables('workspace-name'))]" + }, "resources": [ { - "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId14')]", - "apiVersion": "2022-04-01-preview", - "kind": "Scheduled", - "location": "[parameters('workspace-location')]", + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[[variables('AzureADConnectionName')]", + "location": "[[variables('workspace-location-inline')]", "properties": { - "description": "Identifies an attempt to Bypass conditional access rule(s) in Azure Active Directory.\nThe ConditionalAccessStatus column value details if there was an attempt to bypass Conditional Access\nor if the Conditional access rule was not satisfied (ConditionalAccessStatus == 1).\nReferences:\nhttps://docs.microsoft.com/azure/active-directory/conditional-access/overview\nhttps://docs.microsoft.com/azure/active-directory/reports-monitoring/concept-sign-ins\nhttps://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-sign-ins-error-codes\nConditionalAccessStatus == 0 // Success\nConditionalAccessStatus == 1 // Failure\nConditionalAccessStatus == 2 // Not Applied\nConditionalAccessStatus == 3 // unknown", - "displayName": "Attempt to bypass conditional access rule in Azure AD", - "enabled": false, - "query": "let threshold = 1; // Modify this threshold value to reduce false positives based on your environment\nlet aadFunc = (tableName:string){\ntable(tableName)\n| where ConditionalAccessStatus == 1 or ConditionalAccessStatus =~ \"failure\"\n| mv-apply CAP = parse_json(ConditionalAccessPolicies) on (\n project ConditionalAccessPoliciesName = CAP.displayName, result = CAP.result\n | where result =~ \"failure\"\n)\n| extend DeviceDetail = todynamic(DeviceDetail), Status = todynamic(Status), LocationDetails = todynamic(LocationDetails)\n| extend OS = DeviceDetail.operatingSystem, Browser = DeviceDetail.browser\n| extend State = tostring(LocationDetails.state), City = tostring(LocationDetails.city), Region = tostring(LocationDetails.countryOrRegion)\n| extend StatusCode = tostring(Status.errorCode), StatusDetails = tostring(Status.additionalDetails)\n| extend Status = strcat(StatusCode, \": \", ResultDescription)\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), Status = make_list(Status,10), StatusDetails = make_list(StatusDetails,50), IPAddresses = make_list(IPAddress,100), IPAddressCount = dcount(IPAddress), CorrelationIds = make_list(CorrelationId,100), ConditionalAccessPoliciesName = make_list(ConditionalAccessPoliciesName,100)\nby UserPrincipalName, AppDisplayName, tostring(Browser), tostring(OS), City, State, Region, Type\n| where IPAddressCount > threshold and StatusDetails !has \"MFA successfully completed\"\n| mv-expand IPAddresses, Status, StatusDetails, CorrelationIds\n| extend Status = strcat(Status, \" \", StatusDetails)\n| summarize IPAddresses = make_set(IPAddresses,100), Status = make_set(Status,10), CorrelationIds = make_set(CorrelationIds,100), ConditionalAccessPoliciesName = make_set(ConditionalAccessPoliciesName,100)\nby StartTime, EndTime, UserPrincipalName, AppDisplayName, tostring(Browser), tostring(OS), City, State, Region, IPAddressCount, Type\n| extend timestamp = StartTime, IPAddresses = tostring(IPAddresses), Name = tostring(split(UserPrincipalName,'@',0)[0]), UPNSuffix = tostring(split(UserPrincipalName,'@',1)[0])\n};\nlet aadSignin = aadFunc(\"SigninLogs\");\nlet aadNonInt = aadFunc(\"AADNonInteractiveUserSignInLogs\");\nunion isfuzzy=true aadSignin, aadNonInt\n", - "queryFrequency": "P1D", - "queryPeriod": "P1D", - "severity": "Low", - "suppressionDuration": "PT1H", - "suppressionEnabled": false, - "triggerOperator": "GreaterThan", - "triggerThreshold": 0, - "status": "Available", - "requiredDataConnectors": [ - { - "dataTypes": [ - "SigninLogs" - ], - "connectorId": "AzureActiveDirectory" - }, - { - "dataTypes": [ - "AADNonInteractiveUserSignInLogs" - ], - "connectorId": "AzureActiveDirectory" - } - ], - "tactics": [ - "InitialAccess", - "Persistence" - ], - "techniques": [ - "T1078", - "T1098" - ], - "entityMappings": [ - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "Name" - }, - { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" - } - ] - }, - { - "entityType": "IP", - "fieldMappings": [ - { - "identifier": "Address", - "columnName": "IPAddresses" - } - ] - } - ] + "displayName": "[[variables('AzureADConnectionName')]", + "api": { + "id": "[[variables('_connection-1')]" + } } }, { - "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", - "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId14'),'/'))))]", + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[[variables('AzureSentinelConnectionName')]", + "location": "[[variables('workspace-location-inline')]", + "kind": "V1", "properties": { - "description": "Azure Active Directory Analytics Rule 14", - "parentId": "[variables('analyticRuleId14')]", - "contentId": "[variables('_analyticRulecontentId14')]", - "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion14')]", - "source": { - "kind": "Solution", - "name": "Azure Active Directory", - "sourceId": "[variables('_solutionId')]" - }, - "author": { - "name": "Microsoft", - "email": "[variables('_email')]" - }, - "support": { - "tier": "Microsoft", - "name": "Microsoft Corporation", - "email": "support@microsoft.com", - "link": "https://support.microsoft.com/" + "displayName": "[[variables('AzureSentinelConnectionName')]", + "parameterValueType": "Alternative", + "api": { + "id": "[[variables('_connection-2')]" } } - } - ] - }, - "packageKind": "Solution", - "packageVersion": "[variables('_solutionVersion')]", - "packageName": "[variables('_solutionName')]", - "packageId": "[variables('_solutionId')]", - "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId14')]", - "contentKind": "AnalyticsRule", - "displayName": "Attempt to bypass conditional access rule in Azure AD", - "contentProductId": "[variables('_analyticRulecontentProductId14')]", - "id": "[variables('_analyticRulecontentProductId14')]", - "version": "[variables('analyticRuleVersion14')]" - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", - "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName15')]", - "location": "[parameters('workspace-location')]", - "dependsOn": [ - "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" - ], - "properties": { - "description": "CredentialAddedAfterAdminConsent_AnalyticalRules Analytics Rule with template version 3.0.4", - "mainTemplate": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion15')]", - "parameters": {}, - "variables": {}, - "resources": [ + }, { - "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId15')]", - "apiVersion": "2022-04-01-preview", - "kind": "Scheduled", - "location": "[parameters('workspace-location')]", + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[[variables('Office365ConnectionName')]", + "location": "[[variables('workspace-location-inline')]", "properties": { - "description": "This query will identify instances where Service Principal credentials were added to an application by one user after the application was granted admin consent rights by another user.\n If a threat actor obtains access to an account with sufficient privileges and adds the alternate authentication material triggering this event, the threat actor can now authenticate as the Application or Service Principal using this credential.\n Additional information on OAuth Credential Grants can be found in RFC 6749 Section 4.4 or https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow.\n For further information on AuditLogs please see https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-audit-activities", - "displayName": "Credential added after admin consented to Application", - "enabled": false, - "query": "let auditLookbackStart = 2d;\nlet auditLookbackEnd = 1d;\nAuditLogs\n| where TimeGenerated >= ago(auditLookbackStart)\n| where OperationName =~ \"Consent to application\" \n| where Result =~ \"success\"\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"ServicePrincipal\"\n | extend targetResourceName = tostring(TargetResource.displayName),\n targetResourceID = tostring(TargetResource.id),\n targetResourceType = tostring(TargetResource.type),\n targetModifiedProp = TargetResource.modifiedProperties\n )\n| mv-apply Property = targetModifiedProp on \n (\n where Property.displayName =~ \"ConsentContext.IsAdminConsent\"\n | extend isAdminConsent = trim(@'\"',tostring(Property.newValue))\n )\n| mv-apply Property = targetModifiedProp on \n (\n where Property.displayName =~ \"ConsentAction.Permissions\"\n | extend Consent_Permissions = trim(@'\"',tostring(Property.newValue))\n )\n| mv-apply Property = targetModifiedProp on \n (\n where Property.displayName =~ \"TargetId.ServicePrincipalNames\"\n | extend Consent_ServicePrincipalNames = tostring(extract_all(@\"([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})\",trim(@'\"',tostring(Property.newValue)))[0])\n )\n| extend Consent_InitiatingUserOrApp = iff(isnotempty(InitiatedBy.user.userPrincipalName),tostring(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.app.displayName))\n| extend Consent_InitiatingIpAddress = iff(isnotempty(InitiatedBy.user.ipAddress), tostring(InitiatedBy.user.ipAddress), tostring(InitiatedBy.app.ipAddress))\n| join ( \nAuditLogs\n| where TimeGenerated >= ago(auditLookbackEnd)\n| where OperationName =~ \"Add service principal credentials\"\n| where Result =~ \"success\"\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"ServicePrincipal\"\n | extend targetResourceName = tostring(TargetResource.displayName),\n targetResourceID = tostring(TargetResource.id),\n targetModifiedProp = TargetResource.modifiedProperties\n )\n| mv-apply Property = targetModifiedProp on \n (\n where Property.displayName =~ \"KeyDescription\"\n | extend Credential_KeyDescription = trim(@'\"',tostring(Property.newValue))\n )\n| mv-apply Property = targetModifiedProp on \n (\n where Property.displayName =~ \"Included Updated Properties\"\n | extend UpdatedProperties = trim(@'\"',tostring(Property.newValue))\n )\n| mv-apply Property = targetModifiedProp on \n (\n where Property.displayName =~ \"TargetId.ServicePrincipalNames\"\n | extend Credential_ServicePrincipalNames = tostring(extract_all(@\"([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})\",trim(@'\"',tostring(Property.newValue)))[0])\n )\n| extend Credential_InitiatingUserOrApp = iff(isnotempty(InitiatedBy.user.userPrincipalName),tostring(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.app.displayName))\n| extend Credential_InitiatingIpAddress = iff(isnotempty(InitiatedBy.user.ipAddress), tostring(InitiatedBy.user.ipAddress), tostring(InitiatedBy.app.ipAddress))\n) on targetResourceName, targetResourceID\n| extend TimeConsent = TimeGenerated, TimeCred = TimeGenerated1\n| where TimeConsent < TimeCred \n| project TimeConsent, TimeCred, Consent_InitiatingUserOrApp, Credential_InitiatingUserOrApp, targetResourceName, targetResourceType, isAdminConsent, Consent_ServicePrincipalNames, Credential_ServicePrincipalNames, Consent_Permissions, Credential_KeyDescription, Consent_InitiatingIpAddress, Credential_InitiatingIpAddress\n| extend timestamp = TimeConsent, Name = tostring(split(Credential_InitiatingUserOrApp,'@',0)[0]), UPNSuffix = tostring(split(Credential_InitiatingUserOrApp,'@',1)[0])\n", - "queryFrequency": "P1D", - "queryPeriod": "P2D", - "severity": "Medium", - "suppressionDuration": "PT1H", - "suppressionEnabled": false, - "triggerOperator": "GreaterThan", - "triggerThreshold": 0, - "status": "Available", - "requiredDataConnectors": [ - { - "dataTypes": [ - "AuditLogs" - ], - "connectorId": "AzureActiveDirectory" - } - ], - "tactics": [ - "CredentialAccess" - ], - "entityMappings": [ - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "Name" - }, - { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" - } - ] - }, - { - "entityType": "IP", - "fieldMappings": [ - { - "identifier": "Address", - "columnName": "Consent_InitiatingIpAddress" - } - ] - } - ] - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", - "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId15'),'/'))))]", - "properties": { - "description": "Azure Active Directory Analytics Rule 15", - "parentId": "[variables('analyticRuleId15')]", - "contentId": "[variables('_analyticRulecontentId15')]", - "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion15')]", - "source": { - "kind": "Solution", - "name": "Azure Active Directory", - "sourceId": "[variables('_solutionId')]" - }, - "author": { - "name": "Microsoft", - "email": "[variables('_email')]" - }, - "support": { - "tier": "Microsoft", - "name": "Microsoft Corporation", - "email": "support@microsoft.com", - "link": "https://support.microsoft.com/" + "displayName": "[[variables('Office365ConnectionName')]", + "api": { + "id": "[[variables('_connection-3')]" } } - } - ] - }, - "packageKind": "Solution", - "packageVersion": "[variables('_solutionVersion')]", - "packageName": "[variables('_solutionName')]", - "packageId": "[variables('_solutionId')]", - "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId15')]", - "contentKind": "AnalyticsRule", - "displayName": "Credential added after admin consented to Application", - "contentProductId": "[variables('_analyticRulecontentProductId15')]", - "id": "[variables('_analyticRulecontentProductId15')]", - "version": "[variables('analyticRuleVersion15')]" - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", - "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName16')]", - "location": "[parameters('workspace-location')]", - "dependsOn": [ - "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" - ], - "properties": { - "description": "Cross-tenantAccessSettingsOrganizationAdded_AnalyticalRules Analytics Rule with template version 3.0.4", - "mainTemplate": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion16')]", - "parameters": {}, - "variables": {}, - "resources": [ - { - "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId16')]", - "apiVersion": "2022-04-01-preview", - "kind": "Scheduled", - "location": "[parameters('workspace-location')]", - "properties": { - "description": "Organizations are added in the Cross-tenant Access Settings to control communication inbound or outbound for users and applications. This detection notifies when an Organization is added other than the list that is supposed to exist from the Azure AD Cross-tenant Access Settings.", - "displayName": "Cross-tenant Access Settings Organization Added", - "enabled": false, - "query": "// Tenants IDs can be found by navigating to Azure Active Directory then from menu on the left, select External Identities, then from menu on the left, select Cross-tenant access settings and from the list shown of Tenants\nlet ExpectedTenantIDs = dynamic([\"List of expected tenant IDs\",\"Tenant ID 2\"]);\nAuditLogs\n| where OperationName has \"Add a partner to cross-tenant access setting\"\n| extend InitiatedByActionUserInformation = iff(isnotempty(InitiatedBy.user.userPrincipalName), InitiatedBy.user.userPrincipalName, InitiatedBy.app.displayName)\n| extend InitiatedByIPAdress = InitiatedBy.user.ipAddress\n| mv-apply TargetResource = TargetResources on\n (\n where TargetResource.type =~ \"Policy\"\n | extend Properties = TargetResource.modifiedProperties\n )\n| mv-apply Property = Properties on\n (\n where Property.displayName =~ \"tenantId\"\n | extend ExtTenantIDAdded = trim('\"',tostring(Property.newValue))\n )\n| where ExtTenantIDAdded !in (ExpectedTenantIDs)\n| extend Name = tostring(split(InitiatedByActionUserInformation,'@',0)[0]), UPNSuffix = tostring(split(InitiatedByActionUserInformation,'@',1)[0])\n", - "queryFrequency": "P2D", - "queryPeriod": "P2D", - "severity": "Medium", - "suppressionDuration": "PT1H", - "suppressionEnabled": false, - "triggerOperator": "GreaterThan", - "triggerThreshold": 0, - "status": "Available", - "requiredDataConnectors": [ - { - "dataTypes": [ - "AuditLogs" - ], - "connectorId": "AzureActiveDirectory" - } - ], - "tactics": [ - "InitialAccess", - "Persistence", - "Discovery" - ], - "techniques": [ - "T1078", - "T1136", - "T1087" - ], - "entityMappings": [ - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "Name" - }, - { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" - } - ] - }, - { - "entityType": "IP", - "fieldMappings": [ - { - "identifier": "Address", - "columnName": "InitiatedByIPAdress" - } - ] - } - ] - } }, { - "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", - "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId16'),'/'))))]", + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[[variables('TeamsConnectionName')]", + "location": "[[variables('workspace-location-inline')]", "properties": { - "description": "Azure Active Directory Analytics Rule 16", - "parentId": "[variables('analyticRuleId16')]", - "contentId": "[variables('_analyticRulecontentId16')]", - "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion16')]", - "source": { - "kind": "Solution", - "name": "Azure Active Directory", - "sourceId": "[variables('_solutionId')]" - }, - "author": { - "name": "Microsoft", - "email": "[variables('_email')]" - }, - "support": { - "tier": "Microsoft", - "name": "Microsoft Corporation", - "email": "support@microsoft.com", - "link": "https://support.microsoft.com/" + "displayName": "[[variables('TeamsConnectionName')]", + "api": { + "id": "[[variables('_connection-4')]" } } - } - ] - }, - "packageKind": "Solution", - "packageVersion": "[variables('_solutionVersion')]", - "packageName": "[variables('_solutionName')]", - "packageId": "[variables('_solutionId')]", - "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId16')]", - "contentKind": "AnalyticsRule", - "displayName": "Cross-tenant Access Settings Organization Added", - "contentProductId": "[variables('_analyticRulecontentProductId16')]", - "id": "[variables('_analyticRulecontentProductId16')]", - "version": "[variables('analyticRuleVersion16')]" - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", - "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName17')]", - "location": "[parameters('workspace-location')]", - "dependsOn": [ - "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" - ], - "properties": { - "description": "Cross-tenantAccessSettingsOrganizationDeleted_AnalyticalRules Analytics Rule with template version 3.0.4", - "mainTemplate": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion17')]", - "parameters": {}, - "variables": {}, - "resources": [ - { - "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId17')]", - "apiVersion": "2022-04-01-preview", - "kind": "Scheduled", - "location": "[parameters('workspace-location')]", - "properties": { - "description": "Organizations are added in the Cross-tenant Access Settings to control communication inbound or outbound for users and applications. This detection notifies when an Organization is deleted from the Azure AD Cross-tenant Access Settings.", - "displayName": "Cross-tenant Access Settings Organization Deleted", - "enabled": false, - "query": "AuditLogs\n| where OperationName has \"Delete partner specific cross-tenant access setting\"\n| extend InitiatedByActionUserInformation = iff(isnotempty(InitiatedBy.user.userPrincipalName), InitiatedBy.user.userPrincipalName, InitiatedBy.app.displayName)\n| extend InitiatedByIPAdress = InitiatedBy.user.ipAddress\n| mv-apply TargetResource = TargetResources on\n (\n where TargetResource.type =~ \"Policy\"\n | extend Properties = TargetResource.modifiedProperties\n )\n| mv-apply Property = Properties on\n (\n where Property.displayName =~ \"tenantId\"\n | extend ExtTenantDeleted = trim('\"',tostring(Property.oldValue))\n )\n| extend Name = tostring(split(InitiatedByActionUserInformation,'@',0)[0]), UPNSuffix = tostring(split(InitiatedByActionUserInformation,'@',1)[0])\n", - "queryFrequency": "P2D", - "queryPeriod": "P2D", - "severity": "Medium", - "suppressionDuration": "PT1H", - "suppressionEnabled": false, - "triggerOperator": "GreaterThan", - "triggerThreshold": 0, - "status": "Available", - "requiredDataConnectors": [ - { - "dataTypes": [ - "AuditLogs" - ], - "connectorId": "AzureActiveDirectory" - } - ], - "tactics": [ - "InitialAccess", - "Persistence", - "Discovery" - ], - "techniques": [ - "T1078", - "T1136", - "T1087" - ], - "entityMappings": [ - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "Name" - }, - { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" - } - ] - }, - { - "entityType": "IP", - "fieldMappings": [ - { - "identifier": "Address", - "columnName": "InitiatedByIPAdress" - } - ] - } - ] - } }, { - "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", - "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId17'),'/'))))]", + "type": "Microsoft.Logic/workflows", + "apiVersion": "2017-07-01", + "name": "[[parameters('PlaybookName')]", + "location": "[[variables('workspace-location-inline')]", + "tags": { + "LogicAppsCategory": "security", + "hidden-SentinelTemplateName": "Prompt-User_alert", + "hidden-SentinelTemplateVersion": "1.1", + "hidden-SentinelWorkspaceId": "[[variables('workspaceResourceId')]" + }, + "identity": { + "type": "SystemAssigned" + }, + "dependsOn": [ + "[[resourceId('Microsoft.Web/connections', variables('AzureADConnectionName'))]", + "[[resourceId('Microsoft.Web/connections', variables('AzureSentinelConnectionName'))]", + "[[resourceId('Microsoft.Web/connections', variables('Office365ConnectionName'))]", + "[[resourceId('Microsoft.Web/connections', variables('TeamsConnectionName'))]" + ], "properties": { - "description": "Azure Active Directory Analytics Rule 17", - "parentId": "[variables('analyticRuleId17')]", - "contentId": "[variables('_analyticRulecontentId17')]", - "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion17')]", - "source": { - "kind": "Solution", - "name": "Azure Active Directory", - "sourceId": "[variables('_solutionId')]" - }, - "author": { - "name": "Microsoft", - "email": "[variables('_email')]" - }, - "support": { - "tier": "Microsoft", - "name": "Microsoft Corporation", - "email": "support@microsoft.com", - "link": "https://support.microsoft.com/" - } - } - } - ] - }, - "packageKind": "Solution", - "packageVersion": "[variables('_solutionVersion')]", - "packageName": "[variables('_solutionName')]", - "packageId": "[variables('_solutionId')]", - "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId17')]", - "contentKind": "AnalyticsRule", - "displayName": "Cross-tenant Access Settings Organization Deleted", - "contentProductId": "[variables('_analyticRulecontentProductId17')]", - "id": "[variables('_analyticRulecontentProductId17')]", - "version": "[variables('analyticRuleVersion17')]" - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", - "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName18')]", - "location": "[parameters('workspace-location')]", - "dependsOn": [ - "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" - ], - "properties": { - "description": "Cross-tenantAccessSettingsOrganizationInboundCollaborationSettingsChanged_AnalyticalRules Analytics Rule with template version 3.0.4", - "mainTemplate": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion18')]", - "parameters": {}, - "variables": {}, - "resources": [ - { - "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId18')]", - "apiVersion": "2022-04-01-preview", - "kind": "Scheduled", - "location": "[parameters('workspace-location')]", - "properties": { - "description": "Organizations are added in the Cross-tenant Access Settings to control communication inbound or outbound for users and applications. This detection notifies when Organization Inbound Collaboration Settings are changed for \"Users & Groups\" and for \"Applications\".", - "displayName": "Cross-tenant Access Settings Organization Inbound Collaboration Settings Changed", - "enabled": false, - "query": "//In User & Groups and in Applications, the following \"AccessType\" values in columns PremodifiedInboundSettings and ModifiedInboundSettings are interpreted accordingly:\n// When Access Type in premodified inbound settings value was 1 that means that the initial access was allowed. When Access Type in premodified inbound settings value was 2 that means that the initial access was blocked. \n// When Access Type in modified inbound settings value is 1 that means that now access is allowed. When Access Type in modified inbound settings value is 2 that means that now access is blocked. \nAuditLogs\n| where OperationName has \"Update a partner cross-tenant access setting\"\n| mv-apply TargetResource = TargetResources on\n (\n where TargetResource.type =~ \"Policy\"\n | extend Properties = TargetResource.modifiedProperties\n )\n| mv-apply Property = Properties on\n (\n where Property.displayName =~ \"b2bCollaborationInbound\"\n | extend PremodifiedInboundSettings = trim('\"',tostring(Property.oldValue)),\n ModifiedInboundSettings = trim(@'\"',tostring(Property.newValue))\n )\n| extend InitiatedByActionUserInformation = iff(isnotempty(InitiatedBy.user.userPrincipalName), InitiatedBy.user.userPrincipalName, InitiatedBy.app.displayName)\n| extend InitiatedByIPAdress = InitiatedBy.user.ipAddress\n| where PremodifiedInboundSettings != ModifiedInboundSettings\n| extend Name = tostring(split(InitiatedByActionUserInformation,'@',0)[0]), UPNSuffix = tostring(split(InitiatedByActionUserInformation,'@',1)[0])\n", - "queryFrequency": "P2D", - "queryPeriod": "P2D", - "severity": "Medium", - "suppressionDuration": "PT1H", - "suppressionEnabled": false, - "triggerOperator": "GreaterThan", - "triggerThreshold": 0, - "status": "Available", - "requiredDataConnectors": [ - { - "dataTypes": [ - "AuditLogs" - ], - "connectorId": "AzureActiveDirectory" - } - ], - "tactics": [ - "InitialAccess", - "Persistence", - "Discovery" - ], - "techniques": [ - "T1078", - "T1136", - "T1087" - ], - "entityMappings": [ - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "Name" + "state": "Enabled", + "definition": { + "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", + "actions": { + "Alert_-_Get_incident": { + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "get", + "path": "/Incidents/subscriptions/@{encodeURIComponent(triggerBody()?['WorkspaceSubscriptionId'])}/resourceGroups/@{encodeURIComponent(triggerBody()?['WorkspaceResourceGroup'])}/workspaces/@{encodeURIComponent(triggerBody()?['WorkspaceId'])}/alerts/@{encodeURIComponent(triggerBody()?['SystemAlertId'])}" }, - { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" - } - ] - }, - { - "entityType": "IP", - "fieldMappings": [ - { - "identifier": "Address", - "columnName": "InitiatedByIPAdress" - } - ] - } - ] - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", - "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId18'),'/'))))]", - "properties": { - "description": "Azure Active Directory Analytics Rule 18", - "parentId": "[variables('analyticRuleId18')]", - "contentId": "[variables('_analyticRulecontentId18')]", - "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion18')]", - "source": { - "kind": "Solution", - "name": "Azure Active Directory", - "sourceId": "[variables('_solutionId')]" - }, - "author": { - "name": "Microsoft", - "email": "[variables('_email')]" - }, - "support": { - "tier": "Microsoft", - "name": "Microsoft Corporation", - "email": "support@microsoft.com", - "link": "https://support.microsoft.com/" - } - } - } - ] - }, - "packageKind": "Solution", - "packageVersion": "[variables('_solutionVersion')]", - "packageName": "[variables('_solutionName')]", - "packageId": "[variables('_solutionId')]", - "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId18')]", - "contentKind": "AnalyticsRule", - "displayName": "Cross-tenant Access Settings Organization Inbound Collaboration Settings Changed", - "contentProductId": "[variables('_analyticRulecontentProductId18')]", - "id": "[variables('_analyticRulecontentProductId18')]", - "version": "[variables('analyticRuleVersion18')]" - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", - "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName19')]", - "location": "[parameters('workspace-location')]", - "dependsOn": [ - "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" - ], - "properties": { - "description": "Cross-tenantAccessSettingsOrganizationInboundDirectSettingsChanged_AnalyticalRules Analytics Rule with template version 3.0.4", - "mainTemplate": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion19')]", - "parameters": {}, - "variables": {}, - "resources": [ - { - "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId19')]", - "apiVersion": "2022-04-01-preview", - "kind": "Scheduled", - "location": "[parameters('workspace-location')]", - "properties": { - "description": "Organizations are added in the Cross-tenant Access Settings to control communication inbound or outbound for users and applications. This detection notifies when Organization Inbound Direct Settings are changed for \"Users & Groups\" and for \"Applications\".", - "displayName": "Cross-tenant Access Settings Organization Inbound Direct Settings Changed", - "enabled": false, - "query": "//In User & Groups and in Applications, the following \"AccessType\" values in columns PremodifiedInboundSettings and ModifiedInboundSettings are interpreted accordingly:\n// When Access Type in premodified inbound settings value was 1 that means that the initial access was allowed. When Access Type in premodified inbound settings value was 2 that means that the initial access was blocked. \n// When Access Type in modified inbound settings value is 1 that means that now access is allowed. When Access Type in modified inbound settings value is 2 that means that now access is blocked. \nAuditLogs\n| where OperationName has \"Update a partner cross-tenant access setting\"\n| mv-apply TargetResource = TargetResources on\n (\n where TargetResource.type =~ \"Policy\"\n | extend Properties = TargetResource.modifiedProperties\n )\n| mv-apply Property = Properties on\n (\n where Property.displayName =~ \"b2bDirectConnectInbound\"\n | extend PremodifiedInboundSettings = trim('\"',tostring(Property.oldValue)),\n ModifiedInboundSettings = trim(@'\"',tostring(Property.newValue))\n )\n| extend InitiatedByActionUserInformation = iff(isnotempty(InitiatedBy.user.userPrincipalName), InitiatedBy.user.userPrincipalName, InitiatedBy.app.displayName)\n| extend InitiatedByIPAdress = InitiatedBy.user.ipAddress\n| where PremodifiedInboundSettings != ModifiedInboundSettings\n| extend Name = tostring(split(InitiatedByActionUserInformation,'@',0)[0]), UPNSuffix = tostring(split(InitiatedByActionUserInformation,'@',1)[0])\n", - "queryFrequency": "P2D", - "queryPeriod": "P2D", - "severity": "Medium", - "suppressionDuration": "PT1H", - "suppressionEnabled": false, - "triggerOperator": "GreaterThan", - "triggerThreshold": 0, - "status": "Available", - "requiredDataConnectors": [ - { - "dataTypes": [ - "AuditLogs" - ], - "connectorId": "AzureActiveDirectory" - } - ], - "tactics": [ - "InitialAccess", - "Persistence", - "Discovery" - ], - "techniques": [ - "T1078", - "T1136", - "T1087" - ], - "entityMappings": [ - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "Name" + "type": "ApiConnection" + }, + "Entities_-_Get_Accounts": { + "inputs": { + "body": "@triggerBody()?['Entities']", + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "post", + "path": "/entities/account" }, - { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" - } - ] - }, - { - "entityType": "IP", - "fieldMappings": [ - { - "identifier": "Address", - "columnName": "InitiatedByIPAdress" - } - ] - } - ] - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", - "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId19'),'/'))))]", - "properties": { - "description": "Azure Active Directory Analytics Rule 19", - "parentId": "[variables('analyticRuleId19')]", - "contentId": "[variables('_analyticRulecontentId19')]", - "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion19')]", - "source": { - "kind": "Solution", - "name": "Azure Active Directory", - "sourceId": "[variables('_solutionId')]" - }, - "author": { - "name": "Microsoft", + "runAfter": { + "Alert_-_Get_incident": [ + "Succeeded" + ] + }, + "type": "ApiConnection" + }, + "For_each": { + "actions": { + "Condition_2": { + "actions": { + "Add_comment_to_incident_(V3)": { + "inputs": { + "body": { + "incidentArmId": "@body('Alert_-_Get_incident')?['id']", + "message": "

@{body('Get_user')?['displayName']} confirms they completed the action that triggered the alert.  Closing the incident.

" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "post", + "path": "/Incidents/Comment" + }, + "type": "ApiConnection" + }, + "Update_incident": { + "inputs": { + "body": { + "classification": { + "ClassificationAndReason": "BenignPositive - SuspiciousButExpected", + "ClassificationReasonText": "User Confirmed it was them" + }, + "incidentArmId": "@body('Alert_-_Get_incident')?['id']", + "status": "Closed" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "put", + "path": "/Incidents" + }, + "runAfter": { + "Add_comment_to_incident_(V3)": [ + "Succeeded" + ] + }, + "type": "ApiConnection" + } + }, + "else": { + "actions": { + "Add_comment_to_incident_(V3)_2": { + "inputs": { + "body": { + "incidentArmId": "@body('Alert_-_Get_incident')?['id']", + "message": "

@{body('Get_user')?['displayName']} confirms they did not complete the action. Further investigation is needed.

" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "post", + "path": "/Incidents/Comment" + }, + "type": "ApiConnection" + }, + "Post_message_in_a_chat_or_channel": { + "inputs": { + "body": { + "messageBody": "

New alert from Microsoft Sentinel.
\nPlease investigate ASAP.
\nSeverity : @{body('Alert_-_Get_incident')?['properties']?['severity']}
\nDescription: @{body('Alert_-_Get_incident')?['properties']?['description']}
\n
\n@{body('Get_user')?['displayName']} user confirmed they did not complete the action.

", + "recipient": { + "channelId": "[[parameters('TeamsChannelId')]", + "groupId": "[[parameters('TeamsId')]" + }, + "subject": "Incident @{body('Alert_-_Get_incident')?['properties']?['incidentNumber']} - @{body('Alert_-_Get_incident')?['properties']?['title']}" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['teams']['connectionId']" + } + }, + "method": "post", + "path": "/beta/teams/conversation/message/poster/@{encodeURIComponent('User')}/location/@{encodeURIComponent('Channel')}" + }, + "runAfter": { + "Add_comment_to_incident_(V3)_2": [ + "Succeeded" + ] + }, + "type": "ApiConnection" + } + } + }, + "expression": { + "and": [ + { + "equals": [ + "", + "This was me" + ] + } + ] + }, + "runAfter": { + "Send_approval_email": [ + "Succeeded" + ] + }, + "type": "If" + }, + "Get_user": { + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['azuread']['connectionId']" + } + }, + "method": "get", + "path": "/v1.0/users/@{encodeURIComponent(concat(items('For_each')?['Name'], '@' ,items('For_each')?['UPNSuffix']))}" + }, + "type": "ApiConnection" + }, + "Send_approval_email": { + "inputs": { + "body": { + "Message": { + "Body": "New Alert from Microsoft Sentinel.\nPlease respond ASAP.\nSeverity: @{triggerBody()?['Severity']}\nName: @{triggerBody()?['AlertDisplayName']}\nDescription: @{triggerBody()?['Description']}", + "HideHTMLMessage": false, + "Importance": "High", + "Options": "This was me, This was not me", + "ShowHTMLConfirmationDialog": false, + "Subject": "Security Alert: @{body('Alert_-_Get_incident')?['properties']?['title']}", + "To": "@body('Get_user')?['mail']" + }, + "NotificationUrl": "@{listCallbackUrl()}" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['office365']['connectionId']" + } + }, + "path": "/approvalmail/$subscriptions" + }, + "runAfter": { + "Get_user": [ + "Succeeded" + ] + }, + "type": "ApiConnectionWebhook" + } + }, + "foreach": "@body('Entities_-_Get_Accounts')?['Accounts']", + "runAfter": { + "Entities_-_Get_Accounts": [ + "Succeeded" + ] + }, + "type": "Foreach" + } + }, + "contentVersion": "1.0.0.0", + "parameters": { + "$connections": { + "type": "Object" + } + }, + "triggers": { + "Microsoft_Sentinel_alert": { + "inputs": { + "body": { + "callback_url": "@{listCallbackUrl()}" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "path": "/subscribe" + }, + "type": "ApiConnectionWebhook" + } + } + }, + "parameters": { + "$connections": { + "value": { + "azuread": { + "connectionId": "[[resourceId('Microsoft.Web/connections', variables('AzureADConnectionName'))]", + "connectionName": "[[variables('AzureADConnectionName')]", + "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuread')]" + }, + "azuresentinel": { + "connectionId": "[[resourceId('Microsoft.Web/connections', variables('AzureSentinelConnectionName'))]", + "connectionName": "[[variables('AzureSentinelConnectionName')]", + "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", + "connectionProperties": { + "authentication": { + "type": "ManagedServiceIdentity" + } + } + }, + "office365": { + "connectionId": "[[resourceId('Microsoft.Web/connections', variables('Office365ConnectionName'))]", + "connectionName": "[[variables('Office365ConnectionName')]", + "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]" + }, + "teams": { + "connectionId": "[[resourceId('Microsoft.Web/connections', variables('TeamsConnectionName'))]", + "connectionName": "[[variables('TeamsConnectionName')]", + "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/teams')]" + } + } + } + } + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('Playbook-', last(split(variables('playbookId4'),'/'))))]", + "properties": { + "parentId": "[variables('playbookId4')]", + "contentId": "[variables('_playbookContentId4')]", + "kind": "Playbook", + "version": "[variables('playbookVersion4')]", + "source": { + "kind": "Solution", + "name": "Azure Active Directory", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "Microsoft", "email": "[variables('_email')]" }, "support": { @@ -3345,735 +2241,408 @@ } } } - ] - }, - "packageKind": "Solution", - "packageVersion": "[variables('_solutionVersion')]", - "packageName": "[variables('_solutionName')]", - "packageId": "[variables('_solutionId')]", - "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId19')]", - "contentKind": "AnalyticsRule", - "displayName": "Cross-tenant Access Settings Organization Inbound Direct Settings Changed", - "contentProductId": "[variables('_analyticRulecontentProductId19')]", - "id": "[variables('_analyticRulecontentProductId19')]", - "version": "[variables('analyticRuleVersion19')]" - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", - "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName20')]", - "location": "[parameters('workspace-location')]", - "dependsOn": [ - "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" - ], - "properties": { - "description": "Cross-tenantAccessSettingsOrganizationOutboundCollaborationSettingsChanged_AnalyticalRules Analytics Rule with template version 3.0.4", - "mainTemplate": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion20')]", - "parameters": {}, - "variables": {}, - "resources": [ - { - "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId20')]", - "apiVersion": "2022-04-01-preview", - "kind": "Scheduled", - "location": "[parameters('workspace-location')]", - "properties": { - "description": "Organizations are added in the Cross-tenant Access Settings to control communication inbound or outbound for users and applications. This detection notifies when Organization Outbound Collaboration Settings are changed for \"Users & Groups\" and for \"Applications\".", - "displayName": "Cross-tenant Access Settings Organization Outbound Collaboration Settings Changed", - "enabled": false, - "query": "//In User & Groups and in Applications, the following \"AccessType\" values in columns PremodifiedOutboundSettings and ModifiedOutboundSettings are interpreted accordingly:\n// When Access Type in premodified outbound settings value was 1 that means that the initial access was allowed. When Access Type in premodified outbound settings value was 2 that means that the initial access was blocked. \n// When Access Type in modified outbound settings value is 1 that means that now access is allowed. When Access Type in modified outbound settings value is 2 that means that now access is blocked. \nAuditLogs\n| where OperationName has \"Update a partner cross-tenant access setting\"\n| mv-apply TargetResource = TargetResources on\n (\n where TargetResource.type =~ \"Policy\"\n | extend Properties = TargetResource.modifiedProperties\n )\n| mv-apply Property = Properties on\n (\n where Property.displayName =~ \"b2bCollaborationOutbound\"\n | extend PremodifiedOutboundSettings = trim('\"',tostring(Property.oldValue)),\n ModifiedOutboundSettings = trim(@'\"',tostring(Property.newValue))\n )\n| extend InitiatedByActionUserInformation = iff(isnotempty(InitiatedBy.user.userPrincipalName), InitiatedBy.user.userPrincipalName, InitiatedBy.app.displayName)\n| extend InitiatedByIPAdress = InitiatedBy.user.ipAddress\n| where PremodifiedOutboundSettings != ModifiedOutboundSettings\n| extend Name = tostring(split(InitiatedByActionUserInformation,'@',0)[0]), UPNSuffix = tostring(split(InitiatedByActionUserInformation,'@',1)[0])\n", - "queryFrequency": "P2D", - "queryPeriod": "P2D", - "severity": "Medium", - "suppressionDuration": "PT1H", - "suppressionEnabled": false, - "triggerOperator": "GreaterThan", - "triggerThreshold": 0, - "status": "Available", - "requiredDataConnectors": [ - { - "dataTypes": [ - "AuditLogs" - ], - "connectorId": "AzureActiveDirectory" - } - ], - "tactics": [ - "InitialAccess", - "Persistence", - "Discovery" - ], - "techniques": [ - "T1078", - "T1136", - "T1087" - ], - "entityMappings": [ - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "Name" - }, - { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" - } - ] - }, - { - "entityType": "IP", - "fieldMappings": [ - { - "identifier": "Address", - "columnName": "InitiatedByIPAdress" - } - ] - } + ], + "metadata": { + "title": "Prompt User - Alert", + "description": "This playbook will ask the user if they completed the action from the alert in Microsoft Sentinel. If so, it will close the incident and add a comment. If not, it will post a message to teams for the SOC to investigate and add a comment to the incident.", + "prerequisites": [ + "1. You will need the Team Id and Channel Id." + ], + "postDeployment": [ + "1. Assign Microsoft Sentinel Responder role to the Playbook's managed identity.", + "2. Authorize Azure AD, Microsoft Teams, and Office 365 Outlook Logic App connections." + ], + "lastUpdateTime": "2022-07-11T00:00:00Z", + "entities": [ + "Account" + ], + "tags": [ + "Remediation" + ], + "releaseNotes": [ + { + "version": "1.0.0", + "title": "Added new Post a Teams message action", + "notes": [ + "Initial version" ] } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", - "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId20'),'/'))))]", - "properties": { - "description": "Azure Active Directory Analytics Rule 20", - "parentId": "[variables('analyticRuleId20')]", - "contentId": "[variables('_analyticRulecontentId20')]", - "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion20')]", - "source": { - "kind": "Solution", - "name": "Azure Active Directory", - "sourceId": "[variables('_solutionId')]" - }, - "author": { - "name": "Microsoft", - "email": "[variables('_email')]" - }, - "support": { - "tier": "Microsoft", - "name": "Microsoft Corporation", - "email": "support@microsoft.com", - "link": "https://support.microsoft.com/" - } - } - } - ] + ] + } }, "packageKind": "Solution", "packageVersion": "[variables('_solutionVersion')]", "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId20')]", - "contentKind": "AnalyticsRule", - "displayName": "Cross-tenant Access Settings Organization Outbound Collaboration Settings Changed", - "contentProductId": "[variables('_analyticRulecontentProductId20')]", - "id": "[variables('_analyticRulecontentProductId20')]", - "version": "[variables('analyticRuleVersion20')]" + "contentId": "[variables('_playbookContentId4')]", + "contentKind": "Playbook", + "displayName": "Prompt-User-Alert", + "contentProductId": "[variables('_playbookcontentProductId4')]", + "id": "[variables('_playbookcontentProductId4')]", + "version": "[variables('playbookVersion4')]" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName21')]", + "name": "[variables('playbookTemplateSpecName5')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "Cross-tenantAccessSettingsOrganizationOutboundDirectSettingsChanged_AnalyticalRules Analytics Rule with template version 3.0.4", + "description": "Prompt-User-Incident Playbook with template version 3.0.5", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion21')]", - "parameters": {}, - "variables": {}, + "contentVersion": "[variables('playbookVersion5')]", + "parameters": { + "PlaybookName": { + "defaultValue": "Prompt-User-Incident", + "type": "string" + }, + "TeamsId": { + "metadata": { + "description": "Enter the Teams Group ID" + }, + "type": "string" + }, + "TeamsChannelId": { + "metadata": { + "description": "Enter the Teams Channel ID" + }, + "type": "string" + } + }, + "variables": { + "AzureADConnectionName": "[[concat('azuread-', parameters('PlaybookName'))]", + "AzureSentinelConnectionName": "[[concat('azuresentinel-', parameters('PlaybookName'))]", + "Office365ConnectionName": "[[concat('office365-', parameters('PlaybookName'))]", + "TeamsConnectionName": "[[concat('teams-', parameters('PlaybookName'))]", + "connection-1": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuread')]", + "_connection-1": "[[variables('connection-1')]", + "connection-2": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", + "_connection-2": "[[variables('connection-2')]", + "connection-3": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]", + "_connection-3": "[[variables('connection-3')]", + "connection-4": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/teams')]", + "_connection-4": "[[variables('connection-4')]", + "workspace-location-inline": "[concat('[resourceGroup().locatio', 'n]')]", + "workspace-name": "[parameters('workspace')]", + "workspaceResourceId": "[[resourceId('microsoft.OperationalInsights/Workspaces', variables('workspace-name'))]" + }, "resources": [ { - "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId21')]", - "apiVersion": "2022-04-01-preview", - "kind": "Scheduled", - "location": "[parameters('workspace-location')]", + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[[variables('AzureADConnectionName')]", + "location": "[[variables('workspace-location-inline')]", "properties": { - "description": "Organizations are added in the Cross-tenant Access Settings to control communication inbound or outbound for users and applications. This detection notifies when Organization Outbound Direct Settings are changed for \"Users & Groups\" and for \"Applications\".", - "displayName": "Cross-tenant Access Settings Organization Outbound Direct Settings Changed", - "enabled": false, - "query": "//In User & Groups and in Applications, the following \"AccessType\" values in columns PremodifiedOutboundSettings and ModifiedOutboundSettings are interpreted accordingly:\n// When Access Type in premodified outbound settings value was 1 that means that the initial access was allowed. When Access Type in premodified outbound settings value was 2 that means that the initial access was blocked. \n// When Access Type in modified outbound settings value is 1 that means that now access is allowed. When Access Type in modified outbound settings value is 2 that means that now access is blocked. \nAuditLogs\n| where OperationName has \"Update a partner cross-tenant access setting\"\n| mv-apply TargetResource = TargetResources on\n (\n where TargetResource.type =~ \"Policy\"\n | extend Properties = TargetResource.modifiedProperties\n )\n| mv-apply Property = Properties on\n (\n where Property.displayName =~ \"b2bDirectConnectOutbound\"\n | extend PremodifiedOutboundSettings = trim('\"',tostring(Property.oldValue)),\n ModifiedOutboundSettings = trim(@'\"',tostring(Property.newValue))\n )\n| extend InitiatedByActionUserInformation = iff(isnotempty(InitiatedBy.user.userPrincipalName), InitiatedBy.user.userPrincipalName, InitiatedBy.app.displayName)\n| extend InitiatedByIPAdress = InitiatedBy.user.ipAddress\n| where PremodifiedOutboundSettings != ModifiedOutboundSettings\n| extend Name = tostring(split(InitiatedByActionUserInformation,'@',0)[0]), UPNSuffix = tostring(split(InitiatedByActionUserInformation,'@',1)[0])\n", - "queryFrequency": "P2D", - "queryPeriod": "P2D", - "severity": "Medium", - "suppressionDuration": "PT1H", - "suppressionEnabled": false, - "triggerOperator": "GreaterThan", - "triggerThreshold": 0, - "status": "Available", - "requiredDataConnectors": [ - { - "dataTypes": [ - "AuditLogs" - ], - "connectorId": "AzureActiveDirectory" - } - ], - "tactics": [ - "InitialAccess", - "Persistence", - "Discovery" - ], - "techniques": [ - "T1078", - "T1136", - "T1087" - ], - "entityMappings": [ - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "Name" - }, - { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" - } - ] - }, - { - "entityType": "IP", - "fieldMappings": [ - { - "identifier": "Address", - "columnName": "InitiatedByIPAdress" - } - ] - } - ] + "displayName": "[[variables('AzureADConnectionName')]", + "api": { + "id": "[[variables('_connection-1')]" + } } }, { - "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", - "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId21'),'/'))))]", + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[[variables('AzureSentinelConnectionName')]", + "location": "[[variables('workspace-location-inline')]", + "kind": "V1", "properties": { - "description": "Azure Active Directory Analytics Rule 21", - "parentId": "[variables('analyticRuleId21')]", - "contentId": "[variables('_analyticRulecontentId21')]", - "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion21')]", - "source": { - "kind": "Solution", - "name": "Azure Active Directory", - "sourceId": "[variables('_solutionId')]" - }, - "author": { - "name": "Microsoft", - "email": "[variables('_email')]" - }, - "support": { - "tier": "Microsoft", - "name": "Microsoft Corporation", - "email": "support@microsoft.com", - "link": "https://support.microsoft.com/" - } - } - } - ] - }, - "packageKind": "Solution", - "packageVersion": "[variables('_solutionVersion')]", - "packageName": "[variables('_solutionName')]", - "packageId": "[variables('_solutionId')]", - "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId21')]", - "contentKind": "AnalyticsRule", - "displayName": "Cross-tenant Access Settings Organization Outbound Direct Settings Changed", - "contentProductId": "[variables('_analyticRulecontentProductId21')]", - "id": "[variables('_analyticRulecontentProductId21')]", - "version": "[variables('analyticRuleVersion21')]" - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", - "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName22')]", - "location": "[parameters('workspace-location')]", - "dependsOn": [ - "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" - ], - "properties": { - "description": "DisabledAccountSigninsAcrossManyApplications_AnalyticalRules Analytics Rule with template version 3.0.4", - "mainTemplate": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion22')]", - "parameters": {}, - "variables": {}, - "resources": [ - { - "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId22')]", - "apiVersion": "2022-04-01-preview", - "kind": "Scheduled", - "location": "[parameters('workspace-location')]", - "properties": { - "description": "Identifies failed attempts to sign in to disabled accounts across multiple Azure Applications.\nDefault threshold for Azure Applications attempted to sign in to is 3.\nReferences: https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-sign-ins-error-codes\n50057 - User account is disabled. The account has been disabled by an administrator.", - "displayName": "Attempts to sign in to disabled accounts", - "enabled": false, - "query": "let threshold = 3;\nlet aadFunc = (tableName:string){\ntable(tableName)\n| where ResultType == \"50057\"\n| where ResultDescription =~ \"User account is disabled. The account has been disabled by an administrator.\"\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), applicationCount = dcount(AppDisplayName),\napplicationSet = make_set(AppDisplayName), count() by UserPrincipalName, IPAddress, Type\n| where applicationCount >= threshold\n| extend timestamp = StartTime, Name = tostring(split(UserPrincipalName,'@',0)[0]), UPNSuffix = tostring(split(UserPrincipalName,'@',1)[0])\n};\nlet aadSignin = aadFunc(\"SigninLogs\");\nlet aadNonInt = aadFunc(\"AADNonInteractiveUserSignInLogs\");\nunion isfuzzy=true aadSignin, aadNonInt\n", - "queryFrequency": "P1D", - "queryPeriod": "P1D", - "severity": "Medium", - "suppressionDuration": "PT1H", - "suppressionEnabled": false, - "triggerOperator": "GreaterThan", - "triggerThreshold": 0, - "status": "Available", - "requiredDataConnectors": [ - { - "dataTypes": [ - "SigninLogs" - ], - "connectorId": "AzureActiveDirectory" - }, - { - "dataTypes": [ - "AADNonInteractiveUserSignInLogs" - ], - "connectorId": "AzureActiveDirectory" - } - ], - "tactics": [ - "InitialAccess" - ], - "techniques": [ - "T1078" - ], - "entityMappings": [ - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "Name" - }, - { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" - } - ] - }, - { - "entityType": "IP", - "fieldMappings": [ - { - "identifier": "Address", - "columnName": "IPAddress" - } - ] - } - ] + "displayName": "[[variables('AzureSentinelConnectionName')]", + "parameterValueType": "Alternative", + "api": { + "id": "[[variables('_connection-2')]" + } } }, { - "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", - "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId22'),'/'))))]", + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[[variables('Office365ConnectionName')]", + "location": "[[variables('workspace-location-inline')]", "properties": { - "description": "Azure Active Directory Analytics Rule 22", - "parentId": "[variables('analyticRuleId22')]", - "contentId": "[variables('_analyticRulecontentId22')]", - "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion22')]", - "source": { - "kind": "Solution", - "name": "Azure Active Directory", - "sourceId": "[variables('_solutionId')]" - }, - "author": { - "name": "Microsoft", - "email": "[variables('_email')]" - }, - "support": { - "tier": "Microsoft", - "name": "Microsoft Corporation", - "email": "support@microsoft.com", - "link": "https://support.microsoft.com/" + "displayName": "[[variables('Office365ConnectionName')]", + "api": { + "id": "[[variables('_connection-3')]" } } - } - ] - }, - "packageKind": "Solution", - "packageVersion": "[variables('_solutionVersion')]", - "packageName": "[variables('_solutionName')]", - "packageId": "[variables('_solutionId')]", - "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId22')]", - "contentKind": "AnalyticsRule", - "displayName": "Attempts to sign in to disabled accounts", - "contentProductId": "[variables('_analyticRulecontentProductId22')]", - "id": "[variables('_analyticRulecontentProductId22')]", - "version": "[variables('analyticRuleVersion22')]" - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", - "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName23')]", - "location": "[parameters('workspace-location')]", - "dependsOn": [ - "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" - ], - "properties": { - "description": "DistribPassCrackAttempt_AnalyticalRules Analytics Rule with template version 3.0.4", - "mainTemplate": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion23')]", - "parameters": {}, - "variables": {}, - "resources": [ + }, { - "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId23')]", - "apiVersion": "2022-04-01-preview", - "kind": "Scheduled", - "location": "[parameters('workspace-location')]", + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[[variables('TeamsConnectionName')]", + "location": "[[variables('workspace-location-inline')]", "properties": { - "description": "Identifies distributed password cracking attempts from the Azure Active Directory SigninLogs.\nThe query looks for unusually high number of failed password attempts coming from multiple locations for a user account.\nReferences: https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-sign-ins-error-codes\n50053 Account is locked because the user tried to sign in too many times with an incorrect user ID or password.\n50055 Invalid password, entered expired password.\n50056 Invalid or null password - Password does not exist in store for this user.\n50126 Invalid username or password, or invalid on-premises username or password.", - "displayName": "Distributed Password cracking attempts in AzureAD", - "enabled": false, - "query": "let s_threshold = 30;\nlet l_threshold = 3;\nlet aadFunc = (tableName:string){\ntable(tableName)\n| where OperationName =~ \"Sign-in activity\"\n// Error codes that we want to look at as they are related to the use of incorrect password.\n| where ResultType in (\"50126\", \"50053\" , \"50055\", \"50056\")\n| extend DeviceDetail = todynamic(DeviceDetail), Status = todynamic(DeviceDetail), LocationDetails = todynamic(LocationDetails)\n| extend OS = DeviceDetail.operatingSystem, Browser = DeviceDetail.browser\n| extend StatusCode = tostring(Status.errorCode), StatusDetails = tostring(Status.additionalDetails)\n| extend LocationString = strcat(tostring(LocationDetails.countryOrRegion), \"/\", tostring(LocationDetails.state), \"/\", tostring(LocationDetails.city))\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), LocationCount=dcount(LocationString), Location = make_set(LocationString,100),\nIPAddress = make_set(IPAddress,100), IPAddressCount = dcount(IPAddress), AppDisplayName = make_set(AppDisplayName,100), ResultDescription = make_set(ResultDescription,50),\nBrowser = make_set(Browser,20), OS = make_set(OS,20), SigninCount = count() by UserPrincipalName, Type\n// Setting a generic threshold - Can be different for different environment\n| where SigninCount > s_threshold and LocationCount >= l_threshold\n| extend Location = tostring(Location), IPAddress = tostring(IPAddress), AppDisplayName = tostring(AppDisplayName), ResultDescription = tostring(ResultDescription), Browser = tostring(Browser), OS = tostring(OS)\n| extend timestamp = StartTime, Name = tostring(split(UserPrincipalName,'@',0)[0]), UPNSuffix = tostring(split(UserPrincipalName,'@',1)[0])};\nlet aadSignin = aadFunc(\"SigninLogs\");\nlet aadNonInt = aadFunc(\"AADNonInteractiveUserSignInLogs\");\nunion isfuzzy=true aadSignin, aadNonInt\n", - "queryFrequency": "P1D", - "queryPeriod": "P1D", - "severity": "Medium", - "suppressionDuration": "PT1H", - "suppressionEnabled": false, - "triggerOperator": "GreaterThan", - "triggerThreshold": 0, - "status": "Available", - "requiredDataConnectors": [ - { - "dataTypes": [ - "SigninLogs" - ], - "connectorId": "AzureActiveDirectory" - }, - { - "dataTypes": [ - "AADNonInteractiveUserSignInLogs" - ], - "connectorId": "AzureActiveDirectory" - } - ], - "tactics": [ - "CredentialAccess" - ], - "techniques": [ - "T1110" - ], - "entityMappings": [ - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "Name" - }, - { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" - } - ] - }, - { - "entityType": "IP", - "fieldMappings": [ - { - "identifier": "Address", - "columnName": "IPAddress" - } - ] - } - ] + "displayName": "[[variables('TeamsConnectionName')]", + "api": { + "id": "[[variables('_connection-4')]" + } } }, { - "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", - "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId23'),'/'))))]", + "type": "Microsoft.Logic/workflows", + "apiVersion": "2017-07-01", + "name": "[[parameters('PlaybookName')]", + "location": "[[variables('workspace-location-inline')]", + "tags": { + "LogicAppsCategory": "security", + "hidden-SentinelTemplateName": "Prompt-User", + "hidden-SentinelTemplateVersion": "1.1", + "hidden-SentinelWorkspaceId": "[[variables('workspaceResourceId')]" + }, + "identity": { + "type": "SystemAssigned" + }, + "dependsOn": [ + "[[resourceId('Microsoft.Web/connections', variables('AzureADConnectionName'))]", + "[[resourceId('Microsoft.Web/connections', variables('AzureSentinelConnectionName'))]", + "[[resourceId('Microsoft.Web/connections', variables('Office365ConnectionName'))]", + "[[resourceId('Microsoft.Web/connections', variables('TeamsConnectionName'))]" + ], "properties": { - "description": "Azure Active Directory Analytics Rule 23", - "parentId": "[variables('analyticRuleId23')]", - "contentId": "[variables('_analyticRulecontentId23')]", - "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion23')]", - "source": { - "kind": "Solution", - "name": "Azure Active Directory", - "sourceId": "[variables('_solutionId')]" - }, - "author": { - "name": "Microsoft", - "email": "[variables('_email')]" - }, - "support": { - "tier": "Microsoft", - "name": "Microsoft Corporation", - "email": "support@microsoft.com", - "link": "https://support.microsoft.com/" - } - } - } - ] - }, - "packageKind": "Solution", - "packageVersion": "[variables('_solutionVersion')]", - "packageName": "[variables('_solutionName')]", - "packageId": "[variables('_solutionId')]", - "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId23')]", - "contentKind": "AnalyticsRule", - "displayName": "Distributed Password cracking attempts in AzureAD", - "contentProductId": "[variables('_analyticRulecontentProductId23')]", - "id": "[variables('_analyticRulecontentProductId23')]", - "version": "[variables('analyticRuleVersion23')]" - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", - "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName24')]", - "location": "[parameters('workspace-location')]", - "dependsOn": [ - "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" - ], - "properties": { - "description": "ExplicitMFADeny_AnalyticalRules Analytics Rule with template version 3.0.4", - "mainTemplate": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion24')]", - "parameters": {}, - "variables": {}, - "resources": [ - { - "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId24')]", - "apiVersion": "2022-04-01-preview", - "kind": "Scheduled", - "location": "[parameters('workspace-location')]", - "properties": { - "description": "User explicitly denies MFA push, indicating that login was not expected and the account's password may be compromised.", - "displayName": "Explicit MFA Deny", - "enabled": false, - "query": "let aadFunc = (tableName:string){\ntable(tableName)\n| where ResultType == 500121\n| where Status has \"MFA Denied; user declined the authentication\" or Status has \"MFA denied; Phone App Reported Fraud\"\n| extend Type = Type\n| extend timestamp = TimeGenerated, Name = tostring(split(UserPrincipalName,'@',0)[0]), UPNSuffix = tostring(split(UserPrincipalName,'@',1)[0])\n};\nlet aadSignin = aadFunc(\"SigninLogs\");\nlet aadNonInt = aadFunc(\"AADNonInteractiveUserSignInLogs\");\nunion isfuzzy=true aadSignin, aadNonInt\n", - "queryFrequency": "P1D", - "queryPeriod": "P1D", - "severity": "Medium", - "suppressionDuration": "PT1H", - "suppressionEnabled": false, - "triggerOperator": "GreaterThan", - "triggerThreshold": 0, - "status": "Available", - "requiredDataConnectors": [ - { - "dataTypes": [ - "SigninLogs" - ], - "connectorId": "AzureActiveDirectory" - }, - { - "dataTypes": [ - "AADNonInteractiveUserSignInLogs" - ], - "connectorId": "AzureActiveDirectory" - } - ], - "tactics": [ - "CredentialAccess" - ], - "techniques": [ - "T1110" - ], - "entityMappings": [ - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "Name" + "state": "Enabled", + "definition": { + "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", + "actions": { + "Entities_-_Get_Accounts": { + "inputs": { + "body": "@triggerBody()?['object']?['properties']?['relatedEntities']", + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "post", + "path": "/entities/account" }, - { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" - } - ] + "type": "ApiConnection" + }, + "For_each": { + "actions": { + "Condition_2": { + "actions": { + "Add_comment_to_incident_(V3)": { + "inputs": { + "body": { + "incidentArmId": "@triggerBody()?['object']?['id']", + "message": "

@{body('Get_user')?['displayName']} confirms they completed the action that triggered the alert.  Closing the incident.

" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "post", + "path": "/Incidents/Comment" + }, + "type": "ApiConnection" + }, + "Update_incident": { + "inputs": { + "body": { + "classification": { + "ClassificationAndReason": "BenignPositive - SuspiciousButExpected", + "ClassificationReasonText": "User Confirmed it was them" + }, + "incidentArmId": "@triggerBody()?['object']?['id']", + "status": "Closed" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "put", + "path": "/Incidents" + }, + "runAfter": { + "Add_comment_to_incident_(V3)": [ + "Succeeded" + ] + }, + "type": "ApiConnection" + } + }, + "else": { + "actions": { + "Add_comment_to_incident_(V3)_2": { + "inputs": { + "body": { + "incidentArmId": "@triggerBody()?['object']?['id']", + "message": "

@{body('Get_user')?['displayName']} confirms they did not complete the action. Further investigation is needed.

" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "post", + "path": "/Incidents/Comment" + }, + "type": "ApiConnection" + }, + "Post_message_in_a_chat_or_channel": { + "inputs": { + "body": { + "messageBody": "

New alert from Microsoft Sentinel.
\nPlease investigate ASAP.
\nSeverity : @{triggerBody()?['object']?['properties']?['severity']}
\nDescription: @{triggerBody()?['object']?['properties']?['description']}
\n
\n@{body('Get_user')?['displayName']} user confirmed they did not complete the action.

", + "recipient": { + "channelId": "[[parameters('TeamsChannelId')]", + "groupId": "[[parameters('TeamsId')]" + }, + "subject": "Incident @{triggerBody()?['object']?['properties']?['incidentNumber']} - @{triggerBody()?['object']?['properties']?['title']}" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['teams']['connectionId']" + } + }, + "method": "post", + "path": "/beta/teams/conversation/message/poster/@{encodeURIComponent('User')}/location/@{encodeURIComponent('Channel')}" + }, + "runAfter": { + "Add_comment_to_incident_(V3)_2": [ + "Succeeded" + ] + }, + "type": "ApiConnection" + } + } + }, + "expression": { + "and": [ + { + "equals": [ + "@body('Send_approval_email')?['SelectedOption']", + "This was me" + ] + } + ] + }, + "runAfter": { + "Send_approval_email": [ + "Succeeded" + ] + }, + "type": "If" + }, + "Get_user": { + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['azuread']['connectionId']" + } + }, + "method": "get", + "path": "/v1.0/users/@{encodeURIComponent(concat(items('For_each')?['Name'], '@' ,items('For_each')?['UPNSuffix']))}" + }, + "type": "ApiConnection" + }, + "Send_approval_email": { + "inputs": { + "body": { + "Message": { + "Body": "New Alert from Microsoft Sentinel.\nPlease respond ASAP.\nSeverity: @{triggerBody()?['object']?['properties']?['severity']}\nName: @{triggerBody()?['object']?['properties']?['title']}\nDescription: @{triggerBody()?['object']?['properties']?['description']}", + "HideHTMLMessage": false, + "Importance": "High", + "Options": "This was me, This was not me", + "ShowHTMLConfirmationDialog": false, + "Subject": "Security Alert: @{triggerBody()?['object']?['properties']?['title']}", + "To": "@body('Get_user')?['mail']" + }, + "NotificationUrl": "@{listCallbackUrl()}" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['office365']['connectionId']" + } + }, + "path": "/approvalmail/$subscriptions" + }, + "runAfter": { + "Get_user": [ + "Succeeded" + ] + }, + "type": "ApiConnectionWebhook" + } + }, + "foreach": "@body('Entities_-_Get_Accounts')?['Accounts']", + "runAfter": { + "Entities_-_Get_Accounts": [ + "Succeeded" + ] + }, + "type": "Foreach" + } }, - { - "entityType": "IP", - "fieldMappings": [ - { - "identifier": "Address", - "columnName": "IPAddress" - } - ] + "contentVersion": "1.0.0.0", + "parameters": { + "$connections": { + "type": "Object" + } }, - { - "entityType": "URL", - "fieldMappings": [ - { - "identifier": "Url", - "columnName": "ClientAppUsed" - } - ] + "triggers": { + "Microsoft_Sentinel_incident": { + "inputs": { + "body": { + "callback_url": "@{listCallbackUrl()}" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "path": "/incident-creation" + }, + "type": "ApiConnectionWebhook" + } } - ] - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", - "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId24'),'/'))))]", - "properties": { - "description": "Azure Active Directory Analytics Rule 24", - "parentId": "[variables('analyticRuleId24')]", - "contentId": "[variables('_analyticRulecontentId24')]", - "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion24')]", - "source": { - "kind": "Solution", - "name": "Azure Active Directory", - "sourceId": "[variables('_solutionId')]" - }, - "author": { - "name": "Microsoft", - "email": "[variables('_email')]" }, - "support": { - "tier": "Microsoft", - "name": "Microsoft Corporation", - "email": "support@microsoft.com", - "link": "https://support.microsoft.com/" - } - } - } - ] - }, - "packageKind": "Solution", - "packageVersion": "[variables('_solutionVersion')]", - "packageName": "[variables('_solutionName')]", - "packageId": "[variables('_solutionId')]", - "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId24')]", - "contentKind": "AnalyticsRule", - "displayName": "Explicit MFA Deny", - "contentProductId": "[variables('_analyticRulecontentProductId24')]", - "id": "[variables('_analyticRulecontentProductId24')]", - "version": "[variables('analyticRuleVersion24')]" - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", - "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName25')]", - "location": "[parameters('workspace-location')]", - "dependsOn": [ - "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" - ], - "properties": { - "description": "ExchangeFullAccessGrantedToApp_AnalyticalRules Analytics Rule with template version 3.0.4", - "mainTemplate": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion25')]", - "parameters": {}, - "variables": {}, - "resources": [ - { - "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId25')]", - "apiVersion": "2022-04-01-preview", - "kind": "Scheduled", - "location": "[parameters('workspace-location')]", - "properties": { - "description": "This detection looks for the full_access_as_app permission being granted to an OAuth application with Admin Consent.\nThis permission provide access to all Exchange mailboxes via the EWS API can could be exploited to access sensitive data \nby being added to a compromised application. The application granted this permission should be reviewed to ensure that it \nis absolutely necessary for the applications function.\nRef: https://learn.microsoft.com/graph/auth-limit-mailbox-access", - "displayName": "full_access_as_app Granted To Application", - "enabled": false, - "query": "AuditLogs\n| where LoggedByService =~ \"Core Directory\"\n| where Category =~ \"ApplicationManagement\"\n| where OperationName =~ \"Consent to application\"\n| where TargetResources has \"full_access_as_app\"\n| mv-expand TargetResources\n| extend OAuthAppName = TargetResources.displayName\n| extend ModifiedProperties = TargetResources.modifiedProperties \n| mv-apply Property = ModifiedProperties on \n (\n where Property.displayName =~ \"ConsentContext.isAdminConsent\"\n | extend AdminConsent = tostring(Property.newValue)\n )\n| mv-apply Property = ModifiedProperties on \n (\n where Property.displayName =~ \"ConsentAction.Permissions\"\n | extend Permissions = tostring(Property.newValue)\n )\n| mv-apply Property = ModifiedProperties on \n (\n where Property.displayName =~ \"TargetId.ServicePrincipalNames\"\n | extend AppId = tostring(Property.newValue)\n )\n| mv-expand AdditionalDetails\n| extend GrantUserAgent = tostring(iff(AdditionalDetails.key =~ \"User-Agent\", AdditionalDetails.value, \"\"))\n| parse Permissions with * \"ConsentType: \" GrantConsentType \", Scope: \" GrantScope1 \",\" *\n| where GrantScope1 =~ \"full_access_as_app\"\n| extend GrantIpAddress = tostring(iff(isnotempty(InitiatedBy.user.ipAddress), InitiatedBy.user.ipAddress, InitiatedBy.app.ipAddress))\n| extend GrantInitiatedBy = tostring(iff(isnotempty(InitiatedBy.user.userPrincipalName),InitiatedBy.user.userPrincipalName, InitiatedBy.app.displayName))\n| project-reorder TimeGenerated, OAuthAppName, AppId, AdminConsent, Permissions, GrantIpAddress, GrantInitiatedBy, GrantUserAgent, GrantScope1, GrantConsentType\n| extend Name = split(GrantInitiatedBy, \"@\")[0], UPNSuffix = split(GrantInitiatedBy, \"@\")[1]\n", - "queryFrequency": "PT1H", - "queryPeriod": "PT1H", - "severity": "Medium", - "suppressionDuration": "PT1H", - "suppressionEnabled": false, - "triggerOperator": "GreaterThan", - "triggerThreshold": 0, - "status": "Available", - "requiredDataConnectors": [ - { - "dataTypes": [ - "AuditLogs" - ], - "connectorId": "AzureActiveDirectory" - } - ], - "tactics": [ - "DefenseEvasion" - ], - "techniques": [ - "T1550" - ], - "entityMappings": [ - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "Name" + "parameters": { + "$connections": { + "value": { + "azuread": { + "connectionId": "[[resourceId('Microsoft.Web/connections', variables('AzureADConnectionName'))]", + "connectionName": "[[variables('AzureADConnectionName')]", + "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuread')]" }, - { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" - } - ] - }, - { - "entityType": "IP", - "fieldMappings": [ - { - "identifier": "Address", - "columnName": "GrantIpAddress" + "azuresentinel": { + "connectionId": "[[resourceId('Microsoft.Web/connections', variables('AzureSentinelConnectionName'))]", + "connectionName": "[[variables('AzureSentinelConnectionName')]", + "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", + "connectionProperties": { + "authentication": { + "type": "ManagedServiceIdentity" + } + } + }, + "office365": { + "connectionId": "[[resourceId('Microsoft.Web/connections', variables('Office365ConnectionName'))]", + "connectionName": "[[variables('Office365ConnectionName')]", + "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]" + }, + "teams": { + "connectionId": "[[resourceId('Microsoft.Web/connections', variables('TeamsConnectionName'))]", + "connectionName": "[[variables('TeamsConnectionName')]", + "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/teams')]" } - ] + } } - ], - "customDetails": { - "OAuthApplication": "OAuthAppName", - "OAuthAppId": "AppId", - "UserAgent": "GrantUserAgent" - }, - "alertDetailsOverride": { - "alertDescriptionFormat": "This detection looks for the full_access_as_app permission being granted to an OAuth application with Admin Consent.\nThis permission provide access to all Exchange mailboxes via the EWS API can could be exploited to access sensitive data \nby being added to a compromised application. The application granted this permission should be reviewed to ensure that it \nis absolutely necessary for the applications function.\nIn this case {{GrantInitiatedBy}} granted full_access_as_app to {{OAuthAppName}} from {{GrantIpAddress}}\nRef: https://learn.microsoft.com/graph/auth-limit-mailbox-access\n", - "alertDisplayNameFormat": "User {{GrantInitiatedBy}} granted full_access_as_app to {{OAuthAppName}}" } } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId25'),'/'))))]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('Playbook-', last(split(variables('playbookId5'),'/'))))]", "properties": { - "description": "Azure Active Directory Analytics Rule 25", - "parentId": "[variables('analyticRuleId25')]", - "contentId": "[variables('_analyticRulecontentId25')]", - "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion25')]", + "parentId": "[variables('playbookId5')]", + "contentId": "[variables('_playbookContentId5')]", + "kind": "Playbook", + "version": "[variables('playbookVersion5')]", "source": { "kind": "Solution", "name": "Azure Active Directory", @@ -4091,485 +2660,388 @@ } } } - ] + ], + "metadata": { + "title": "Prompt User - Incident", + "description": "This playbook will ask the user if they completed the action from the Incident in Microsoft Sentinel. If so, it will close the incident and add a comment. If not, it will post a message to teams for the SOC to investigate and add a comment to the incident.", + "prerequisites": [ + "1. You will need the Team Id and Channel Id." + ], + "postDeployment": [ + "1. Assign Microsoft Sentinel Responder role to the Playbook's managed identity.", + "2. Authorize Azure AD, Microsoft Teams, and Office 365 Outlook Logic App connections." + ], + "lastUpdateTime": "2022-07-11T00:00:00Z", + "entities": [ + "Account" + ], + "tags": [ + "Remediation" + ], + "releaseNotes": [ + { + "version": "1.0.0", + "title": "Added new Post a Teams message action", + "notes": [ + "Initial version" + ] + } + ] + } }, "packageKind": "Solution", "packageVersion": "[variables('_solutionVersion')]", "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId25')]", - "contentKind": "AnalyticsRule", - "displayName": "full_access_as_app Granted To Application", - "contentProductId": "[variables('_analyticRulecontentProductId25')]", - "id": "[variables('_analyticRulecontentProductId25')]", - "version": "[variables('analyticRuleVersion25')]" + "contentId": "[variables('_playbookContentId5')]", + "contentKind": "Playbook", + "displayName": "Prompt-User-Incident", + "contentProductId": "[variables('_playbookcontentProductId5')]", + "id": "[variables('_playbookcontentProductId5')]", + "version": "[variables('playbookVersion5')]" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName26')]", + "name": "[variables('playbookTemplateSpecName6')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "FailedLogonToAzurePortal_AnalyticalRules Analytics Rule with template version 3.0.4", + "description": "Reset-AADPassword-AlertTrigger Playbook with template version 3.0.5", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion26')]", - "parameters": {}, - "variables": {}, + "contentVersion": "[variables('playbookVersion6')]", + "parameters": { + "PlaybookName": { + "defaultValue": "Reset-AADPassword-AlertTrigger", + "type": "string" + } + }, + "variables": { + "MicrosoftSentinelConnectionName": "[[concat('microsoftsentinel-', parameters('PlaybookName'))]", + "office365ConnectionName": "[[concat('office365-', parameters('PlaybookName'))]", + "connection-2": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", + "_connection-2": "[[variables('connection-2')]", + "connection-3": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]", + "_connection-3": "[[variables('connection-3')]", + "workspace-location-inline": "[concat('[resourceGroup().locatio', 'n]')]", + "workspace-name": "[parameters('workspace')]", + "workspaceResourceId": "[[resourceId('microsoft.OperationalInsights/Workspaces', variables('workspace-name'))]" + }, "resources": [ { - "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId26')]", - "apiVersion": "2022-04-01-preview", - "kind": "Scheduled", - "location": "[parameters('workspace-location')]", "properties": { - "description": "Identifies failed login attempts in the Azure Active Directory SigninLogs to the Azure Portal. Many failed logon\nattempts or some failed logon attempts from multiple IPs could indicate a potential brute force attack.\nThe following are excluded due to success and non-failure results:\nReferences: https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-sign-ins-error-codes\n0 - successful logon\n50125 - Sign-in was interrupted due to a password reset or password registration entry.\n50140 - This error occurred due to 'Keep me signed in' interrupt when the user was signing-in.", - "displayName": "Failed login attempts to Azure Portal", - "enabled": false, - "query": "let timeRange = 1d;\nlet lookBack = 7d;\nlet threshold_Failed = 5;\nlet threshold_FailedwithSingleIP = 20;\nlet threshold_IPAddressCount = 2;\nlet isGUID = \"[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}\";\nlet aadFunc = (tableName:string){\nlet azPortalSignins = materialize(table(tableName)\n| where TimeGenerated >= ago(lookBack)\n// Azure Portal only\n| where AppDisplayName =~ \"Azure Portal\")\n;\nlet successPortalSignins = azPortalSignins\n| where TimeGenerated >= ago(timeRange)\n// Azure Portal only and exclude non-failure Result Types\n| where ResultType in (\"0\", \"50125\", \"50140\")\n// Tagging identities not resolved to friendly names\n//| extend Unresolved = iff(Identity matches regex isGUID, true, false)\n| distinct TimeGenerated, UserPrincipalName\n;\nlet failPortalSignins = azPortalSignins\n| where TimeGenerated >= ago(timeRange)\n// Azure Portal only and exclude non-failure Result Types\n| where ResultType !in (\"0\", \"50125\", \"50140\", \"70044\", \"70043\")\n// Tagging identities not resolved to friendly names\n| extend Unresolved = iff(Identity matches regex isGUID, true, false)\n;\n// Verify there is no success for the same connection attempt after the fail\nlet failnoSuccess = failPortalSignins | join kind= leftouter (\n successPortalSignins\n) on UserPrincipalName\n| where TimeGenerated > TimeGenerated1 or isempty(TimeGenerated1)\n| project-away TimeGenerated1, UserPrincipalName1\n;\n// Lookup up resolved identities from last 7 days\nlet identityLookup = azPortalSignins\n| where TimeGenerated >= ago(lookBack)\n| where not(Identity matches regex isGUID)\n| summarize by UserId, lu_UserDisplayName = UserDisplayName, lu_UserPrincipalName = UserPrincipalName;\n// Join resolved names to unresolved list from portal signins\nlet unresolvedNames = failnoSuccess | where Unresolved == true | join kind= inner (\n identityLookup\n) on UserId\n| extend UserDisplayName = lu_UserDisplayName, UserPrincipalName = lu_UserPrincipalName\n| project-away lu_UserDisplayName, lu_UserPrincipalName;\n// Join Signins that had resolved names with list of unresolved that now have a resolved name\nlet u_azPortalSignins = failnoSuccess | where Unresolved == false | union unresolvedNames;\nu_azPortalSignins\n| extend DeviceDetail = todynamic(DeviceDetail), Status = todynamic(DeviceDetail), LocationDetails = todynamic(LocationDetails)\n| extend Status = strcat(ResultType, \": \", ResultDescription), OS = tostring(DeviceDetail.operatingSystem), Browser = tostring(DeviceDetail.browser)\n| extend State = tostring(LocationDetails.state), City = tostring(LocationDetails.city), Region = tostring(LocationDetails.countryOrRegion)\n| extend FullLocation = strcat(Region,'|', State, '|', City) \n| summarize TimeGenerated = make_list(TimeGenerated,100), Status = make_list(Status,100), IPAddresses = make_list(IPAddress,100), IPAddressCount = dcount(IPAddress), FailedLogonCount = count()\nby UserPrincipalName, UserId, UserDisplayName, AppDisplayName, Browser, OS, FullLocation, Type\n| mvexpand TimeGenerated, IPAddresses, Status\n| extend TimeGenerated = todatetime(tostring(TimeGenerated)), IPAddress = tostring(IPAddresses), Status = tostring(Status)\n| project-away IPAddresses\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserPrincipalName, UserId, UserDisplayName, Status, FailedLogonCount, IPAddress, IPAddressCount, AppDisplayName, Browser, OS, FullLocation, Type\n| where (IPAddressCount >= threshold_IPAddressCount and FailedLogonCount >= threshold_Failed) or FailedLogonCount >= threshold_FailedwithSingleIP\n| extend timestamp = StartTime, Name = tostring(split(UserPrincipalName,'@',0)[0]), UPNSuffix = tostring(split(UserPrincipalName,'@',1)[0])\n};\nlet aadSignin = aadFunc(\"SigninLogs\");\nlet aadNonInt = aadFunc(\"AADNonInteractiveUserSignInLogs\");\nunion isfuzzy=true aadSignin, aadNonInt\n", - "queryFrequency": "P1D", - "queryPeriod": "P7D", - "severity": "Low", - "suppressionDuration": "PT1H", - "suppressionEnabled": false, - "triggerOperator": "GreaterThan", - "triggerThreshold": 0, - "status": "Available", - "requiredDataConnectors": [ - { - "dataTypes": [ - "SigninLogs" - ], - "connectorId": "AzureActiveDirectory" - }, - { - "dataTypes": [ - "AADNonInteractiveUserSignInLogs" - ], - "connectorId": "AzureActiveDirectory" - } - ], - "tactics": [ - "CredentialAccess" - ], - "techniques": [ - "T1110" - ], - "entityMappings": [ - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "Name" - }, - { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" - } - ] + "provisioningState": "Succeeded", + "state": "Enabled", + "definition": { + "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "$connections": { + "type": "Object" + } }, - { - "entityType": "IP", - "fieldMappings": [ - { - "identifier": "Address", - "columnName": "IPAddress" - } - ] - } - ] - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", - "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId26'),'/'))))]", - "properties": { - "description": "Azure Active Directory Analytics Rule 26", - "parentId": "[variables('analyticRuleId26')]", - "contentId": "[variables('_analyticRulecontentId26')]", - "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion26')]", - "source": { - "kind": "Solution", - "name": "Azure Active Directory", - "sourceId": "[variables('_solutionId')]" - }, - "author": { - "name": "Microsoft", - "email": "[variables('_email')]" - }, - "support": { - "tier": "Microsoft", - "name": "Microsoft Corporation", - "email": "support@microsoft.com", - "link": "https://support.microsoft.com/" - } - } - } - ] - }, - "packageKind": "Solution", - "packageVersion": "[variables('_solutionVersion')]", - "packageName": "[variables('_solutionName')]", - "packageId": "[variables('_solutionId')]", - "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId26')]", - "contentKind": "AnalyticsRule", - "displayName": "Failed login attempts to Azure Portal", - "contentProductId": "[variables('_analyticRulecontentProductId26')]", - "id": "[variables('_analyticRulecontentProductId26')]", - "version": "[variables('analyticRuleVersion26')]" - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", - "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName27')]", - "location": "[parameters('workspace-location')]", - "dependsOn": [ - "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" - ], - "properties": { - "description": "FirstAppOrServicePrincipalCredential_AnalyticalRules Analytics Rule with template version 3.0.4", - "mainTemplate": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion27')]", - "parameters": {}, - "variables": {}, - "resources": [ - { - "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId27')]", - "apiVersion": "2022-04-01-preview", - "kind": "Scheduled", - "location": "[parameters('workspace-location')]", - "properties": { - "description": "This will alert when an admin or app owner account adds a new credential to an Application or Service Principal where there was no previous verify KeyCredential associated.\nIf a threat actor obtains access to an account with sufficient privileges and adds the alternate authentication material triggering this event, the threat actor can now authenticate as the Application or Service Principal using this credential.\nAdditional information on OAuth Credential Grants can be found in RFC 6749 Section 4.4 or https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow\nFor further information on AuditLogs please see https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-audit-activities.", - "displayName": "First access credential added to Application or Service Principal where no credential was present", - "enabled": false, - "query": "AuditLogs\n| where OperationName has (\"Certificates and secrets management\")\n| where Result =~ \"success\"\n| where tostring(InitiatedBy.user.userPrincipalName) has \"@\" or tostring(InitiatedBy.app.displayName) has \"@\"\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"Application\"\n | extend targetDisplayName = tostring(TargetResource.displayName),\n targetId = tostring(TargetResource.id),\n targetType = tostring(TargetResource.type),\n keyEvents = TargetResource.modifiedProperties\n )\n| mv-apply Property = keyEvents on \n (\n where Property.displayName =~ \"KeyDescription\"\n | extend new_value_set = parse_json(tostring(Property.newValue)),\n old_value_set = parse_json(tostring(Property.oldValue))\n )\n| where old_value_set == \"[]\" \n| mv-expand new_value_set\n| parse new_value_set with * \"KeyIdentifier=\" keyIdentifier:string \",KeyType=\" keyType:string \",KeyUsage=\" keyUsage:string \",DisplayName=\" keyDisplayName:string \"]\" *\n| where keyUsage =~ \"Verify\"\n| mv-apply AdditionalDetail = AdditionalDetails on \n (\n where AdditionalDetail.key =~ \"User-Agent\"\n | extend UserAgent = tostring(AdditionalDetail.value)\n )\n| extend InitiatingUserOrApp = iff(isnotempty(InitiatedBy.user.userPrincipalName),tostring(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.app.displayName))\n| extend InitiatingIpAddress = iff(isnotempty(InitiatedBy.user.ipAddress), tostring(InitiatedBy.user.ipAddress), tostring(InitiatedBy.app.ipAddress))\n| project-away new_value_set, old_value_set\n| project-reorder TimeGenerated, OperationName, InitiatingUserOrApp, InitiatingIpAddress, UserAgent, targetDisplayName, targetId, targetType, keyDisplayName, keyType, keyUsage, keyIdentifier, CorrelationId, TenantId\n| extend timestamp = TimeGenerated, Name = tostring(split(InitiatingUserOrApp,'@',0)[0]), UPNSuffix = tostring(split(InitiatingUserOrApp,'@',1)[0])\n", - "queryFrequency": "PT1H", - "queryPeriod": "PT1H", - "severity": "High", - "suppressionDuration": "PT1H", - "suppressionEnabled": false, - "triggerOperator": "GreaterThan", - "triggerThreshold": 0, - "status": "Available", - "requiredDataConnectors": [ - { - "dataTypes": [ - "AuditLogs" - ], - "connectorId": "AzureActiveDirectory" - } - ], - "tactics": [ - "DefenseEvasion" - ], - "techniques": [ - "T1550" - ], - "entityMappings": [ - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "Name" - }, - { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" + "triggers": { + "Microsoft_Sentinel_alert": { + "type": "ApiConnectionWebhook", + "inputs": { + "body": { + "callback_url": "@{listCallbackUrl()}" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" + } + }, + "path": "/subscribe" } - ] + } }, - { - "entityType": "IP", - "fieldMappings": [ - { - "identifier": "Address", - "columnName": "InitiatingIpAddress" + "actions": { + "Alert_-_Get_incident": { + "runAfter": { + "Set_variable_-_password": [ + "Succeeded" + ] + }, + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" + } + }, + "method": "get", + "path": "/Incidents/subscriptions/@{encodeURIComponent(triggerBody()?['WorkspaceSubscriptionId'])}/resourceGroups/@{encodeURIComponent(triggerBody()?['WorkspaceResourceGroup'])}/workspaces/@{encodeURIComponent(triggerBody()?['WorkspaceId'])}/alerts/@{encodeURIComponent(triggerBody()?['SystemAlertId'])}" } - ] - }, - { - "entityType": "CloudApplication", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "targetDisplayName" + }, + "Entities_-_Get_Accounts": { + "runAfter": { + "Alert_-_Get_incident": [ + "Succeeded" + ] + }, + "type": "ApiConnection", + "inputs": { + "body": "@triggerBody()?['Entities']", + "host": { + "connection": { + "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" + } + }, + "method": "post", + "path": "/entities/account" } - ] - } - ] - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", - "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId27'),'/'))))]", - "properties": { - "description": "Azure Active Directory Analytics Rule 27", - "parentId": "[variables('analyticRuleId27')]", - "contentId": "[variables('_analyticRulecontentId27')]", - "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion27')]", - "source": { - "kind": "Solution", - "name": "Azure Active Directory", - "sourceId": "[variables('_solutionId')]" - }, - "author": { - "name": "Microsoft", - "email": "[variables('_email')]" - }, - "support": { - "tier": "Microsoft", - "name": "Microsoft Corporation", - "email": "support@microsoft.com", - "link": "https://support.microsoft.com/" - } - } - } - ] - }, - "packageKind": "Solution", - "packageVersion": "[variables('_solutionVersion')]", - "packageName": "[variables('_solutionName')]", - "packageId": "[variables('_solutionId')]", - "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId27')]", - "contentKind": "AnalyticsRule", - "displayName": "First access credential added to Application or Service Principal where no credential was present", - "contentProductId": "[variables('_analyticRulecontentProductId27')]", - "id": "[variables('_analyticRulecontentProductId27')]", - "version": "[variables('analyticRuleVersion27')]" - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", - "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName28')]", - "location": "[parameters('workspace-location')]", - "dependsOn": [ - "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" - ], - "properties": { - "description": "GuestAccountsAddedinAADGroupsOtherThanTheOnesSpecified_AnalyticalRules Analytics Rule with template version 3.0.4", - "mainTemplate": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion28')]", - "parameters": {}, - "variables": {}, - "resources": [ - { - "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId28')]", - "apiVersion": "2022-04-01-preview", - "kind": "Scheduled", - "location": "[parameters('workspace-location')]", - "properties": { - "description": "Guest Accounts are added in the Organization Tenants to perform various tasks i.e projects execution, support etc.. This detection notifies when guest users are added to Azure AD Groups other than the ones specified and poses a risk to gain access to sensitive apps or data.", - "displayName": "Guest accounts added in AAD Groups other than the ones specified", - "enabled": false, - "query": "// OBJECT ID of AAD Groups can be found by navigating to Azure Active Directory then from menu on the left, select Groups and from the list shown of AAD Groups, the Second Column shows the ObjectID of each\nlet GroupIDs = dynamic([\"List with Custom AAD GROUP OBJECT ID 1\",\"Custom AAD GROUP OBJECT ID 2\"]);\nAuditLogs\n| where OperationName in ('Add member to group', 'Add owner to group')\n| extend InitiatedByActionUserInformation = iff(isnotempty(InitiatedBy.user.userPrincipalName), InitiatedBy.user.userPrincipalName, InitiatedBy.app.displayName)\n| extend InitiatedByIPAdress = InitiatedBy.user.ipAddress \n// Uncomment the following line to filter events where the inviting user was a guest user\n//| where InitiatedBy has_any (\"CUSTOM DOMAIN NAME#\", \"#EXT#\")\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"User\"\n | extend InvitedUser = trim(@'\"',tostring(TargetResource.userPrincipalName)),\n Properties = TargetResource.modifiedProperties\n )\n| mv-apply Property = Properties on \n (\n where Property.displayName =~ \"Group.DisplayName\"\n | extend AADGroup = trim('\"',tostring(Property.newValue))\n )\n| where InvitedUser has_any (\"CUSTOM DOMAIN NAME#\", \"#EXT#\")\n| mv-apply Property = Properties on\n (\n where Property.displayName =~ \"Group.ObjectID\"\n | extend AADGroupId = trim('\"',tostring(Property.newValue))\n )\n| where AADGroupId !in (GroupIDs)\n| extend Name = tostring(split(InitiatedByActionUserInformation,'@',0)[0]), UPNSuffix = tostring(split(InitiatedByActionUserInformation,'@',1)[0])\n", - "queryFrequency": "P1D", - "queryPeriod": "P1D", - "severity": "High", - "suppressionDuration": "PT1H", - "suppressionEnabled": false, - "triggerOperator": "GreaterThan", - "triggerThreshold": 0, - "status": "Available", - "requiredDataConnectors": [ - { - "dataTypes": [ - "AuditLogs" - ], - "connectorId": "AzureActiveDirectory" - } - ], - "tactics": [ - "InitialAccess", - "Persistence", - "Discovery" - ], - "techniques": [ - "T1078", - "T1136", - "T1087" - ], - "entityMappings": [ - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "InvitedUser" + }, + "For_each": { + "foreach": "@body('Entities_-_Get_Accounts')?['Accounts']", + "actions": { + "Condition_-_is_manager_available": { + "actions": { + "Add_comment_to_incident_-_manager_available": { + "runAfter": { + "Send_an_email_-_to_manager_with_password_details": [ + "Succeeded" + ] + }, + "type": "ApiConnection", + "inputs": { + "body": { + "incidentArmId": "@body('Alert_-_Get_incident')?['id']", + "message": "

User @{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])} password was reset in AAD and their manager @{body('Parse_JSON_-_HTTP_-_get_manager')?['userPrincipalName']} was contacted using playbook.

" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" + } + }, + "method": "post", + "path": "/Incidents/Comment" + } + }, + "Parse_JSON_-_HTTP_-_get_manager": { + "type": "ParseJson", + "inputs": { + "content": "@body('HTTP_-_get_manager')", + "schema": { + "properties": { + "userPrincipalName": { + "type": "string" + } + }, + "type": "object" + } + } + }, + "Send_an_email_-_to_manager_with_password_details": { + "runAfter": { + "Parse_JSON_-_HTTP_-_get_manager": [ + "Succeeded" + ] + }, + "type": "ApiConnection", + "inputs": { + "body": { + "Body": "

User, @{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])}, was involved in part of a security incident.  As part of remediation, the user password has been reset.
\n
\nThe temporary password is: @{variables('Password')}
\n
\nThe user will be required to reset this password upon login.

", + "Subject": "A user password was reset due to security incident.", + "To": "@body('Parse_JSON_-_HTTP_-_get_manager')?['userPrincipalName']" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['office365']['connectionId']" + } + }, + "method": "post", + "path": "/v2/Mail" + } + } + }, + "runAfter": { + "HTTP_-_get_manager": [ + "Succeeded", + "Failed" + ] + }, + "else": { + "actions": { + "Add_comment_to_incident_-_manager_not_available": { + "type": "ApiConnection", + "inputs": { + "body": { + "incidentArmId": "@body('Alert_-_Get_incident')?['id']", + "message": "

User @{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])} password was reset in AAD but the user doesn't have a manager.
\n
\nThe temporary password is: @{variables('Password')}
\n
\nThe user will be required to reset this password upon login.

" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" + } + }, + "method": "post", + "path": "/Incidents/Comment" + } + } + } + }, + "expression": { + "and": [ + { + "equals": [ + "@outputs('HTTP_-_get_manager')['statusCode']", + 200 + ] + } + ] + }, + "type": "If" + }, + "HTTP_-_get_manager": { + "runAfter": { + "HTTP_-_reset_a_password": [ + "Succeeded" + ] + }, + "type": "Http", + "inputs": { + "authentication": { + "audience": "https://graph.microsoft.com", + "type": "ManagedServiceIdentity" + }, + "method": "GET", + "uri": "https://graph.microsoft.com/v1.0/users/@{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])}/manager" + } + }, + "HTTP_-_reset_a_password": { + "type": "Http", + "inputs": { + "authentication": { + "audience": "https://graph.microsoft.com", + "type": "ManagedServiceIdentity" + }, + "body": { + "passwordProfile": { + "forceChangePasswordNextSignIn": true, + "forceChangePasswordNextSignInWithMfa": false, + "password": "@{variables('Password')}" + } + }, + "method": "PATCH", + "uri": "https://graph.microsoft.com/v1.0/users/@{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])}" + } + } + }, + "runAfter": { + "Entities_-_Get_Accounts": [ + "Succeeded" + ] + }, + "type": "Foreach" + }, + "Initialize_variable": { + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "Password", + "type": "String", + "value": "null" + } + ] } - ] - }, - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "Name" + }, + "Set_variable_-_password": { + "runAfter": { + "Initialize_variable": [ + "Succeeded" + ] }, - { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" + "type": "SetVariable", + "inputs": { + "name": "Password", + "value": "@{substring(guid(), 0, 10)}" } - ] - }, - { - "entityType": "IP", - "fieldMappings": [ - { - "identifier": "Address", - "columnName": "InitiatedByIPAdress" + } + } + }, + "parameters": { + "$connections": { + "value": { + "microsoftsentinel": { + "connectionId": "[[resourceId('Microsoft.Web/connections', variables('MicrosoftSentinelConnectionName'))]", + "connectionName": "[[variables('MicrosoftSentinelConnectionName')]", + "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", + "connectionProperties": { + "authentication": { + "type": "ManagedServiceIdentity" + } + } + }, + "office365": { + "connectionId": "[[resourceId('Microsoft.Web/connections', variables('office365ConnectionName'))]", + "connectionName": "[[variables('office365ConnectionName')]", + "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]" } - ] + } } - ] - } + } + }, + "name": "[[parameters('PlaybookName')]", + "type": "Microsoft.Logic/workflows", + "location": "[[variables('workspace-location-inline')]", + "tags": { + "LogicAppsCategory": "security", + "hidden-SentinelTemplateName": "Reset-AADUserPassword_alert", + "hidden-SentinelTemplateVersion": "1.1", + "hidden-SentinelWorkspaceId": "[[variables('workspaceResourceId')]" + }, + "identity": { + "type": "SystemAssigned" + }, + "apiVersion": "2017-07-01", + "dependsOn": [ + "[[resourceId('Microsoft.Web/connections', variables('MicrosoftSentinelConnectionName'))]", + "[[resourceId('Microsoft.Web/connections', variables('office365ConnectionName'))]" + ] }, { - "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", - "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId28'),'/'))))]", - "properties": { - "description": "Azure Active Directory Analytics Rule 28", - "parentId": "[variables('analyticRuleId28')]", - "contentId": "[variables('_analyticRulecontentId28')]", - "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion28')]", - "source": { - "kind": "Solution", - "name": "Azure Active Directory", - "sourceId": "[variables('_solutionId')]" - }, - "author": { - "name": "Microsoft", - "email": "[variables('_email')]" - }, - "support": { - "tier": "Microsoft", - "name": "Microsoft Corporation", - "email": "support@microsoft.com", - "link": "https://support.microsoft.com/" + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[[variables('MicrosoftSentinelConnectionName')]", + "location": "[[variables('workspace-location-inline')]", + "kind": "V1", + "properties": { + "displayName": "[[variables('MicrosoftSentinelConnectionName')]", + "parameterValueType": "Alternative", + "api": { + "id": "[[variables('_connection-2')]" } } - } - ] - }, - "packageKind": "Solution", - "packageVersion": "[variables('_solutionVersion')]", - "packageName": "[variables('_solutionName')]", - "packageId": "[variables('_solutionId')]", - "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId28')]", - "contentKind": "AnalyticsRule", - "displayName": "Guest accounts added in AAD Groups other than the ones specified", - "contentProductId": "[variables('_analyticRulecontentProductId28')]", - "id": "[variables('_analyticRulecontentProductId28')]", - "version": "[variables('analyticRuleVersion28')]" - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", - "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName29')]", - "location": "[parameters('workspace-location')]", - "dependsOn": [ - "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" - ], - "properties": { - "description": "MailPermissionsAddedToApplication_AnalyticalRules Analytics Rule with template version 3.0.4", - "mainTemplate": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion29')]", - "parameters": {}, - "variables": {}, - "resources": [ + }, { - "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId29')]", - "apiVersion": "2022-04-01-preview", - "kind": "Scheduled", - "location": "[parameters('workspace-location')]", + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[[variables('office365ConnectionName')]", + "location": "[[variables('workspace-location-inline')]", + "kind": "V1", "properties": { - "description": "This query look for applications that have been granted (Delegated or App/Role) permissions to Read Mail (Permissions field has Mail.Read) and subsequently has been consented to. This can help identify applications that have been abused to gain access to mailboxes.", - "displayName": "Mail.Read Permissions Granted to Application", - "enabled": false, - "query": "AuditLogs\n| where Category =~ \"ApplicationManagement\"\n| where ActivityDisplayName has_any (\"Add delegated permission grant\",\"Add app role assignment to service principal\") \n| where Result =~ \"success\"\n| where tostring(InitiatedBy.user.userPrincipalName) has \"@\" or tostring(InitiatedBy.app.displayName) has \"@\"\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"ServicePrincipal\" and array_length(TargetResource.modifiedProperties) > 0 and isnotnull(TargetResource.displayName)\n | extend props = TargetResource.modifiedProperties,\n Type = tostring(TargetResource.type),\n PermissionsAddedTo = tostring(TargetResource.displayName)\n )\n| mv-apply Property = props on \n (\n where Property.displayName =~ \"DelegatedPermissionGrant.Scope\"\n | extend DisplayName = tostring(Property.displayName), Permissions = trim('\"',tostring(Property.newValue))\n )\n| where Permissions has_any (\"Mail.Read\", \"Mail.ReadWrite\")\n| mv-apply AdditionalDetail = AdditionalDetails on \n (\n where AdditionalDetail.key =~ \"User-Agent\"\n | extend UserAgent = tostring(AdditionalDetail.value)\n )\n| extend InitiatingUser = tostring(InitiatedBy.user.userPrincipalName)\n| extend UserIPAddress = tostring(InitiatedBy.user.ipAddress) \n| project-away props, TargetResource*, AdditionalDetail*, Property, InitiatedBy\n| join kind=leftouter(\n AuditLogs\n | where ActivityDisplayName has \"Consent to application\"\n | mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"ServicePrincipal\"\n | extend AppName = tostring(TargetResource.displayName),\n AppId = tostring(TargetResource.id)\n )\n | project AppName, AppId, CorrelationId) on CorrelationId\n| project-reorder TimeGenerated, OperationName, InitiatingUser, UserIPAddress, UserAgent, PermissionsAddedTo, Permissions, AppName, AppId, CorrelationId\n| extend timestamp = TimeGenerated, Name = tostring(split(InitiatingUser,'@',0)[0]), UPNSuffix = tostring(split(InitiatingUser,'@',1)[0])\n", - "queryFrequency": "P1D", - "queryPeriod": "P1D", - "severity": "Medium", - "suppressionDuration": "PT1H", - "suppressionEnabled": false, - "triggerOperator": "GreaterThan", - "triggerThreshold": 0, - "status": "Available", - "requiredDataConnectors": [ - { - "dataTypes": [ - "AuditLogs" - ], - "connectorId": "AzureActiveDirectory" - } - ], - "tactics": [ - "Persistence" - ], - "techniques": [ - "T1098" - ], - "entityMappings": [ - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "Name" - }, - { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" - } - ] - }, - { - "entityType": "IP", - "fieldMappings": [ - { - "identifier": "Address", - "columnName": "UserIPAddress" - } - ] - } - ] + "displayName": "[[variables('office365ConnectionName')]", + "api": { + "id": "[[variables('_connection-3')]" + } } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId29'),'/'))))]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('Playbook-', last(split(variables('playbookId6'),'/'))))]", "properties": { - "description": "Azure Active Directory Analytics Rule 29", - "parentId": "[variables('analyticRuleId29')]", - "contentId": "[variables('_analyticRulecontentId29')]", - "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion29')]", + "parentId": "[variables('playbookId6')]", + "contentId": "[variables('_playbookContentId6')]", + "kind": "Playbook", + "version": "[variables('playbookVersion6')]", "source": { "kind": "Solution", "name": "Azure Active Directory", @@ -4587,236 +3059,399 @@ } } } - ] + ], + "metadata": { + "title": "Reset Azure AD User Password - Alert Trigger", + "description": "This playbook will reset the user password using Graph API. It will send the password (which is a random guid substring) to the user's manager. The user will have to reset the password upon login.", + "prerequisites": [ + "None" + ], + "postDeployment": [ + "1. Assign Password Administrator permission to managed identity.", + "2. Assign Microsoft Sentinel Responder permission to managed identity.", + "3. Authorize Office 365 Outlook connection" + ], + "lastUpdateTime": "2022-07-11T00:00:00Z", + "entities": [ + "Account" + ], + "tags": [ + "Remediation" + ], + "releaseNotes": [ + { + "version": "1.0.0", + "title": " Added manager notification action", + "notes": [ + "Initial version" + ] + } + ] + } }, "packageKind": "Solution", "packageVersion": "[variables('_solutionVersion')]", "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId29')]", - "contentKind": "AnalyticsRule", - "displayName": "Mail.Read Permissions Granted to Application", - "contentProductId": "[variables('_analyticRulecontentProductId29')]", - "id": "[variables('_analyticRulecontentProductId29')]", - "version": "[variables('analyticRuleVersion29')]" + "contentId": "[variables('_playbookContentId6')]", + "contentKind": "Playbook", + "displayName": "Reset-AADPassword-AlertTrigger", + "contentProductId": "[variables('_playbookcontentProductId6')]", + "id": "[variables('_playbookcontentProductId6')]", + "version": "[variables('playbookVersion6')]" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName30')]", + "name": "[variables('playbookTemplateSpecName7')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "MaliciousOAuthApp_O365AttackToolkit_AnalyticalRules Analytics Rule with template version 3.0.4", + "description": "Reset-AADUserPassword-EntityTrigger Playbook with template version 3.0.5", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion30')]", - "parameters": {}, - "variables": {}, + "contentVersion": "[variables('playbookVersion7')]", + "parameters": { + "PlaybookName": { + "defaultValue": "Reset-AADUserPassword-EntityTrigger", + "type": "string" + } + }, + "variables": { + "MicrosoftSentinelConnectionName": "[[concat('microsoftsentinel-', parameters('PlaybookName'))]", + "office365ConnectionName": "[[concat('office365-', parameters('PlaybookName'))]", + "connection-2": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", + "_connection-2": "[[variables('connection-2')]", + "connection-3": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]", + "_connection-3": "[[variables('connection-3')]", + "workspace-location-inline": "[concat('[resourceGroup().locatio', 'n]')]", + "workspace-name": "[parameters('workspace')]", + "workspaceResourceId": "[[resourceId('microsoft.OperationalInsights/Workspaces', variables('workspace-name'))]" + }, "resources": [ { - "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId30')]", - "apiVersion": "2022-04-01-preview", - "kind": "Scheduled", - "location": "[parameters('workspace-location')]", "properties": { - "description": "This will alert when a user consents to provide a previously-unknown Azure application with the same OAuth permissions used by the MDSec O365 Attack Toolkit (https://github.com/mdsecactivebreach/o365-attack-toolkit).\nThe default permissions/scope for the MDSec O365 Attack toolkit change sometimes but often include contacts.read, user.read, mail.read, notes.read.all, mailboxsettings.readwrite, files.readwrite.all, mail.send, files.read, and files.read.all.\nConsent to applications with these permissions should be rare, especially as the knownApplications list is expanded, especially as the knownApplications list is expanded. Public contributions to expand this filter are welcome!\nFor further information on AuditLogs please see https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-audit-activities.", - "displayName": "Suspicious application consent similar to O365 Attack Toolkit", - "enabled": false, - "query": "let detectionTime = 1d;\nlet joinLookback = 14d;\nlet threshold = 5;\nlet o365_attack_regex = \"contacts.read|user.read|mail.read|notes.read.all|mailboxsettings.readwrite|Files.ReadWrite.All|mail.send|files.read|files.read.all\";\nlet o365_attack = dynamic([\"contacts.read\", \"user.read\", \"mail.read\", \"notes.read.all\", \"mailboxsettings.readwrite\", \"Files.ReadWrite.All\", \"mail.send\", \"files.read\", \"files.read.all\"]);\nAuditLogs\n| where TimeGenerated > ago(detectionTime)\n| where LoggedByService =~ \"Core Directory\"\n| where Category =~ \"ApplicationManagement\"\n| where OperationName =~ \"Consent to application\"\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"ServicePrincipal\"\n | extend AppDisplayName = tostring(TargetResource.displayName),\n AppClientId = tostring(TargetResource.id),\n props = TargetResource.modifiedProperties\n )\n| where AppClientId !in ((externaldata(knownAppClientId:string, knownAppDisplayName:string)[@\"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Sample%20Data/Feeds/Microsoft.OAuth.KnownApplications.csv\"] with (format=\"csv\"))) // NOTE: a MATCH from this list will cause the alert to NOT fire - please modify for your environment!\n| mv-apply ConsentFull = props on \n (\n where ConsentFull.displayName =~ \"ConsentAction.Permissions\"\n )\n| parse ConsentFull with * \"ConsentType: \" GrantConsentType \", Scope: \" GrantScope1 \", CreatedDateTime\" * \"]\" *\n| where GrantConsentType != \"AllPrincipals\" // NOTE: we are ignoring if OAuth application was granted to all users via an admin - but admin due diligence should be audited occasionally\n| where ConsentFull has_any (o365_attack) \n| extend GrantScopeCount = countof(tolower(GrantScope1), o365_attack_regex, 'regex')\n| where GrantScopeCount > threshold\n| extend GrantIpAddress = iff(isnotempty(InitiatedBy.user.ipAddress), tostring(InitiatedBy.user.ipAddress), tostring(InitiatedBy.app.ipAddress))\n| extend GrantInitiatedBy = iff(isnotempty(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.app.displayName))\n| mv-apply AdditionalDetail = AdditionalDetails on \n (\n where AdditionalDetail.key =~ \"User-Agent\"\n | extend GrantUserAgent = AdditionalDetail.value\n )\n| project TimeGenerated, GrantConsentType, GrantScope1, GrantInitiatedBy, AppDisplayName, GrantIpAddress, GrantUserAgent, AppClientId, OperationName, ConsentFull, CorrelationId\n| join kind = leftouter (AuditLogs\n | where TimeGenerated > ago(joinLookback)\n | where LoggedByService =~ \"Core Directory\"\n | where Category =~ \"ApplicationManagement\"\n | where OperationName =~ \"Add service principal\"\n | mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"ServicePrincipal\"\n | extend props = TargetResource.modifiedProperties,\n AppClientId = tostring(TargetResource.id)\n )\n | mv-apply Property = props on \n (\n where Property.displayName =~ \"AppAddress\" and Property.newValue has \"AddressType\"\n | extend AppReplyURLs = trim('\"',tostring(Property.newValue))\n )\n | distinct AppClientId, tostring(AppReplyURLs)\n) on AppClientId\n| join kind = innerunique (AuditLogs\n | where TimeGenerated > ago(joinLookback)\n | where LoggedByService =~ \"Core Directory\"\n | where Category =~ \"ApplicationManagement\"\n | where OperationName =~ \"Add OAuth2PermissionGrant\" or OperationName =~ \"Add delegated permission grant\"\n | mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"ServicePrincipal\" and array_length(TargetResource.modifiedProperties) > 0 and isnotnull(TargetResource.displayName)\n | extend GrantAuthentication = tostring(TargetResource.displayName)\n )\n | extend GrantOperation = OperationName\n | project GrantAuthentication, GrantOperation, CorrelationId\n ) on CorrelationId\n| project TimeGenerated, GrantConsentType, GrantScope1, GrantInitiatedBy, AppDisplayName, AppReplyURLs, GrantIpAddress, GrantUserAgent, AppClientId, GrantAuthentication, OperationName, GrantOperation, CorrelationId, ConsentFull\n| extend timestamp = TimeGenerated, Name = tostring(split(GrantInitiatedBy,'@',0)[0]), UPNSuffix = tostring(split(GrantInitiatedBy,'@',1)[0])\n", - "queryFrequency": "P1D", - "queryPeriod": "P14D", - "severity": "High", - "suppressionDuration": "PT1H", - "suppressionEnabled": false, - "triggerOperator": "GreaterThan", - "triggerThreshold": 0, - "status": "Available", - "requiredDataConnectors": [ - { - "dataTypes": [ - "AuditLogs" - ], - "connectorId": "AzureActiveDirectory" - } - ], - "tactics": [ - "CredentialAccess", - "DefenseEvasion" - ], - "techniques": [ - "T1528", - "T1550" - ], - "entityMappings": [ - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "Name" - }, - { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" - } - ] + "provisioningState": "Succeeded", + "state": "Enabled", + "definition": { + "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "$connections": { + "type": "Object" + } }, - { - "entityType": "IP", - "fieldMappings": [ - { - "identifier": "Address", - "columnName": "GrantIpAddress" + "triggers": { + "Microsoft_Sentinel_entity": { + "type": "ApiConnectionWebhook", + "inputs": { + "body": { + "callback_url": "@{listCallbackUrl()}" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" + } + }, + "path": "/entity/@{encodeURIComponent('Account')}" } - ] + } }, - { - "entityType": "CloudApplication", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "AppDisplayName" + "actions": { + "Condition_-_is_manager_available": { + "actions": { + "Condition_2": { + "actions": { + "Add_comment_to_incident_-_manager_available": { + "type": "ApiConnection", + "inputs": { + "body": { + "incidentArmId": "@triggerBody()?['IncidentArmID']", + "message": "

User @{variables('AccountDetails')} password was reset in AAD and their manager @{body('Parse_JSON_-_HTTP_-_get_manager')?['userPrincipalName']} was contacted using playbook.

" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" + } + }, + "method": "post", + "path": "/Incidents/Comment" + } + } + }, + "runAfter": { + "Send_an_email_-_to_manager_with_password_details": [ + "Succeeded" + ] + }, + "expression": { + "and": [ + { + "not": { + "equals": [ + "@triggerBody()?['IncidentArmID']", + "@null" + ] + } + } + ] + }, + "type": "If" + }, + "Parse_JSON_-_HTTP_-_get_manager": { + "type": "ParseJson", + "inputs": { + "content": "@body('HTTP_-_get_manager')", + "schema": { + "properties": { + "userPrincipalName": { + "type": "string" + } + }, + "type": "object" + } + } + }, + "Send_an_email_-_to_manager_with_password_details": { + "runAfter": { + "Parse_JSON_-_HTTP_-_get_manager": [ + "Succeeded" + ] + }, + "type": "ApiConnection", + "inputs": { + "body": { + "Body": "

User, @{variables('AccountDetails')}, was involved in part of a security incident.  As part of remediation, the user password has been reset.
\n
\nThe temporary password is: @{variables('Password')}
\n
\nThe user will be required to reset this password upon login.

", + "Subject": "A user password was reset due to security incident.", + "To": "@body('Parse_JSON_-_HTTP_-_get_manager')?['userPrincipalName']" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['office365']['connectionId']" + } + }, + "method": "post", + "path": "/v2/Mail" + } + } + }, + "runAfter": { + "HTTP_-_get_manager": [ + "Succeeded", + "Failed" + ] + }, + "else": { + "actions": { + "Condition": { + "actions": { + "Add_comment_to_incident_-_manager_not_available": { + "type": "ApiConnection", + "inputs": { + "body": { + "incidentArmId": "@triggerBody()?['IncidentArmID']", + "message": "

User @{variables('AccountDetails')} password was reset in AAD but the user doesn't have a manager.
\n
\nThe temporary password is: @{variables('Password')}
\n
\nThe user will be required to reset this password upon login.

" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" + } + }, + "method": "post", + "path": "/Incidents/Comment" + } + } + }, + "expression": { + "and": [ + { + "not": { + "equals": [ + "@triggerBody()?['IncidentArmID']", + "@null" + ] + } + } + ] + }, + "type": "If" + } + } + }, + "expression": { + "and": [ + { + "equals": [ + "@outputs('HTTP_-_get_manager')['statusCode']", + 200 + ] + } + ] + }, + "type": "If" + }, + "HTTP_-_get_manager": { + "runAfter": { + "HTTP_-_reset_a_password": [ + "Succeeded" + ] + }, + "type": "Http", + "inputs": { + "authentication": { + "audience": "https://graph.microsoft.com", + "type": "ManagedServiceIdentity" + }, + "method": "GET", + "uri": "https://graph.microsoft.com/v1.0/users/@{variables('AccountDetails')}/manager" } - ] + }, + "HTTP_-_reset_a_password": { + "runAfter": { + "Initialize_variable_Account": [ + "Succeeded" + ] + }, + "type": "Http", + "inputs": { + "authentication": { + "audience": "https://graph.microsoft.com", + "type": "ManagedServiceIdentity" + }, + "body": { + "passwordProfile": { + "forceChangePasswordNextSignIn": true, + "forceChangePasswordNextSignInWithMfa": false, + "password": "@{variables('Password')}" + } + }, + "method": "PATCH", + "uri": "https://graph.microsoft.com/v1.0/users/@{variables('AccountDetails')}" + } + }, + "Initialize_variable": { + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "Password", + "type": "String", + "value": "null" + } + ] + } + }, + "Initialize_variable_Account": { + "runAfter": { + "Set_variable_-_password": [ + "Succeeded" + ] + }, + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "AccountDetails", + "type": "string", + "value": "@{concat(triggerBody()?['Entity']?['properties']?['Name'],'@',triggerBody()?['Entity']?['properties']?['UPNSuffix'])}" + } + ] + } + }, + "Set_variable_-_password": { + "runAfter": { + "Initialize_variable": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "Password", + "value": "@{substring(guid(), 0, 10)}" + } + } } - ] - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", - "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId30'),'/'))))]", - "properties": { - "description": "Azure Active Directory Analytics Rule 30", - "parentId": "[variables('analyticRuleId30')]", - "contentId": "[variables('_analyticRulecontentId30')]", - "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion30')]", - "source": { - "kind": "Solution", - "name": "Azure Active Directory", - "sourceId": "[variables('_solutionId')]" - }, - "author": { - "name": "Microsoft", - "email": "[variables('_email')]" }, - "support": { - "tier": "Microsoft", - "name": "Microsoft Corporation", - "email": "support@microsoft.com", - "link": "https://support.microsoft.com/" - } - } - } - ] - }, - "packageKind": "Solution", - "packageVersion": "[variables('_solutionVersion')]", - "packageName": "[variables('_solutionName')]", - "packageId": "[variables('_solutionId')]", - "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId30')]", - "contentKind": "AnalyticsRule", - "displayName": "Suspicious application consent similar to O365 Attack Toolkit", - "contentProductId": "[variables('_analyticRulecontentProductId30')]", - "id": "[variables('_analyticRulecontentProductId30')]", - "version": "[variables('analyticRuleVersion30')]" - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", - "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName31')]", - "location": "[parameters('workspace-location')]", - "dependsOn": [ - "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" - ], - "properties": { - "description": "MaliciousOAuthApp_PwnAuth_AnalyticalRules Analytics Rule with template version 3.0.4", - "mainTemplate": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion31')]", - "parameters": {}, - "variables": {}, - "resources": [ - { - "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId31')]", - "apiVersion": "2022-04-01-preview", - "kind": "Scheduled", - "location": "[parameters('workspace-location')]", - "properties": { - "description": "This will alert when a user consents to provide a previously-unknown Azure application with the same OAuth permissions used by the FireEye PwnAuth toolkit (https://github.com/fireeye/PwnAuth).\nThe default permissions/scope for the PwnAuth toolkit are user.read, offline_access, mail.readwrite, mail.send, and files.read.all.\nConsent to applications with these permissions should be rare, especially as the knownApplications list is expanded. Public contributions to expand this filter are welcome!\nFor further information on AuditLogs please see https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-audit-activities.", - "displayName": "Suspicious application consent similar to PwnAuth", - "enabled": false, - "query": "let detectionTime = 1d;\nlet joinLookback = 14d;\nAuditLogs\n| where TimeGenerated > ago(detectionTime)\n| where LoggedByService =~ \"Core Directory\"\n| where Category =~ \"ApplicationManagement\"\n| where OperationName =~ \"Consent to application\"\n| where TargetResources has \"offline\"\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"ServicePrincipal\"\n | extend AppDisplayName = tostring(TargetResource.displayName),\n AppClientId = tostring(TargetResource.id),\n props = TargetResource.modifiedProperties\n )\n| where AppClientId !in ((externaldata(knownAppClientId:string, knownAppDisplayName:string)[@\"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Sample%20Data/Feeds/Microsoft.OAuth.KnownApplications.csv\"] with (format=\"csv\")))\n| mv-apply ConsentFull = props on \n (\n where ConsentFull.displayName =~ \"ConsentAction.Permissions\"\n )\n| parse ConsentFull with * \"ConsentType: \" GrantConsentType \", Scope: \" GrantScope1 \"]\" *\n| where ConsentFull has_all (\"user.read\", \"offline_access\", \"mail.readwrite\", \"mail.send\", \"files.read.all\")\n| where GrantConsentType != \"AllPrincipals\" // NOTE: we are ignoring if OAuth application was granted to all users via an admin - but admin due diligence should be audited occasionally\n| extend GrantIpAddress = iff(isnotempty(InitiatedBy.user.ipAddress), tostring(InitiatedBy.user.ipAddress), tostring(InitiatedBy.app.ipAddress))\n| extend GrantInitiatedBy = iff(isnotempty(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.app.displayName))\n| mv-apply AdditionalDetail = AdditionalDetails on \n (\n where AdditionalDetail.key =~ \"User-Agent\"\n | extend GrantUserAgent = AdditionalDetail.value\n )\n| project TimeGenerated, GrantConsentType, GrantScope1, GrantInitiatedBy, AppDisplayName, GrantIpAddress, GrantUserAgent, AppClientId, OperationName, ConsentFull, CorrelationId\n| join kind = leftouter (AuditLogs\n| where TimeGenerated > ago(joinLookback)\n| where LoggedByService =~ \"Core Directory\"\n| where Category =~ \"ApplicationManagement\"\n| where OperationName =~ \"Add service principal\"\n | mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"ServicePrincipal\"\n | extend props = TargetResource.modifiedProperties,\n AppClientId = tostring(TargetResource.id)\n )\n | mv-apply Property = props on \n (\n where Property.displayName =~ \"AppAddress\" and Property.newValue has \"AddressType\"\n | extend AppReplyURLs = trim('\"',tostring(Property.newValue))\n )\n| distinct AppClientId, tostring(AppReplyURLs)\n)\non AppClientId\n| join kind = innerunique (AuditLogs\n| where TimeGenerated > ago(joinLookback)\n| where LoggedByService =~ \"Core Directory\"\n| where Category =~ \"ApplicationManagement\"\n| where OperationName =~ \"Add OAuth2PermissionGrant\" or OperationName =~ \"Add delegated permission grant\"\n | mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"ServicePrincipal\" and array_length(TargetResource.modifiedProperties) > 0 and isnotnull(TargetResource.displayName)\n | extend GrantAuthentication = tostring(TargetResource.displayName)\n )\n| extend GrantOperation = OperationName\n| project GrantAuthentication, GrantOperation, CorrelationId\n) on CorrelationId\n| project TimeGenerated, GrantConsentType, GrantScope1, GrantInitiatedBy, AppDisplayName, AppReplyURLs, GrantIpAddress, GrantUserAgent, AppClientId, GrantAuthentication, OperationName, GrantOperation, CorrelationId, ConsentFull\n| extend timestamp = TimeGenerated, Name = tostring(split(GrantInitiatedBy,'@',0)[0]), UPNSuffix = tostring(split(GrantInitiatedBy,'@',1)[0])\n", - "queryFrequency": "P1D", - "queryPeriod": "P14D", - "severity": "Medium", - "suppressionDuration": "PT1H", - "suppressionEnabled": false, - "triggerOperator": "GreaterThan", - "triggerThreshold": 0, - "status": "Available", - "requiredDataConnectors": [ - { - "dataTypes": [ - "AuditLogs" - ], - "connectorId": "AzureActiveDirectory" - } - ], - "tactics": [ - "CredentialAccess", - "DefenseEvasion" - ], - "techniques": [ - "T1528", - "T1550" - ], - "entityMappings": [ - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "Name" + "parameters": { + "$connections": { + "value": { + "microsoftsentinel": { + "connectionId": "[[resourceId('Microsoft.Web/connections', variables('MicrosoftSentinelConnectionName'))]", + "connectionName": "[[variables('MicrosoftSentinelConnectionName')]", + "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", + "connectionProperties": { + "authentication": { + "type": "ManagedServiceIdentity" + } + } }, - { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" - } - ] - }, - { - "entityType": "IP", - "fieldMappings": [ - { - "identifier": "Address", - "columnName": "GrantIpAddress" + "office365": { + "connectionId": "[[resourceId('Microsoft.Web/connections', variables('office365ConnectionName'))]", + "connectionName": "[[variables('office365ConnectionName')]", + "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]" } - ] + } } - ] + } + }, + "name": "[[parameters('PlaybookName')]", + "type": "Microsoft.Logic/workflows", + "location": "[[variables('workspace-location-inline')]", + "tags": { + "LogicAppsCategory": "security", + "hidden-SentinelTemplateName": "Reset-AADUserPassword-EntityTrigger", + "hidden-SentinelTemplateVersion": "1.1", + "hidden-SentinelWorkspaceId": "[[variables('workspaceResourceId')]" + }, + "identity": { + "type": "SystemAssigned" + }, + "apiVersion": "2017-07-01", + "dependsOn": [ + "[[resourceId('Microsoft.Web/connections', variables('MicrosoftSentinelConnectionName'))]", + "[[resourceId('Microsoft.Web/connections', variables('office365ConnectionName'))]" + ] + }, + { + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[[variables('MicrosoftSentinelConnectionName')]", + "location": "[[variables('workspace-location-inline')]", + "kind": "V1", + "properties": { + "displayName": "[[variables('MicrosoftSentinelConnectionName')]", + "parameterValueType": "Alternative", + "api": { + "id": "[[variables('_connection-2')]" + } + } + }, + { + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[[variables('office365ConnectionName')]", + "location": "[[variables('workspace-location-inline')]", + "kind": "V1", + "properties": { + "displayName": "[[variables('office365ConnectionName')]", + "api": { + "id": "[[variables('_connection-3')]" + } } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId31'),'/'))))]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('Playbook-', last(split(variables('playbookId7'),'/'))))]", "properties": { - "description": "Azure Active Directory Analytics Rule 31", - "parentId": "[variables('analyticRuleId31')]", - "contentId": "[variables('_analyticRulecontentId31')]", - "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion31')]", + "parentId": "[variables('playbookId7')]", + "contentId": "[variables('_playbookContentId7')]", + "kind": "Playbook", + "version": "[variables('playbookVersion7')]", "source": { "kind": "Solution", "name": "Azure Active Directory", @@ -4834,230 +3469,367 @@ } } } - ] + ], + "metadata": { + "title": "Reset Azure AD User Password - Entity trigger", + "description": "This playbook will reset the user password using Graph API. It will send the password (which is a random guid substring) to the user's manager. The user will have to reset the password upon login.", + "postDeployment": [ + "1. Assign Password Administrator permission to managed identity.", + "2. Assign Microsoft Sentinel Responder permission to managed identity.", + "3. Authorize Office 365 Outlook connection" + ], + "lastUpdateTime": "2022-12-06T00:00:00Z", + "entities": [ + "Account" + ], + "tags": [ + "Remediation" + ], + "releaseNotes": { + "version": "1.1", + "title": "[variables('blanks')]", + "notes": [ + "Initial version" + ] + } + } }, "packageKind": "Solution", "packageVersion": "[variables('_solutionVersion')]", "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId31')]", - "contentKind": "AnalyticsRule", - "displayName": "Suspicious application consent similar to PwnAuth", - "contentProductId": "[variables('_analyticRulecontentProductId31')]", - "id": "[variables('_analyticRulecontentProductId31')]", - "version": "[variables('analyticRuleVersion31')]" + "contentId": "[variables('_playbookContentId7')]", + "contentKind": "Playbook", + "displayName": "Reset-AADUserPassword-EntityTrigger", + "contentProductId": "[variables('_playbookcontentProductId7')]", + "id": "[variables('_playbookcontentProductId7')]", + "version": "[variables('playbookVersion7')]" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName32')]", + "name": "[variables('playbookTemplateSpecName8')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "MFARejectedbyUser_AnalyticalRules Analytics Rule with template version 3.0.4", + "description": "Reset-AADPassword-IncidentTrigger Playbook with template version 3.0.5", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion32')]", - "parameters": {}, - "variables": {}, + "contentVersion": "[variables('playbookVersion8')]", + "parameters": { + "PlaybookName": { + "defaultValue": "Reset-AADPassword-IncidentTrigger", + "type": "string" + } + }, + "variables": { + "MicrosoftSentinelConnectionName": "[[concat('microsoftsentinel-', parameters('PlaybookName'))]", + "office365ConnectionName": "[[concat('office365-', parameters('PlaybookName'))]", + "connection-2": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", + "_connection-2": "[[variables('connection-2')]", + "connection-3": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]", + "_connection-3": "[[variables('connection-3')]", + "workspace-location-inline": "[concat('[resourceGroup().locatio', 'n]')]", + "workspace-name": "[parameters('workspace')]", + "workspaceResourceId": "[[resourceId('microsoft.OperationalInsights/Workspaces', variables('workspace-name'))]" + }, "resources": [ { - "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId32')]", - "apiVersion": "2022-04-01-preview", - "kind": "Scheduled", - "location": "[parameters('workspace-location')]", "properties": { - "description": "Identifies occurances where a user has rejected an MFA prompt. This could be an indicator that a threat actor has compromised the username and password of this user account and is using it to try and log into the account.\nRef : https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-user-accounts#monitoring-for-failed-unusual-sign-ins\nThis query has also been updated to include UEBA logs IdentityInfo and BehaviorAnalytics for contextual information around the results.", - "displayName": "MFA Rejected by User", - "enabled": false, - "query": "let riskScoreCutoff = 20; //Adjust this based on volume of results\nSigninLogs\n| where ResultType == 500121\n| extend additionalDetails_ = tostring(Status.additionalDetails)\n| extend UserPrincipalName = tolower(UserPrincipalName)\n| where additionalDetails_ =~ \"MFA denied; user declined the authentication\" or additionalDetails_ has \"fraud\"\n| summarize StartTime = min(TimeGenerated), EndTIme = max(TimeGenerated) by UserPrincipalName, UserId, AADTenantId, IPAddress\n| extend Name = tostring(split(UserPrincipalName,'@',0)[0]), UPNSuffix = tostring(split(UserPrincipalName,'@',1)[0])\n| join kind=leftouter (\n IdentityInfo\n | summarize LatestReportTime = arg_max(TimeGenerated, *) by AccountUPN\n | extend BlastRadiusInt = iif(BlastRadius == \"High\", 1, 0)\n | project AccountUPN, Tags, JobTitle, GroupMembership, AssignedRoles, UserType, IsAccountEnabled, BlastRadiusInt\n | summarize\n Tags = make_set(Tags, 1000),\n GroupMembership = make_set(GroupMembership, 1000),\n AssignedRoles = make_set(AssignedRoles, 1000),\n BlastRadiusInt = sum(BlastRadiusInt),\n UserType = make_set(UserType, 1000),\n UserAccountControl = make_set(UserType, 1000)\n by AccountUPN\n | extend UserPrincipalName=tolower(AccountUPN)\n) on UserPrincipalName\n| join kind=leftouter (\n BehaviorAnalytics\n | where ActivityType in (\"FailedLogOn\", \"LogOn\")\n | where isnotempty(SourceIPAddress)\n | project UsersInsights, DevicesInsights, ActivityInsights, InvestigationPriority, SourceIPAddress\n | project-rename IPAddress = SourceIPAddress\n | summarize\n UsersInsights = make_set(UsersInsights, 1000),\n DevicesInsights = make_set(DevicesInsights, 1000),\n IPInvestigationPriority = sum(InvestigationPriority)\n by IPAddress)\non IPAddress\n| extend UEBARiskScore = BlastRadiusInt + IPInvestigationPriority\n| where UEBARiskScore > riskScoreCutoff\n| sort by UEBARiskScore desc \n", - "queryFrequency": "PT1H", - "queryPeriod": "PT1H", - "severity": "Medium", - "suppressionDuration": "PT1H", - "suppressionEnabled": false, - "triggerOperator": "GreaterThan", - "triggerThreshold": 0, - "status": "Available", - "requiredDataConnectors": [ - { - "dataTypes": [ - "SigninLogs" - ], - "connectorId": "AzureActiveDirectory" + "provisioningState": "Succeeded", + "state": "Enabled", + "definition": { + "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "$connections": { + "type": "Object" + } }, - { - "dataTypes": [ - "BehaviorAnalytics" - ], - "connectorId": "BehaviorAnalytics" + "triggers": { + "Microsoft_Sentinel_incident": { + "type": "ApiConnectionWebhook", + "inputs": { + "body": { + "callback_url": "@{listCallbackUrl()}" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" + } + }, + "path": "/incident-creation" + } + } }, - { - "dataTypes": [ - "IdentityInfo" - ], - "connectorId": "IdentityInfo" - } - ], - "tactics": [ - "InitialAccess" - ], - "techniques": [ - "T1078" - ], - "entityMappings": [ - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "Name" + "actions": { + "Entities_-_Get_Accounts": { + "runAfter": { + "Set_variable_-_password": [ + "Succeeded" + ] }, - { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" + "type": "ApiConnection", + "inputs": { + "body": "@triggerBody()?['object']?['properties']?['relatedEntities']", + "host": { + "connection": { + "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" + } + }, + "method": "post", + "path": "/entities/account" + } + }, + "For_each": { + "foreach": "@body('Entities_-_Get_Accounts')?['Accounts']", + "actions": { + "Condition_-_is_manager_available": { + "actions": { + "Add_comment_to_incident_-_manager_available": { + "runAfter": { + "Send_an_email_-_to_manager_with_password_details": [ + "Succeeded" + ] + }, + "type": "ApiConnection", + "inputs": { + "body": { + "incidentArmId": "@triggerBody()?['object']?['id']", + "message": "

User @{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])} password was reset in AAD and their manager @{body('Parse_JSON_-_HTTP_-_get_manager')?['userPrincipalName']} was contacted using playbook.

" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" + } + }, + "method": "post", + "path": "/Incidents/Comment" + } + }, + "Parse_JSON_-_HTTP_-_get_manager": { + "type": "ParseJson", + "inputs": { + "content": "@body('HTTP_-_get_manager')", + "schema": { + "properties": { + "userPrincipalName": { + "type": "string" + } + }, + "type": "object" + } + } + }, + "Send_an_email_-_to_manager_with_password_details": { + "runAfter": { + "Parse_JSON_-_HTTP_-_get_manager": [ + "Succeeded" + ] + }, + "type": "ApiConnection", + "inputs": { + "body": { + "Body": "

User, @{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])}, was involved in part of a security incident.  As part of remediation, the user password has been reset.
\n
\nThe temporary password is: @{variables('Password')}
\n
\nThe user will be required to reset this password upon login.

", + "Subject": "A user password was reset due to security incident.", + "To": "@body('Parse_JSON_-_HTTP_-_get_manager')?['userPrincipalName']" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['office365']['connectionId']" + } + }, + "method": "post", + "path": "/v2/Mail" + } + } + }, + "runAfter": { + "HTTP_-_get_manager": [ + "Succeeded", + "Failed" + ] + }, + "else": { + "actions": { + "Add_comment_to_incident_-_manager_not_available": { + "type": "ApiConnection", + "inputs": { + "body": { + "incidentArmId": "@triggerBody()?['object']?['id']", + "message": "

User @{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])} password was reset in AAD but the user doesn't have a manager.
\n
\nThe temporary password is: @{variables('Password')}
\n
\nThe user will be required to reset this password upon login.

" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" + } + }, + "method": "post", + "path": "/Incidents/Comment" + } + } + } + }, + "expression": { + "and": [ + { + "equals": [ + "@outputs('HTTP_-_get_manager')['statusCode']", + 200 + ] + } + ] + }, + "type": "If" + }, + "HTTP_-_get_manager": { + "runAfter": { + "HTTP_-_reset_a_password": [ + "Succeeded" + ] + }, + "type": "Http", + "inputs": { + "authentication": { + "audience": "https://graph.microsoft.com", + "type": "ManagedServiceIdentity" + }, + "method": "GET", + "uri": "https://graph.microsoft.com/v1.0/users/@{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])}/manager" + } + }, + "HTTP_-_reset_a_password": { + "type": "Http", + "inputs": { + "authentication": { + "audience": "https://graph.microsoft.com", + "type": "ManagedServiceIdentity" + }, + "body": { + "passwordProfile": { + "forceChangePasswordNextSignIn": true, + "forceChangePasswordNextSignInWithMfa": false, + "password": "@{variables('Password')}" + } + }, + "method": "PATCH", + "uri": "https://graph.microsoft.com/v1.0/users/@{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])}" + } + } }, - { - "identifier": "AadUserId", - "columnName": "UserId" + "runAfter": { + "Entities_-_Get_Accounts": [ + "Succeeded" + ] + }, + "type": "Foreach" + }, + "Initialize_variable": { + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "Password", + "type": "String", + "value": "null" + } + ] } - ] - }, - { - "entityType": "IP", - "fieldMappings": [ - { - "identifier": "Address", - "columnName": "IPAddress" + }, + "Set_variable_-_password": { + "runAfter": { + "Initialize_variable": [ + "Succeeded" + ] + }, + "type": "SetVariable", + "inputs": { + "name": "Password", + "value": "@{substring(guid(), 0, 10)}" } - ] + } } - ] - } + }, + "parameters": { + "$connections": { + "value": { + "microsoftsentinel": { + "connectionId": "[[resourceId('Microsoft.Web/connections', variables('MicrosoftSentinelConnectionName'))]", + "connectionName": "[[variables('MicrosoftSentinelConnectionName')]", + "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", + "connectionProperties": { + "authentication": { + "type": "ManagedServiceIdentity" + } + } + }, + "office365": { + "connectionId": "[[resourceId('Microsoft.Web/connections', variables('office365ConnectionName'))]", + "connectionName": "[[variables('office365ConnectionName')]", + "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]" + } + } + } + } + }, + "name": "[[parameters('PlaybookName')]", + "type": "Microsoft.Logic/workflows", + "location": "[[variables('workspace-location-inline')]", + "tags": { + "LogicAppsCategory": "security", + "hidden-SentinelTemplateName": "Reset-AADUserPassword", + "hidden-SentinelTemplateVersion": "1.1", + "hidden-SentinelWorkspaceId": "[[variables('workspaceResourceId')]" + }, + "identity": { + "type": "SystemAssigned" + }, + "apiVersion": "2017-07-01", + "dependsOn": [ + "[[resourceId('Microsoft.Web/connections', variables('MicrosoftSentinelConnectionName'))]", + "[[resourceId('Microsoft.Web/connections', variables('office365ConnectionName'))]" + ] }, { - "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", - "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId32'),'/'))))]", + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[[variables('MicrosoftSentinelConnectionName')]", + "location": "[[variables('workspace-location-inline')]", + "kind": "V1", "properties": { - "description": "Azure Active Directory Analytics Rule 32", - "parentId": "[variables('analyticRuleId32')]", - "contentId": "[variables('_analyticRulecontentId32')]", - "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion32')]", - "source": { - "kind": "Solution", - "name": "Azure Active Directory", - "sourceId": "[variables('_solutionId')]" - }, - "author": { - "name": "Microsoft", - "email": "[variables('_email')]" - }, - "support": { - "tier": "Microsoft", - "name": "Microsoft Corporation", - "email": "support@microsoft.com", - "link": "https://support.microsoft.com/" + "displayName": "[[variables('MicrosoftSentinelConnectionName')]", + "parameterValueType": "Alternative", + "api": { + "id": "[[variables('_connection-2')]" } } - } - ] - }, - "packageKind": "Solution", - "packageVersion": "[variables('_solutionVersion')]", - "packageName": "[variables('_solutionName')]", - "packageId": "[variables('_solutionId')]", - "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId32')]", - "contentKind": "AnalyticsRule", - "displayName": "MFA Rejected by User", - "contentProductId": "[variables('_analyticRulecontentProductId32')]", - "id": "[variables('_analyticRulecontentProductId32')]", - "version": "[variables('analyticRuleVersion32')]" - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", - "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName33')]", - "location": "[parameters('workspace-location')]", - "dependsOn": [ - "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" - ], - "properties": { - "description": "MultipleAdmin_membership_removals_from_NewAdmin_AnalyticalRules Analytics Rule with template version 3.0.4", - "mainTemplate": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion33')]", - "parameters": {}, - "variables": {}, - "resources": [ + }, { - "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId33')]", - "apiVersion": "2022-04-01-preview", - "kind": "Scheduled", - "location": "[parameters('workspace-location')]", + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[[variables('office365ConnectionName')]", + "location": "[[variables('workspace-location-inline')]", + "kind": "V1", "properties": { - "description": "This query detects when newly created Global admin removes multiple existing global admins which can be an attempt by adversaries to lock down organization and retain sole access. \n Investigate reasoning and intention of multiple membership removal by new Global admins and take necessary actions accordingly.", - "displayName": "Multiple admin membership removals from newly created admin.", - "enabled": false, - "query": "let lookback = 7d; \nlet timeframe = 1h; \nlet GlobalAdminsRemoved = AuditLogs \n| where TimeGenerated > ago(timeframe) \n| where Category =~ \"RoleManagement\" \n| where AADOperationType in (\"Unassign\", \"RemoveEligibleRole\") \n| where ActivityDisplayName has_any (\"Remove member from role\", \"Remove eligible member from role\") \n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"User\"\n | extend Target = tostring(TargetResource.userPrincipalName),\n props = TargetResource.modifiedProperties\n )\n| mv-apply Property = props on \n (\n where Property.displayName =~ \"Role.DisplayName\"\n | extend RoleName = trim('\"',tostring(Property.oldValue))\n )\n| where RoleName =~ \"Global Administrator\" // Add other Privileged role if applicable \n| extend InitiatingApp = tostring(InitiatedBy.app.displayName) \n| extend Initiator = iif(isnotempty(InitiatingApp), InitiatingApp, tostring(InitiatedBy.user.userPrincipalName)) \n| where Initiator != \"MS-PIM\" // Filtering PIM events \n| summarize RemovedGlobalAdminTime = max(TimeGenerated), TargetAdmins = make_set(Target,100) by OperationName, RoleName, Initiator, Result; \nlet GlobalAdminsAdded = AuditLogs \n| where TimeGenerated > ago(lookback) \n| where Category =~ \"RoleManagement\" \n| where AADOperationType in (\"Assign\", \"AssignEligibleRole\") \n| where ActivityDisplayName has_any (\"Add eligible member to role\", \"Add member to role\") and Result == \"success\" \n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"User\"\n | extend Target = tostring(TargetResource.userPrincipalName),\n props = TargetResource.modifiedProperties\n )\n| mv-apply Property = props on \n (\n where Property.displayName =~ \"Role.DisplayName\"\n | extend RoleName = trim('\"',tostring(Property.newValue))\n )\n| where RoleName =~ \"Global Administrator\" // Add other Privileged role if applicable \n| extend InitiatingApp = tostring(InitiatedBy.app.displayName) \n| extend Initiator = iif(isnotempty(InitiatingApp), InitiatingApp, tostring(InitiatedBy.user.userPrincipalName)) \n| where Initiator != \"MS-PIM\" // Filtering PIM events \n| summarize AddedGlobalAdminTime = max(TimeGenerated) by OperationName, RoleName, Target, Initiator, Result \n| extend AccountCustomEntity = Target; \nGlobalAdminsAdded \n| join kind= inner GlobalAdminsRemoved on $left.Target == $right.Initiator \n| where AddedGlobalAdminTime < RemovedGlobalAdminTime \n| extend NoofAdminsRemoved = array_length(TargetAdmins) \n| where NoofAdminsRemoved > 1\n| project AddedGlobalAdminTime, Initiator, Target, AccountCustomEntity, RemovedGlobalAdminTime, TargetAdmins, NoofAdminsRemoved\n| extend Name = tostring(split(AccountCustomEntity,'@',0)[0]), UPNSuffix = tostring(split(AccountCustomEntity,'@',1)[0])\n", - "queryFrequency": "PT1H", - "queryPeriod": "P7D", - "severity": "Medium", - "suppressionDuration": "PT1H", - "suppressionEnabled": false, - "triggerOperator": "GreaterThan", - "triggerThreshold": 0, - "status": "Available", - "requiredDataConnectors": [ - { - "dataTypes": [ - "AuditLogs" - ], - "connectorId": "AzureActiveDirectory" - } - ], - "tactics": [ - "Impact" - ], - "techniques": [ - "T1531" - ], - "entityMappings": [ - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "Name" - }, - { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" - } - ] - } - ] + "displayName": "[[variables('office365ConnectionName')]", + "api": { + "id": "[[variables('_connection-3')]" + } } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId33'),'/'))))]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('Playbook-', last(split(variables('playbookId8'),'/'))))]", "properties": { - "description": "Azure Active Directory Analytics Rule 33", - "parentId": "[variables('analyticRuleId33')]", - "contentId": "[variables('_analyticRulecontentId33')]", - "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion33')]", + "parentId": "[variables('playbookId8')]", + "contentId": "[variables('_playbookContentId8')]", + "kind": "Playbook", + "version": "[variables('playbookVersion8')]", "source": { "kind": "Solution", "name": "Azure Active Directory", @@ -5075,112 +3847,328 @@ } } } - ] + ], + "metadata": { + "title": "Reset Azure AD User Password - Incident Trigger", + "description": "This playbook will reset the user password using Graph API. It will send the password (which is a random guid substring) to the user's manager. The user will have to reset the password upon login.", + "prerequisites": [ + "None" + ], + "postDeployment": [ + "1. Assign Password Administrator permission to managed identity.", + "2. Assign Microsoft Sentinel Responder permission to managed identity.", + "3. Authorize Office 365 Outlook connection" + ], + "lastUpdateTime": "2022-07-11T00:00:00Z", + "entities": [ + "Account" + ], + "tags": [ + "Remediation" + ], + "releaseNotes": [ + { + "version": "1.0.0", + "title": " Added manager notification action", + "notes": [ + "Initial version" + ] + } + ] + } }, "packageKind": "Solution", "packageVersion": "[variables('_solutionVersion')]", "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId33')]", - "contentKind": "AnalyticsRule", - "displayName": "Multiple admin membership removals from newly created admin.", - "contentProductId": "[variables('_analyticRulecontentProductId33')]", - "id": "[variables('_analyticRulecontentProductId33')]", - "version": "[variables('analyticRuleVersion33')]" + "contentId": "[variables('_playbookContentId8')]", + "contentKind": "Playbook", + "displayName": "Reset-AADPassword-IncidentTrigger", + "contentProductId": "[variables('_playbookcontentProductId8')]", + "id": "[variables('_playbookcontentProductId8')]", + "version": "[variables('playbookVersion8')]" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName34')]", + "name": "[variables('playbookTemplateSpecName9')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "NewAppOrServicePrincipalCredential_AnalyticalRules Analytics Rule with template version 3.0.4", + "description": "Revoke-AADSignInSessions-alert Playbook with template version 3.0.5", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion34')]", - "parameters": {}, - "variables": {}, + "contentVersion": "[variables('playbookVersion9')]", + "parameters": { + "PlaybookName": { + "defaultValue": "Revoke-AADSignInSessions-alert", + "type": "string" + }, + "UserName": { + "defaultValue": "@", + "type": "string" + } + }, + "variables": { + "AzureSentinelConnectionName": "[[concat('azuresentinel-', parameters('PlaybookName'))]", + "Office365ConnectionName": "[[concat('office365-', parameters('PlaybookName'))]", + "Office365UsersConnectionName": "[[concat('office365users-', parameters('PlaybookName'))]", + "connection-1": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", + "_connection-1": "[[variables('connection-1')]", + "connection-2": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]", + "_connection-2": "[[variables('connection-2')]", + "connection-3": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365users')]", + "_connection-3": "[[variables('connection-3')]", + "workspace-location-inline": "[concat('[resourceGroup().locatio', 'n]')]", + "workspace-name": "[parameters('workspace')]", + "workspaceResourceId": "[[resourceId('microsoft.OperationalInsights/Workspaces', variables('workspace-name'))]" + }, "resources": [ { - "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId34')]", - "apiVersion": "2022-04-01-preview", - "kind": "Scheduled", - "location": "[parameters('workspace-location')]", + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[[variables('AzureSentinelConnectionName')]", + "location": "[[variables('workspace-location-inline')]", + "kind": "V1", "properties": { - "description": "This will alert when an admin or app owner account adds a new credential to an Application or Service Principal where a verify KeyCredential was already present for the app.\nIf a threat actor obtains access to an account with sufficient privileges and adds the alternate authentication material triggering this event, the threat actor can now authenticate as the Application or Service Principal using this credential.\nAdditional information on OAuth Credential Grants can be found in RFC 6749 Section 4.4 or https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow\nFor further information on AuditLogs please see https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-audit-activities.", - "displayName": "New access credential added to Application or Service Principal", - "enabled": false, - "query": "AuditLogs\n| where OperationName has_any (\"Add service principal\", \"Certificates and secrets management\") // captures \"Add service principal\", \"Add service principal credentials\", and \"Update application - Certificates and secrets management\" events\n| where Result =~ \"success\"\n| where tostring(InitiatedBy.user.userPrincipalName) has \"@\" or tostring(InitiatedBy.app.displayName) has \"@\"\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"Application\"\n | extend targetDisplayName = tostring(TargetResource.displayName),\n targetId = tostring(TargetResource.id),\n targetType = tostring(TargetResource.type),\n keyEvents = TargetResource.modifiedProperties\n )\n| mv-apply Property = keyEvents on \n (\n where Property.displayName =~ \"KeyDescription\"\n | extend new_value_set = parse_json(tostring(Property.newValue)),\n old_value_set = parse_json(tostring(Property.oldValue))\n )\n| where old_value_set != \"[]\"\n| extend diff = set_difference(new_value_set, old_value_set)\n| where isnotempty(diff)\n| parse diff with * \"KeyIdentifier=\" keyIdentifier:string \",KeyType=\" keyType:string \",KeyUsage=\" keyUsage:string \",DisplayName=\" keyDisplayName:string \"]\" *\n| where keyUsage =~ \"Verify\"\n| mv-apply AdditionalDetail = AdditionalDetails on \n (\n where AdditionalDetail.key =~ \"User-Agent\"\n | extend UserAgent = tostring(AdditionalDetail.value)\n )\n| extend InitiatingUserOrApp = iff(isnotempty(InitiatedBy.user.userPrincipalName),tostring(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.app.displayName))\n| extend InitiatingIpAddress = iff(isnotempty(InitiatedBy.user.ipAddress), tostring(InitiatedBy.user.ipAddress), tostring(InitiatedBy.app.ipAddress))\n// The below line is currently commented out but Microsoft Sentinel users can modify this query to show only Application or only Service Principal events in their environment\n//| where targetType =~ \"Application\" // or targetType =~ \"ServicePrincipal\"\n| project-away diff, new_value_set, old_value_set\n| project-reorder TimeGenerated, OperationName, InitiatingUserOrApp, InitiatingIpAddress, UserAgent, targetDisplayName, targetId, targetType, keyDisplayName, keyType, keyUsage, keyIdentifier, CorrelationId, TenantId\n| extend timestamp = TimeGenerated, Name = tostring(split(InitiatingUserOrApp,'@',0)[0]), UPNSuffix = tostring(split(InitiatingUserOrApp,'@',1)[0])\n", - "queryFrequency": "PT1H", - "queryPeriod": "PT1H", - "severity": "Medium", - "suppressionDuration": "PT1H", - "suppressionEnabled": false, - "triggerOperator": "GreaterThan", - "triggerThreshold": 0, - "status": "Available", - "requiredDataConnectors": [ - { - "dataTypes": [ - "AuditLogs" - ], - "connectorId": "AzureActiveDirectory" - } - ], - "tactics": [ - "DefenseEvasion" - ], - "techniques": [ - "T1550" - ], - "entityMappings": [ - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "Name" - }, - { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" - } - ] - }, - { - "entityType": "IP", - "fieldMappings": [ - { - "identifier": "Address", - "columnName": "InitiatingIpAddress" - } - ] - } - ] + "displayName": "[[parameters('PlaybookName')]", + "parameterValueType": "Alternative", + "api": { + "id": "[[variables('_connection-1')]" + } } }, { - "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", - "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId34'),'/'))))]", + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[[variables('Office365ConnectionName')]", + "location": "[[variables('workspace-location-inline')]", "properties": { - "description": "Azure Active Directory Analytics Rule 34", - "parentId": "[variables('analyticRuleId34')]", - "contentId": "[variables('_analyticRulecontentId34')]", - "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion34')]", - "source": { - "kind": "Solution", - "name": "Azure Active Directory", - "sourceId": "[variables('_solutionId')]" - }, - "author": { + "displayName": "[[parameters('UserName')]", + "api": { + "id": "[[variables('_connection-2')]" + } + } + }, + { + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[[variables('Office365UsersConnectionName')]", + "location": "[[variables('workspace-location-inline')]", + "properties": { + "displayName": "[[parameters('UserName')]", + "api": { + "id": "[[variables('_connection-3')]" + } + } + }, + { + "type": "Microsoft.Logic/workflows", + "apiVersion": "2017-07-01", + "name": "[[parameters('PlaybookName')]", + "location": "[[variables('workspace-location-inline')]", + "tags": { + "LogicAppsCategory": "security", + "hidden-SentinelTemplateName": "Revoke-AADSigninSessions_alert", + "hidden-SentinelTemplateVersion": "1.0", + "hidden-SentinelWorkspaceId": "[[variables('workspaceResourceId')]" + }, + "identity": { + "type": "SystemAssigned" + }, + "dependsOn": [ + "[[resourceId('Microsoft.Web/connections', variables('AzureSentinelConnectionName'))]", + "[[resourceId('Microsoft.Web/connections', variables('Office365ConnectionName'))]", + "[[resourceId('Microsoft.Web/connections', variables('Office365UsersConnectionName'))]" + ], + "properties": { + "state": "Enabled", + "definition": { + "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", + "actions": { + "Alert_-_Get_incident": { + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "get", + "path": "/Incidents/subscriptions/@{encodeURIComponent(triggerBody()?['WorkspaceSubscriptionId'])}/resourceGroups/@{encodeURIComponent(triggerBody()?['WorkspaceResourceGroup'])}/workspaces/@{encodeURIComponent(triggerBody()?['WorkspaceId'])}/alerts/@{encodeURIComponent(triggerBody()?['SystemAlertId'])}" + }, + "type": "ApiConnection" + }, + "Entities_-_Get_Accounts": { + "inputs": { + "body": "@triggerBody()?['Entities']", + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "post", + "path": "/entities/account" + }, + "runAfter": { + "Alert_-_Get_incident": [ + "Succeeded" + ] + }, + "type": "ApiConnection" + }, + "For_each": { + "actions": { + "Add_comment_to_incident_(V3)": { + "inputs": { + "body": { + "incidentArmId": "@body('Alert_-_Get_incident')?['id']", + "message": "

User @{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])} singin sessions were revoked in AAD and their manager @{body('Get_manager_(V2)')?['displayName']} was contacted using playbook.

" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "post", + "path": "/Incidents/Comment" + }, + "runAfter": { + "Send_an_email_(V2)": [ + "Succeeded" + ] + }, + "type": "ApiConnection" + }, + "Get_manager_(V2)": { + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['office365users']['connectionId']" + } + }, + "method": "get", + "path": "/codeless/v1.0/users/@{encodeURIComponent(concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix']))}/manager" + }, + "runAfter": { + "HTTP": [ + "Succeeded" + ] + }, + "type": "ApiConnection" + }, + "HTTP": { + "inputs": { + "authentication": { + "audience": "https://graph.microsoft.com", + "type": "ManagedServiceIdentity" + }, + "method": "POST", + "uri": "https://graph.microsoft.com/v1.0/users/@{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])}/revokeSignInSessions" + }, + "type": "Http" + }, + "Send_an_email_(V2)": { + "inputs": { + "body": { + "Body": "

User, @{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])}, was involved in part of a security incident.  As part of remediation, the user signin sessions have been revoked.  The user will need to reauthenticate in all applications.

", + "Subject": "User signin sessions were reset due to security incident.", + "To": "@body('Get_manager_(V2)')?['mail']" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['office365']['connectionId']" + } + }, + "method": "post", + "path": "/v2/Mail" + }, + "runAfter": { + "Get_manager_(V2)": [ + "Succeeded" + ] + }, + "type": "ApiConnection" + } + }, + "foreach": "@body('Entities_-_Get_Accounts')?['Accounts']", + "runAfter": { + "Entities_-_Get_Accounts": [ + "Succeeded" + ] + }, + "type": "Foreach" + } + }, + "contentVersion": "1.0.0.0", + "parameters": { + "$connections": { + "type": "Object" + } + }, + "triggers": { + "Microsoft_Sentinel_alert": { + "inputs": { + "body": { + "callback_url": "@{listCallbackUrl()}" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "path": "/subscribe" + }, + "type": "ApiConnectionWebhook" + } + } + }, + "parameters": { + "$connections": { + "value": { + "azuresentinel": { + "connectionId": "[[resourceId('Microsoft.Web/connections', variables('AzureSentinelConnectionName'))]", + "connectionName": "[[variables('AzureSentinelConnectionName')]", + "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", + "connectionProperties": { + "authentication": { + "type": "ManagedServiceIdentity" + } + } + }, + "office365": { + "connectionId": "[[resourceId('Microsoft.Web/connections', variables('Office365ConnectionName'))]", + "connectionName": "[[variables('Office365ConnectionName')]", + "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]" + }, + "office365users": { + "connectionId": "[[resourceId('Microsoft.Web/connections', variables('Office365UsersConnectionName'))]", + "connectionName": "[[variables('Office365UsersConnectionName')]", + "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365users')]" + } + } + } + } + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('Playbook-', last(split(variables('playbookId9'),'/'))))]", + "properties": { + "parentId": "[variables('playbookId9')]", + "contentId": "[variables('_playbookContentId9')]", + "kind": "Playbook", + "version": "[variables('playbookVersion9')]", + "source": { + "kind": "Solution", + "name": "Azure Active Directory", + "sourceId": "[variables('_solutionId')]" + }, + "author": { "name": "Microsoft", "email": "[variables('_email')]" }, @@ -5192,99 +4180,208 @@ } } } - ] + ], + "metadata": { + "title": "Revoke-AADSignInSessions alert trigger", + "description": "This playbook will revoke all signin sessions for the user using Graph API. It will send an email to the user's manager.", + "prerequisites": [ + "1. You must create an app registration for graph api with appropriate permissions.", + "2. You will need to add the managed identity that is created by the logic app to the Password Administrator role in Azure AD." + ], + "comments": "This playbook will revoke all signin sessions for the user using Graph API using a Beta API. It will send and email to the user's manager.", + "lastUpdateTime": "2021-07-14T00:00:00Z", + "entities": [ + "Account" + ], + "tags": [ + "Remediation" + ], + "releaseNotes": { + "version": "1.0", + "title": "[variables('blanks')]", + "notes": [ + "Initial version" + ] + } + } }, "packageKind": "Solution", "packageVersion": "[variables('_solutionVersion')]", "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId34')]", - "contentKind": "AnalyticsRule", - "displayName": "New access credential added to Application or Service Principal", - "contentProductId": "[variables('_analyticRulecontentProductId34')]", - "id": "[variables('_analyticRulecontentProductId34')]", - "version": "[variables('analyticRuleVersion34')]" - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "contentId": "[variables('_playbookContentId9')]", + "contentKind": "Playbook", + "displayName": "Revoke-AADSignInSessions-alert", + "contentProductId": "[variables('_playbookcontentProductId9')]", + "id": "[variables('_playbookcontentProductId9')]", + "version": "[variables('playbookVersion9')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName35')]", + "name": "[variables('playbookTemplateSpecName10')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "NRT_ADFSDomainTrustMods_AnalyticalRules Analytics Rule with template version 3.0.4", + "description": "Revoke-AADSignIn-Session-entityTrigger Playbook with template version 3.0.5", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion35')]", - "parameters": {}, - "variables": {}, + "contentVersion": "[variables('playbookVersion10')]", + "parameters": { + "PlaybookName": { + "defaultValue": "Revoke-AADSignIn-Session-entityTrigger", + "type": "string" + } + }, + "variables": { + "MicrosoftSentinelConnectionName": "[[concat('MicrosoftSentinel-', parameters('PlaybookName'))]", + "connection-2": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/Azuresentinel')]", + "_connection-2": "[[variables('connection-2')]", + "workspace-location-inline": "[concat('[resourceGroup().locatio', 'n]')]", + "workspace-name": "[parameters('workspace')]", + "workspaceResourceId": "[[resourceId('microsoft.OperationalInsights/Workspaces', variables('workspace-name'))]" + }, "resources": [ { - "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId35')]", - "apiVersion": "2022-04-01-preview", - "kind": "NRT", - "location": "[parameters('workspace-location')]", "properties": { - "description": "This will alert when a user or application modifies the federation settings on the domain or Update domain authentication from Managed to Federated.\nFor example, this alert will trigger when a new Active Directory Federated Service (ADFS) TrustedRealm object, such as a signing certificate, is added to the domain.\nModification to domain federation settings should be rare. Confirm the added or modified target domain/URL is legitimate administrator behavior.\nTo understand why an authorized user may update settings for a federated domain in Office 365, Azure, or Intune, see: https://docs.microsoft.com/office365/troubleshoot/active-directory/update-federated-domain-office-365.\nFor details on security realms that accept security tokens, see the ADFS Proxy Protocol (MS-ADFSPP) specification: https://docs.microsoft.com/openspecs/windows_protocols/ms-adfspp/e7b9ea73-1980-4318-96a6-da559486664b.\nFor further information on AuditLogs please see https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-audit-activities.", - "displayName": "NRT Modified domain federation trust settings", - "enabled": false, - "query": "AuditLogs\n| where OperationName =~ \"Set federation settings on domain\" or OperationName =~ \"Set domain authentication\"\n//| where Result =~ \"success\" // commenting out, as it may be interesting to capture failed attempts\n| mv-expand TargetResources\n| extend modifiedProperties = parse_json(TargetResources).modifiedProperties\n| mv-apply Property = modifiedProperties on \n (\n where Property.displayName =~ \"LiveType\"\n | extend targetDisplayName = tostring(Property.displayName),\n NewDomainValue = tostring(Property.newValue)\n )\n| extend Federated = iif(OperationName =~ \"Set domain authentication\", iif(NewDomainValue has \"Federated\", True, False), True)\n| where Federated == True\n| mv-expand AdditionalDetails\n| mv-apply AdditionalDetail = AdditionalDetails on \n (\n where AdditionalDetail.key =~ \"User-Agent\"\n | extend UserAgent = tostring(AdditionalDetail.value)\n )\n| extend InitiatingUserOrApp = iff(isnotempty(InitiatedBy.user.userPrincipalName),tostring(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.app.displayName))\n| extend InitiatingIpAddress = iff(isnotempty(InitiatedBy.user.ipAddress), tostring(InitiatedBy.user.ipAddress), tostring(InitiatedBy.app.ipAddress))\n| project-reorder TimeGenerated, OperationName, InitiatingUserOrApp, AADOperationType, targetDisplayName, Result, InitiatingIpAddress, UserAgent, CorrelationId, TenantId, AADTenantId\n| extend Name = tostring(split(InitiatingUserOrApp,'@',0)[0]), UPNSuffix = tostring(split(InitiatingUserOrApp,'@',1)[0])\n", - "severity": "High", - "suppressionDuration": "PT1H", - "suppressionEnabled": false, - "status": "Available", - "requiredDataConnectors": [ - { - "dataTypes": [ - "AuditLogs" - ], - "connectorId": "AzureActiveDirectory" - } - ], - "tactics": [ - "CredentialAccess" - ], - "entityMappings": [ - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "Name" - }, - { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" + "provisioningState": "Succeeded", + "state": "Enabled", + "definition": { + "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "$connections": { + "type": "Object" + } + }, + "triggers": { + "Microsoft_Sentinel_entity": { + "type": "ApiConnectionWebhook", + "inputs": { + "body": { + "callback_url": "@{listCallbackUrl()}" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" + } + }, + "path": "/entity/@{encodeURIComponent('Account')}" } - ] + } }, - { - "entityType": "IP", - "fieldMappings": [ - { - "identifier": "Address", - "columnName": "InitiatingIpAddress" + "actions": { + "Condition": { + "actions": { + "Add_comment_to_incident_(V3)_-_session_revoked": { + "type": "ApiConnection", + "inputs": { + "body": { + "incidentArmId": "@triggerBody()?['IncidentArmID']", + "message": "

Sign-in session revoked for the user - @{concat(triggerBody()?['Entity']?['properties']?['Name'], '@', triggerBody()?['Entity']?['properties']?['upnSuffix'])}

" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" + } + }, + "method": "post", + "path": "/Incidents/Comment" + } + } + }, + "runAfter": { + "HTTP_-_revoke_sign-in_session": [ + "Succeeded" + ] + }, + "expression": { + "and": [ + { + "not": { + "equals": [ + "@triggerBody()?['IncidentArmID']", + "@null" + ] + } + } + ] + }, + "type": "If" + }, + "HTTP_-_revoke_sign-in_session": { + "type": "Http", + "inputs": { + "authentication": { + "audience": "https://graph.microsoft.com", + "type": "ManagedServiceIdentity" + }, + "method": "POST", + "uri": "https://graph.microsoft.com/v1.0/users/@{concat(triggerBody()?['Entity']?['properties']?['Name'], '@', triggerBody()?['Entity']?['properties']?['upnSuffix'])}/revokeSignInSessions" } - ] + } } - ] + }, + "parameters": { + "$connections": { + "value": { + "microsoftsentinel": { + "connectionId": "[[resourceId('Microsoft.Web/connections', variables('MicrosoftSentinelConnectionName'))]", + "connectionName": "[[variables('MicrosoftSentinelConnectionName')]", + "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/Azuresentinel')]", + "connectionProperties": { + "authentication": { + "type": "ManagedServiceIdentity" + } + } + } + } + } + } + }, + "name": "[[parameters('PlaybookName')]", + "type": "Microsoft.Logic/workflows", + "location": "[[variables('workspace-location-inline')]", + "tags": { + "hidden-SentinelTemplateName": "Revoke-AADSignIn-Session-entityTrigger", + "hidden-SentinelTemplateVersion": "1.0", + "hidden-SentinelWorkspaceId": "[[variables('workspaceResourceId')]" + }, + "identity": { + "type": "SystemAssigned" + }, + "apiVersion": "2017-07-01", + "dependsOn": [ + "[[resourceId('Microsoft.Web/connections', variables('MicrosoftSentinelConnectionName'))]" + ] + }, + { + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[[variables('MicrosoftSentinelConnectionName')]", + "location": "[[variables('workspace-location-inline')]", + "kind": "V1", + "properties": { + "displayName": "[[variables('MicrosoftSentinelConnectionName')]", + "parameterValueType": "Alternative", + "api": { + "id": "[[variables('_connection-2')]" + } } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId35'),'/'))))]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('Playbook-', last(split(variables('playbookId10'),'/'))))]", "properties": { - "description": "Azure Active Directory Analytics Rule 35", - "parentId": "[variables('analyticRuleId35')]", - "contentId": "[variables('_analyticRulecontentId35')]", - "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion35')]", + "parentId": "[variables('playbookId10')]", + "contentId": "[variables('_playbookContentId10')]", + "kind": "Playbook", + "version": "[variables('playbookVersion10')]", "source": { "kind": "Solution", "name": "Azure Active Directory", @@ -5302,328 +4399,313 @@ } } } - ] + ], + "metadata": { + "title": "Revoke AAD Sign-in session using entity trigger", + "description": "This playbook will revoke user's sign-in sessions and user will have to perform authentication again. It invalidates all the refresh tokens issued to applications for a user (as well as session cookies in a user's browser), by resetting the signInSessionsValidFromDateTime user property to the current date-time.", + "postDeployment": [ + "1. Add Microsoft Sentinel Responder role to the managed identity.", + "2. Assign User.ReadWrite.All and Directory.ReadWrite.All API permissions to the managed identity." + ], + "lastUpdateTime": "2022-12-22T00:00:00Z", + "entities": [ + "Account" + ], + "releaseNotes": { + "version": "1.0", + "title": "[variables('blanks')]", + "notes": [ + "Initial version" + ] + } + } }, "packageKind": "Solution", "packageVersion": "[variables('_solutionVersion')]", "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId35')]", - "contentKind": "AnalyticsRule", - "displayName": "NRT Modified domain federation trust settings", - "contentProductId": "[variables('_analyticRulecontentProductId35')]", - "id": "[variables('_analyticRulecontentProductId35')]", - "version": "[variables('analyticRuleVersion35')]" + "contentId": "[variables('_playbookContentId10')]", + "contentKind": "Playbook", + "displayName": "Revoke-AADSignIn-Session-entityTrigger", + "contentProductId": "[variables('_playbookcontentProductId10')]", + "id": "[variables('_playbookcontentProductId10')]", + "version": "[variables('playbookVersion10')]" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName36')]", + "name": "[variables('playbookTemplateSpecName11')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "NRT_AuthenticationMethodsChangedforVIPUsers_AnalyticalRules Analytics Rule with template version 3.0.4", + "description": "Revoke-AADSignInSessions-incident Playbook with template version 3.0.5", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion36')]", - "parameters": {}, - "variables": {}, - "resources": [ - { - "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId36')]", - "apiVersion": "2022-04-01-preview", - "kind": "NRT", - "location": "[parameters('workspace-location')]", - "properties": { - "description": "Identifies authentication methods being changed for a list of VIP users watchlist. This could be an indication of an attacker adding an auth method to the account so they can have continued access.", - "displayName": "NRT Authentication Methods Changed for VIP Users", - "enabled": false, - "query": "let security_info_actions = dynamic([\"User registered security info\", \"User changed default security info\", \"User deleted security info\", \"Admin updated security info\", \"User reviewed security info\", \"Admin deleted security info\", \"Admin registered security info\"]);\nlet VIPUsers = (_GetWatchlist('VIPUsers') | distinct \"User Principal Name\");\nAuditLogs\n| where Category =~ \"UserManagement\"\n| where ActivityDisplayName in (security_info_actions)\n| extend Initiator = tostring(InitiatedBy.user.userPrincipalName)\n| extend IP = tostring(InitiatedBy.user.ipAddress)\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"User\"\n | extend Target = trim(@'\"',tolower(tostring(TargetResource.userPrincipalName)))\n )\n| where Target in~ (VIPUsers)\n| summarize Start=min(TimeGenerated), End=max(TimeGenerated), Actions = make_set(ResultReason) by Initiator, IP, Result, Target\n| extend Name = tostring(split(Target,'@',0)[0]), UPNSuffix = tostring(split(Target,'@',1)[0])\n", - "severity": "Medium", - "suppressionDuration": "PT1H", - "suppressionEnabled": false, - "status": "Available", - "requiredDataConnectors": [ - { - "dataTypes": [ - "AuditLogs" - ], - "connectorId": "AzureActiveDirectory" - } - ], - "tactics": [ - "Persistence" - ], - "techniques": [ - "T1098" - ], - "entityMappings": [ - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "Name" - }, - { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" - } - ] - }, - { - "entityType": "IP", - "fieldMappings": [ - { - "identifier": "Address", - "columnName": "IP" - } - ] - } - ] - } + "contentVersion": "[variables('playbookVersion11')]", + "parameters": { + "PlaybookName": { + "defaultValue": "Revoke-AADSignInSessions-incident", + "type": "string" }, + "UserName": { + "defaultValue": "@", + "type": "string" + } + }, + "variables": { + "AzureSentinelConnectionName": "[[concat('azuresentinel-', parameters('PlaybookName'))]", + "Office365ConnectionName": "[[concat('office365-', parameters('PlaybookName'))]", + "Office365UsersConnectionName": "[[concat('office365users-', parameters('PlaybookName'))]", + "connection-1": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", + "_connection-1": "[[variables('connection-1')]", + "connection-2": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]", + "_connection-2": "[[variables('connection-2')]", + "connection-3": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365users')]", + "_connection-3": "[[variables('connection-3')]", + "workspace-location-inline": "[concat('[resourceGroup().locatio', 'n]')]", + "workspace-name": "[parameters('workspace')]", + "workspaceResourceId": "[[resourceId('microsoft.OperationalInsights/Workspaces', variables('workspace-name'))]" + }, + "resources": [ { - "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", - "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId36'),'/'))))]", + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[[variables('AzureSentinelConnectionName')]", + "location": "[[variables('workspace-location-inline')]", + "kind": "V1", "properties": { - "description": "Azure Active Directory Analytics Rule 36", - "parentId": "[variables('analyticRuleId36')]", - "contentId": "[variables('_analyticRulecontentId36')]", - "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion36')]", - "source": { - "kind": "Solution", - "name": "Azure Active Directory", - "sourceId": "[variables('_solutionId')]" - }, - "author": { - "name": "Microsoft", - "email": "[variables('_email')]" - }, - "support": { - "tier": "Microsoft", - "name": "Microsoft Corporation", - "email": "support@microsoft.com", - "link": "https://support.microsoft.com/" + "displayName": "[[parameters('PlaybookName')]", + "parameterValueType": "Alternative", + "api": { + "id": "[[variables('_connection-1')]" } } - } - ] - }, - "packageKind": "Solution", - "packageVersion": "[variables('_solutionVersion')]", - "packageName": "[variables('_solutionName')]", - "packageId": "[variables('_solutionId')]", - "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId36')]", - "contentKind": "AnalyticsRule", - "displayName": "NRT Authentication Methods Changed for VIP Users", - "contentProductId": "[variables('_analyticRulecontentProductId36')]", - "id": "[variables('_analyticRulecontentProductId36')]", - "version": "[variables('analyticRuleVersion36')]" - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", - "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName37')]", - "location": "[parameters('workspace-location')]", - "dependsOn": [ - "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" - ], - "properties": { - "description": "nrt_FirstAppOrServicePrincipalCredential_AnalyticalRules Analytics Rule with template version 3.0.4", - "mainTemplate": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion37')]", - "parameters": {}, - "variables": {}, - "resources": [ + }, { - "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId37')]", - "apiVersion": "2022-04-01-preview", - "kind": "NRT", - "location": "[parameters('workspace-location')]", + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[[variables('Office365ConnectionName')]", + "location": "[[variables('workspace-location-inline')]", "properties": { - "description": "This will alert when an admin or app owner account adds a new credential to an Application or Service Principal where there was no previous verify KeyCredential associated.\nIf a threat actor obtains access to an account with sufficient privileges and adds the alternate authentication material triggering this event, the threat actor can now authenticate as the Application or Service Principal using this credential.\nAdditional information on OAuth Credential Grants can be found in RFC 6749 Section 4.4 or https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow\nFor further information on AuditLogs please see https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-audit-activities.", - "displayName": "NRT First access credential added to Application or Service Principal where no credential was present", - "enabled": false, - "query": "AuditLogs\n| where OperationName has_any (\"Add service principal\", \"Certificates and secrets management\")\n| where Result =~ \"success\"\n| where tostring(InitiatedBy.user.userPrincipalName) has \"@\" or tostring(InitiatedBy.app.displayName) has \"@\"\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"Application\"\n | extend targetDisplayName = tostring(TargetResource.displayName),\n targetId = tostring(TargetResource.id),\n targetType = tostring(TargetResource.type),\n keyEvents = TargetResource.modifiedProperties\n )\n| mv-apply Property = keyEvents on \n (\n where Property.displayName =~ \"KeyDescription\"\n | extend new_value_set = parse_json(tostring(Property.newValue)),\n old_value_set = parse_json(tostring(Property.oldValue))\n )\n| where old_value_set == \"[]\"\n| mv-expand new_value_set\n| parse new_value_set with * \"KeyIdentifier=\" keyIdentifier:string \",KeyType=\" keyType:string \",KeyUsage=\" keyUsage:string \",DisplayName=\" keyDisplayName:string \"]\" *\n| where keyUsage == \"Verify\"\n | mv-apply AdditionalDetail = AdditionalDetails on \n (\n where AdditionalDetail.key =~ \"User-Agent\"\n | extend UserAgent = tostring(AdditionalDetail.value)\n )\n| extend InitiatingUserOrApp = iff(isnotempty(InitiatedBy.user.userPrincipalName),tostring(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.app.displayName))\n| extend InitiatingIpAddress = iff(isnotempty(InitiatedBy.user.ipAddress), tostring(InitiatedBy.user.ipAddress), tostring(InitiatedBy.app.ipAddress))\n//| where targetType =~ \"Application\" // or targetType =~ \"ServicePrincipal\"\n| project-away new_value_set, old_value_set\n| project-reorder TimeGenerated, OperationName, InitiatingUserOrApp, InitiatingIpAddress, UserAgent, targetDisplayName, targetId, targetType, keyDisplayName, keyType, keyUsage, keyIdentifier, CorrelationId, TenantId\n| extend timestamp = TimeGenerated, Name = tostring(split(InitiatingUserOrApp,'@',0)[0]), UPNSuffix = tostring(split(InitiatingUserOrApp,'@',1)[0])\n", - "severity": "Medium", - "suppressionDuration": "PT1H", - "suppressionEnabled": false, - "status": "Available", - "requiredDataConnectors": [ - { - "dataTypes": [ - "AuditLogs" - ], - "connectorId": "AzureActiveDirectory" - } - ], - "tactics": [ - "DefenseEvasion" - ], - "techniques": [ - "T1550" - ], - "entityMappings": [ - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "Name" - }, - { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" - } - ] - }, - { - "entityType": "IP", - "fieldMappings": [ - { - "identifier": "Address", - "columnName": "InitiatingIpAddress" - } - ] - } - ] + "displayName": "[[parameters('UserName')]", + "api": { + "id": "[[variables('_connection-2')]" + } } }, { - "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", - "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId37'),'/'))))]", + "type": "Microsoft.Web/connections", + "apiVersion": "2016-06-01", + "name": "[[variables('Office365UsersConnectionName')]", + "location": "[[variables('workspace-location-inline')]", "properties": { - "description": "Azure Active Directory Analytics Rule 37", - "parentId": "[variables('analyticRuleId37')]", - "contentId": "[variables('_analyticRulecontentId37')]", - "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion37')]", - "source": { - "kind": "Solution", - "name": "Azure Active Directory", - "sourceId": "[variables('_solutionId')]" - }, - "author": { - "name": "Microsoft", - "email": "[variables('_email')]" - }, - "support": { - "tier": "Microsoft", - "name": "Microsoft Corporation", - "email": "support@microsoft.com", - "link": "https://support.microsoft.com/" + "displayName": "[[parameters('UserName')]", + "api": { + "id": "[[variables('_connection-3')]" } } - } - ] - }, - "packageKind": "Solution", - "packageVersion": "[variables('_solutionVersion')]", - "packageName": "[variables('_solutionName')]", - "packageId": "[variables('_solutionId')]", - "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId37')]", - "contentKind": "AnalyticsRule", - "displayName": "NRT First access credential added to Application or Service Principal where no credential was present", - "contentProductId": "[variables('_analyticRulecontentProductId37')]", - "id": "[variables('_analyticRulecontentProductId37')]", - "version": "[variables('analyticRuleVersion37')]" - } - }, - { - "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", - "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName38')]", - "location": "[parameters('workspace-location')]", - "dependsOn": [ - "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" - ], - "properties": { - "description": "NRT_NewAppOrServicePrincipalCredential_AnalyticalRules Analytics Rule with template version 3.0.4", - "mainTemplate": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion38')]", - "parameters": {}, - "variables": {}, - "resources": [ + }, { - "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId38')]", - "apiVersion": "2022-04-01-preview", - "kind": "NRT", - "location": "[parameters('workspace-location')]", + "type": "Microsoft.Logic/workflows", + "apiVersion": "2017-07-01", + "name": "[[parameters('PlaybookName')]", + "location": "[[variables('workspace-location-inline')]", + "tags": { + "LogicAppsCategory": "security", + "hidden-SentinelTemplateName": "Revoke-AADSigninSessions", + "hidden-SentinelTemplateVersion": "1.0", + "hidden-SentinelWorkspaceId": "[[variables('workspaceResourceId')]" + }, + "identity": { + "type": "SystemAssigned" + }, + "dependsOn": [ + "[[resourceId('Microsoft.Web/connections', variables('AzureSentinelConnectionName'))]", + "[[resourceId('Microsoft.Web/connections', variables('Office365ConnectionName'))]", + "[[resourceId('Microsoft.Web/connections', variables('Office365UsersConnectionName'))]" + ], "properties": { - "description": "This will alert when an admin or app owner account adds a new credential to an Application or Service Principal where a verify KeyCredential was already present for the app.\nIf a threat actor obtains access to an account with sufficient privileges and adds the alternate authentication material triggering this event, the threat actor can now authenticate as the Application or Service Principal using this credential.\nAdditional information on OAuth Credential Grants can be found in RFC 6749 Section 4.4 or https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow\nFor further information on AuditLogs please see https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-audit-activities.", - "displayName": "NRT New access credential added to Application or Service Principal", - "enabled": false, - "query": "AuditLogs\n| where OperationName has_any (\"Add service principal\", \"Certificates and secrets management\") // captures \"Add service principal\", \"Add service principal credentials\", and \"Update application - Certificates and secrets management\" events\n| where Result =~ \"success\"\n| where tostring(InitiatedBy.user.userPrincipalName) has \"@\" or tostring(InitiatedBy.app.displayName) has \"@\"\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"Application\"\n | extend targetDisplayName = tostring(TargetResource.displayName),\n targetId = tostring(TargetResource.id),\n targetType = tostring(TargetResource.type),\n keyEvents = TargetResource.modifiedProperties\n )\n| mv-apply Property = keyEvents on \n (\n where Property.displayName =~ \"KeyDescription\"\n | extend new_value_set = parse_json(tostring(Property.newValue)),\n old_value_set = parse_json(tostring(Property.oldValue))\n )\n| where old_value_set != \"[]\"\n| extend diff = set_difference(new_value_set, old_value_set)\n| where diff != \"[]\"\n| parse diff with * \"KeyIdentifier=\" keyIdentifier:string \",KeyType=\" keyType:string \",KeyUsage=\" keyUsage:string \",DisplayName=\" keyDisplayName:string \"]\" *\n| where keyUsage =~ \"Verify\"\n| mv-apply AdditionalDetail = AdditionalDetails on \n (\n where AdditionalDetail.key =~ \"User-Agent\"\n | extend UserAgent = tostring(AdditionalDetail.value)\n )\n| extend InitiatingUserOrApp = iff(isnotempty(InitiatedBy.user.userPrincipalName),tostring(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.app.displayName))\n| extend InitiatingIpAddress = iff(isnotempty(InitiatedBy.user.ipAddress), tostring(InitiatedBy.user.ipAddress), tostring(InitiatedBy.app.ipAddress))\n// The below line is currently commented out but Microsoft Sentinel users can modify this query to show only Application or only Service Principal events in their environment\n//| where targetType =~ \"Application\" // or targetType =~ \"ServicePrincipal\"\n| project-away diff, new_value_set, old_value_set\n| project-reorder TimeGenerated, OperationName, InitiatingUserOrApp, InitiatingIpAddress, UserAgent, targetDisplayName, targetId, targetType, keyDisplayName, keyType, keyUsage, keyIdentifier, CorrelationId, TenantId\n| extend timestamp = TimeGenerated, Name = tostring(split(InitiatingUserOrApp,'@',0)[0]), UPNSuffix = tostring(split(InitiatingUserOrApp,'@',1)[0])\n", - "severity": "Medium", - "suppressionDuration": "PT1H", - "suppressionEnabled": false, - "status": "Available", - "requiredDataConnectors": [ - { - "dataTypes": [ - "AuditLogs" - ], - "connectorId": "AzureActiveDirectory" - } - ], - "tactics": [ - "DefenseEvasion" - ], - "techniques": [ - "T1550" - ], - "entityMappings": [ - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "Name" + "state": "Enabled", + "definition": { + "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", + "actions": { + "Alert_-_Get_incident": { + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "get", + "path": "/Incidents/subscriptions/@{encodeURIComponent(triggerBody()?['WorkspaceSubscriptionId'])}/resourceGroups/@{encodeURIComponent(triggerBody()?['WorkspaceResourceGroup'])}/workspaces/@{encodeURIComponent(triggerBody()?['WorkspaceId'])}/alerts/@{encodeURIComponent(triggerBody()?['SystemAlertId'])}" }, - { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" - } - ] + "type": "ApiConnection" + }, + "Entities_-_Get_Accounts": { + "inputs": { + "body": "@triggerBody()?['Entities']", + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "post", + "path": "/entities/account" + }, + "runAfter": { + "Alert_-_Get_incident": [ + "Succeeded" + ] + }, + "type": "ApiConnection" + }, + "For_each": { + "actions": { + "Add_comment_to_incident_(V3)": { + "inputs": { + "body": { + "incidentArmId": "@body('Alert_-_Get_incident')?['id']", + "message": "

User @{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])} singin sessions were revoked in AAD and their manager @{body('Get_manager_(V2)')?['displayName']} was contacted using playbook.

" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "method": "post", + "path": "/Incidents/Comment" + }, + "runAfter": { + "Send_an_email_(V2)": [ + "Succeeded" + ] + }, + "type": "ApiConnection" + }, + "Get_manager_(V2)": { + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['office365users']['connectionId']" + } + }, + "method": "get", + "path": "/codeless/v1.0/users/@{encodeURIComponent(concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix']))}/manager" + }, + "runAfter": { + "HTTP": [ + "Succeeded" + ] + }, + "type": "ApiConnection" + }, + "HTTP": { + "inputs": { + "authentication": { + "audience": "https://graph.microsoft.com", + "type": "ManagedServiceIdentity" + }, + "method": "POST", + "uri": "https://graph.microsoft.com/v1.0/users/@{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])}/revokeSignInSessions" + }, + "type": "Http" + }, + "Send_an_email_(V2)": { + "inputs": { + "body": { + "Body": "

User, @{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])}, was involved in part of a security incident.  As part of remediation, the user signin sessions have been revoked.  The user will need to reauthenticate in all applications.

", + "Subject": "User signin sessions were reset due to security incident.", + "To": "@body('Get_manager_(V2)')?['mail']" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['office365']['connectionId']" + } + }, + "method": "post", + "path": "/v2/Mail" + }, + "runAfter": { + "Get_manager_(V2)": [ + "Succeeded" + ] + }, + "type": "ApiConnection" + } + }, + "foreach": "@body('Entities_-_Get_Accounts')?['Accounts']", + "runAfter": { + "Entities_-_Get_Accounts": [ + "Succeeded" + ] + }, + "type": "Foreach" + } }, - { - "entityType": "IP", - "fieldMappings": [ - { - "identifier": "Address", - "columnName": "InitiatingIpAddress" + "contentVersion": "1.0.0.0", + "parameters": { + "$connections": { + "type": "Object" + } + }, + "triggers": { + "Microsoft_Sentinel_alert": { + "inputs": { + "body": { + "callback_url": "@{listCallbackUrl()}" + }, + "host": { + "connection": { + "name": "@parameters('$connections')['azuresentinel']['connectionId']" + } + }, + "path": "/subscribe" + }, + "type": "ApiConnectionWebhook" + } + } + }, + "parameters": { + "$connections": { + "value": { + "azuresentinel": { + "connectionId": "[[resourceId('Microsoft.Web/connections', variables('AzureSentinelConnectionName'))]", + "connectionName": "[[variables('AzureSentinelConnectionName')]", + "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", + "connectionProperties": { + "authentication": { + "type": "ManagedServiceIdentity" + } + } + }, + "office365": { + "connectionId": "[[resourceId('Microsoft.Web/connections', variables('Office365ConnectionName'))]", + "connectionName": "[[variables('Office365ConnectionName')]", + "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]" + }, + "office365users": { + "connectionId": "[[resourceId('Microsoft.Web/connections', variables('Office365UsersConnectionName'))]", + "connectionName": "[[variables('Office365UsersConnectionName')]", + "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365users')]" } - ] + } } - ] + } } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId38'),'/'))))]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('Playbook-', last(split(variables('playbookId11'),'/'))))]", "properties": { - "description": "Azure Active Directory Analytics Rule 38", - "parentId": "[variables('analyticRuleId38')]", - "contentId": "[variables('_analyticRulecontentId38')]", - "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion38')]", + "parentId": "[variables('playbookId11')]", + "contentId": "[variables('_playbookContentId11')]", + "kind": "Playbook", + "version": "[variables('playbookVersion11')]", "source": { "kind": "Solution", "name": "Azure Active Directory", @@ -5641,115 +4723,83 @@ } } } - ] + ], + "metadata": { + "title": "Revoke AAD SignIn Sessions - incident trigger", + "description": "This playbook will revoke all signin sessions for the user using Graph API. It will send an email to the user's manager.", + "prerequisites": "1. You will need to grant User.ReadWrite.All permissions to the managed identity.", + "lastUpdateTime": "2021-07-14T00:00:00Z", + "entities": [ + "Account" + ], + "tags": [ + "Remediation" + ], + "releaseNotes": { + "version": "1.0", + "title": "[variables('blanks')]", + "notes": [ + "Initial version" + ] + } + } }, "packageKind": "Solution", "packageVersion": "[variables('_solutionVersion')]", "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId38')]", - "contentKind": "AnalyticsRule", - "displayName": "NRT New access credential added to Application or Service Principal", - "contentProductId": "[variables('_analyticRulecontentProductId38')]", - "id": "[variables('_analyticRulecontentProductId38')]", - "version": "[variables('analyticRuleVersion38')]" + "contentId": "[variables('_playbookContentId11')]", + "contentKind": "Playbook", + "displayName": "Revoke-AADSignInSessions-incident", + "contentProductId": "[variables('_playbookcontentProductId11')]", + "id": "[variables('_playbookcontentProductId11')]", + "version": "[variables('playbookVersion11')]" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName39')]", + "name": "[variables('workbookTemplateSpecName1')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "NRT_PIMElevationRequestRejected_AnalyticalRules Analytics Rule with template version 3.0.4", + "description": "AzureActiveDirectoryAuditLogsWorkbook Workbook with template version 3.0.5", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion39')]", + "contentVersion": "[variables('workbookVersion1')]", "parameters": {}, "variables": {}, "resources": [ { - "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId39')]", - "apiVersion": "2022-04-01-preview", - "kind": "NRT", + "type": "Microsoft.Insights/workbooks", + "name": "[variables('workbookContentId1')]", "location": "[parameters('workspace-location')]", + "kind": "shared", + "apiVersion": "2021-08-01", + "metadata": { + "description": "Gain insights into Azure Active Directory by connecting Microsoft Sentinel and using the audit logs to gather insights around Azure AD scenarios. \nYou can learn about user operations, including password and group management, device activities, and top active users and apps." + }, "properties": { - "description": "Identifies when a user is rejected for a privileged role elevation via PIM. Monitor rejections for indicators of attacker compromise of the requesting account.\nRef : https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-privileged-identity-management", - "displayName": "NRT PIM Elevation Request Rejected", - "enabled": false, - "query": "AuditLogs\n| where ActivityDisplayName =~'Add member to role completed (PIM activation)'\n| where Result =~ \"failure\"\n| mv-apply ResourceItem = TargetResources on \n (\n where ResourceItem.type =~ \"Role\"\n | extend Role = trim(@'\"',tostring(ResourceItem.displayName))\n )\n| mv-apply ResourceItem = TargetResources on \n (\n where ResourceItem.type =~ \"User\"\n | extend User = trim(@'\"',tostring(ResourceItem.userPrincipalName))\n )\n| project-reorder TimeGenerated, User, Role, OperationName, Result, ResultDescription\n| where isnotempty(InitiatedBy.user)\n| extend InitiatingUser = tostring(InitiatedBy.user.userPrincipalName), InitiatingIpAddress = tostring(InitiatedBy.user.ipAddress)\n| extend InitiatingName = tostring(split(InitiatingUser,'@',0)[0]), InitiatingUPNSuffix = tostring(split(InitiatingUser,'@',1)[0])\n| extend UserName = tostring(split(User,'@',0)[0]), UserUPNSuffix = tostring(split(User,'@',1)[0])\n", - "severity": "High", - "suppressionDuration": "PT1H", - "suppressionEnabled": false, - "status": "Available", - "requiredDataConnectors": [ - { - "dataTypes": [ - "AuditLogs" - ], - "connectorId": "AzureActiveDirectory" - } - ], - "tactics": [ - "Persistence" - ], - "techniques": [ - "T1078" - ], - "entityMappings": [ - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "InitiatingName" - }, - { - "identifier": "UPNSuffix", - "columnName": "InitiatingUPNSuffix" - } - ] - }, - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "UserName" - }, - { - "identifier": "UPNSuffix", - "columnName": "UserUPNSuffix" - } - ] - }, - { - "entityType": "IP", - "fieldMappings": [ - { - "identifier": "Address", - "columnName": "InitiatingIpAddress" - } - ] - } - ] + "displayName": "[parameters('workbook1-name')]", + "serializedData": "{\"version\":\"Notebook/1.0\",\"items\":[{\"type\":1,\"content\":{\"json\":\"## Azure AD audit logs\"},\"name\":\"text - 1\"},{\"type\":9,\"content\":{\"version\":\"KqlParameterItem/1.0\",\"parameters\":[{\"id\":\"bc372bf5-2dcd-4efa-aa85-94b6e6fafe14\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"TimeRange\",\"type\":4,\"isRequired\":true,\"value\":{\"durationMs\":7776000000},\"typeSettings\":{\"selectableValues\":[{\"durationMs\":300000},{\"durationMs\":900000},{\"durationMs\":1800000},{\"durationMs\":3600000},{\"durationMs\":14400000},{\"durationMs\":43200000},{\"durationMs\":86400000},{\"durationMs\":172800000},{\"durationMs\":259200000},{\"durationMs\":604800000},{\"durationMs\":1209600000},{\"durationMs\":2419200000},{\"durationMs\":2592000000},{\"durationMs\":5184000000},{\"durationMs\":7776000000}],\"allowCustom\":true}},{\"id\":\"e032b9f7-5449-4180-9c20-75760afa96f6\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"User\",\"type\":2,\"isRequired\":true,\"multiSelect\":true,\"quote\":\"'\",\"delimiter\":\",\",\"query\":\"AuditLogs\\r\\n| where SourceSystem == \\\"Azure AD\\\"\\r\\n| extend initiator = iif (tostring(InitiatedBy.user.userPrincipalName) != \\\"\\\", tostring(InitiatedBy.user.userPrincipalName), \\\"unknown\\\")\\r\\n//| where initiator!= \\\"\\\"\\r\\n| summarize Count = count() by initiator\\r\\n| order by Count desc, initiator asc\\r\\n| project Value = initiator, Label = strcat(initiator, ' - ', Count), Selected = false\",\"value\":[\"value::all\"],\"typeSettings\":{\"additionalResourceOptions\":[\"value::all\"],\"selectAllValue\":\"All\"},\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},{\"id\":\"0a59a0b3-6d93-4fee-bdbe-147383c510c6\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"Category\",\"type\":2,\"isRequired\":true,\"multiSelect\":true,\"quote\":\"'\",\"delimiter\":\",\",\"query\":\"AuditLogs\\r\\n| extend initiator = iif (tostring(InitiatedBy.user.userPrincipalName) != \\\"\\\", tostring(InitiatedBy.user.userPrincipalName), \\\"unknown\\\")\\r\\n| where \\\"{User:lable}\\\" == \\\"All\\\" or initiator in ({User})\\r\\n| summarize Count = count() by Category\\r\\n| order by Count desc, Category asc\\r\\n| project Value = Category, Label = strcat(Category, ' - ', Count)\",\"value\":[\"value::all\"],\"typeSettings\":{\"additionalResourceOptions\":[\"value::all\"],\"selectAllValue\":\"All\"},\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},{\"id\":\"4d2b245b-5e59-4eb6-9f51-ba926581ab47\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"Result\",\"type\":2,\"isRequired\":true,\"multiSelect\":true,\"quote\":\"'\",\"delimiter\":\",\",\"query\":\"AuditLogs\\r\\n| extend initiator = iif (tostring(InitiatedBy.user.userPrincipalName) != \\\"\\\", tostring(InitiatedBy.user.userPrincipalName), \\\"unknown\\\")\\r\\n| where \\\"{User:lable}\\\" == \\\"All\\\" or initiator in ({User})\\r\\n| summarize Count = count() by Result\\r\\n| order by Count desc, Result asc\\r\\n| project Value = Result, Label = strcat(Result, ' - ', Count, ' sign-ins')\",\"value\":[\"value::all\"],\"typeSettings\":{\"additionalResourceOptions\":[\"value::all\"],\"selectAllValue\":\"All\"},\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"}],\"style\":\"pills\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},\"name\":\"parameters - 1\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let data = AuditLogs\\r\\n| where \\\"{Category:lable}\\\" == \\\"All\\\" or Category in ({Category})\\r\\n| where \\\"{Result:lable}\\\" == \\\"All\\\" or Result in ({Result})\\r\\n| extend initiatingUserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)\\r\\n| where initiatingUserPrincipalName != \\\"\\\" \\r\\n| where \\\"{User:lable}\\\" == \\\"All\\\" or initiatingUserPrincipalName in ({User});\\r\\ndata\\r\\n| summarize Count = count() by Category\\r\\n| join kind = fullouter (datatable(Category:string)['Medium', 'high', 'low']) on Category\\r\\n| project Category = iff(Category == '', Category1, Category), Count = iff(Category == '', 0, Count)\\r\\n| join kind = inner (data\\r\\n | make-series Trend = count() default = 0 on TimeGenerated from {TimeRange:start} to {TimeRange:end} step {TimeRange:grain} by Category)\\r\\n on Category\\r\\n| project-away Category1, TimeGenerated\\r\\n| extend Category = Category\\r\\n| union (\\r\\n data \\r\\n | summarize Count = count() \\r\\n | extend jkey = 1\\r\\n | join kind=inner (data\\r\\n | make-series Trend = count() default = 0 on TimeGenerated from {TimeRange:start} to {TimeRange:end} step {TimeRange:grain}\\r\\n | extend jkey = 1) on jkey\\r\\n | extend Category = 'All', Categorys = '*' \\r\\n)\\r\\n| order by Count desc\\r\\n| take 10\",\"size\":4,\"title\":\"Categories volume\",\"timeContext\":{\"durationMs\":7776000000},\"timeContextFromParameter\":\"TimeRange\",\"exportFieldName\":\"Category\",\"exportParameterName\":\"CategoryFIlter\",\"exportDefaultValue\":\"All\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"tiles\",\"tileSettings\":{\"titleContent\":{\"columnMatch\":\"Category\",\"formatter\":1,\"formatOptions\":{\"showIcon\":true}},\"leftContent\":{\"columnMatch\":\"Count\",\"formatter\":12,\"formatOptions\":{\"palette\":\"auto\",\"showIcon\":true},\"numberFormat\":{\"unit\":17,\"options\":{\"style\":\"decimal\",\"maximumFractionDigits\":2,\"maximumSignificantDigits\":3}}},\"secondaryContent\":{\"columnMatch\":\"Trend\",\"formatter\":21,\"formatOptions\":{\"palette\":\"purple\",\"showIcon\":true}},\"showBorder\":false}},\"name\":\"query - 4\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let data = AuditLogs\\r\\n| where \\\"{Result:lable}\\\" == \\\"All\\\" or Result in ({Result})\\r\\n| extend initiator = iif (tostring(InitiatedBy.user.userPrincipalName) != \\\"\\\", tostring(InitiatedBy.user.userPrincipalName), \\\"unknown\\\")\\r\\n| where \\\"{User:lable}\\\" == \\\"All\\\" or initiator in ({User})\\r\\n| where \\\"{Category:lable}\\\" == \\\"All\\\" or Category in ({Category})\\r\\n| where Category == '{CategoryFIlter}' or '{CategoryFIlter}' == \\\"All\\\";\\r\\nlet appData = data\\r\\n| summarize TotalCount = count() by OperationName, Category\\r\\n| join kind=inner (data\\r\\n | make-series Trend = count() default = 0 on TimeGenerated in range({TimeRange:start}, {TimeRange:end}, {TimeRange:grain}) by OperationName\\r\\n | project-away TimeGenerated) on OperationName\\r\\n| order by TotalCount desc, OperationName asc\\r\\n| project OperationName, TotalCount, Trend, Category\\r\\n| serialize Id = row_number();\\r\\ndata\\r\\n| summarize TotalCount = count() by initiator = iif (tostring(InitiatedBy.user.userPrincipalName) != \\\"\\\", tostring(InitiatedBy.user.userPrincipalName), \\\"unknown\\\"), Category, OperationName\\r\\n| join kind=inner (data\\r\\n | make-series Trend = count() default = 0 on TimeGenerated in range({TimeRange:start}, {TimeRange:end}, {TimeRange:grain}) by OperationName, initiator = iif (tostring(InitiatedBy.user.userPrincipalName) != \\\"\\\", tostring(InitiatedBy.user.userPrincipalName), \\\"unknown\\\")\\r\\n | project-away TimeGenerated) on OperationName, initiator\\r\\n| order by TotalCount desc, OperationName asc\\r\\n| project OperationName, initiator, TotalCount, Category, Trend\\r\\n| serialize Id = row_number(1000000)\\r\\n| join kind=inner (appData) on OperationName\\r\\n| project Id, Name = initiator, Type = 'initiator', ['Operations Count'] = TotalCount, Trend, Category, ParentId = Id1\\r\\n| union (appData \\r\\n | project Id, Name = OperationName, Type = 'Operation', ['Operations Count'] = TotalCount, Category, Trend)\\r\\n| order by ['Operations Count'] desc, Name asc\",\"size\":0,\"showAnalytics\":true,\"title\":\"User activities\",\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"exportParameterName\":\"UserInfo\",\"exportDefaultValue\":\"{ \\\"Name\\\":\\\"\\\", \\\"Type\\\":\\\"*\\\"}\",\"showExportToExcel\":true,\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"gridSettings\":{\"formatters\":[{\"columnMatch\":\"Id\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Type\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Operations Count\",\"formatter\":8,\"formatOptions\":{\"min\":0,\"palette\":\"blue\",\"showIcon\":true},\"numberFormat\":{\"unit\":0,\"options\":{\"style\":\"decimal\"}}},{\"columnMatch\":\"Trend\",\"formatter\":9,\"formatOptions\":{\"min\":0,\"palette\":\"turquoise\",\"showIcon\":true},\"numberFormat\":{\"unit\":0,\"options\":{\"style\":\"decimal\"}}},{\"columnMatch\":\"ParentId\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}}],\"rowLimit\":1000,\"filter\":true,\"hierarchySettings\":{\"idColumn\":\"Id\",\"parentColumn\":\"ParentId\",\"treeType\":0,\"expanderColumn\":\"Name\"}}},\"customWidth\":\"70\",\"showPin\":true,\"name\":\"query - 2\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let details = dynamic({UserInfo});\\r\\nAuditLogs\\r\\n| where \\\"{Category:lable}\\\" == \\\"All\\\" or Category in ({Category})\\r\\n| where \\\"{Result:lable}\\\" == \\\"All\\\" or Result in ({Result})\\r\\n| extend initiatingUserPrincipalName = iif (tostring(InitiatedBy.user.userPrincipalName) != \\\"\\\", tostring(InitiatedBy.user.userPrincipalName), \\\"unknown\\\")\\r\\n//| where initiatingUserPrincipalName != \\\"\\\" \\r\\n| where \\\"{User:lable}\\\" == \\\"All\\\" or initiatingUserPrincipalName in ({User})\\r\\n| where details.Type == '*' or (details.Type == 'initiator' and initiatingUserPrincipalName == details.Name) or (details.Type == 'Operation' and OperationName == details.Name)\\r\\n| summarize Activities = count() by initiatingUserPrincipalName\\r\\n| sort by Activities desc nulls last \",\"size\":0,\"title\":\"Top active users\",\"timeContext\":{\"durationMs\":7776000000},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"piechart\"},\"customWidth\":\"30\",\"name\":\"query - 3\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let details = dynamic({UserInfo});\\r\\nlet data = AuditLogs\\r\\n| extend initiator = iif (tostring(InitiatedBy.user.userPrincipalName) != \\\"\\\", tostring(InitiatedBy.user.userPrincipalName), \\\"unknown\\\")\\r\\n| where details.Type == '*' or (details.Type == 'initiator' and initiator == details.Name) or (details.Type == 'Operation' and OperationName == details.Name)\\r\\n| where \\\"{Category:lable}\\\" == \\\"All\\\" or Category in ({Category})\\r\\n| where \\\"{Result:lable}\\\" == \\\"All\\\" or Result in ({Result})\\r\\n| where \\\"{User:lable}\\\" == \\\"All\\\" or initiator in ({User});\\r\\nlet appData = data\\r\\n| summarize TotalCount = count() by Result\\r\\n| join kind=inner (data\\r\\n | make-series Trend = count() default = 0 on TimeGenerated in range({TimeRange:start}, {TimeRange:end}, {TimeRange:grain}) by Result\\r\\n | project-away TimeGenerated) on Result\\r\\n| order by TotalCount desc, Result asc\\r\\n| project Result, TotalCount, Trend\\r\\n| serialize Id = row_number();\\r\\ndata\\r\\n| summarize TotalCount = count() by OperationName, Result\\r\\n| join kind=inner (data\\r\\n | make-series Trend = count() default = 0 on TimeGenerated in range({TimeRange:start}, {TimeRange:end}, {TimeRange:grain}) by Result, OperationName\\r\\n | project-away TimeGenerated) on Result, OperationName\\r\\n| order by TotalCount desc, Result asc\\r\\n| project Result, OperationName, TotalCount, Trend\\r\\n| serialize Id = row_number(1000000)\\r\\n| join kind=inner (appData) on Result\\r\\n| project Id, Name = OperationName, Type = 'Operation', ['Results Count'] = TotalCount, Trend, ParentId = Id1\\r\\n| union (appData \\r\\n | project Id, Name = Result, Type = 'Result', ['Results Count'] = TotalCount, Trend)\\r\\n| order by ['Results Count'] desc, Name asc\",\"size\":0,\"title\":\"Result status\",\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"exportParameterName\":\"ResultInfo\",\"exportDefaultValue\":\"{ \\\"Name\\\":\\\"\\\", \\\"Type\\\":\\\"*\\\"}\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"gridSettings\":{\"formatters\":[{\"columnMatch\":\"Id\",\"formatter\":5},{\"columnMatch\":\"Type\",\"formatter\":5},{\"columnMatch\":\"Results Count\",\"formatter\":8,\"formatOptions\":{\"min\":0,\"palette\":\"grayBlue\"}},{\"columnMatch\":\"Trend\",\"formatter\":9,\"formatOptions\":{\"palette\":\"greenDark\"}},{\"columnMatch\":\"ParentId\",\"formatter\":5}],\"hierarchySettings\":{\"idColumn\":\"Id\",\"parentColumn\":\"ParentId\",\"treeType\":0,\"expanderColumn\":\"Name\"}}},\"customWidth\":\"70\",\"name\":\"query - 5\"}],\"fallbackResourceIds\":[\"\"],\"fromTemplateId\":\"sentinel-AzureActiveDirectoryAuditLogs\",\"$schema\":\"https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json\"}\n", + "version": "1.0", + "sourceId": "[variables('workspaceResourceId')]", + "category": "sentinel" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId39'),'/'))))]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('Workbook-', last(split(variables('workbookId1'),'/'))))]", "properties": { - "description": "Azure Active Directory Analytics Rule 39", - "parentId": "[variables('analyticRuleId39')]", - "contentId": "[variables('_analyticRulecontentId39')]", - "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion39')]", + "description": "@{workbookKey=AzureActiveDirectoryAuditLogsWorkbook; logoFileName=azureactivedirectory_logo.svg; description=Gain insights into Azure Active Directory by connecting Microsoft Sentinel and using the audit logs to gather insights around Azure AD scenarios. \nYou can learn about user operations, including password and group management, device activities, and top active users and apps.; dataTypesDependencies=System.Object[]; dataConnectorsDependencies=System.Object[]; previewImagesFileNames=System.Object[]; version=1.2.0; title=Azure AD Audit logs; templateRelativePath=AzureActiveDirectoryAuditLogs.json; subtitle=; provider=Microsoft}.description", + "parentId": "[variables('workbookId1')]", + "contentId": "[variables('_workbookContentId1')]", + "kind": "Workbook", + "version": "[variables('workbookVersion1')]", "source": { "kind": "Solution", "name": "Azure Active Directory", @@ -5764,6 +4814,19 @@ "name": "Microsoft Corporation", "email": "support@microsoft.com", "link": "https://support.microsoft.com/" + }, + "dependencies": { + "operator": "AND", + "criteria": [ + { + "contentId": "AuditLogs", + "kind": "DataType" + }, + { + "contentId": "AzureActiveDirectory", + "kind": "DataConnector" + } + ] } } } @@ -5774,95 +4837,57 @@ "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId39')]", - "contentKind": "AnalyticsRule", - "displayName": "NRT PIM Elevation Request Rejected", - "contentProductId": "[variables('_analyticRulecontentProductId39')]", - "id": "[variables('_analyticRulecontentProductId39')]", - "version": "[variables('analyticRuleVersion39')]" + "contentId": "[variables('_workbookContentId1')]", + "contentKind": "Workbook", + "displayName": "[parameters('workbook1-name')]", + "contentProductId": "[variables('_workbookcontentProductId1')]", + "id": "[variables('_workbookcontentProductId1')]", + "version": "[variables('workbookVersion1')]" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName40')]", + "name": "[variables('workbookTemplateSpecName2')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "NRT_PrivlegedRoleAssignedOutsidePIM_AnalyticalRules Analytics Rule with template version 3.0.4", + "description": "AzureActiveDirectorySigninsWorkbook Workbook with template version 3.0.5", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion40')]", + "contentVersion": "[variables('workbookVersion2')]", "parameters": {}, "variables": {}, "resources": [ { - "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId40')]", - "apiVersion": "2022-04-01-preview", - "kind": "NRT", + "type": "Microsoft.Insights/workbooks", + "name": "[variables('workbookContentId2')]", "location": "[parameters('workspace-location')]", + "kind": "shared", + "apiVersion": "2021-08-01", + "metadata": { + "description": "Gain insights into Azure Active Directory by connecting Microsoft Sentinel and using the sign-in logs to gather insights around Azure AD scenarios. \nYou can learn about sign-in operations, such as user sign-ins and locations, email addresses, and IP addresses of your users, as well as failed activities and the errors that triggered the failures." + }, "properties": { - "description": "Identifies a privileged role being assigned to a user outside of PIM\nRef : https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-privileged-accounts#things-to-monitor-1", - "displayName": "NRT Privileged Role Assigned Outside PIM", - "enabled": false, - "query": "AuditLogs\n| where Category =~ \"RoleManagement\"\n| where OperationName has \"Add member to role outside of PIM\"\n or (LoggedByService =~ \"Core Directory\" and OperationName =~ \"Add member to role\" and Identity != \"MS-PIM\")\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"User\"\n | extend UserPrincipalName = tostring(TargetResource.userPrincipalName)\n )\n| extend IpAddress = tostring(InitiatedBy.user.ipAddress), Name = tostring(split(UserPrincipalName,'@',0)[0]), UPNSuffix = tostring(split(UserPrincipalName,'@',1)[0])\n", - "severity": "Low", - "suppressionDuration": "PT1H", - "suppressionEnabled": false, - "status": "Available", - "requiredDataConnectors": [ - { - "dataTypes": [ - "AuditLogs" - ], - "connectorId": "AzureActiveDirectory" - } - ], - "tactics": [ - "PrivilegeEscalation" - ], - "techniques": [ - "T1078" - ], - "entityMappings": [ - { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "Name" - }, - { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" - } - ] - }, - { - "entityType": "IP", - "fieldMappings": [ - { - "identifier": "Address", - "columnName": "IpAddress" - } - ] - } - ] + "displayName": "[parameters('workbook2-name')]", + "serializedData": "{\"version\":\"Notebook/1.0\",\"items\":[{\"type\":1,\"content\":{\"json\":\"## Sign-in Analysis\"},\"name\":\"text - 0\"},{\"type\":9,\"content\":{\"version\":\"KqlParameterItem/1.0\",\"parameters\":[{\"id\":\"13f56671-7604-4427-a4d8-663f3da0cbc5\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"TimeRange\",\"type\":4,\"isRequired\":true,\"value\":{\"durationMs\":1209600000},\"typeSettings\":{\"selectableValues\":[{\"durationMs\":300000,\"createdTime\":\"2018-11-13T19:33:10.162Z\",\"isInitialTime\":false,\"grain\":1,\"useDashboardTimeRange\":false},{\"durationMs\":900000,\"createdTime\":\"2018-11-13T19:33:10.164Z\",\"isInitialTime\":false,\"grain\":1,\"useDashboardTimeRange\":false},{\"durationMs\":1800000,\"createdTime\":\"2018-11-13T19:33:10.164Z\",\"isInitialTime\":false,\"grain\":1,\"useDashboardTimeRange\":false},{\"durationMs\":3600000,\"createdTime\":\"2018-11-13T19:33:10.164Z\",\"isInitialTime\":false,\"grain\":1,\"useDashboardTimeRange\":false},{\"durationMs\":14400000,\"createdTime\":\"2018-11-13T19:33:10.164Z\",\"isInitialTime\":false,\"grain\":1,\"useDashboardTimeRange\":false},{\"durationMs\":43200000,\"createdTime\":\"2018-11-13T19:33:10.164Z\",\"isInitialTime\":false,\"grain\":1,\"useDashboardTimeRange\":false},{\"durationMs\":86400000,\"createdTime\":\"2018-11-13T19:33:10.165Z\",\"isInitialTime\":false,\"grain\":1,\"useDashboardTimeRange\":false},{\"durationMs\":172800000,\"createdTime\":\"2018-11-13T19:33:10.166Z\",\"isInitialTime\":false,\"grain\":1,\"useDashboardTimeRange\":false},{\"durationMs\":259200000,\"createdTime\":\"2018-11-13T19:33:10.166Z\",\"isInitialTime\":false,\"grain\":1,\"useDashboardTimeRange\":false},{\"durationMs\":604800000,\"createdTime\":\"2018-11-13T19:33:10.166Z\",\"isInitialTime\":false,\"grain\":1,\"useDashboardTimeRange\":false},{\"durationMs\":1209600000,\"createdTime\":\"2018-11-13T19:33:10.166Z\",\"isInitialTime\":false,\"grain\":1,\"useDashboardTimeRange\":false},{\"durationMs\":2592000000,\"createdTime\":\"2018-11-13T19:33:10.167Z\",\"isInitialTime\":false,\"grain\":1,\"useDashboardTimeRange\":false}],\"allowCustom\":true}},{\"id\":\"3b5cc420-8ad8-4523-ba28-a54910756794\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"Apps\",\"type\":2,\"isRequired\":true,\"multiSelect\":true,\"quote\":\"'\",\"delimiter\":\",\",\"query\":\"SigninLogs\\r\\n| summarize Count = count() by AppDisplayName\\r\\n| order by Count desc, AppDisplayName asc\\r\\n| project Value = AppDisplayName, Label = strcat(AppDisplayName, ' - ', Count, ' sign-ins'), Selected = false\\r\\n\",\"value\":[\"value::all\"],\"typeSettings\":{\"limitSelectTo\":10,\"additionalResourceOptions\":[\"value::all\"],\"selectAllValue\":\"*\"},\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},{\"id\":\"0611ecce-d6a0-4a6f-a1bc-6be314ae36a7\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"UserNamePrefix\",\"type\":2,\"isRequired\":true,\"multiSelect\":true,\"quote\":\"'\",\"delimiter\":\",\",\"query\":\"SigninLogs\\r\\n|where AppDisplayName in ({Apps}) or '*' in ({Apps})\\r\\n| summarize Count = count() by UserDisplayName\\r\\n| order by Count desc, UserDisplayName asc\\r\\n| project Value = UserDisplayName, Label = strcat(UserDisplayName, ' - ', Count, ' sign-ins'), Selected = false\\r\\n| extend prefix = substring(Value, 0, 1)\\r\\n| distinct prefix\\r\\n| sort by prefix asc\",\"value\":[\"value::all\"],\"typeSettings\":{\"additionalResourceOptions\":[\"value::all\"],\"selectAllValue\":\"*\",\"showDefault\":false},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},{\"id\":\"f7f7970b-58c1-474f-9043-62243d2d4edd\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"Users\",\"label\":\"UserName\",\"type\":2,\"isRequired\":true,\"multiSelect\":true,\"quote\":\"'\",\"delimiter\":\",\",\"query\":\"SigninLogs\\r\\n|where AppDisplayName in ({Apps}) or '*' in ({Apps})\\r\\n| summarize Count = count() by UserDisplayName\\r\\n| order by Count desc, UserDisplayName asc\\r\\n| project Value = UserDisplayName, Label = strcat(UserDisplayName, ' - ', Count, ' sign-ins'), Selected = false\\r\\n| where (substring(Value, 0, 1) in ({UserNamePrefix})) or ('*' in ({UserNamePrefix}))\\r\\n| sort by Value asc\\r\\n\",\"value\":[\"value::all\"],\"typeSettings\":{\"limitSelectTo\":10000000,\"additionalResourceOptions\":[\"value::all\"],\"selectAllValue\":\"\",\"showDefault\":false},\"timeContext\":{\"durationMs\":1209600000},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},{\"id\":\"85568f4e-9ad4-46c5-91d4-0ee1b2c8f3aa\",\"version\":\"KqlParameterItem/1.0\",\"name\":\"Category\",\"type\":2,\"isRequired\":true,\"multiSelect\":true,\"quote\":\"'\",\"delimiter\":\",\",\"value\":[\"value::all\"],\"typeSettings\":{\"additionalResourceOptions\":[\"value::all\"],\"selectAllValue\":\"\"},\"jsonData\":\"[\\\"SignInLogs\\\", \\\"NonInteractiveUserSignInLogs\\\"]\"}],\"style\":\"pills\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\"},\"name\":\"parameters - 1\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let data = \\r\\nunion SigninLogs,AADNonInteractiveUserSignInLogs\\r\\n| where Category in ({Category})\\r\\n|where AppDisplayName in ({Apps}) or '*' in ({Apps})\\r\\n|where UserDisplayName in ({Users});\\r\\ndata\\r\\n| summarize count() by UserPrincipalName, bin (TimeGenerated,5m)\\r\\n\",\"size\":0,\"title\":\"Sign-in Trend over Time\",\"timeContext\":{\"durationMs\":86400000},\"timeContextFromParameter\":\"TimeRange\",\"timeBrushParameterName\":\"TimeBrush\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"timechart\"},\"name\":\"query - 19\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let nonInteractive = AADNonInteractiveUserSignInLogs\\r\\n| extend LocationDetails = parse_json(LocationDetails)\\r\\n| extend Status = parse_json(Status);\\r\\nlet data = \\r\\nunion SigninLogs,nonInteractive\\r\\n| where Category in ({Category})\\r\\n|where AppDisplayName in ({Apps}) or '*' in ({Apps})\\r\\n|where UserDisplayName in ({Users}) \\r\\n|extend errorCode = Status.errorCode\\r\\n|extend SigninStatus = case(errorCode == 0, \\\"Success\\\", errorCode == 50058, \\\"Pending user action\\\",errorCode == 50140, \\\"Pending user action\\\", errorCode == 51006, \\\"Pending user action\\\", errorCode == 50059, \\\"Pending user action\\\",errorCode == 65001, \\\"Pending user action\\\", errorCode == 52004, \\\"Pending user action\\\", errorCode == 50055, \\\"Pending user action\\\", errorCode == 50144, \\\"Pending user action\\\", errorCode == 50072, \\\"Pending user action\\\", errorCode == 50074, \\\"Pending user action\\\", errorCode == 16000, \\\"Pending user action\\\", errorCode == 16001, \\\"Pending user action\\\", errorCode == 16003, \\\"Pending user action\\\", errorCode == 50127, \\\"Pending user action\\\", errorCode == 50125, \\\"Pending user action\\\", errorCode == 50129, \\\"Pending user action\\\", errorCode == 50143, \\\"Pending user action\\\", errorCode == 81010, \\\"Pending user action\\\", errorCode == 81014, \\\"Pending user action\\\", errorCode == 81012 ,\\\"Pending user action\\\", \\\"Failure\\\");\\r\\ndata\\r\\n| summarize Count = count() by SigninStatus\\r\\n| join kind = fullouter (datatable(SigninStatus:string)['Success', 'Pending action (Interrupts)', 'Failure']) on SigninStatus\\r\\n| project SigninStatus = iff(SigninStatus == '', SigninStatus1, SigninStatus), Count = iff(SigninStatus == '', 0, Count)\\r\\n| join kind = inner (data\\r\\n | make-series Trend = count() default = 0 on TimeGenerated from {TimeRange:start} to {TimeRange:end} step {TimeRange:grain} by SigninStatus)\\r\\n on SigninStatus\\r\\n| project-away SigninStatus1, TimeGenerated\\r\\n| extend Status = SigninStatus\\r\\n| union (\\r\\n data \\r\\n | summarize Count = count()\\r\\n | extend jkey = 1\\r\\n | join kind=inner (data\\r\\n | make-series Trend = count() default = 0 on TimeGenerated from {TimeRange:start} to {TimeRange:end} step {TimeRange:grain}\\r\\n | extend jkey = 1) on jkey\\r\\n | extend SigninStatus = 'All Sign-ins', Status = '*' \\r\\n)\\r\\n| order by Count desc\\r\\n\\r\\n\\r\\n\\r\\n\",\"size\":3,\"timeContext\":{\"durationMs\":1209600000},\"timeContextFromParameter\":\"TimeBrush\",\"exportFieldName\":\"Status\",\"exportParameterName\":\"SigninStatus\",\"exportDefaultValue\":\"*\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"tiles\",\"tileSettings\":{\"titleContent\":{\"columnMatch\":\"SigninStatus\",\"formatter\":1,\"formatOptions\":{\"showIcon\":true}},\"leftContent\":{\"columnMatch\":\"Count\",\"formatter\":12,\"formatOptions\":{\"palette\":\"blue\",\"showIcon\":true},\"numberFormat\":{\"unit\":17,\"options\":{\"style\":\"decimal\",\"maximumFractionDigits\":2,\"maximumSignificantDigits\":3}}},\"secondaryContent\":{\"columnMatch\":\"Trend\",\"formatter\":9,\"formatOptions\":{\"min\":0,\"palette\":\"blue\",\"showIcon\":true}},\"showBorder\":false}},\"name\":\"query - 5\"},{\"type\":1,\"content\":{\"json\":\"
\\r\\n💡 _Click on a tile or a row in the grid to drill-in further_\"},\"name\":\"text - 6 - Copy\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let nonInteractive = AADNonInteractiveUserSignInLogs\\r\\n| extend LocationDetails = parse_json(LocationDetails)\\r\\n| extend Status = parse_json(Status);\\r\\nlet data = \\r\\nunion SigninLogs,nonInteractive\\r\\n| extend AppDisplayName = iff(AppDisplayName == '', 'Unknown', AppDisplayName)\\r\\n|where AppDisplayName in ({Apps}) or '*' in ({Apps})\\r\\n|where UserDisplayName in ({Users}) \\r\\n| extend Country = iff(LocationDetails.countryOrRegion == '', 'Unknown country', tostring(LocationDetails.countryOrRegion))\\r\\n| extend City = iff(LocationDetails.city == '', 'Unknown city', tostring(LocationDetails.city))\\r\\n| extend errorCode = Status.errorCode\\r\\n| extend SigninStatus = case(errorCode == 0, \\\"Success\\\", errorCode == 50058, \\\"Pending user action\\\",errorCode == 50140, \\\"Pending user action\\\", errorCode == 51006, \\\"Pending user action\\\", errorCode == 50059, \\\"Pending user action\\\",errorCode == 65001, \\\"Pending user action\\\", errorCode == 52004, \\\"Pending user action\\\", errorCode == 50055, \\\"Pending user action\\\", errorCode == 50144, \\\"Pending user action\\\", errorCode == 50072, \\\"Pending user action\\\", errorCode == 50074, \\\"Pending user action\\\", errorCode == 16000, \\\"Pending user action\\\", errorCode == 16001, \\\"Pending user action\\\", errorCode == 16003, \\\"Pending user action\\\", errorCode == 50127, \\\"Pending user action\\\", errorCode == 50125, \\\"Pending user action\\\", errorCode == 50129, \\\"Pending user action\\\", errorCode == 50143, \\\"Pending user action\\\", errorCode == 81010, \\\"Pending user action\\\", errorCode == 81014, \\\"Pending user action\\\", errorCode == 81012 ,\\\"Pending user action\\\", \\\"Failure\\\")\\r\\n| where SigninStatus == '{SigninStatus}' or '{SigninStatus}' == '*' or '{SigninStatus}' == 'All Sign-ins';\\r\\nlet countryData = data\\r\\n| summarize TotalCount = count(), SuccessCount = countif(SigninStatus == \\\"Success\\\"), FailureCount = countif(SigninStatus == \\\"Failure\\\"), InterruptCount = countif(SigninStatus == \\\"Pending user action\\\") by Country,Category\\r\\n| join kind=inner\\r\\n(\\r\\n data\\r\\n| make-series Trend = count() default = 0 on TimeGenerated in range({TimeRange:start}, {TimeRange:end}, {TimeRange:grain}) by Country\\r\\n| project-away TimeGenerated\\r\\n)\\r\\non Country\\r\\n| project Country, TotalCount, SuccessCount,FailureCount,InterruptCount,Trend,Category\\r\\n| order by TotalCount desc, Country asc;\\r\\ndata\\r\\n| summarize TotalCount = count(), SuccessCount = countif(SigninStatus == \\\"Success\\\"), FailureCount = countif(SigninStatus == \\\"Failure\\\"), InterruptCount = countif(SigninStatus == \\\"Pending user action\\\") by Country, City,Category\\r\\n| join kind=inner\\r\\n(\\r\\n data \\r\\n| make-series Trend = count() default = 0 on TimeGenerated in range({TimeRange:start}, {TimeRange:end}, {TimeRange:grain}) by Country, City\\r\\n| project-away TimeGenerated\\r\\n)\\r\\non Country, City\\r\\n| order by TotalCount desc, Country asc\\r\\n| project Country, City,TotalCount, SuccessCount,FailureCount,InterruptCount, Trend,Category\\r\\n| join kind=inner\\r\\n(\\r\\n countryData\\r\\n)\\r\\non Country\\r\\n| summarize arg_max(TotalCount, SuccessCount, FailureCount, InterruptCount) by Country, City, Category, tostring(Trend)\\r\\n| project Id = strcat(City, '-', Category), Name = City, Type = 'City', ['Sign-in Count'] = TotalCount, Trend, ['Failure Count'] = FailureCount, ['Interrupt Count'] = InterruptCount, ['Success Rate'] = 1.0 * SuccessCount / TotalCount, ParentId = strcat(Country, '-', Category),Category\\r\\n| union (countryData\\r\\n| summarize arg_max(TotalCount, SuccessCount, FailureCount, InterruptCount) by Country, Category, tostring(Trend)\\r\\n| project Id = strcat(Country, '-', Category), Name = Country, Type = 'Country', ['Sign-in Count'] = TotalCount, Trend, ['Failure Count'] = FailureCount, ['Interrupt Count'] = InterruptCount, ['Success Rate'] = 1.0 * SuccessCount / TotalCount, ParentId = 'root',Category)\\r\\n| where Category in ({Category})\\r\\n| order by ['Sign-in Count'] desc, Name asc\\r\\n\",\"size\":1,\"showAnalytics\":true,\"title\":\"Sign-ins by Location\",\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeBrush\",\"showRefreshButton\":true,\"exportMultipleValues\":true,\"exportedParameters\":[{\"fieldName\":\"Name\",\"parameterName\":\"LocationDetail\",\"parameterType\":1}],\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"table\",\"gridSettings\":{\"formatters\":[{\"columnMatch\":\"Id\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Type\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Sign-in Count\",\"formatter\":8,\"formatOptions\":{\"min\":0,\"palette\":\"blue\",\"showIcon\":true},\"numberFormat\":{\"unit\":17,\"options\":{\"style\":\"decimal\"}}},{\"columnMatch\":\"Trend\",\"formatter\":9,\"formatOptions\":{\"min\":0,\"palette\":\"blue\",\"showIcon\":true}},{\"columnMatch\":\"Failure Count|Interrupt Count\",\"formatter\":8,\"formatOptions\":{\"min\":0,\"palette\":\"orange\",\"showIcon\":true},\"numberFormat\":{\"unit\":17,\"options\":{\"style\":\"decimal\"}}},{\"columnMatch\":\"Success Rate\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true},\"numberFormat\":{\"unit\":0,\"options\":{\"style\":\"percent\"}}},{\"columnMatch\":\"ParentId\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}}],\"filter\":true,\"hierarchySettings\":{\"idColumn\":\"Id\",\"parentColumn\":\"ParentId\",\"treeType\":0,\"expanderColumn\":\"Name\",\"expandTopLevel\":false}}},\"customWidth\":\"67\",\"showPin\":true,\"name\":\"query - 8\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let selectedCountry = dynamic([{LocationDetail}]);\\r\\nlet nonInteractive = AADNonInteractiveUserSignInLogs\\r\\n| extend LocationDetails = parse_json(LocationDetails),Status = parse_json(Status),ConditionalAccessPolicies = parse_json(ConditionalAccessPolicies),DeviceDetail =parse_json(DeviceDetail);\\r\\nlet details = dynamic({ \\\"Name\\\":\\\"\\\", \\\"Type\\\":\\\"*\\\"});\\r\\nlet data = union SigninLogs,nonInteractive\\r\\n| extend AppDisplayName = iff(AppDisplayName == '', 'Unknown', AppDisplayName)\\r\\n|where AppDisplayName in ({Apps}) or '*' in ({Apps})\\r\\n|where UserDisplayName in ({Users}) \\r\\n| extend Country = tostring(LocationDetails.countryOrRegion)\\r\\n| extend City = tostring(LocationDetails.city) \\r\\n| where array_length(selectedCountry) == 0 or \\\"*\\\" in (selectedCountry) or Country in (selectedCountry) or City in (selectedCountry) \\r\\n| extend errorCode = Status.errorCode\\r\\n| extend SigninStatus = case(errorCode == 0, \\\"Success\\\", errorCode == 50058, \\\"Pending user action\\\",errorCode == 50140, \\\"Pending user action\\\", errorCode == 51006, \\\"Pending user action\\\", errorCode == 50059, \\\"Pending user action\\\",errorCode == 65001, \\\"Pending user action\\\", errorCode == 52004, \\\"Pending user action\\\", errorCode == 50055, \\\"Pending user action\\\", errorCode == 50144, \\\"Pending user action\\\", errorCode == 50072, \\\"Pending user action\\\", errorCode == 50074, \\\"Pending user action\\\", errorCode == 16000, \\\"Pending user action\\\", errorCode == 16001, \\\"Pending user action\\\", errorCode == 16003, \\\"Pending user action\\\", errorCode == 50127, \\\"Pending user action\\\", errorCode == 50125, \\\"Pending user action\\\", errorCode == 50129, \\\"Pending user action\\\", errorCode == 50143, \\\"Pending user action\\\", errorCode == 81010, \\\"Pending user action\\\", errorCode == 81014, \\\"Pending user action\\\", errorCode == 81012 ,\\\"Pending user action\\\", \\\"Failure\\\")\\r\\n| where SigninStatus == '{SigninStatus}' or '{SigninStatus}' == '*' or '{SigninStatus}' == 'All Sign-ins'\\r\\n| where details.Type == '*' or (details.Type == 'Country' and Country == details.Name) or (details.Type == 'City' and City == details.Name);\\r\\ndata\\r\\n| top 200 by TimeGenerated desc\\r\\n| extend TimeFromNow = now() - TimeGenerated\\r\\n| extend TimeAgo = strcat(case(TimeFromNow < 2m, strcat(toint(TimeFromNow / 1m), ' seconds'), TimeFromNow < 2h, strcat(toint(TimeFromNow / 1m), ' minutes'), TimeFromNow < 2d, strcat(toint(TimeFromNow / 1h), ' hours'), strcat(toint(TimeFromNow / 1d), ' days')), ' ago')\\r\\n| project User = UserDisplayName, ['Sign-in Status'] = strcat(iff(SigninStatus == 'Success', '✔️', '❌'), ' ', SigninStatus), ['Sign-in Time'] = TimeAgo, App = AppDisplayName, ['Error code'] = errorCode, ['Result type'] = ResultType, ['Result signature'] = ResultSignature, ['Result description'] = ResultDescription, ['Conditional access policies'] = ConditionalAccessPolicies, ['Conditional access status'] = ConditionalAccessStatus, ['Operating system'] = DeviceDetail.operatingSystem, Browser = DeviceDetail.browser, ['Country or region'] = LocationDetails.countryOrRegion, ['State'] = LocationDetails.state, ['City'] = LocationDetails.city, ['Time generated'] = TimeGenerated, Status, ['User principal name'] = UserPrincipalName, Category\\r\\n| where Category in ({Category})\\r\\n\\r\\n\\r\\n\",\"size\":1,\"showAnalytics\":true,\"title\":\"Location Sign-in details\",\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeBrush\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"gridSettings\":{\"formatters\":[{\"columnMatch\":\"Sign-in Status\",\"formatter\":7,\"formatOptions\":{\"linkTarget\":\"CellDetails\",\"showIcon\":true}},{\"columnMatch\":\"App\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Error code\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Result type\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Result signature\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Result description\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Conditional access policies\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Conditional access status\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Operating system\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Browser\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Time generated\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Status\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"User principal name\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"TimeGenerated\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}}],\"filter\":true}},\"customWidth\":\"33\",\"name\":\"query - 8\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let nonInteractive = AADNonInteractiveUserSignInLogs | extend LocationDetails = parse_json(LocationDetails), Status = parse_json(Status), DeviceDetail = parse_json(DeviceDetail);\\r\\nlet data = \\r\\nunion SigninLogs,nonInteractive\\r\\n|where AppDisplayName in ({Apps}) or '*' in ({Apps})\\r\\n|where UserDisplayName in ({Users}) \\r\\n | extend errorCode = Status.errorCode\\r\\n | extend SigninStatus = case(errorCode == 0, \\\"Success\\\", errorCode == 50058, \\\"Pending user action\\\", errorCode == 50140, \\\"Pending user action\\\", errorCode == 51006, \\\"Pending user action\\\", errorCode == 50059, \\\"Pending user action\\\", errorCode == 65001, \\\"Pending user action\\\", errorCode == 52004, \\\"Pending user action\\\", errorCode == 50055, \\\"Pending user action\\\", errorCode == 50144, \\\"Pending user action\\\", errorCode == 50072, \\\"Pending user action\\\", errorCode == 50074, \\\"Pending user action\\\", errorCode == 16000, \\\"Pending user action\\\", errorCode == 16001, \\\"Pending user action\\\", errorCode == 16003, \\\"Pending user action\\\", errorCode == 50127, \\\"Pending user action\\\", errorCode == 50125, \\\"Pending user action\\\", errorCode == 50129, \\\"Pending user action\\\", errorCode == 50143, \\\"Pending user action\\\", errorCode == 81010, \\\"Pending user action\\\", errorCode == 81014, \\\"Pending user action\\\", errorCode == 81012, \\\"Pending user action\\\", \\\"Failure\\\")\\r\\n| where SigninStatus == '{SigninStatus}' or '{SigninStatus}' == '*' or '{SigninStatus}' == 'All Sign-ins';\\r\\nlet appData = data\\r\\n | summarize TotalCount = count(), SuccessCount = countif(SigninStatus == \\\"Success\\\"), FailureCount = countif(SigninStatus == \\\"Failure\\\"), InterruptCount = countif(SigninStatus == \\\"Pending user action\\\") by Os = tostring(DeviceDetail.operatingSystem) ,Category\\r\\n | where Os != ''\\r\\n | join kind=inner (data\\r\\n | make-series Trend = count() default = 0 on TimeGenerated in range({TimeRange:start}, {TimeRange:end}, {TimeRange:grain}) by Os = tostring(DeviceDetail.operatingSystem)\\r\\n | project-away TimeGenerated)\\r\\n on Os\\r\\n | order by TotalCount desc, Os asc\\r\\n | project Os, TotalCount, SuccessCount, FailureCount, InterruptCount, Trend,Category\\r\\n | serialize Id = row_number();\\r\\ndata\\r\\n| summarize TotalCount = count(), SuccessCount = countif(SigninStatus == \\\"Success\\\"), FailureCount = countif(SigninStatus == \\\"Failure\\\"), InterruptCount = countif(SigninStatus == \\\"Pending user action\\\") by Os = tostring(DeviceDetail.operatingSystem), Browser = tostring(DeviceDetail.browser),Category\\r\\n| join kind=inner (data\\r\\n | make-series Trend = count() default = 0 on TimeGenerated in range({TimeRange:start}, {TimeRange:end}, {TimeRange:grain})by Os = tostring(DeviceDetail.operatingSystem), Browser = tostring(DeviceDetail.browser)\\r\\n | project-away TimeGenerated)\\r\\n on Os, Browser\\r\\n| order by TotalCount desc, Os asc\\r\\n| project Os, Browser, TotalCount, SuccessCount, FailureCount, InterruptCount, Trend,Category\\r\\n| serialize Id = row_number(1000000)\\r\\n| join kind=inner (appData) on Os\\r\\n| project Id, Name = Browser, Type = 'Browser', ['Sign-in Count'] = TotalCount, Trend, ['Failure Count'] = FailureCount, ['Interrupt Count'] = InterruptCount, ['Success Rate'] = 1.0 * SuccessCount / TotalCount, ParentId = Id1,Category\\r\\n| union (appData \\r\\n | project Id, Name = Os, Type = 'Operating System', ['Sign-in Count'] = TotalCount, Trend, ['Failure Count'] = FailureCount, ['Interrupt Count'] = InterruptCount, ['Success Rate'] = 1.0 * SuccessCount / TotalCount, ParentId = -1,Category)\\r\\n| where Category in ({Category})\\r\\n| order by ['Sign-in Count'] desc, Name asc\\r\\n\",\"size\":1,\"showAnalytics\":true,\"title\":\"Sign-ins by Device\",\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeBrush\",\"exportedParameters\":[{\"parameterName\":\"DeviceDetail\",\"defaultValue\":\"{ \\\"Name\\\":\\\"\\\", \\\"Type\\\":\\\"*\\\"}\"},{\"fieldName\":\"Category\",\"parameterName\":\"exportCategory\",\"parameterType\":1,\"defaultValue\":\"*\"},{\"fieldName\":\"Name\",\"parameterName\":\"exportName\",\"parameterType\":1,\"defaultValue\":\"*\"}],\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"table\",\"gridSettings\":{\"formatters\":[{\"columnMatch\":\"Id\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Type\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Sign-in Count\",\"formatter\":8,\"formatOptions\":{\"min\":0,\"palette\":\"blue\",\"showIcon\":true},\"numberFormat\":{\"unit\":17,\"options\":{\"style\":\"decimal\"}}},{\"columnMatch\":\"Trend\",\"formatter\":9,\"formatOptions\":{\"min\":0,\"palette\":\"blue\",\"showIcon\":true},\"numberFormat\":{\"unit\":17,\"options\":{\"style\":\"decimal\"}}},{\"columnMatch\":\"Failure Count|Interrupt Count\",\"formatter\":8,\"formatOptions\":{\"min\":0,\"palette\":\"orange\",\"showIcon\":true},\"numberFormat\":{\"unit\":17,\"options\":{\"style\":\"decimal\"}}},{\"columnMatch\":\"Success Rate\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true},\"numberFormat\":{\"unit\":0,\"options\":{\"style\":\"percent\"}}},{\"columnMatch\":\"ParentId\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}}],\"filter\":true,\"hierarchySettings\":{\"idColumn\":\"Id\",\"parentColumn\":\"ParentId\",\"treeType\":0,\"expanderColumn\":\"Name\",\"expandTopLevel\":false}}},\"customWidth\":\"67\",\"showPin\":true,\"name\":\"query - 9\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let nonInteractive = AADNonInteractiveUserSignInLogs\\r\\n| extend LocationDetails = parse_json(LocationDetails),Status = parse_json(Status),ConditionalAccessPolicies = parse_json(ConditionalAccessPolicies),DeviceDetail =parse_json(DeviceDetail);\\r\\nlet details = dynamic({ \\\"Name\\\":\\\"\\\", \\\"Type\\\":\\\"*\\\"});\\r\\nlet data = union SigninLogs,nonInteractive\\r\\n| extend AppDisplayName = iff(AppDisplayName == '', 'Unknown', AppDisplayName)\\r\\n|where AppDisplayName in ({Apps}) or '*' in ({Apps})\\r\\n|where UserDisplayName in ({Users}) \\r\\n| extend Country = tostring(LocationDetails.countryOrRegion)\\r\\n| extend City = tostring(LocationDetails.city)\\r\\n| extend errorCode = Status.errorCode\\r\\n| extend SigninStatus = case(errorCode == 0, \\\"Success\\\", errorCode == 50058, \\\"Pending user action\\\",errorCode == 50140, \\\"Pending user action\\\", errorCode == 51006, \\\"Pending user action\\\", errorCode == 50059, \\\"Pending user action\\\",errorCode == 65001, \\\"Pending user action\\\", errorCode == 52004, \\\"Pending user action\\\", errorCode == 50055, \\\"Pending user action\\\", errorCode == 50144, \\\"Pending user action\\\", errorCode == 50072, \\\"Pending user action\\\", errorCode == 50074, \\\"Pending user action\\\", errorCode == 16000, \\\"Pending user action\\\", errorCode == 16001, \\\"Pending user action\\\", errorCode == 16003, \\\"Pending user action\\\", errorCode == 50127, \\\"Pending user action\\\", errorCode == 50125, \\\"Pending user action\\\", errorCode == 50129, \\\"Pending user action\\\", errorCode == 50143, \\\"Pending user action\\\", errorCode == 81010, \\\"Pending user action\\\", errorCode == 81014, \\\"Pending user action\\\", errorCode == 81012 ,\\\"Pending user action\\\", \\\"Failure\\\")\\r\\n| where SigninStatus == '{SigninStatus}' or '{SigninStatus}' == '*' or '{SigninStatus}' == 'All Sign-ins'\\r\\n| where details.Type == '*' or (details.Type == 'Country' and Country == details.Name) or (details.Type == 'City' and City == details.Name);\\r\\ndata\\r\\n| top 200 by TimeGenerated desc\\r\\n| extend TimeFromNow = now() - TimeGenerated\\r\\n| extend TimeAgo = strcat(case(TimeFromNow < 2m, strcat(toint(TimeFromNow / 1m), ' seconds'), TimeFromNow < 2h, strcat(toint(TimeFromNow / 1m), ' minutes'), TimeFromNow < 2d, strcat(toint(TimeFromNow / 1h), ' hours'), strcat(toint(TimeFromNow / 1d), ' days')), ' ago')\\r\\n| project User = UserDisplayName, ['Sign-in Status'] = strcat(iff(SigninStatus == 'Success', '✔️', '❌'), ' ', SigninStatus), ['Sign-in Time'] = TimeAgo, App = AppDisplayName, ['Error code'] = errorCode, ['Result type'] = ResultType, ['Result signature'] = ResultSignature, ['Result description'] = ResultDescription, ['Conditional access policies'] = ConditionalAccessPolicies, ['Conditional access status'] = ConditionalAccessStatus, ['Operating system'] = DeviceDetail.operatingSystem, Browser = DeviceDetail.browser, ['Country or region'] = LocationDetails.countryOrRegion, ['State'] = LocationDetails.state, ['City'] = LocationDetails.city, ['Time generated'] = TimeGenerated, Status, ['User principal name'] = UserPrincipalName, Category, Name = tostring(DeviceDetail.operatingSystem)\\r\\n| where Category in ('{exportCategory}') or \\\"*\\\" in ('{exportCategory}')\\r\\n| where Name in ('{exportName}') or \\\"*\\\" in ('{exportName}')\",\"size\":1,\"showAnalytics\":true,\"title\":\"Device Sign-in details\",\"timeContext\":{\"durationMs\":0},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"gridSettings\":{\"formatters\":[{\"columnMatch\":\"Sign-in Status\",\"formatter\":7,\"formatOptions\":{\"linkTarget\":\"CellDetails\"}},{\"columnMatch\":\"App\",\"formatter\":5},{\"columnMatch\":\"Error code\",\"formatter\":5},{\"columnMatch\":\"Result type\",\"formatter\":5},{\"columnMatch\":\"Result signature\",\"formatter\":5},{\"columnMatch\":\"Result description\",\"formatter\":5},{\"columnMatch\":\"Conditional access policies\",\"formatter\":5},{\"columnMatch\":\"Conditional access status\",\"formatter\":5},{\"columnMatch\":\"Operating system\",\"formatter\":5},{\"columnMatch\":\"Browser\",\"formatter\":5},{\"columnMatch\":\"Country or region\",\"formatter\":5},{\"columnMatch\":\"State\",\"formatter\":5},{\"columnMatch\":\"City\",\"formatter\":5},{\"columnMatch\":\"Time generated\",\"formatter\":5},{\"columnMatch\":\"Status\",\"formatter\":5},{\"columnMatch\":\"User principal name\",\"formatter\":5},{\"columnMatch\":\"Category\",\"formatter\":5},{\"columnMatch\":\"Name\",\"formatter\":5}],\"filter\":true}},\"customWidth\":\"33\",\"name\":\"query - 8 - Copy\"},{\"type\":1,\"content\":{\"json\":\"## Sign-ins using Conditional Access\"},\"name\":\"text - 12\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let nonInteractive = AADNonInteractiveUserSignInLogs\\r\\n| extend LocationDetails = parse_json(LocationDetails)\\r\\n| extend Status = parse_json(Status)\\r\\n| extend ConditionalAccessPolicies = parse_json(ConditionalAccessPolicies);\\r\\nlet data = \\r\\nunion SigninLogs,nonInteractive\\r\\n|where AppDisplayName in ({Apps}) or '*' in ({Apps})\\r\\n|where UserDisplayName in ({Users}) \\r\\n|extend CAStatus = case(ConditionalAccessStatus ==\\\"success\\\",\\\"Successful\\\",\\r\\n ConditionalAccessStatus == \\\"failure\\\", \\\"Failed\\\", \\r\\n ConditionalAccessStatus == \\\"notApplied\\\", \\\"Not applied\\\", \\r\\n isempty(ConditionalAccessStatus), \\\"Not applied\\\", \\r\\n \\\"Disabled\\\")\\r\\n|mvexpand ConditionalAccessPolicies\\r\\n|extend CAGrantControlName = tostring(ConditionalAccessPolicies.enforcedGrantControls[0])\\r\\n|extend CAGrantControl = case(CAGrantControlName contains \\\"MFA\\\", \\\"Require MFA\\\", \\r\\n CAGrantControlName contains \\\"Terms of Use\\\", \\\"Require Terms of Use\\\", \\r\\n CAGrantControlName contains \\\"Privacy\\\", \\\"Require Privacy Statement\\\", \\r\\n CAGrantControlName contains \\\"Device\\\", \\\"Require Device Compliant\\\", \\r\\n CAGrantControlName contains \\\"Azure AD Joined\\\", \\\"Require Hybird Azure AD Joined Device\\\", \\r\\n CAGrantControlName contains \\\"Apps\\\", \\\"Require Approved Apps\\\",\\r\\n \\\"Other\\\");\\r\\ndata\\r\\n| where Category in ({Category})\\r\\n| summarize Count = dcount(Id) by CAStatus\\r\\n| join kind = inner (data\\r\\n | make-series Trend = dcount(Id) default = 0 on TimeGenerated in range({TimeRange:start}, {TimeRange:end}, {TimeRange:grain}) by CAStatus\\r\\n ) on CAStatus\\r\\n| project-away CAStatus1, TimeGenerated\\r\\n| order by Count desc\",\"size\":4,\"title\":\"Conditional access status\",\"timeContext\":{\"durationMs\":1209600000},\"timeContextFromParameter\":\"TimeBrush\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"tiles\",\"tileSettings\":{\"titleContent\":{\"columnMatch\":\"CAStatus\",\"formatter\":1},\"subtitleContent\":{\"columnMatch\":\"Category\"},\"leftContent\":{\"columnMatch\":\"Count\",\"formatter\":12,\"formatOptions\":{\"palette\":\"auto\"},\"numberFormat\":{\"unit\":17,\"options\":{\"maximumSignificantDigits\":3,\"maximumFractionDigits\":2}}},\"showBorder\":false}},\"name\":\"query - 9\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let nonInteractive = AADNonInteractiveUserSignInLogs\\r\\n| extend LocationDetails = parse_json(LocationDetails)\\r\\n| extend Status = parse_json(Status)\\r\\n| extend ConditionalAccessPolicies = parse_json(ConditionalAccessPolicies);\\r\\nlet data = \\r\\nunion SigninLogs,nonInteractive|where AppDisplayName in ({Apps}) or '*' in ({Apps})\\r\\n|where UserDisplayName in ({Users}) \\r\\n|extend errorCode = toint(Status.errorCode)\\r\\n|extend Reason = tostring(Status.failureReason)\\r\\n|extend CAStatus = case(ConditionalAccessStatus ==0,\\\"✔️ Success\\\", \\r\\n ConditionalAccessStatus == 1, \\\"❌ Failure\\\", \\r\\n ConditionalAccessStatus == 2, \\\"⚠️ Not Applied\\\", \\r\\n ConditionalAccessStatus == \\\"\\\", \\\"⚠️ Not Applied\\\", \\r\\n \\\"🚫 Disabled\\\")\\r\\n|mvexpand ConditionalAccessPolicies\\r\\n|extend CAGrantControlName = tostring(ConditionalAccessPolicies.enforcedGrantControls[0])\\r\\n|extend CAGrantControl = case(CAGrantControlName contains \\\"MFA\\\", \\\"Require MFA\\\", \\r\\n CAGrantControlName contains \\\"Terms of Use\\\", \\\"Require Terms of Use\\\", \\r\\n CAGrantControlName contains \\\"Privacy\\\", \\\"Require Privacy Statement\\\", \\r\\n CAGrantControlName contains \\\"Device\\\", \\\"Require Device Compliant\\\", \\r\\n CAGrantControlName contains \\\"Azure AD Joined\\\", \\\"Require Hybird Azure AD Joined Device\\\", \\r\\n CAGrantControlName contains \\\"Apps\\\", \\\"Require Approved Apps\\\",\\\"Other\\\");\\r\\ndata\\r\\n| summarize Count = dcount(Id) by CAStatus, CAGrantControl\\r\\n| project Id = strcat(CAStatus, '/', CAGrantControl), Name = CAGrantControl, Parent = CAStatus, Count, Type = 'CAGrantControl'\\r\\n| join kind = inner (data\\r\\n | make-series Trend = dcount(Id) default = 0 on TimeGenerated in range({TimeRange:start}, {TimeRange:end}, {TimeRange:grain}) by CAStatus, CAGrantControl\\r\\n | project Id = strcat(CAStatus, '/', CAGrantControl), Trend\\r\\n ) on Id\\r\\n| project-away Id1\\r\\n| union (data\\r\\n | where Category in ({Category})\\r\\n | summarize Count = dcount(Id) by CAStatus\\r\\n | project Id = CAStatus, Name = CAStatus, Parent = '', Count, Type = 'CAStatus'\\r\\n | join kind = inner (data\\r\\n | make-series Trend = dcount(Id) default = 0 on TimeGenerated in range({TimeRange:start}, {TimeRange:end}, {TimeRange:grain}) by CAStatus\\r\\n | project Id = CAStatus, Trend\\r\\n ) on Id\\r\\n | project-away Id1)\\r\\n| order by Count desc\",\"size\":0,\"title\":\"Conditional access status\",\"timeContext\":{\"durationMs\":1209600000},\"timeContextFromParameter\":\"TimeBrush\",\"exportParameterName\":\"Detail\",\"exportDefaultValue\":\"{ \\\"Name\\\":\\\"\\\", \\\"Type\\\":\\\"*\\\", \\\"Parent\\\":\\\"*\\\"}\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"table\",\"gridSettings\":{\"formatters\":[{\"columnMatch\":\"Id\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Parent\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Count\",\"formatter\":8,\"formatOptions\":{\"min\":0,\"palette\":\"blue\",\"showIcon\":true},\"numberFormat\":{\"unit\":0,\"options\":{\"style\":\"decimal\"}}},{\"columnMatch\":\"Type\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Trend\",\"formatter\":9,\"formatOptions\":{\"min\":0,\"palette\":\"blue\",\"showIcon\":true}}],\"hierarchySettings\":{\"idColumn\":\"Id\",\"parentColumn\":\"Parent\",\"treeType\":0,\"expanderColumn\":\"Name\",\"expandTopLevel\":true}}},\"customWidth\":\"50\",\"name\":\"query - 10\",\"styleSettings\":{\"margin\":\"50\"}},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let details = dynamic({Detail});\\r\\nlet nonInteractive = AADNonInteractiveUserSignInLogs\\r\\n| extend LocationDetails = parse_json(LocationDetails)\\r\\n| extend Status = parse_json(Status)\\r\\n| extend ConditionalAccessPolicies = parse_json(ConditionalAccessPolicies);\\r\\nlet data = \\r\\nunion SigninLogs,nonInteractive\\r\\n|where AppDisplayName in ({Apps}) or '*' in ({Apps})\\r\\n|where UserDisplayName in ({Users}) \\r\\n|extend errorCode = toint(Status.errorCode)\\r\\n|extend Reason = tostring(Status.failureReason)\\r\\n|extend CAStatus = case(ConditionalAccessStatus ==\\\"success\\\",\\\"✔️ Success\\\", \\r\\n ConditionalAccessStatus == \\\"failure\\\", \\\"❌ Failure\\\", \\r\\n ConditionalAccessStatus == \\\"notApplied\\\", \\\"⚠️ Not Applied\\\", \\r\\n ConditionalAccessStatus == \\\"\\\", \\\"⚠️ Not Applied\\\", \\r\\n \\\"🚫 Disabled\\\")\\r\\n|mvexpand ConditionalAccessPolicies\\r\\n|extend CAGrantControlName = tostring(ConditionalAccessPolicies.enforcedGrantControls[0])\\r\\n|extend CAGrantControl = case(CAGrantControlName contains \\\"MFA\\\", \\\"Require MFA\\\", \\r\\n CAGrantControlName contains \\\"Terms of Use\\\", \\\"Require Terms of Use\\\", \\r\\n CAGrantControlName contains \\\"Privacy\\\", \\\"Require Privacy Statement\\\", \\r\\n CAGrantControlName contains \\\"Device\\\", \\\"Require Device Compliant\\\", \\r\\n CAGrantControlName contains \\\"Azure AD Joined\\\", \\\"Require Hybird Azure AD Joined Device\\\", \\r\\n CAGrantControlName contains \\\"Apps\\\", \\\"Require Approved Apps\\\",\\r\\n \\\"Other\\\")\\r\\n|extend CAGrantControlRank = case(CAGrantControlName contains \\\"MFA\\\", 1, \\r\\n CAGrantControlName contains \\\"Terms of Use\\\", 2, \\r\\n CAGrantControlName contains \\\"Privacy\\\", 3, \\r\\n CAGrantControlName contains \\\"Device\\\", 4, \\r\\n CAGrantControlName contains \\\"Azure AD Joined\\\", 5, \\r\\n CAGrantControlName contains \\\"Apps\\\", 6,\\r\\n 7)\\r\\n| where details.Type == '*' or (details.Type == 'CAStatus' and CAStatus == details.Name) or (details.Type == 'CAGrantControl' and CAGrantControl == details.Name and CAStatus == details.Parent);\\r\\ndata\\r\\n| order by CAGrantControlRank desc\\r\\n| summarize CAGrantControls = make_set(CAGrantControl) by AppDisplayName, CAStatus, TimeGenerated, UserDisplayName, Category\\r\\n| extend CAGrantControlText = replace(@\\\",\\\", \\\", \\\", replace(@'\\\"', @'', replace(@\\\"\\\\]\\\", @\\\"\\\", replace(@\\\"\\\\[\\\", @\\\"\\\", tostring(CAGrantControls)))))\\r\\n| extend CAGrantControlSummary = case(array_length(CAGrantControls) > 1, strcat(CAGrantControls[0], ' + ', array_length(CAGrantControls) - 1, ' more'), array_length(CAGrantControls) == 1, tostring(CAGrantControls[0]), 'None')\\r\\n| top 200 by TimeGenerated desc\\r\\n| extend TimeFromNow = now() - TimeGenerated\\r\\n| extend TimeAgo = strcat(case(TimeFromNow < 2m, strcat(toint(TimeFromNow / 1m), ' seconds'), TimeFromNow < 2h, strcat(toint(TimeFromNow / 1m), ' minutes'), TimeFromNow < 2d, strcat(toint(TimeFromNow / 1h), ' hours'), strcat(toint(TimeFromNow / 1d), ' days')), ' ago')\\r\\n| project Application = AppDisplayName, ['CA Status'] = CAStatus, ['CA Grant Controls'] = CAGrantControlSummary, ['All CA Grant Controls'] = CAGrantControlText, ['Sign-in Time'] = TimeAgo, ['User'] = UserDisplayName, Category\\r\\n| where Category in ({Category})\",\"size\":0,\"showAnalytics\":true,\"title\":\"Recent sign-ins\",\"timeContext\":{\"durationMs\":1209600000},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"table\",\"gridSettings\":{\"formatters\":[{\"columnMatch\":\"CA Grant Controls\",\"formatter\":1,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"All CA Grant Controls\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"User\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}}]}},\"customWidth\":\"50\",\"showPin\":true,\"name\":\"query - 7 - Copy\"},{\"type\":1,\"content\":{\"json\":\"## Troubleshooting Sign-ins\"},\"name\":\"text - 13\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let nonInteractive = AADNonInteractiveUserSignInLogs\\r\\n| extend LocationDetails = parse_json(LocationDetails)\\r\\n| extend Status = parse_json(Status);\\r\\nlet data = \\r\\nunion SigninLogs,nonInteractive|where AppDisplayName in ({Apps}) or '*' in ({Apps})\\r\\n|where UserDisplayName in ({Users}) \\r\\n|extend errorCode = Status.errorCode\\r\\n|extend SigninStatus = case(errorCode == 0, \\\"Success\\\", errorCode == 50058, \\\"Pending action (Interrupts)\\\",errorCode == 50140, \\\"Pending action (Interrupts)\\\", errorCode == 51006, \\\"Pending action (Interrupts)\\\", errorCode == 50059, \\\"Pending action (Interrupts)\\\",errorCode == 65001, \\\"Pending action (Interrupts)\\\", errorCode == 52004, \\\"Pending action (Interrupts)\\\", errorCode == 50055, \\\"Pending action (Interrupts)\\\", errorCode == 50144, \\\"Pending action (Interrupts)\\\", errorCode == 50072, \\\"Pending action (Interrupts)\\\", errorCode == 50074, \\\"Pending action (Interrupts)\\\", errorCode == 16000, \\\"Pending action (Interrupts)\\\", errorCode == 16001, \\\"Pending action (Interrupts)\\\", errorCode == 16003, \\\"Pending action (Interrupts)\\\", errorCode == 50127, \\\"Pending action (Interrupts)\\\", errorCode == 50125, \\\"Pending action (Interrupts)\\\", errorCode == 50129, \\\"Pending action (Interrupts)\\\", errorCode == 50143, \\\"Pending action (Interrupts)\\\", errorCode == 81010, \\\"Pending action (Interrupts)\\\", errorCode == 81014, \\\"Pending action (Interrupts)\\\", errorCode == 81012 ,\\\"Pending action (Interrupts)\\\", \\\"Failure\\\");\\r\\ndata\\r\\n| summarize Count = count() by SigninStatus, Category\\r\\n| join kind = fullouter (datatable(SigninStatus:string)['Success', 'Pending action (Interrupts)', 'Failure']) on SigninStatus\\r\\n| project SigninStatus = iff(SigninStatus == '', SigninStatus1, SigninStatus), Count = iff(SigninStatus == '', 0, Count), Category\\r\\n| join kind = inner (data\\r\\n | make-series Trend = count() default = 0 on TimeGenerated from {TimeRange:start} to {TimeRange:end} step {TimeRange:grain} by SigninStatus)\\r\\n on SigninStatus\\r\\n| project-away SigninStatus1, TimeGenerated\\r\\n| extend Status = SigninStatus\\r\\n| union (\\r\\n data \\r\\n | summarize Count = count() \\r\\n | extend jkey = 1\\r\\n | join kind=inner (data\\r\\n | make-series Trend = count() default = 0 on TimeGenerated from {TimeRange:start} to {TimeRange:end} step {TimeRange:grain}\\r\\n | extend jkey = 1) on jkey\\r\\n | extend SigninStatus = 'All Sign-ins', Status = '*' \\r\\n)\\r\\n| where Category in ({Category})\\r\\n| order by Count desc\\r\\n\\r\\n\\r\\n\\r\\n\",\"size\":3,\"timeContext\":{\"durationMs\":1209600000},\"timeContextFromParameter\":\"TimeRange\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"tiles\",\"tileSettings\":{\"titleContent\":{\"columnMatch\":\"SigninStatus\",\"formatter\":1,\"formatOptions\":{\"showIcon\":true}},\"leftContent\":{\"columnMatch\":\"Count\",\"formatter\":12,\"formatOptions\":{\"palette\":\"blue\",\"showIcon\":true},\"numberFormat\":{\"unit\":17,\"options\":{\"style\":\"decimal\",\"maximumFractionDigits\":2,\"maximumSignificantDigits\":3}}},\"secondaryContent\":{\"columnMatch\":\"Trend\",\"formatter\":9,\"formatOptions\":{\"min\":0,\"palette\":\"blue\",\"showIcon\":true}},\"showBorder\":false}},\"name\":\"query - 5\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let nonInteractive = AADNonInteractiveUserSignInLogs\\r\\n| extend LocationDetails = parse_json(LocationDetails)\\r\\n| extend Status = parse_json(Status);\\r\\nlet data = \\r\\nunion SigninLogs,nonInteractive|where AppDisplayName in ({Apps}) or '*' in ({Apps})\\r\\n|where UserDisplayName in ({Users}) \\r\\n| extend ErrorCode = tostring(Status.errorCode) \\r\\n| extend FailureReason = tostring(Status.failureReason) \\r\\n| where ErrorCode !in (\\\"0\\\",\\\"50058\\\",\\\"50148\\\",\\\"50140\\\", \\\"51006\\\", \\\"50059\\\", \\\"65001\\\", \\\"52004\\\", \\\"50055\\\", \\\"50144\\\",\\\"50072\\\", \\\"50074\\\", \\\"16000\\\",\\\"16001\\\", \\\"16003\\\", \\\"50127\\\", \\\"50125\\\", \\\"50129\\\",\\\"50143\\\", \\\"81010\\\", \\\"81014\\\", \\\"81012\\\") \\r\\n|summarize errCount = count() by ErrorCode, tostring(FailureReason), Category| sort by errCount, Category\\r\\n|project ['❌ Error Code'] = ErrorCode, ['Reason']= FailureReason, ['Error Count'] = toint(errCount), Category\\r\\n|where Category in ({Category});\\r\\ndata\",\"size\":1,\"showAnalytics\":true,\"title\":\"Summary of top errors\",\"timeContext\":{\"durationMs\":1209600000},\"timeContextFromParameter\":\"TimeBrush\",\"exportFieldName\":\"❌ Error Code\",\"exportParameterName\":\"ErrorCode\",\"exportDefaultValue\":\"*\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"table\",\"gridSettings\":{\"formatters\":[{\"columnMatch\":\"Error Count\",\"formatter\":8,\"formatOptions\":{\"min\":0,\"palette\":\"orange\",\"showIcon\":true}}],\"filter\":true}},\"customWidth\":\"67\",\"showPin\":true,\"name\":\"query - 5\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let nonInteractive = AADNonInteractiveUserSignInLogs\\r\\n| extend LocationDetails = parse_json(LocationDetails)\\r\\n| extend Status = parse_json(Status)\\r\\n| extend DeviceDetail = parse_json(DeviceDetail)\\r\\n| extend ConditionalAccessPolicies = parse_json(ConditionalAccessPolicies);\\r\\nlet data=\\r\\nunion SigninLogs,nonInteractive\\r\\n|where AppDisplayName in ({Apps}) or '*' in ({Apps})\\r\\n|where UserDisplayName in ({Users}) \\r\\n| extend ErrorCode = tostring(Status.errorCode) \\r\\n| extend FailureReason = tostring(Status.failureReason) \\r\\n| where ErrorCode !in (\\\"0\\\",\\\"50058\\\",\\\"50148\\\",\\\"50140\\\", \\\"51006\\\", \\\"50059\\\", \\\"65001\\\", \\\"52004\\\", \\\"50055\\\", \\\"50144\\\",\\\"50072\\\", \\\"50074\\\", \\\"16000\\\",\\\"16001\\\", \\\"16003\\\", \\\"50127\\\", \\\"50125\\\", \\\"50129\\\",\\\"50143\\\", \\\"81010\\\", \\\"81014\\\", \\\"81012\\\") \\r\\n| where '{ErrorCode}' == '*' or '{ErrorCode}' == ErrorCode\\r\\n| top 200 by TimeGenerated desc\\r\\n| extend TimeFromNow = now() - TimeGenerated\\r\\n| extend TimeAgo = strcat(case(TimeFromNow < 2m, strcat(toint(TimeFromNow / 1m), ' seconds'), TimeFromNow < 2h, strcat(toint(TimeFromNow / 1m), ' minutes'), TimeFromNow < 2d, strcat(toint(TimeFromNow / 1h), ' hours'), strcat(toint(TimeFromNow / 1d), ' days')), ' ago')\\r\\n| project User = UserDisplayName, IPAddress, ['❌ Error Code'] = ErrorCode, ['Sign-in Time'] = TimeAgo, App = AppDisplayName, ['Error code'] = ErrorCode, ['Result type'] = ResultType, ['Result signature'] = ResultSignature, ['Result description'] = ResultDescription, ['Conditional access policies'] = ConditionalAccessPolicies, ['Conditional access status'] = ConditionalAccessStatus, ['Operating system'] = DeviceDetail.operatingSystem, Browser = DeviceDetail.browser, ['Country or region'] = LocationDetails.countryOrRegion, ['State'] = LocationDetails.state, ['City'] = LocationDetails.city, ['Time generated'] = TimeGenerated, Status, ['User principal name'] = UserPrincipalName, Category\\r\\n| where Category in ({Category});\\r\\ndata\\r\\n\\r\\n\\r\\n\",\"size\":1,\"showAnalytics\":true,\"title\":\"Sign-ins with errors\",\"timeContext\":{\"durationMs\":1209600000},\"timeContextFromParameter\":\"TimeBrush\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"visualization\":\"table\",\"gridSettings\":{\"formatters\":[{\"columnMatch\":\"❌ Error Code\",\"formatter\":7,\"formatOptions\":{\"linkTarget\":\"GenericDetails\",\"showIcon\":true}},{\"columnMatch\":\"App\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Error code\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Result type\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Result signature\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Result description\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Conditional access policies\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Conditional access status\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Operating system\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Browser\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Country or region\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"State\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"City\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Time generated\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Status\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"User principal name\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}}],\"filter\":true}},\"customWidth\":\"33\",\"name\":\"query - 5 - Copy\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let nonInteractive = AADNonInteractiveUserSignInLogs\\r\\n| extend LocationDetails = parse_json(LocationDetails)\\r\\n| extend Status = parse_json(Status);\\r\\nlet data = \\r\\nunion SigninLogs,nonInteractive|where AppDisplayName in ({Apps}) or '*' in ({Apps})\\r\\n|where UserDisplayName in ({Users}) \\r\\n| extend ErrorCode = tostring(Status.errorCode) \\r\\n| extend FailureReason = Status.failureReason \\r\\n| where ErrorCode in (\\\"50058\\\",\\\"50140\\\", \\\"51006\\\", \\\"50059\\\", \\\"65001\\\", \\\"52004\\\", \\\"50055\\\", \\\"50144\\\",\\\"50072\\\", \\\"50074\\\", \\\"16000\\\",\\\"16001\\\", \\\"16003\\\", \\\"50127\\\", \\\"50125\\\", \\\"50129\\\",\\\"50143\\\", \\\"81010\\\", \\\"81014\\\", \\\"81012\\\") \\r\\n|summarize errCount = count() by ErrorCode, tostring(FailureReason), Category\\r\\n| sort by errCount\\r\\n|project ['❌ Error Code'] = ErrorCode, ['Reason'] = FailureReason, ['Interrupt Count'] = toint(errCount), Category\\r\\n| where Category in ({Category});\\r\\ndata\",\"size\":1,\"showAnalytics\":true,\"title\":\"Summary of sign-ins waiting on user action\",\"timeContext\":{\"durationMs\":1209600000},\"timeContextFromParameter\":\"TimeBrush\",\"exportFieldName\":\"❌ Error Code\",\"exportParameterName\":\"InterruptErrorCode\",\"exportDefaultValue\":\"*\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"gridSettings\":{\"formatters\":[{\"columnMatch\":\"Interrupt Count\",\"formatter\":8,\"formatOptions\":{\"min\":0,\"palette\":\"orange\"}}],\"filter\":true}},\"customWidth\":\"67\",\"showPin\":true,\"name\":\"query - 7\"},{\"type\":3,\"content\":{\"version\":\"KqlItem/1.0\",\"query\":\"let nonInteractive = AADNonInteractiveUserSignInLogs\\r\\n| extend LocationDetails = parse_json(LocationDetails)\\r\\n| extend ConditionalAccessPolicies = parse_json(ConditionalAccessPolicies)\\r\\n| extend DeviceDetail = parse_json(DeviceDetail)\\r\\n| extend Status = parse_json(Status);\\r\\nlet data = \\r\\nunion SigninLogs,nonInteractive \\r\\n|where AppDisplayName in ({Apps}) or '*' in ({Apps})\\r\\n|where UserDisplayName in ({Users}) \\r\\n| extend ErrorCode = tostring(Status.errorCode) \\r\\n| extend FailureReason = Status.failureReason \\r\\n| where ErrorCode in (\\\"50058\\\",\\\"50140\\\", \\\"51006\\\", \\\"50059\\\", \\\"65001\\\", \\\"52004\\\", \\\"50055\\\", \\\"50144\\\",\\\"50072\\\", \\\"50074\\\", \\\"16000\\\",\\\"16001\\\", \\\"16003\\\", \\\"50127\\\", \\\"50125\\\", \\\"50129\\\",\\\"50143\\\", \\\"81010\\\", \\\"81014\\\", \\\"81012\\\") \\r\\n| where '{InterruptErrorCode}' == '*' or '{InterruptErrorCode}' == ErrorCode\\r\\n| top 200 by TimeGenerated desc\\r\\n| extend TimeFromNow = now() - TimeGenerated\\r\\n| extend TimeAgo = strcat(case(TimeFromNow < 2m, strcat(toint(TimeFromNow / 1m), ' seconds'), TimeFromNow < 2h, strcat(toint(TimeFromNow / 1m), ' minutes'), TimeFromNow < 2d, strcat(toint(TimeFromNow / 1h), ' hours'), strcat(toint(TimeFromNow / 1d), ' days')), ' ago')\\r\\n| project User = UserDisplayName, IPAddress, ['❌ Error Code'] = ErrorCode, ['Sign-in Time'] = TimeAgo, App = AppDisplayName, ['Error code'] = ErrorCode, ['Result type'] = ResultType, ['Result signature'] = ResultSignature, ['Result description'] = ResultDescription, ['Conditional access policies'] = ConditionalAccessPolicies, ['Conditional access status'] = ConditionalAccessStatus, ['Operating system'] = DeviceDetail.operatingSystem, Browser = DeviceDetail.browser, ['Country or region'] = LocationDetails.countryOrRegion, ['State'] = LocationDetails.state, ['City'] = LocationDetails.city, ['Time generated'] = TimeGenerated, Status, ['User principal name'] = UserPrincipalName, Category\\r\\n| where Category in ({Category});\\r\\ndata\\r\\n\\r\\n\",\"size\":1,\"showAnalytics\":true,\"title\":\"Sign-ins waiting on user action\",\"timeContext\":{\"durationMs\":1209600000},\"timeContextFromParameter\":\"TimeBrush\",\"queryType\":0,\"resourceType\":\"microsoft.operationalinsights/workspaces\",\"gridSettings\":{\"formatters\":[{\"columnMatch\":\"❌ Error Code\",\"formatter\":7,\"formatOptions\":{\"linkTarget\":\"GenericDetails\",\"showIcon\":true}},{\"columnMatch\":\"App\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Error code\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Result type\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Result signature\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Result description\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Conditional access policies\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Conditional access status\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Operating system\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Browser\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Country or region\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"State\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"City\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Time generated\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"Status\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}},{\"columnMatch\":\"User principal name\",\"formatter\":5,\"formatOptions\":{\"showIcon\":true}}],\"filter\":true}},\"customWidth\":\"33\",\"showPin\":true,\"name\":\"query - 7 - Copy\"}],\"fromTemplateId\":\"sentinel-AzureActiveDirectorySigninLogs\",\"$schema\":\"https://github.com/Microsoft/Application-Insights-Workbooks/blob/master/schema/workbook.json\"}\n", + "version": "1.0", + "sourceId": "[variables('workspaceResourceId')]", + "category": "sentinel" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId40'),'/'))))]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('Workbook-', last(split(variables('workbookId2'),'/'))))]", "properties": { - "description": "Azure Active Directory Analytics Rule 40", - "parentId": "[variables('analyticRuleId40')]", - "contentId": "[variables('_analyticRulecontentId40')]", - "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion40')]", + "description": "@{workbookKey=AzureActiveDirectorySigninLogsWorkbook; logoFileName=azureactivedirectory_logo.svg; description=Gain insights into Azure Active Directory by connecting Microsoft Sentinel and using the sign-in logs to gather insights around Azure AD scenarios. \nYou can learn about sign-in operations, such as user sign-ins and locations, email addresses, and IP addresses of your users, as well as failed activities and the errors that triggered the failures.; dataTypesDependencies=System.Object[]; dataConnectorsDependencies=System.Object[]; previewImagesFileNames=System.Object[]; version=2.4.0; title=Azure AD Sign-in logs; templateRelativePath=AzureActiveDirectorySignins.json; subtitle=; provider=Microsoft}.description", + "parentId": "[variables('workbookId2')]", + "contentId": "[variables('_workbookContentId2')]", + "kind": "Workbook", + "version": "[variables('workbookVersion2')]", "source": { "kind": "Solution", "name": "Azure Active Directory", @@ -5877,6 +4902,19 @@ "name": "Microsoft Corporation", "email": "support@microsoft.com", "link": "https://support.microsoft.com/" + }, + "dependencies": { + "operator": "AND", + "criteria": [ + { + "contentId": "SigninLogs", + "kind": "DataType" + }, + { + "contentId": "AzureActiveDirectory", + "kind": "DataConnector" + } + ] } } } @@ -5887,87 +4925,85 @@ "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId40')]", - "contentKind": "AnalyticsRule", - "displayName": "NRT Privileged Role Assigned Outside PIM", - "contentProductId": "[variables('_analyticRulecontentProductId40')]", - "id": "[variables('_analyticRulecontentProductId40')]", - "version": "[variables('analyticRuleVersion40')]" + "contentId": "[variables('_workbookContentId2')]", + "contentKind": "Workbook", + "displayName": "[parameters('workbook2-name')]", + "contentProductId": "[variables('_workbookcontentProductId2')]", + "id": "[variables('_workbookcontentProductId2')]", + "version": "[variables('workbookVersion2')]" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName41')]", + "name": "[variables('analyticRuleTemplateSpecName1')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "NRT_UseraddedtoPrivilgedGroups_AnalyticalRules Analytics Rule with template version 3.0.4", + "description": "AccountCreatedandDeletedinShortTimeframe_AnalyticalRules Analytics Rule with template version 3.0.5", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion41')]", + "contentVersion": "[variables('analyticRuleVersion1')]", "parameters": {}, "variables": {}, "resources": [ { "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId41')]", + "name": "[variables('analyticRulecontentId1')]", "apiVersion": "2022-04-01-preview", - "kind": "NRT", + "kind": "Scheduled", "location": "[parameters('workspace-location')]", "properties": { - "description": "This will alert when a user is added to any of the Privileged Groups.\nFor further information on AuditLogs please see https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-audit-activities.\nFor Administrator role permissions in Azure Active Directory please see https://docs.microsoft.com/azure/active-directory/users-groups-roles/directory-assign-admin-roles", - "displayName": "NRT User added to Azure Active Directory Privileged Groups", + "description": "Search for user principal name (UPN) events. Look for accounts created and then deleted in under 24 hours. Attackers may create an account for their use, and then remove the account when no longer needed.\nRef : https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-user-accounts#short-lived-account", + "displayName": "Account Created and Deleted in Short Timeframe", "enabled": false, - "query": "let OperationList = dynamic([\"Add member to role\",\"Add member to role in PIM requested (permanent)\"]);\nlet PrivilegedGroups = dynamic([\"UserAccountAdmins\",\"PrivilegedRoleAdmins\",\"TenantAdmins\"]);\nAuditLogs\n//| where LoggedByService =~ \"Core Directory\"\n| where Category =~ \"RoleManagement\"\n| where OperationName in~ (OperationList)\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"User\"\n | extend TargetUserPrincipalName = tostring(TargetResource.userPrincipalName),\n modProps = TargetResource.modifiedProperties\n )\n| mv-apply Property = modProps on \n (\n where Property.displayName =~ \"Role.WellKnownObjectName\"\n | extend DisplayName = trim('\"',tostring(Property.displayName)),\n GroupName = trim('\"',tostring(Property.newValue))\n )\n| extend AppId = InitiatedBy.app.appId,\n InitiatedByDisplayName = case(isnotempty(InitiatedBy.app.displayName), InitiatedBy.app.displayName, isnotempty(InitiatedBy.user.displayName), InitiatedBy.user.displayName, \"not available\"),\n ServicePrincipalId = tostring(InitiatedBy.app.servicePrincipalId),\n ServicePrincipalName = tostring(InitiatedBy.app.servicePrincipalName),\n UserId = InitiatedBy.user.id,\n UserIPAddress = InitiatedBy.user.ipAddress,\n UserRoles = InitiatedBy.user.roles,\n UserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)\n| where GroupName in~ (PrivilegedGroups)\n// If you don't want to alert for operations from PIM, remove below filtering for MS-PIM.\n//| where InitiatedByDisplayName != \"MS-PIM\"\n| project TimeGenerated, AADOperationType, Category, OperationName, AADTenantId, AppId, InitiatedByDisplayName, ServicePrincipalId, ServicePrincipalName, DisplayName, GroupName, UserId, UserIPAddress, UserRoles, UserPrincipalName, TargetUserPrincipalName\n| extend AccountCustomEntity = case(isnotempty(ServicePrincipalName), ServicePrincipalName, \n isnotempty(UserPrincipalName), UserPrincipalName, \n \"\")\n| extend AccountName = tostring(split(AccountCustomEntity,'@',0)[0]), AccountUPNSuffix = tostring(split(AccountCustomEntity,'@',1)[0])\n| extend TargetName = tostring(split(TargetUserPrincipalName,'@',0)[0]), TargetUPNSuffix = tostring(split(TargetUserPrincipalName,'@',1)[0])\n", - "severity": "Medium", + "query": "let queryfrequency = 1h;\nlet queryperiod = 1d;\nAuditLogs\n| where TimeGenerated > ago(queryfrequency)\n| where OperationName =~ \"Delete user\"\n//extend UserPrincipalName = tostring(TargetResources[0].userPrincipalName)\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type == \"User\"\n | extend UserPrincipalName = extract(@'([a-f0-9]{32})?(.*)', 2, tostring(TargetResource.userPrincipalName))\n )\n| extend DeletedByUser = tostring(InitiatedBy.user.userPrincipalName), DeletedByIPAddress = tostring(InitiatedBy.user.ipAddress)\n| extend DeletedByApp = tostring(InitiatedBy.app.displayName)\n| project Deletion_TimeGenerated = TimeGenerated, UserPrincipalName, DeletedByUser, DeletedByIPAddress, DeletedByApp, Deletion_AdditionalDetails = AdditionalDetails, Deletion_InitiatedBy = InitiatedBy, Deletion_TargetResources = TargetResources\n| join kind=inner (\n AuditLogs\n | where TimeGenerated > ago(queryperiod)\n | where OperationName =~ \"Add user\" \n | mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type == \"User\"\n | extend UserPrincipalName = trim(@'\"',tostring(TargetResource.userPrincipalName))\n )\n | project-rename Creation_TimeGenerated = TimeGenerated\n) on UserPrincipalName\n| extend TimeDelta = Deletion_TimeGenerated - Creation_TimeGenerated\n| where TimeDelta between (time(0s) .. queryperiod)\n| extend CreatedByUser = tostring(InitiatedBy.user.userPrincipalName), CreatedByIPAddress = tostring(InitiatedBy.user.ipAddress)\n| extend CreatedByApp = tostring(InitiatedBy.app.displayName)\n| project Creation_TimeGenerated, Deletion_TimeGenerated, TimeDelta, UserPrincipalName, DeletedByUser, DeletedByIPAddress, DeletedByApp, CreatedByUser, CreatedByIPAddress, CreatedByApp, Creation_AdditionalDetails = AdditionalDetails, Creation_InitiatedBy = InitiatedBy, Creation_TargetResources = TargetResources, Deletion_AdditionalDetails, Deletion_InitiatedBy, Deletion_TargetResources\n| extend timestamp = Deletion_TimeGenerated, Name = tostring(split(UserPrincipalName,'@',0)[0]), UPNSuffix = tostring(split(UserPrincipalName,'@',1)[0])\n", + "queryFrequency": "PT1H", + "queryPeriod": "P1D", + "severity": "High", "suppressionDuration": "PT1H", "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, "status": "Available", "requiredDataConnectors": [ { + "connectorId": "AzureActiveDirectory", "dataTypes": [ - "AuditLogs" - ], - "connectorId": "AzureActiveDirectory" + "SigninLogs" + ] } ], "tactics": [ - "Persistence", - "PrivilegeEscalation" + "InitialAccess" ], "techniques": [ - "T1098", "T1078" ], "entityMappings": [ { - "entityType": "Account", "fieldMappings": [ { - "identifier": "Name", - "columnName": "AccountName" + "columnName": "Name", + "identifier": "Name" }, { - "identifier": "UPNSuffix", - "columnName": "AccountUPNSuffix" + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" } - ] + ], + "entityType": "Account" }, { - "entityType": "Account", "fieldMappings": [ { - "identifier": "Name", - "columnName": "TargetName" - }, - { - "identifier": "UPNSuffix", - "columnName": "TargetUPNSuffix" + "columnName": "DeletedByIPAddress", + "identifier": "Address" } - ] + ], + "entityType": "IP" } ] } @@ -5975,13 +5011,13 @@ { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId41'),'/'))))]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId1'),'/'))))]", "properties": { - "description": "Azure Active Directory Analytics Rule 41", - "parentId": "[variables('analyticRuleId41')]", - "contentId": "[variables('_analyticRulecontentId41')]", + "description": "Azure Active Directory Analytics Rule 1", + "parentId": "[variables('analyticRuleId1')]", + "contentId": "[variables('_analyticRulecontentId1')]", "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion41')]", + "version": "[variables('analyticRuleVersion1')]", "source": { "kind": "Solution", "name": "Azure Active Directory", @@ -6006,44 +5042,44 @@ "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId41')]", + "contentId": "[variables('_analyticRulecontentId1')]", "contentKind": "AnalyticsRule", - "displayName": "NRT User added to Azure Active Directory Privileged Groups", - "contentProductId": "[variables('_analyticRulecontentProductId41')]", - "id": "[variables('_analyticRulecontentProductId41')]", - "version": "[variables('analyticRuleVersion41')]" + "displayName": "Account Created and Deleted in Short Timeframe", + "contentProductId": "[variables('_analyticRulecontentProductId1')]", + "id": "[variables('_analyticRulecontentProductId1')]", + "version": "[variables('analyticRuleVersion1')]" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName42')]", + "name": "[variables('analyticRuleTemplateSpecName2')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "PIMElevationRequestRejected_AnalyticalRules Analytics Rule with template version 3.0.4", + "description": "AccountCreatedDeletedByNonApprovedUser_AnalyticalRules Analytics Rule with template version 3.0.5", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion42')]", + "contentVersion": "[variables('analyticRuleVersion2')]", "parameters": {}, "variables": {}, "resources": [ { "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId42')]", + "name": "[variables('analyticRulecontentId2')]", "apiVersion": "2022-04-01-preview", "kind": "Scheduled", "location": "[parameters('workspace-location')]", "properties": { - "description": "Identifies when a user is rejected for a privileged role elevation via PIM. Monitor rejections for indicators of attacker compromise of the requesting account.\nRef : https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-privileged-identity-management", - "displayName": "PIM Elevation Request Rejected", + "description": "Identifies accounts that were created or deleted by a defined list of non-approved user principal names. Add to this list before running the query for accurate results.\nRef : https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-user-accounts", + "displayName": "Account created or deleted by non-approved user", "enabled": false, - "query": "AuditLogs\n| where (ActivityDisplayName =~'Add member to role completed (PIM activation)' and Result =~ \"failure\") or ActivityDisplayName =~'Add member to role request denied (PIM activation)'\n| mv-apply ResourceItem = TargetResources on \n (\n where ResourceItem.type =~ \"Role\"\n | extend Role = trim(@'\"',tostring(ResourceItem.displayName))\n )\n| mv-apply ResourceItem = TargetResources on \n (\n where ResourceItem.type =~ \"User\"\n | extend User = trim(@'\"',tostring(ResourceItem.userPrincipalName))\n )\n| project-reorder TimeGenerated, User, Role, OperationName, Result, ResultDescription\n| where isnotempty(InitiatedBy.user)\n| extend InitiatingUser = tostring(InitiatedBy.user.userPrincipalName), InitiatingIpAddress = tostring(InitiatedBy.user.ipAddress)\n| extend InitiatingName = tostring(split(InitiatingUser,'@',0)[0]), InitiatingUPNSuffix = tostring(split(InitiatingUser,'@',1)[0])\n| extend UserName = tostring(split(User,'@',0)[0]), UserUPNSuffix = tostring(split(User,'@',1)[0])\n", - "queryFrequency": "PT2H", - "queryPeriod": "PT2H", - "severity": "High", + "query": "// Add non-approved user principal names to the list below to search for their account creation/deletion activity\n// ex: dynamic([\"UPN1\", \"upn123\"])\nlet nonapproved_users = dynamic([]);\nAuditLogs\n| where OperationName =~ \"Add user\" or OperationName =~ \"Delete user\"\n| where Result =~ \"success\"\n| extend InitiatingUser = tostring(InitiatedBy.user.userPrincipalName)\n| where InitiatingUser has_any (nonapproved_users)\n| project-reorder TimeGenerated, ResourceId, OperationName, InitiatingUser, TargetResources\n| extend InitiatedUserIpAddress = tostring(InitiatedBy.user.ipAddress)\n| extend Name = tostring(split(InitiatingUser,'@',0)[0]), UPNSuffix = tostring(split(InitiatingUser,'@',1)[0])\n", + "queryFrequency": "P1D", + "queryPeriod": "P1D", + "severity": "Medium", "suppressionDuration": "PT1H", "suppressionEnabled": false, "triggerOperator": "GreaterThan", @@ -6051,53 +5087,40 @@ "status": "Available", "requiredDataConnectors": [ { + "connectorId": "AzureActiveDirectory", "dataTypes": [ "AuditLogs" - ], - "connectorId": "AzureActiveDirectory" + ] } ], "tactics": [ - "Persistence" + "InitialAccess" ], "techniques": [ "T1078" ], "entityMappings": [ { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "InitiatingName" - }, - { - "identifier": "UPNSuffix", - "columnName": "InitiatingUPNSuffix" - } - ] - }, - { - "entityType": "Account", "fieldMappings": [ { - "identifier": "Name", - "columnName": "UserName" + "columnName": "Name", + "identifier": "Name" }, { - "identifier": "UPNSuffix", - "columnName": "UserUPNSuffix" + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" } - ] + ], + "entityType": "Account" }, { - "entityType": "IP", "fieldMappings": [ { - "identifier": "Address", - "columnName": "InitiatingIpAddress" + "columnName": "InitiatedUserIpAddress", + "identifier": "Address" } - ] + ], + "entityType": "IP" } ] } @@ -6105,13 +5128,13 @@ { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId42'),'/'))))]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId2'),'/'))))]", "properties": { - "description": "Azure Active Directory Analytics Rule 42", - "parentId": "[variables('analyticRuleId42')]", - "contentId": "[variables('_analyticRulecontentId42')]", + "description": "Azure Active Directory Analytics Rule 2", + "parentId": "[variables('analyticRuleId2')]", + "contentId": "[variables('_analyticRulecontentId2')]", "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion42')]", + "version": "[variables('analyticRuleVersion2')]", "source": { "kind": "Solution", "name": "Azure Active Directory", @@ -6136,43 +5159,43 @@ "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId42')]", + "contentId": "[variables('_analyticRulecontentId2')]", "contentKind": "AnalyticsRule", - "displayName": "PIM Elevation Request Rejected", - "contentProductId": "[variables('_analyticRulecontentProductId42')]", - "id": "[variables('_analyticRulecontentProductId42')]", - "version": "[variables('analyticRuleVersion42')]" + "displayName": "Account created or deleted by non-approved user", + "contentProductId": "[variables('_analyticRulecontentProductId2')]", + "id": "[variables('_analyticRulecontentProductId2')]", + "version": "[variables('analyticRuleVersion2')]" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName43')]", + "name": "[variables('analyticRuleTemplateSpecName3')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "PrivilegedAccountsSigninFailureSpikes_AnalyticalRules Analytics Rule with template version 3.0.4", + "description": "ADFSDomainTrustMods_AnalyticalRules Analytics Rule with template version 3.0.5", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion43')]", + "contentVersion": "[variables('analyticRuleVersion3')]", "parameters": {}, "variables": {}, "resources": [ { "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId43')]", + "name": "[variables('analyticRulecontentId3')]", "apiVersion": "2022-04-01-preview", "kind": "Scheduled", "location": "[parameters('workspace-location')]", "properties": { - "description": " Identifies spike in failed sign-ins from Privileged accounts. Privileged accounts list can be based on IdentityInfo UEBA table.\nSpike is determined based on Time series anomaly which will look at historical baseline values.\nRef : https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-privileged-accounts#things-to-monitor", - "displayName": "Privileged Accounts - Sign in Failure Spikes", + "description": "This will alert when a user or application modifies the federation settings on the domain or Update domain authentication from Managed to Federated.\nFor example, this alert will trigger when a new Active Directory Federated Service (ADFS) TrustedRealm object, such as a signing certificate, is added to the domain.\nModification to domain federation settings should be rare. Confirm the added or modified target domain/URL is legitimate administrator behavior.\nTo understand why an authorized user may update settings for a federated domain in Office 365, Azure, or Intune, see: https://docs.microsoft.com/office365/troubleshoot/active-directory/update-federated-domain-office-365.\nFor details on security realms that accept security tokens, see the ADFS Proxy Protocol (MS-ADFSPP) specification: https://docs.microsoft.com/openspecs/windows_protocols/ms-adfspp/e7b9ea73-1980-4318-96a6-da559486664b.\nFor further information on AuditLogs please see https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-audit-activities.", + "displayName": "Modified domain federation trust settings", "enabled": false, - "query": "let starttime = 14d;\nlet timeframe = 1d;\nlet scorethreshold = 3;\nlet baselinethreshold = 5;\nlet aadFunc = (tableName:string){\n IdentityInfo\n | where TimeGenerated > ago(starttime)\n | summarize arg_max(TimeGenerated, *) by AccountUPN\n | mv-expand AssignedRoles\n | where AssignedRoles contains 'Admin'\n | summarize Roles = make_list(AssignedRoles) by AccountUPN = tolower(AccountUPN)\n | join kind=inner (\n table(tableName)\n | where TimeGenerated between (startofday(ago(starttime))..startofday(now()))\n | where ResultType != 0\n | extend UserPrincipalName = tolower(UserPrincipalName)\n ) on $left.AccountUPN == $right.UserPrincipalName\n | extend timestamp = TimeGenerated, AccountCustomEntity = UserPrincipalName, Roles = tostring(Roles)\n};\nlet aadSignin = aadFunc(\"SigninLogs\");\nlet aadNonInt = aadFunc(\"AADNonInteractiveUserSignInLogs\");\nlet allSignins = union isfuzzy=true aadSignin, aadNonInt;\nlet TimeSeriesAlerts = \n allSignins\n | make-series HourlyCount=count() on TimeGenerated from startofday(ago(starttime)) to startofday(now()) step 1h by UserPrincipalName, Roles\n | extend (anomalies, score, baseline) = series_decompose_anomalies(HourlyCount, scorethreshold, -1, 'linefit')\n | mv-expand HourlyCount to typeof(double), TimeGenerated to typeof(datetime), anomalies to typeof(double), score to typeof(double), baseline to typeof(long)\n // Filtering low count events per baselinethreshold\n | where anomalies > 0 and baseline > baselinethreshold\n | extend AnomalyHour = TimeGenerated\n | project UserPrincipalName, Roles, AnomalyHour, TimeGenerated, HourlyCount, baseline, anomalies, score;\n// Filter the alerts for specified timeframe\nTimeSeriesAlerts\n| where TimeGenerated > startofday(ago(timeframe))\n| join kind=inner ( \n allSignins\n | where TimeGenerated > startofday(ago(timeframe))\n // create a new column and round to hour\n | extend DateHour = bin(TimeGenerated, 1h)\n | summarize PartialFailedSignins = count(), LatestAnomalyTime = arg_max(TimeGenerated, *) by bin(TimeGenerated, 1h), OperationName, Category, ResultType, ResultDescription, UserPrincipalName, Roles, UserDisplayName, AppDisplayName, ClientAppUsed, IPAddress, ResourceDisplayName\n) on UserPrincipalName, $left.AnomalyHour == $right.DateHour\n| project LatestAnomalyTime, OperationName, Category, UserPrincipalName, Roles = todynamic(Roles), UserDisplayName, ResultType, ResultDescription, AppDisplayName, ClientAppUsed, UserAgent, IPAddress, Location, AuthenticationRequirement, ConditionalAccessStatus, ResourceDisplayName, PartialFailedSignins, TotalFailedSignins = HourlyCount, baseline, anomalies, score\n| extend timestamp = LatestAnomalyTime, Name = tostring(split(UserPrincipalName,'@',0)[0]), UPNSuffix = tostring(split(UserPrincipalName,'@',1)[0])\n", + "query": "(union isfuzzy=true\n(\nAuditLogs\n| where OperationName =~ \"Set federation settings on domain\"\n//| where Result =~ \"success\" // commenting out, as it may be interesting to capture failed attempts\n| mv-expand TargetResources\n| extend modifiedProperties = parse_json(TargetResources).modifiedProperties\n| mv-expand modifiedProperties\n| extend targetDisplayName = tostring(parse_json(modifiedProperties).displayName)\n),\n(\nAuditLogs\n| where OperationName =~ \"Set domain authentication\"\n//| where Result =~ \"success\" // commenting out, as it may be interesting to capture failed attempts\n| mv-expand TargetResources\n| extend modifiedProperties = parse_json(TargetResources).modifiedProperties\n| mv-expand modifiedProperties\n| mv-apply Property = modifiedProperties on \n (\n where Property.displayName =~ \"LiveType\"\n | extend targetDisplayName = tostring(Property.displayName),\n NewDomainValue = tostring(Property.newValue)\n )\n| where NewDomainValue has \"Federated\"\n)\n)\n| mv-apply AdditionalDetail = AdditionalDetails on \n (\n where AdditionalDetail.key =~ \"User-Agent\"\n | extend UserAgent = tostring(AdditionalDetail.value)\n )\n| extend InitiatingUserOrApp = iff(isnotempty(InitiatedBy.user.userPrincipalName),tostring(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.app.displayName))\n| extend InitiatingIpAddress = iff(isnotempty(InitiatedBy.user.ipAddress), tostring(InitiatedBy.user.ipAddress), tostring(InitiatedBy.app.ipAddress))\n| project-reorder TimeGenerated, OperationName, InitiatingUserOrApp, AADOperationType, targetDisplayName, Result, InitiatingIpAddress, UserAgent, CorrelationId, TenantId, AADTenantId\n| extend timestamp = TimeGenerated, Name = tostring(split(InitiatingUserOrApp,'@',0)[0]), UPNSuffix = tostring(split(InitiatingUserOrApp,'@',1)[0])\n", "queryFrequency": "P1D", - "queryPeriod": "P14D", + "queryPeriod": "P1D", "severity": "High", "suppressionDuration": "PT1H", "suppressionEnabled": false, @@ -6181,46 +5204,37 @@ "status": "Available", "requiredDataConnectors": [ { + "connectorId": "AzureActiveDirectory", "dataTypes": [ - "SigninLogs" - ], - "connectorId": "AzureActiveDirectory" - }, - { - "dataTypes": [ - "AADNonInteractiveUserSignInLogs" - ], - "connectorId": "AzureActiveDirectory" + "AuditLogs" + ] } ], "tactics": [ - "InitialAccess" - ], - "techniques": [ - "T1078" + "CredentialAccess" ], "entityMappings": [ { - "entityType": "Account", "fieldMappings": [ { - "identifier": "Name", - "columnName": "Name" + "columnName": "Name", + "identifier": "Name" }, { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" } - ] + ], + "entityType": "Account" }, { - "entityType": "IP", "fieldMappings": [ { - "identifier": "Address", - "columnName": "IPAddress" + "columnName": "InitiatingIpAddress", + "identifier": "Address" } - ] + ], + "entityType": "IP" } ] } @@ -6228,13 +5242,13 @@ { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId43'),'/'))))]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId3'),'/'))))]", "properties": { - "description": "Azure Active Directory Analytics Rule 43", - "parentId": "[variables('analyticRuleId43')]", - "contentId": "[variables('_analyticRulecontentId43')]", + "description": "Azure Active Directory Analytics Rule 3", + "parentId": "[variables('analyticRuleId3')]", + "contentId": "[variables('_analyticRulecontentId3')]", "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion43')]", + "version": "[variables('analyticRuleVersion3')]", "source": { "kind": "Solution", "name": "Azure Active Directory", @@ -6259,44 +5273,44 @@ "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId43')]", + "contentId": "[variables('_analyticRulecontentId3')]", "contentKind": "AnalyticsRule", - "displayName": "Privileged Accounts - Sign in Failure Spikes", - "contentProductId": "[variables('_analyticRulecontentProductId43')]", - "id": "[variables('_analyticRulecontentProductId43')]", - "version": "[variables('analyticRuleVersion43')]" + "displayName": "Modified domain federation trust settings", + "contentProductId": "[variables('_analyticRulecontentProductId3')]", + "id": "[variables('_analyticRulecontentProductId3')]", + "version": "[variables('analyticRuleVersion3')]" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName44')]", + "name": "[variables('analyticRuleTemplateSpecName4')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "PrivlegedRoleAssignedOutsidePIM_AnalyticalRules Analytics Rule with template version 3.0.4", + "description": "ADFSSignInLogsPasswordSpray_AnalyticalRules Analytics Rule with template version 3.0.5", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion44')]", + "contentVersion": "[variables('analyticRuleVersion4')]", "parameters": {}, "variables": {}, "resources": [ { "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId44')]", + "name": "[variables('analyticRulecontentId4')]", "apiVersion": "2022-04-01-preview", "kind": "Scheduled", "location": "[parameters('workspace-location')]", "properties": { - "description": "Identifies a privileged role being assigned to a user outside of PIM\nRef : https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-privileged-accounts#things-to-monitor-1", - "displayName": "Privileged Role Assigned Outside PIM", + "description": "Identifies evidence of password spray activity against Connect Health for AD FS sign-in events by looking for failures from multiple accounts from the same IP address within a time window.\nReference: https://adfshelp.microsoft.com/References/ConnectHealthErrorCodeReference", + "displayName": "Password spray attack against ADFSSignInLogs", "enabled": false, - "query": "AuditLogs\n| where Category =~ \"RoleManagement\"\n| where OperationName has \"Add member to role outside of PIM\"\n or (LoggedByService =~ \"Core Directory\" and OperationName =~ \"Add member to role\" and Identity != \"MS-PIM\")\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"User\"\n | extend UserPrincipalName = tostring(TargetResource.userPrincipalName)\n )\n| extend IpAddress = tostring(InitiatedBy.user.ipAddress), Name = tostring(split(UserPrincipalName,'@',0)[0]), UPNSuffix = tostring(split(UserPrincipalName,'@',1)[0])\n", - "queryFrequency": "P1D", - "queryPeriod": "P1D", - "severity": "Low", + "query": "let queryfrequency = 30m;\nlet accountthreshold = 10;\nlet successCodes = dynamic([0, 50144]);\nADFSSignInLogs\n| extend IngestionTime = ingestion_time()\n| where IngestionTime > ago(queryfrequency)\n| where not(todynamic(AuthenticationDetails)[0].authenticationMethod == \"Integrated Windows Authentication\")\n| summarize\n DistinctFailureCount = dcountif(UserPrincipalName, ResultType !in (successCodes)),\n DistinctSuccessCount = dcountif(UserPrincipalName, ResultType in (successCodes)),\n SuccessAccounts = make_set_if(UserPrincipalName, ResultType in (successCodes), 250),\n arg_min(TimeGenerated, *)\n by IPAddress\n| where DistinctFailureCount > DistinctSuccessCount and DistinctFailureCount >= accountthreshold\n//| extend SuccessAccounts = iff(array_length(SuccessAccounts) != 0, SuccessAccounts, dynamic([\"null\"]))\n//| mv-expand SuccessAccounts\n| project TimeGenerated, Category, OperationName, IPAddress, DistinctFailureCount, DistinctSuccessCount, SuccessAccounts, AuthenticationRequirement, ConditionalAccessStatus, IsInteractive, UserAgent, NetworkLocationDetails, DeviceDetail, TokenIssuerType, TokenIssuerName, ResourceIdentity\n", + "queryFrequency": "PT30M", + "queryPeriod": "PT1H", + "severity": "Medium", "suppressionDuration": "PT1H", "suppressionEnabled": false, "triggerOperator": "GreaterThan", @@ -6304,40 +5318,27 @@ "status": "Available", "requiredDataConnectors": [ { + "connectorId": "AzureActiveDirectory", "dataTypes": [ - "AuditLogs" - ], - "connectorId": "AzureActiveDirectory" + "ADFSSignInLogs" + ] } ], "tactics": [ - "PrivilegeEscalation" + "CredentialAccess" ], "techniques": [ - "T1078" + "T1110" ], "entityMappings": [ { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "Name" - }, - { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" - } - ] - }, - { - "entityType": "IP", "fieldMappings": [ { - "identifier": "Address", - "columnName": "IpAddress" + "columnName": "IPAddress", + "identifier": "Address" } - ] + ], + "entityType": "IP" } ] } @@ -6345,13 +5346,13 @@ { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId44'),'/'))))]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId4'),'/'))))]", "properties": { - "description": "Azure Active Directory Analytics Rule 44", - "parentId": "[variables('analyticRuleId44')]", - "contentId": "[variables('_analyticRulecontentId44')]", + "description": "Azure Active Directory Analytics Rule 4", + "parentId": "[variables('analyticRuleId4')]", + "contentId": "[variables('_analyticRulecontentId4')]", "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion44')]", + "version": "[variables('analyticRuleVersion4')]", "source": { "kind": "Solution", "name": "Azure Active Directory", @@ -6376,96 +5377,87 @@ "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId44')]", + "contentId": "[variables('_analyticRulecontentId4')]", "contentKind": "AnalyticsRule", - "displayName": "Privileged Role Assigned Outside PIM", - "contentProductId": "[variables('_analyticRulecontentProductId44')]", - "id": "[variables('_analyticRulecontentProductId44')]", - "version": "[variables('analyticRuleVersion44')]" + "displayName": "Password spray attack against ADFSSignInLogs", + "contentProductId": "[variables('_analyticRulecontentProductId4')]", + "id": "[variables('_analyticRulecontentProductId4')]", + "version": "[variables('analyticRuleVersion4')]" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName45')]", + "name": "[variables('analyticRuleTemplateSpecName5')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "RareApplicationConsent_AnalyticalRules Analytics Rule with template version 3.0.4", + "description": "AdminPromoAfterRoleMgmtAppPermissionGrant_AnalyticalRules Analytics Rule with template version 3.0.5", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion45')]", + "contentVersion": "[variables('analyticRuleVersion5')]", "parameters": {}, "variables": {}, "resources": [ { "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId45')]", + "name": "[variables('analyticRulecontentId5')]", "apiVersion": "2022-04-01-preview", "kind": "Scheduled", "location": "[parameters('workspace-location')]", "properties": { - "description": "This will alert when the \"Consent to application\" operation occurs by a user that has not done this operation before or rarely does this.\nThis could indicate that permissions to access the listed Azure App were provided to a malicious actor.\nConsent to application, Add service principal and Add OAuth2PermissionGrant should typically be rare events.\nThis may help detect the Oauth2 attack that can be initiated by this publicly available tool - https://github.com/fireeye/PwnAuth\nFor further information on AuditLogs please see https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-audit-activities.", - "displayName": "Rare application consent", + "description": "This rule looks for a service principal being granted the Microsoft Graph RoleManagement.ReadWrite.Directory (application) permission before being used to add an Azure AD object or user account to an Admin directory role (i.e. Global Administrators).\nThis is a known attack path that is usually abused when a service principal already has the AppRoleAssignment.ReadWrite.All permission granted. This permission allows an app to manage permission grants for application permissions to any API.\nA service principal can promote itself or other service principals to admin roles (i.e. Global Administrators). This would be considered a privilege escalation technique.\nRef : https://docs.microsoft.com/graph/permissions-reference#role-management-permissions, https://docs.microsoft.com/graph/api/directoryrole-post-members?view=graph-rest-1.0&tabs=http", + "displayName": "Admin promotion after Role Management Application Permission Grant", "enabled": false, - "query": "let current = 1d;\nlet auditLookback = 7d;\n// Setting threshold to 3 as a default, change as needed.\n// Any operation that has been initiated by a user or app more than 3 times in the past 7 days will be excluded\nlet threshold = 3;\n// Gather initial data from lookback period, excluding current, adjust current to more than a single day if no results\nlet AuditTrail = AuditLogs | where TimeGenerated >= ago(auditLookback) and TimeGenerated < ago(current)\n// 2 other operations that can be part of malicious activity in this situation are\n// \"Add OAuth2PermissionGrant\" and \"Add service principal\", extend the filter below to capture these too\n| where OperationName has \"Consent to application\"\n| extend InitiatedBy = iff(isnotempty(tostring(InitiatedBy.user.userPrincipalName)),\n tostring(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.app.displayName))\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"ServicePrincipal\"\n | extend TargetResourceName = tolower(tostring(TargetResource.displayName))\n )\n| summarize max(TimeGenerated), OperationCount = count() by OperationName, InitiatedBy, TargetResourceName\n// only including operations initiated by a user or app that is above the threshold so we produce only rare and has not occurred in last 7 days\n| where OperationCount > threshold;\n// Gather current period of audit data\nlet RecentConsent = AuditLogs | where TimeGenerated >= ago(current)\n| where OperationName has \"Consent to application\"\n| extend IpAddress = case(\n isnotempty(tostring(InitiatedBy.user.ipAddress)) and tostring(InitiatedBy.user.ipAddress) != 'null', tostring(InitiatedBy.user.ipAddress),\n isnotempty(tostring(InitiatedBy.app.ipAddress)) and tostring(InitiatedBy.app.ipAddress) != 'null', tostring(InitiatedBy.app.ipAddress),\n 'Not Available')\n| extend InitiatedBy = iff(isnotempty(tostring(InitiatedBy.user.userPrincipalName)),\n tostring(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.app.displayName))\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"ServicePrincipal\"\n | extend TargetResourceName = tolower(tostring(TargetResource.displayName)),\n props = TargetResource.modifiedProperties\n )\n| parse props with * \"ConsentType: \" ConsentType \"]\" *\n| mv-apply AdditionalDetail = AdditionalDetails on \n (\n where AdditionalDetail.key =~ \"User-Agent\"\n | extend UserAgent = tostring(AdditionalDetail.value)\n )\n| project TimeGenerated, InitiatedBy, IpAddress, TargetResourceName, Category, OperationName, ConsentType, UserAgent, CorrelationId, Type;\n// Exclude previously seen audit activity for \"Consent to application\" that was seen in the lookback period\n// First for rare InitiatedBy\nlet RareConsentBy = RecentConsent | join kind= leftanti AuditTrail on OperationName, InitiatedBy\n| extend Reason = \"Previously unseen user consenting\";\n// Second for rare TargetResourceName\nlet RareConsentApp = RecentConsent | join kind= leftanti AuditTrail on OperationName, TargetResourceName\n| extend Reason = \"Previously unseen app granted consent\";\nRareConsentBy | union RareConsentApp\n| summarize Reason = make_set(Reason,100) by TimeGenerated, InitiatedBy, IpAddress, TargetResourceName, Category, OperationName, ConsentType, UserAgent, CorrelationId, Type\n| extend timestamp = TimeGenerated, Name = tolower(tostring(split(InitiatedBy,'@',0)[0])), UPNSuffix = tolower(tostring(split(InitiatedBy,'@',1)[0]))\n", - "queryFrequency": "P1D", - "queryPeriod": "P7D", - "severity": "Medium", + "query": "let query_frequency = 1h;\nlet query_period = 2h;\nAuditLogs\n| where TimeGenerated > ago(query_period)\n| where Category =~ \"ApplicationManagement\" and LoggedByService =~ \"Core Directory\"\n| where OperationName =~ \"Add app role assignment to service principal\"\n| mv-expand TargetResource = TargetResources\n| mv-expand modifiedProperty = TargetResource[\"modifiedProperties\"]\n| where tostring(modifiedProperty[\"displayName\"]) == \"AppRole.Value\"\n| extend PermissionGrant = tostring(modifiedProperty[\"newValue\"])\n| where PermissionGrant has \"RoleManagement.ReadWrite.Directory\"\n| mv-apply modifiedProperty = TargetResource[\"modifiedProperties\"] on (\n summarize modifiedProperties = make_bag(\n bag_pack(tostring(modifiedProperty[\"displayName\"]),\n bag_pack(\"oldValue\", trim(@'[\\\"\\s]+', tostring(modifiedProperty[\"oldValue\"])),\n \"newValue\", trim(@'[\\\"\\s]+', tostring(modifiedProperty[\"newValue\"])))), 100)\n)\n| project\n PermissionGrant_TimeGenerated = TimeGenerated,\n PermissionGrant_OperationName = OperationName,\n PermissionGrant_Result = Result,\n PermissionGrant,\n AppDisplayName = tostring(modifiedProperties[\"ServicePrincipal.DisplayName\"][\"newValue\"]),\n AppServicePrincipalId = tostring(modifiedProperties[\"ServicePrincipal.ObjectID\"][\"newValue\"]),\n PermissionGrant_InitiatedBy = InitiatedBy,\n PermissionGrant_TargetResources = TargetResources,\n PermissionGrant_AdditionalDetails = AdditionalDetails,\n PermissionGrant_CorrelationId = CorrelationId\n| join kind=inner (\n AuditLogs\n | where TimeGenerated > ago(query_frequency)\n | where Category =~ \"RoleManagement\" and LoggedByService =~ \"Core Directory\" and AADOperationType =~ \"Assign\"\n | where isnotempty(InitiatedBy[\"app\"])\n | mv-expand TargetResource = TargetResources\n | mv-expand modifiedProperty = TargetResource[\"modifiedProperties\"]\n | where tostring(modifiedProperty[\"displayName\"]) in (\"Role.DisplayName\", \"RoleDefinition.DisplayName\")\n | extend RoleAssignment = tostring(modifiedProperty[\"newValue\"])\n | where RoleAssignment contains \"Admin\"\n | project\n RoleAssignment_TimeGenerated = TimeGenerated,\n RoleAssignment_OperationName = OperationName,\n RoleAssignment_Result = Result,\n RoleAssignment,\n TargetType = tostring(TargetResources[0][\"type\"]),\n Target = iff(isnotempty(TargetResources[0][\"displayName\"]), tostring(TargetResources[0][\"displayName\"]), tolower(TargetResources[0][\"userPrincipalName\"])),\n TargetId = tostring(TargetResources[0][\"id\"]),\n RoleAssignment_InitiatedBy = InitiatedBy,\n RoleAssignment_TargetResources = TargetResources,\n RoleAssignment_AdditionalDetails = AdditionalDetails,\n RoleAssignment_CorrelationId = CorrelationId,\n AppServicePrincipalId = tostring(InitiatedBy[\"app\"][\"servicePrincipalId\"])\n ) on AppServicePrincipalId\n| where PermissionGrant_TimeGenerated < RoleAssignment_TimeGenerated\n| extend\n TargetName = tostring(split(Target, \"@\")[0]),\n TargetUPNSuffix = tostring(split(Target, \"@\")[1])\n| project PermissionGrant_TimeGenerated, PermissionGrant_OperationName, PermissionGrant_Result, PermissionGrant, AppDisplayName, AppServicePrincipalId, PermissionGrant_InitiatedBy, PermissionGrant_TargetResources, PermissionGrant_AdditionalDetails, PermissionGrant_CorrelationId, RoleAssignment_TimeGenerated, RoleAssignment_OperationName, RoleAssignment_Result, RoleAssignment, TargetType, Target, TargetName, TargetUPNSuffix, TargetId, RoleAssignment_InitiatedBy, RoleAssignment_TargetResources, RoleAssignment_AdditionalDetails, RoleAssignment_CorrelationId\n", + "queryFrequency": "PT1H", + "queryPeriod": "PT2H", + "severity": "High", "suppressionDuration": "PT1H", "suppressionEnabled": false, "triggerOperator": "GreaterThan", - "triggerThreshold": 3, + "triggerThreshold": 0, "status": "Available", "requiredDataConnectors": [ { + "connectorId": "AzureActiveDirectory", "dataTypes": [ "AuditLogs" - ], - "connectorId": "AzureActiveDirectory" + ] } ], "tactics": [ - "Persistence", - "PrivilegeEscalation" + "PrivilegeEscalation", + "Persistence" ], "techniques": [ - "T1136", - "T1068" + "T1098", + "T1078" ], "entityMappings": [ { - "entityType": "Account", "fieldMappings": [ { - "identifier": "Name", - "columnName": "Name" - }, - { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" + "columnName": "AppDisplayName", + "identifier": "Name" } - ] + ], + "entityType": "Account" }, { - "entityType": "CloudApplication", "fieldMappings": [ { - "identifier": "Name", - "columnName": "TargetResourceName" - } - ] - }, - { - "entityType": "IP", - "fieldMappings": [ + "columnName": "TargetName", + "identifier": "Name" + }, { - "identifier": "Address", - "columnName": "IpAddress" + "columnName": "TargetUPNSuffix", + "identifier": "UPNSuffix" } - ] + ], + "entityType": "Account" } ] } @@ -6473,13 +5465,13 @@ { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId45'),'/'))))]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId5'),'/'))))]", "properties": { - "description": "Azure Active Directory Analytics Rule 45", - "parentId": "[variables('analyticRuleId45')]", - "contentId": "[variables('_analyticRulecontentId45')]", + "description": "Azure Active Directory Analytics Rule 5", + "parentId": "[variables('analyticRuleId5')]", + "contentId": "[variables('_analyticRulecontentId5')]", "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion45')]", + "version": "[variables('analyticRuleVersion5')]", "source": { "kind": "Solution", "name": "Azure Active Directory", @@ -6504,43 +5496,43 @@ "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId45')]", + "contentId": "[variables('_analyticRulecontentId5')]", "contentKind": "AnalyticsRule", - "displayName": "Rare application consent", - "contentProductId": "[variables('_analyticRulecontentProductId45')]", - "id": "[variables('_analyticRulecontentProductId45')]", - "version": "[variables('analyticRuleVersion45')]" + "displayName": "Admin promotion after Role Management Application Permission Grant", + "contentProductId": "[variables('_analyticRulecontentProductId5')]", + "id": "[variables('_analyticRulecontentProductId5')]", + "version": "[variables('analyticRuleVersion5')]" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName46')]", + "name": "[variables('analyticRuleTemplateSpecName6')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "SeamlessSSOPasswordSpray_AnalyticalRules Analytics Rule with template version 3.0.4", + "description": "AnomalousUserAppSigninLocationIncrease-detection_AnalyticalRules Analytics Rule with template version 3.0.5", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion46')]", + "contentVersion": "[variables('analyticRuleVersion6')]", "parameters": {}, "variables": {}, "resources": [ { "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId46')]", + "name": "[variables('analyticRulecontentId6')]", "apiVersion": "2022-04-01-preview", "kind": "Scheduled", "location": "[parameters('workspace-location')]", "properties": { - "description": "This query detects when there is a spike in Azure AD Seamless SSO errors. They may not be caused by a Password Spray attack, but the cause of the errors might need to be investigated.\nAzure AD only logs the requests that matched existing accounts, thus there might have been unlogged requests for non-existing accounts.", - "displayName": "Password spray attack against Azure AD Seamless SSO", + "description": "This query over Azure Active Directory sign-in considers all user sign-ins for each Azure Active\nDirectory application and picks out the most anomalous change in location profile for a user within an\nindividual application", + "displayName": "Anomalous sign-in location by user account and authenticating application", "enabled": false, - "query": "let account_threshold = 5;\nAADNonInteractiveUserSignInLogs\n//| where ResultType == \"81016\"\n| where ResultType startswith \"81\"\n| summarize DistinctAccounts = dcount(UserPrincipalName), DistinctAddresses = make_set(IPAddress,100) by ResultType\n| where DistinctAccounts > account_threshold\n| mv-expand IPAddress = DistinctAddresses\n| extend IPAddress = tostring(IPAddress)\n| join kind=leftouter (union isfuzzy=true SigninLogs, AADNonInteractiveUserSignInLogs) on IPAddress\n| summarize\n StartTime = min(TimeGenerated),\n EndTime = max(TimeGenerated),\n UserPrincipalName = make_set(UserPrincipalName,100),\n UserAgent = make_set(UserAgent,100),\n ResultDescription = take_any(ResultDescription),\n ResultSignature = take_any(ResultSignature)\n by IPAddress, Type, ResultType\n| project Type, StartTime, EndTime, IPAddress, ResultType, ResultDescription, ResultSignature, UserPrincipalName, UserAgent = iff(array_length(UserAgent) == 1, UserAgent[0], UserAgent)\n| extend Name = tostring(split(UserPrincipalName[0],'@',0)[0]), UPNSuffix = tostring(split(UserPrincipalName[0],'@',1)[0])\n", - "queryFrequency": "PT1H", - "queryPeriod": "PT1H", + "query": "// Adjust this figure to adjust how sensitive this detection is\nlet sensitivity = 2.5;\nlet AuthEvents = materialize(\nunion isfuzzy=True SigninLogs, AADNonInteractiveUserSignInLogs\n| where TimeGenerated > ago(7d)\n| where ResultType == 0\n| extend LocationDetails = LocationDetails_dynamic\n| extend Location = strcat(LocationDetails.countryOrRegion, \"-\", LocationDetails.state,\"-\", LocationDetails.city)\n| where Location != \"--\");\nAuthEvents\n| summarize dcount(Location) by AppDisplayName, AppId, UserPrincipalName, UserId, bin(startofday(TimeGenerated), 1d)\n| where dcount_Location > 2\n| summarize CountOfLocations = make_list(dcount_Location, 10000), TimeStamp = make_list(TimeGenerated, 10000) by AppId, UserId\n| extend (Anomalies, Score, Baseline) = series_decompose_anomalies(CountOfLocations, sensitivity, -1, 'linefit')\n| mv-expand CountOfLocations to typeof(double), TimeStamp to typeof(datetime), Anomalies to typeof(double), Score to typeof(double), Baseline to typeof(long)\n| where Anomalies > 0\n| join kind=inner( AuthEvents | extend TimeStamp = startofday(TimeGenerated)) on UserId, AppId\n| extend SignInDetails = bag_pack(\"TimeGenerated\", TimeGenerated, \"Location\", Location, \"Source\", IPAddress, \"Device\", DeviceDetail_dynamic)\n| summarize SignInDetailsSet=make_set(SignInDetails, 1000) by UserId, UserPrincipalName, CountOfLocations, TimeStamp, AppId, AppDisplayName\n| extend Name = split(UserPrincipalName, \"@\")[0], UPNSuffix = split(UserPrincipalName, \"@\")[1]\n", + "queryFrequency": "P1D", + "queryPeriod": "P7D", "severity": "Medium", "suppressionDuration": "PT1H", "suppressionEnabled": false, @@ -6549,54 +5541,65 @@ "status": "Available", "requiredDataConnectors": [ { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "SigninLogs" + ] + }, + { + "connectorId": "AzureActiveDirectory", "dataTypes": [ "AADNonInteractiveUserSignInLogs" - ], - "connectorId": "AzureActiveDirectory" + ] } ], "tactics": [ - "CredentialAccess" + "InitialAccess" ], "techniques": [ - "T1110" + "T1078" ], "entityMappings": [ { - "entityType": "Account", "fieldMappings": [ { - "identifier": "Name", - "columnName": "Name" + "columnName": "Name", + "identifier": "Name" }, { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" - } - ] - }, - { - "entityType": "IP", - "fieldMappings": [ + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" + }, { - "identifier": "Address", - "columnName": "IPAddress" + "columnName": "UserId", + "identifier": "AadUserId" } - ] + ], + "entityType": "Account" } - ] + ], + "eventGroupingSettings": { + "aggregationKind": "SingleAlert" + }, + "customDetails": { + "Application": "AppDisplayName" + }, + "alertDetailsOverride": { + "alertDisplayNameFormat": "Anomalous sign-in location by {{UserPrincipalName}} to {{AppDisplayName}}", + "alertDescriptionFormat": "This query over Azure Active Directory sign-in considers all user sign-ins for each Azure Active\nDirectory application and picks out the most anomalous change in location profile for a user within an\nindividual application. This has detected {{UserPrincipalName}} signing into {{AppDisplayName}} from {{CountOfLocations}} \ndifferent locations.\n" + } } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId46'),'/'))))]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId6'),'/'))))]", "properties": { - "description": "Azure Active Directory Analytics Rule 46", - "parentId": "[variables('analyticRuleId46')]", - "contentId": "[variables('_analyticRulecontentId46')]", + "description": "Azure Active Directory Analytics Rule 6", + "parentId": "[variables('analyticRuleId6')]", + "contentId": "[variables('_analyticRulecontentId6')]", "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion46')]", + "version": "[variables('analyticRuleVersion6')]", "source": { "kind": "Solution", "name": "Azure Active Directory", @@ -6621,44 +5624,44 @@ "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId46')]", + "contentId": "[variables('_analyticRulecontentId6')]", "contentKind": "AnalyticsRule", - "displayName": "Password spray attack against Azure AD Seamless SSO", - "contentProductId": "[variables('_analyticRulecontentProductId46')]", - "id": "[variables('_analyticRulecontentProductId46')]", - "version": "[variables('analyticRuleVersion46')]" + "displayName": "Anomalous sign-in location by user account and authenticating application", + "contentProductId": "[variables('_analyticRulecontentProductId6')]", + "id": "[variables('_analyticRulecontentProductId6')]", + "version": "[variables('analyticRuleVersion6')]" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName47')]", + "name": "[variables('analyticRuleTemplateSpecName7')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "Sign-in Burst from Multiple Locations_AnalyticalRules Analytics Rule with template version 3.0.4", + "description": "AuthenticationMethodsChangedforPrivilegedAccount_AnalyticalRules Analytics Rule with template version 3.0.5", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion47')]", + "contentVersion": "[variables('analyticRuleVersion7')]", "parameters": {}, "variables": {}, "resources": [ { "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId47')]", + "name": "[variables('analyticRulecontentId7')]", "apiVersion": "2022-04-01-preview", "kind": "Scheduled", "location": "[parameters('workspace-location')]", "properties": { - "description": "This detection triggers when there is a Signin burst from multiple locations in GitHub (AAD SSO).\n This detection is based on configurable threshold which can be prone to false positives. To view the anomaly based equivalent of thie detection, please see here https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Azure%20Active%20Directory/Analytic%20Rules/AnomalousUserAppSigninLocationIncrease-detection.yaml. ", - "displayName": "GitHub Signin Burst from Multiple Locations", + "description": "Identifies authentication methods being changed for a privileged account. This could be an indication of an attacker adding an auth method to the account so they can have continued access.\nRef : https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-privileged-accounts#things-to-monitor-1", + "displayName": "Authentication Methods Changed for Privileged Account", "enabled": false, - "query": "let locationThreshold = 1;\nlet aadFunc = (tableName:string){\ntable(tableName)\n| where AppDisplayName =~ \"GitHub.com\"\n| where ResultType == 0\n| summarize CountOfLocations = dcount(Location), Locations = make_set(Location,100), BurstStartTime = min(TimeGenerated), BurstEndTime = max(TimeGenerated) by UserPrincipalName, Type\n| where CountOfLocations > locationThreshold\n| extend timestamp = BurstStartTime\n};\nlet aadSignin = aadFunc(\"SigninLogs\");\nlet aadNonInt = aadFunc(\"AADNonInteractiveUserSignInLogs\");\nunion isfuzzy=true aadSignin, aadNonInt\n| extend Name = tostring(split(UserPrincipalName,'@',0)[0]), UPNSuffix = tostring(split(UserPrincipalName,'@',1)[0])\n", - "queryFrequency": "PT1H", - "queryPeriod": "PT1H", - "severity": "Medium", + "query": "let queryperiod = 14d;\nlet queryfrequency = 2h;\nlet security_info_actions = dynamic([\"User registered security info\", \"User changed default security info\", \"User deleted security info\", \"Admin updated security info\", \"User reviewed security info\", \"Admin deleted security info\", \"Admin registered security info\"]);\nlet VIPUsers = (\n IdentityInfo\n | where TimeGenerated > ago(queryperiod)\n | mv-expand AssignedRoles\n | where AssignedRoles contains 'Admin'\n | summarize by AccountUPN);\nAuditLogs\n| where TimeGenerated > ago(queryfrequency)\n| where Category =~ \"UserManagement\"\n| where ActivityDisplayName in (security_info_actions)\n| extend Initiator = tostring(InitiatedBy.user.userPrincipalName)\n| extend IP = tostring(InitiatedBy.user.ipAddress)\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"User\"\n | extend Target = tostring(TargetResource.userPrincipalName)\n )\n| where Target in~ (VIPUsers)\n// Uncomment the line below if you are experiencing high volumes of Target entities. If this is uncommented, the Target column will not be mapped to an entity.\n//| summarize Start=min(TimeGenerated), End=max(TimeGenerated), Actions = make_set(ResultReason, MaxSize=8), Targets=make_set(Target, MaxSize=256) by Initiator, IP, Result\n// Comment out this line below, if line above is used.\n| summarize Start=min(TimeGenerated), End=max(TimeGenerated), Actions = make_set(ResultReason, MaxSize=8) by Initiator, IP, Result, Targets = Target\n| extend InitiatorName = tostring(split(Initiator,'@',0)[0]), \n InitiatorUPNSuffix = tostring(split(Initiator,'@',1)[0]),\n TargetName = iff(tostring(Targets) has \"[\", \"\", tostring(split(Targets,'@',0)[0])), \n TargetUPNSuffix = iff(tostring(Targets) has \"[\", \"\", tostring(split(Targets,'@',1)[0]))\n", + "queryFrequency": "PT2H", + "queryPeriod": "P14D", + "severity": "High", "suppressionDuration": "PT1H", "suppressionEnabled": false, "triggerOperator": "GreaterThan", @@ -6666,37 +5669,53 @@ "status": "Available", "requiredDataConnectors": [ { + "connectorId": "AzureActiveDirectory", "dataTypes": [ - "SigninLogs" - ], - "connectorId": "AzureActiveDirectory" - }, - { - "dataTypes": [ - "AADNonInteractiveUserSignInLogs" - ], - "connectorId": "AzureActiveDirectory" + "AuditLogs" + ] } ], "tactics": [ - "CredentialAccess" + "Persistence" ], "techniques": [ - "T1110" + "T1098" ], "entityMappings": [ { - "entityType": "Account", "fieldMappings": [ { - "identifier": "Name", - "columnName": "Name" + "columnName": "InitiatorName", + "identifier": "Name" }, { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" + "columnName": "InitiatorUPNSuffix", + "identifier": "UPNSuffix" } - ] + ], + "entityType": "Account" + }, + { + "fieldMappings": [ + { + "columnName": "TargetName", + "identifier": "Name" + }, + { + "columnName": "TargetUPNSuffix", + "identifier": "UPNSuffix" + } + ], + "entityType": "Account" + }, + { + "fieldMappings": [ + { + "columnName": "IP", + "identifier": "Address" + } + ], + "entityType": "IP" } ] } @@ -6704,13 +5723,13 @@ { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId47'),'/'))))]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId7'),'/'))))]", "properties": { - "description": "Azure Active Directory Analytics Rule 47", - "parentId": "[variables('analyticRuleId47')]", - "contentId": "[variables('_analyticRulecontentId47')]", + "description": "Azure Active Directory Analytics Rule 7", + "parentId": "[variables('analyticRuleId7')]", + "contentId": "[variables('_analyticRulecontentId7')]", "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion47')]", + "version": "[variables('analyticRuleVersion7')]", "source": { "kind": "Solution", "name": "Azure Active Directory", @@ -6735,44 +5754,44 @@ "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId47')]", + "contentId": "[variables('_analyticRulecontentId7')]", "contentKind": "AnalyticsRule", - "displayName": "GitHub Signin Burst from Multiple Locations", - "contentProductId": "[variables('_analyticRulecontentProductId47')]", - "id": "[variables('_analyticRulecontentProductId47')]", - "version": "[variables('analyticRuleVersion47')]" + "displayName": "Authentication Methods Changed for Privileged Account", + "contentProductId": "[variables('_analyticRulecontentProductId7')]", + "id": "[variables('_analyticRulecontentProductId7')]", + "version": "[variables('analyticRuleVersion7')]" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName48')]", + "name": "[variables('analyticRuleTemplateSpecName8')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "SigninAttemptsByIPviaDisabledAccounts_AnalyticalRules Analytics Rule with template version 3.0.4", + "description": "AzureAADPowerShellAnomaly_AnalyticalRules Analytics Rule with template version 3.0.5", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion48')]", + "contentVersion": "[variables('analyticRuleVersion8')]", "parameters": {}, "variables": {}, "resources": [ { "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId48')]", + "name": "[variables('analyticRulecontentId8')]", "apiVersion": "2022-04-01-preview", "kind": "Scheduled", "location": "[parameters('workspace-location')]", "properties": { - "description": "Identifies IPs with failed attempts to sign in to one or more disabled accounts using the IP through which successful signins from other accounts have happened.\nThis could indicate an attacker who obtained credentials for a list of accounts and is attempting to login with those accounts, some of which may have already been disabled.\nReferences: https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-sign-ins-error-codes\n50057 - User account is disabled. The account has been disabled by an administrator.\nThis query has also been updated to include UEBA logs IdentityInfo and BehaviorAnalytics for contextual information around the results.", - "displayName": "Sign-ins from IPs that attempt sign-ins to disabled accounts", + "description": "This will alert when a user or application signs in using Azure Active Directory PowerShell to access non-Active Directory resources, such as the Azure Key Vault, which may be undesired or unauthorized behavior.\nFor capabilities and expected behavior of the Azure Active Directory PowerShell module, see: https://docs.microsoft.com/powershell/module/azuread/?view=azureadps-2.0.\nFor further information on Azure Active Directory Signin activity reports, see: https://docs.microsoft.com/azure/active-directory/reports-monitoring/concept-sign-ins.", + "displayName": "Azure Active Directory PowerShell accessing non-AAD resources", "enabled": false, - "query": "let aadFunc = (tableName: string) {\nlet failed_signins = table(tableName)\n| where ResultType == \"50057\"\n| where ResultDescription == \"User account is disabled. The account has been disabled by an administrator.\";\nlet disabled_users = failed_signins | summarize by UserPrincipalName;\ntable(tableName)\n | where ResultType == 0\n | where isnotempty(UserPrincipalName)\n | where UserPrincipalName !in (disabled_users)\n| summarize\n successfulAccountsTargettedCount = dcount(UserPrincipalName),\n successfulAccountSigninSet = make_set(UserPrincipalName, 100),\n successfulApplicationSet = make_set(AppDisplayName, 100)\n by IPAddress, Type\n // Assume IPs associated with sign-ins from 100+ distinct user accounts are safe\n | where successfulAccountsTargettedCount < 50\n | where isnotempty(successfulAccountsTargettedCount)\n | join kind=inner (failed_signins\n| summarize\n StartTime = min(TimeGenerated),\n EndTime = max(TimeGenerated),\n totalDisabledAccountLoginAttempts = count(),\n disabledAccountsTargettedCount = dcount(UserPrincipalName),\n applicationsTargeted = dcount(AppDisplayName),\n disabledAccountSet = make_set(UserPrincipalName, 100),\n disabledApplicationSet = make_set(AppDisplayName, 100)\nby IPAddress, Type\n| order by totalDisabledAccountLoginAttempts desc) on IPAddress\n| project StartTime, EndTime, IPAddress, totalDisabledAccountLoginAttempts, disabledAccountsTargettedCount, disabledAccountSet, disabledApplicationSet, successfulApplicationSet, successfulAccountsTargettedCount, successfulAccountSigninSet, Type\n| order by totalDisabledAccountLoginAttempts};\nlet aadSignin = aadFunc(\"SigninLogs\");\nlet aadNonInt = aadFunc(\"AADNonInteractiveUserSignInLogs\");\nunion isfuzzy=true aadSignin, aadNonInt\n| join kind=leftouter (\n BehaviorAnalytics\n | where ActivityType in (\"FailedLogOn\", \"LogOn\")\n | where EventSource =~ \"Azure AD\"\n | project UsersInsights, DevicesInsights, ActivityInsights, InvestigationPriority, SourceIPAddress, UserPrincipalName\n | project-rename IPAddress = SourceIPAddress\n | summarize\n Users = make_set(UserPrincipalName, 100),\n UsersInsights = make_set(UsersInsights, 100),\n DevicesInsights = make_set(DevicesInsights, 100),\n IPInvestigationPriority = sum(InvestigationPriority)\n by IPAddress\n) on IPAddress\n| extend SFRatio = toreal(toreal(disabledAccountsTargettedCount)/toreal(successfulAccountsTargettedCount))\n| where SFRatio >= 0.5\n| sort by IPInvestigationPriority desc\n", - "queryFrequency": "P1D", - "queryPeriod": "P1D", - "severity": "Medium", + "query": "let aadFunc = (tableName:string){\ntable(tableName)\n| where AppId =~ \"1b730954-1685-4b74-9bfd-dac224a7b894\" // AppDisplayName IS Azure Active Directory PowerShell\n| where TokenIssuerType =~ \"AzureAD\"\n| where ResourceIdentity !in (\"00000002-0000-0000-c000-000000000000\", \"00000003-0000-0000-c000-000000000000\") // ResourceDisplayName IS NOT Windows Azure Active Directory OR Microsoft Graph\n| extend Status = todynamic(Status)\n| where Status.errorCode == 0 // Success\n| project-reorder IPAddress, UserAgent, ResourceDisplayName, UserDisplayName, UserId, UserPrincipalName, Type\n| order by TimeGenerated desc\n// New entity mapping\n| extend timestamp = TimeGenerated, Name = tostring(split(UserPrincipalName,'@',0)[0]), UPNSuffix = tostring(split(UserPrincipalName,'@',1)[0])\n};\nlet aadSignin = aadFunc(\"SigninLogs\");\nlet aadNonInt = aadFunc(\"AADNonInteractiveUserSignInLogs\");\nunion isfuzzy=true aadSignin, aadNonInt\n", + "queryFrequency": "PT1H", + "queryPeriod": "PT1H", + "severity": "Low", "suppressionDuration": "PT1H", "suppressionEnabled": false, "triggerOperator": "GreaterThan", @@ -6780,41 +5799,50 @@ "status": "Available", "requiredDataConnectors": [ { + "connectorId": "AzureActiveDirectory", "dataTypes": [ "SigninLogs" - ], - "connectorId": "AzureActiveDirectory" + ] }, { + "connectorId": "AzureActiveDirectory", "dataTypes": [ "AADNonInteractiveUserSignInLogs" - ], - "connectorId": "AzureActiveDirectory" - }, - { - "dataTypes": [ - "BehaviorAnalytics" - ], - "connectorId": "BehaviorAnalytics" + ] } ], "tactics": [ - "InitialAccess", - "Persistence" + "InitialAccess" ], "techniques": [ - "T1078", - "T1098" + "T1078" ], "entityMappings": [ { - "entityType": "IP", "fieldMappings": [ { - "identifier": "Address", - "columnName": "IPAddress" + "columnName": "Name", + "identifier": "Name" + }, + { + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" + }, + { + "columnName": "UserId", + "identifier": "AadUserId" } - ] + ], + "entityType": "Account" + }, + { + "fieldMappings": [ + { + "columnName": "IPAddress", + "identifier": "Address" + } + ], + "entityType": "IP" } ] } @@ -6822,13 +5850,13 @@ { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId48'),'/'))))]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId8'),'/'))))]", "properties": { - "description": "Azure Active Directory Analytics Rule 48", - "parentId": "[variables('analyticRuleId48')]", - "contentId": "[variables('_analyticRulecontentId48')]", + "description": "Azure Active Directory Analytics Rule 8", + "parentId": "[variables('analyticRuleId8')]", + "contentId": "[variables('_analyticRulecontentId8')]", "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion48')]", + "version": "[variables('analyticRuleVersion8')]", "source": { "kind": "Solution", "name": "Azure Active Directory", @@ -6853,44 +5881,44 @@ "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId48')]", + "contentId": "[variables('_analyticRulecontentId8')]", "contentKind": "AnalyticsRule", - "displayName": "Sign-ins from IPs that attempt sign-ins to disabled accounts", - "contentProductId": "[variables('_analyticRulecontentProductId48')]", - "id": "[variables('_analyticRulecontentProductId48')]", - "version": "[variables('analyticRuleVersion48')]" + "displayName": "Azure Active Directory PowerShell accessing non-AAD resources", + "contentProductId": "[variables('_analyticRulecontentProductId8')]", + "id": "[variables('_analyticRulecontentProductId8')]", + "version": "[variables('analyticRuleVersion8')]" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName49')]", + "name": "[variables('analyticRuleTemplateSpecName9')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "SigninBruteForce-AzurePortal_AnalyticalRules Analytics Rule with template version 3.0.4", + "description": "AzureADRoleManagementPermissionGrant_AnalyticalRules Analytics Rule with template version 3.0.5", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion49')]", + "contentVersion": "[variables('analyticRuleVersion9')]", "parameters": {}, "variables": {}, "resources": [ { "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId49')]", + "name": "[variables('analyticRulecontentId9')]", "apiVersion": "2022-04-01-preview", "kind": "Scheduled", "location": "[parameters('workspace-location')]", "properties": { - "description": "Detects Azure Portal brute force attacks by monitoring for multiple authentication failures and a successful login within a 20-minute window. Default settings: 10 failures, 25 deviations.\nRef: https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-sign-ins-error-codes.", - "displayName": "Brute force attack against Azure Portal", + "description": "Identifies when the Microsoft Graph RoleManagement.ReadWrite.Directory (Delegated or Application) permission is granted to a service principal.\nThis permission allows an application to read and manage the role-based access control (RBAC) settings for your company's directory.\nAn adversary could use this permission to add an Azure AD object to an Admin directory role and escalate privileges.\nRef : https://docs.microsoft.com/graph/permissions-reference#role-management-permissions\nRef : https://docs.microsoft.com/graph/api/directoryrole-post-members?view=graph-rest-1.0&tabs=http", + "displayName": "Azure AD Role Management Permission Grant", "enabled": false, - "query": "// Set threshold value for deviation\nlet threshold = 25;\n// Set the time range for the query\nlet timeRange = 24h;\n// Set the authentication window duration\nlet authenticationWindow = 20m;\n// Define a reusable function 'aadFunc' that takes a table name as input\nlet aadFunc = (tableName: string) {\n // Query the specified table\n table(tableName)\n // Filter data within the last 24 hours\n | where TimeGenerated > ago(1d)\n // Filter records related to \"Azure Portal\" applications\n | where AppDisplayName has \"Azure Portal\"\n // Extract and transform some fields\n | extend\n DeviceDetail = todynamic(DeviceDetail),\n LocationDetails = todynamic(LocationDetails)\n | extend\n OS = tostring(DeviceDetail.operatingSystem),\n Browser = tostring(DeviceDetail.browser),\n State = tostring(LocationDetails.state),\n City = tostring(LocationDetails.city),\n Region = tostring(LocationDetails.countryOrRegion)\n // Categorize records as Success or Failure based on ResultType\n | extend FailureOrSuccess = iff(ResultType in (\"0\", \"50125\", \"50140\", \"70043\", \"70044\"), \"Success\", \"Failure\")\n // Sort and identify sessions\n | sort by UserPrincipalName asc, TimeGenerated asc\n | extend SessionStartedUtc = row_window_session(TimeGenerated, timeRange, authenticationWindow, UserPrincipalName != prev(UserPrincipalName) or prev(FailureOrSuccess) == \"Success\")\n // Summarize data\n | summarize FailureOrSuccessCount = count() by FailureOrSuccess, UserId, UserDisplayName, AppDisplayName, IPAddress, Browser, OS, State, City, Region, Type, CorrelationId, bin(TimeGenerated, authenticationWindow), ResultType, UserPrincipalName, SessionStartedUtc\n | summarize FailureCountBeforeSuccess = sumif(FailureOrSuccessCount, FailureOrSuccess == \"Failure\"), StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), makelist(FailureOrSuccess), IPAddress = make_set(IPAddress, 15), make_set(Browser, 15), make_set(City, 15), make_set(State, 15), make_set(Region, 15), make_set(ResultType, 15) by SessionStartedUtc, UserPrincipalName, CorrelationId, AppDisplayName, UserId, Type\n // Filter records where \"Success\" occurs in the middle of a session\n | where array_index_of(list_FailureOrSuccess, \"Success\") != 0\n | where array_index_of(list_FailureOrSuccess, \"Success\") == array_length(list_FailureOrSuccess) - 1\n // Remove unnecessary columns from the output\n | project-away SessionStartedUtc, list_FailureOrSuccess\n // Join with another table and calculate deviation\n | join kind=inner (\n table(tableName)\n | where TimeGenerated > ago(7d)\n | where AppDisplayName has \"Azure Portal\"\n | extend FailureOrSuccess = iff(ResultType in (\"0\", \"50125\", \"50140\", \"70043\", \"70044\"), \"Success\", \"Failure\")\n | summarize avgFailures = avg(todouble(FailureOrSuccess == \"Failure\")) by UserPrincipalName\n ) on UserPrincipalName\n | extend Deviation = abs(FailureCountBeforeSuccess - avgFailures) / avgFailures\n // Filter records based on deviation and failure count criteria\n | where Deviation > threshold and FailureCountBeforeSuccess >= 10\n // Expand the IPAddress array\n | mv-expand IPAddress\n | extend IPAddress = tostring(IPAddress)\n | extend timestamp = StartTime\n};\n// Call 'aadFunc' with different table names and union the results\nlet aadSignin = aadFunc(\"SigninLogs\");\nlet aadNonInt = aadFunc(\"AADNonInteractiveUserSignInLogs\");\nunion isfuzzy=true aadSignin, aadNonInt\n// Additional transformation: Split UserPrincipalName\n| extend Name = tostring(split(UserPrincipalName,'@',0)[0]), UPNSuffix = tostring(split(UserPrincipalName,'@',1)[0])\n", - "queryFrequency": "P1D", - "queryPeriod": "P7D", - "severity": "Medium", + "query": "AuditLogs\n| where Category =~ \"ApplicationManagement\" and LoggedByService =~ \"Core Directory\" and OperationName in~ (\"Add delegated permission grant\", \"Add app role assignment to service principal\")\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"ServicePrincipal\" and array_length(TargetResource.modifiedProperties) > 0 and isnotnull(TargetResource.displayName)\n | extend props = TargetResource.modifiedProperties\n )\n| mv-apply Property = props on \n (\n where Property.displayName in~ (\"AppRole.Value\",\"DelegatedPermissionGrant.Scope\")\n | extend DisplayName = tostring(Property.displayName), PermissionGrant = trim('\"',tostring(Property.newValue))\n )\n| where PermissionGrant has \"RoleManagement.ReadWrite.Directory\"\n| mv-apply Property = props on \n (\n where Property.displayName =~ \"ServicePrincipal.DisplayName\"\n | extend AppDisplayName = trim('\"',tostring(Property.newValue))\n )\n| mv-apply Property = props on \n (\n where Property.displayName =~ \"ServicePrincipal.ObjectID\"\n | extend AppServicePrincipalId = trim('\"',tostring(Property.newValue))\n )\n| extend \n Initiator = iif(isnotempty(InitiatedBy.app), tostring(InitiatedBy.app.displayName), tostring(InitiatedBy.user.userPrincipalName)),\n InitiatorId = iif(isnotempty(InitiatedBy.app), tostring(InitiatedBy.app.servicePrincipalId), tostring(InitiatedBy.user.id))\n| project TimeGenerated, OperationName, Result, PermissionGrant, AppDisplayName, AppServicePrincipalId, Initiator, InitiatorId, InitiatedBy, TargetResources, AdditionalDetails, CorrelationId\n| extend Name = tostring(split(Initiator,'@',0)[0]), UPNSuffix = tostring(split(Initiator,'@',1)[0])\n", + "queryFrequency": "PT2H", + "queryPeriod": "PT2H", + "severity": "High", "suppressionDuration": "PT1H", "suppressionEnabled": false, "triggerOperator": "GreaterThan", @@ -6898,50 +5926,42 @@ "status": "Available", "requiredDataConnectors": [ { + "connectorId": "AzureActiveDirectory", "dataTypes": [ - "SigninLogs" - ], - "connectorId": "AzureActiveDirectory" - }, - { - "dataTypes": [ - "AADNonInteractiveUserSignInLogs" - ], - "connectorId": "AzureActiveDirectory" + "AuditLogs" + ] } ], "tactics": [ - "CredentialAccess" + "Persistence", + "Impact" ], "techniques": [ - "T1110" + "T1098", + "T1078" ], "entityMappings": [ { - "entityType": "Account", "fieldMappings": [ { - "identifier": "Name", - "columnName": "Name" - }, - { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" + "columnName": "Name", + "identifier": "Name" }, { - "identifier": "AadUserId", - "columnName": "UserId" + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" } - ] + ], + "entityType": "Account" }, { - "entityType": "IP", "fieldMappings": [ { - "identifier": "Address", - "columnName": "IPAddress" + "columnName": "AppDisplayName", + "identifier": "Name" } - ] + ], + "entityType": "Account" } ] } @@ -6949,13 +5969,13 @@ { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId49'),'/'))))]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId9'),'/'))))]", "properties": { - "description": "Azure Active Directory Analytics Rule 49", - "parentId": "[variables('analyticRuleId49')]", - "contentId": "[variables('_analyticRulecontentId49')]", + "description": "Azure Active Directory Analytics Rule 9", + "parentId": "[variables('analyticRuleId9')]", + "contentId": "[variables('_analyticRulecontentId9')]", "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion49')]", + "version": "[variables('analyticRuleVersion9')]", "source": { "kind": "Solution", "name": "Azure Active Directory", @@ -6980,43 +6000,43 @@ "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId49')]", + "contentId": "[variables('_analyticRulecontentId9')]", "contentKind": "AnalyticsRule", - "displayName": "Brute force attack against Azure Portal", - "contentProductId": "[variables('_analyticRulecontentProductId49')]", - "id": "[variables('_analyticRulecontentProductId49')]", - "version": "[variables('analyticRuleVersion49')]" + "displayName": "Azure AD Role Management Permission Grant", + "contentProductId": "[variables('_analyticRulecontentProductId9')]", + "id": "[variables('_analyticRulecontentProductId9')]", + "version": "[variables('analyticRuleVersion9')]" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName50')]", + "name": "[variables('analyticRuleTemplateSpecName10')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "SigninPasswordSpray_AnalyticalRules Analytics Rule with template version 3.0.4", + "description": "AzurePortalSigninfromanotherAzureTenant_AnalyticalRules Analytics Rule with template version 3.0.5", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion50')]", + "contentVersion": "[variables('analyticRuleVersion10')]", "parameters": {}, "variables": {}, "resources": [ { "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId50')]", + "name": "[variables('analyticRulecontentId10')]", "apiVersion": "2022-04-01-preview", "kind": "Scheduled", "location": "[parameters('workspace-location')]", "properties": { - "description": "Identifies evidence of password spray activity against Azure AD applications by looking for failures from multiple accounts from the same\nIP address within a time window. If the number of accounts breaches the threshold just once, all failures from the IP address within the time range\nare bought into the result. Details on whether there were successful authentications by the IP address within the time window are also included.\nThis can be an indicator that an attack was successful.\nThe default failure acccount threshold is 5, Default time window for failures is 20m and default look back window is 3 days\nNote: Due to the number of possible accounts involved in a password spray it is not possible to map identities to a custom entity.\nReferences: https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-sign-ins-error-codes.", - "displayName": "Password spray attack against Azure AD application", + "description": "This query looks for successful sign in attempts to the Azure Portal where the user who is signing in from another Azure tenant,\n and the IP address the login attempt is from is an Azure IP. A threat actor who compromises an Azure tenant may look\n to pivot to other tenants leveraging cross-tenant delegated access in this manner.", + "displayName": "Azure Portal sign in from another Azure Tenant", "enabled": false, - "query": "let timeRange = 3d;\nlet lookBack = 7d;\nlet authenticationWindow = 20m;\nlet authenticationThreshold = 5;\nlet isGUID = \"[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}\";\nlet failureCodes = dynamic([50053, 50126, 50055]); // invalid password, account is locked - too many sign ins, expired password\nlet successCodes = dynamic([0, 50055, 50057, 50155, 50105, 50133, 50005, 50076, 50079, 50173, 50158, 50072, 50074, 53003, 53000, 53001, 50129]);\n// Lookup up resolved identities from last 7 days\nlet aadFunc = (tableName:string){\nlet identityLookup = table(tableName)\n| where TimeGenerated >= ago(lookBack)\n| where not(Identity matches regex isGUID)\n| where isnotempty(UserId)\n| summarize by UserId, lu_UserDisplayName = UserDisplayName, lu_UserPrincipalName = UserPrincipalName, Type;\n// collect window threshold breaches\ntable(tableName)\n| where TimeGenerated > ago(timeRange)\n| where ResultType in(failureCodes)\n| summarize FailedPrincipalCount = dcount(UserPrincipalName) by bin(TimeGenerated, authenticationWindow), IPAddress, AppDisplayName, Type\n| where FailedPrincipalCount >= authenticationThreshold\n| summarize WindowThresholdBreaches = count() by IPAddress, Type\n| join kind= inner (\n// where we breached a threshold, join the details back on all failure data\ntable(tableName)\n| where TimeGenerated > ago(timeRange)\n| where ResultType in(failureCodes)\n| extend LocationDetails = todynamic(LocationDetails)\n| extend FullLocation = strcat(LocationDetails.countryOrRegion,'|', LocationDetails.state, '|', LocationDetails.city)\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), make_set(ClientAppUsed,20), make_set(FullLocation,20), FailureCount = count() by IPAddress, AppDisplayName, UserPrincipalName, UserDisplayName, Identity, UserId, Type\n// lookup any unresolved identities\n| extend UnresolvedUserId = iff(Identity matches regex isGUID, UserId, \"\")\n| join kind= leftouter (\n identityLookup\n) on $left.UnresolvedUserId==$right.UserId\n| extend UserDisplayName=iff(isempty(lu_UserDisplayName), UserDisplayName, lu_UserDisplayName)\n| extend UserPrincipalName=iff(isempty(lu_UserPrincipalName), UserPrincipalName, lu_UserPrincipalName)\n| summarize StartTime = min(StartTime), EndTime = max(EndTime), make_set(UserPrincipalName,20), make_set(UserDisplayName,20), make_set(set_ClientAppUsed,20), make_set(set_FullLocation,20), make_list(FailureCount,20) by IPAddress, AppDisplayName, Type\n| extend FailedPrincipalCount = array_length(set_UserPrincipalName)\n) on IPAddress\n| project IPAddress, StartTime, EndTime, TargetedApplication=AppDisplayName, FailedPrincipalCount, UserPrincipalNames=set_UserPrincipalName, UserDisplayNames=set_UserDisplayName, ClientAppsUsed=set_set_ClientAppUsed, Locations=set_set_FullLocation, FailureCountByPrincipal=list_FailureCount, WindowThresholdBreaches, Type\n| join kind= inner (\ntable(tableName) // get data on success vs. failure history for each IP\n| where TimeGenerated > ago(timeRange)\n| where ResultType in(successCodes) or ResultType in(failureCodes) // success or failure types\n| summarize GlobalSuccessPrincipalCount = dcountif(UserPrincipalName, (ResultType in (successCodes))), ResultTypeSuccesses = make_set_if(ResultType, (ResultType in (successCodes))), GlobalFailPrincipalCount = dcountif(UserPrincipalName, (ResultType in (failureCodes))), ResultTypeFailures = make_set_if(ResultType, (ResultType in (failureCodes))) by IPAddress, Type\n| where GlobalFailPrincipalCount > GlobalSuccessPrincipalCount // where the number of failed principals is greater than success - eliminates FPs from IPs who authenticate successfully alot and as a side effect have alot of failures\n) on IPAddress\n| project-away IPAddress1\n| extend timestamp=StartTime\n};\nlet aadSignin = aadFunc(\"SigninLogs\");\nlet aadNonInt = aadFunc(\"AADNonInteractiveUserSignInLogs\");\nunion isfuzzy=true aadSignin, aadNonInt\n", - "queryFrequency": "P1D", - "queryPeriod": "P7D", + "query": "// Get details of current Azure Ranges (note this URL updates regularly so will need to be manually updated over time)\n// You may find the name of the new JSON here: https://www.microsoft.com/download/details.aspx?id=56519\n// On the downloads page, click the 'details' button, and then replace just the filename in the URL below\nlet azure_ranges = externaldata(changeNumber: string, cloud: string, values: dynamic)\n[\"https://raw.githubusercontent.com/microsoft/mstic/master/PublicFeeds/MSFTIPRanges/ServiceTags_Public.json\"] with(format='multijson')\n| mv-expand values\n| mv-expand values.properties.addressPrefixes\n| mv-expand values_properties_addressPrefixes\n| summarize by tostring(values_properties_addressPrefixes)\n| extend isipv4 = parse_ipv4(values_properties_addressPrefixes)\n| extend isipv6 = parse_ipv6(values_properties_addressPrefixes)\n| extend ip_type = case(isnotnull(isipv4), \"v4\", \"v6\")\n| summarize make_list(values_properties_addressPrefixes) by ip_type\n;\nSigninLogs\n// Limiting to Azure Portal really reduces false positives and helps focus on potential admin activity\n| where ResultType == 0\n| where AppDisplayName =~ \"Azure Portal\"\n| extend isipv4 = parse_ipv4(IPAddress)\n| extend ip_type = case(isnotnull(isipv4), \"v4\", \"v6\")\n // Only get logons where the IP address is in an Azure range\n| join kind=fullouter (azure_ranges) on ip_type\n| extend ipv6_match = ipv6_is_in_any_range(IPAddress, list_values_properties_addressPrefixes)\n| extend ipv4_match = ipv4_is_in_any_range(IPAddress, list_values_properties_addressPrefixes)\n| where ipv4_match or ipv6_match \n// Limit to where the user is external to the tenant\n| where HomeTenantId != ResourceTenantId\n// Further limit it to just access to the current tenant (you can drop this if you wanted to look elsewhere as well but it helps reduce FPs)\n| where ResourceTenantId == AADTenantId\n| summarize FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated), make_set(ResourceDisplayName) by UserPrincipalName, IPAddress, UserAgent, Location, HomeTenantId, ResourceTenantId, UserId\n| extend AccountName = split(UserPrincipalName, \"@\")[0]\n| extend UPNSuffix = split(UserPrincipalName, \"@\")[1]\n", + "queryFrequency": "PT1H", + "queryPeriod": "PT1H", "severity": "Medium", "suppressionDuration": "PT1H", "suppressionEnabled": false, @@ -7025,47 +6045,62 @@ "status": "Available", "requiredDataConnectors": [ { + "connectorId": "AzureActiveDirectory", "dataTypes": [ "SigninLogs" - ], - "connectorId": "AzureActiveDirectory" - }, - { - "dataTypes": [ - "AADNonInteractiveUserSignInLogs" - ], - "connectorId": "AzureActiveDirectory" + ] } ], "tactics": [ - "CredentialAccess" + "InitialAccess" ], "techniques": [ - "T1110" + "T1199" ], "entityMappings": [ { - "entityType": "IP", "fieldMappings": [ { - "identifier": "Address", - "columnName": "IPAddress" + "columnName": "AccountName", + "identifier": "Name" + }, + { + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" + }, + { + "columnName": "UserId", + "identifier": "AadUserId" } - ] + ], + "entityType": "Account" + }, + { + "fieldMappings": [ + { + "columnName": "IPAddress", + "identifier": "Address" + } + ], + "entityType": "IP" } - ] + ], + "alertDetailsOverride": { + "alertDisplayNameFormat": "Azure Portal sign in by {{UserPrincipalName}} from another Azure Tenant with IP Address {{IPAddress}}", + "alertDescriptionFormat": "This query looks for successful sign in attempts to the Azure Portal where the user who is signing in from another Azure tenant,\nand the IP address the login attempt is from is an Azure IP. A threat actor who compromises an Azure tenant may look\nto pivot to other tenants leveraging cross-tenant delegated access in this manner.\nIn this instance {{UserPrincipalName}} logged in at {{FirstSeen}} from IP Address {{IPAddress}}.\n" + } } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId50'),'/'))))]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId10'),'/'))))]", "properties": { - "description": "Azure Active Directory Analytics Rule 50", - "parentId": "[variables('analyticRuleId50')]", - "contentId": "[variables('_analyticRulecontentId50')]", + "description": "Azure Active Directory Analytics Rule 10", + "parentId": "[variables('analyticRuleId10')]", + "contentId": "[variables('_analyticRulecontentId10')]", "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion50')]", + "version": "[variables('analyticRuleVersion10')]", "source": { "kind": "Solution", "name": "Azure Active Directory", @@ -7090,43 +6125,43 @@ "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId50')]", + "contentId": "[variables('_analyticRulecontentId10')]", "contentKind": "AnalyticsRule", - "displayName": "Password spray attack against Azure AD application", - "contentProductId": "[variables('_analyticRulecontentProductId50')]", - "id": "[variables('_analyticRulecontentProductId50')]", - "version": "[variables('analyticRuleVersion50')]" + "displayName": "Azure Portal sign in from another Azure Tenant", + "contentProductId": "[variables('_analyticRulecontentProductId10')]", + "id": "[variables('_analyticRulecontentProductId10')]", + "version": "[variables('analyticRuleVersion10')]" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName51')]", + "name": "[variables('analyticRuleTemplateSpecName11')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "SuccessThenFail_DiffIP_SameUserandApp_AnalyticalRules Analytics Rule with template version 3.0.4", + "description": "Brute Force Attack against GitHub Account_AnalyticalRules Analytics Rule with template version 3.0.5", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion51')]", + "contentVersion": "[variables('analyticRuleVersion11')]", "parameters": {}, "variables": {}, "resources": [ { "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId51')]", + "name": "[variables('analyticRulecontentId11')]", "apiVersion": "2022-04-01-preview", "kind": "Scheduled", "location": "[parameters('workspace-location')]", "properties": { - "description": "Identifies when a user account successfully logs onto an Azure App from one IP and within 10 mins failed to logon to the same App via a different IP (may indicate a malicious attempt at password guessing with known account). UEBA added for context.", - "displayName": "Successful logon from IP and failure from a different IP", + "description": "Attackers who are trying to guess your users' passwords or use brute-force methods to get in. If your organization is using SSO with Azure Active Directory, authentication logs to GitHub.com will be generated. Using the following query can help you identify a sudden increase in failed logon attempt of users.", + "displayName": "Brute Force Attack against GitHub Account", "enabled": false, - "query": "let riskScoreCutoff = 20; //Adjust this based on volume of results\nlet logonDiff = 10m; let aadFunc = (tableName:string){ table(tableName)\n| where ResultType == \"0\"\n| where AppDisplayName !in (\"Office 365 Exchange Online\", \"Skype for Business Online\") // To remove false-positives, add more Apps to this array\n// ---------- Fix for SuccessBlock to also consider IPv6\n| extend SuccessIPv6Block = strcat(split(IPAddress, \":\")[0], \":\", split(IPAddress, \":\")[1], \":\", split(IPAddress, \":\")[2], \":\", split(IPAddress, \":\")[3])\n| extend SuccessIPv4Block = strcat(split(IPAddress, \".\")[0], \".\", split(IPAddress, \".\")[1])\n// ------------------\n| project SuccessLogonTime = TimeGenerated, UserPrincipalName, SuccessIPAddress = IPAddress, SuccessLocation = Location, AppDisplayName, SuccessIPBlock = iff(IPAddress contains \":\", strcat(split(IPAddress, \":\")[0], \":\", split(IPAddress, \":\")[1]), strcat(split(IPAddress, \".\")[0], \".\", split(IPAddress, \".\")[1])), Type\n| join kind= inner (\n table(tableName)\n | where ResultType !in (\"0\", \"50140\")\n | where ResultDescription !~ \"Other\"\n | where AppDisplayName !in (\"Office 365 Exchange Online\", \"Skype for Business Online\")\n | project FailedLogonTime = TimeGenerated, UserPrincipalName, FailedIPAddress = IPAddress, FailedLocation = Location, AppDisplayName, ResultType, ResultDescription, Type \n) on UserPrincipalName, AppDisplayName\n| where SuccessLogonTime < FailedLogonTime and FailedLogonTime - SuccessLogonTime <= logonDiff and FailedIPAddress !startswith SuccessIPBlock\n| summarize FailedLogonTime = max(FailedLogonTime), SuccessLogonTime = max(SuccessLogonTime) by UserPrincipalName, SuccessIPAddress, SuccessLocation, AppDisplayName, FailedIPAddress, FailedLocation, ResultType, ResultDescription, Type\n| extend timestamp = SuccessLogonTime\n| extend UserPrincipalName = tolower(UserPrincipalName)};\nlet aadSignin = aadFunc(\"SigninLogs\");\nlet aadNonInt = aadFunc(\"AADNonInteractiveUserSignInLogs\");\nunion isfuzzy=true aadSignin, aadNonInt\n| extend Name = tostring(split(UserPrincipalName,'@',0)[0]), UPNSuffix = tostring(split(UserPrincipalName,'@',1)[0])\n// UEBA context below - make sure you have these 2 datatypes, otherwise the query will not work. If so, comment all that is below.\n| join kind=leftouter (\n IdentityInfo\n | summarize LatestReportTime = arg_max(TimeGenerated, *) by AccountUPN\n | extend BlastRadiusInt = iif(BlastRadius == \"High\", 1, 0)\n | project AccountUPN, Tags, JobTitle, GroupMembership, AssignedRoles, UserType, IsAccountEnabled, BlastRadiusInt\n | summarize\n Tags = make_set(Tags, 1000),\n GroupMembership = make_set(GroupMembership, 1000),\n AssignedRoles = make_set(AssignedRoles, 1000),\n BlastRadiusInt = sum(BlastRadiusInt),\n UserType = make_set(UserType, 1000),\n UserAccountControl = make_set(UserType, 1000)\n by AccountUPN\n | extend UserPrincipalName=tolower(AccountUPN)\n) on UserPrincipalName\n| join kind=leftouter (\n BehaviorAnalytics\n | where ActivityType in (\"FailedLogOn\", \"LogOn\")\n | where isnotempty(SourceIPAddress)\n | project UsersInsights, DevicesInsights, ActivityInsights, InvestigationPriority, SourceIPAddress\n | project-rename FailedIPAddress = SourceIPAddress\n | summarize\n UsersInsights = make_set(UsersInsights, 1000),\n DevicesInsights = make_set(DevicesInsights, 1000),\n IPInvestigationPriority = sum(InvestigationPriority)\n by FailedIPAddress)\non FailedIPAddress\n| extend UEBARiskScore = BlastRadiusInt + IPInvestigationPriority\n| where UEBARiskScore > riskScoreCutoff\n| sort by UEBARiskScore desc \n", - "queryFrequency": "P1D", - "queryPeriod": "P1D", + "query": "let LearningPeriod = 7d;\nlet BinTime = 1h;\nlet RunTime = 1h;\nlet StartTime = 1h; \nlet sensitivity = 2.5;\nlet EndRunTime = StartTime - RunTime;\nlet EndLearningTime = StartTime + LearningPeriod;\nlet aadFunc = (tableName:string){\ntable(tableName) \n| where TimeGenerated between (ago(EndLearningTime) .. ago(EndRunTime))\n| where AppDisplayName =~ \"GitHub.com\"\n| where ResultType != 0\n| make-series FailedLogins = count() on TimeGenerated from ago(LearningPeriod) to ago(EndRunTime) step BinTime by UserPrincipalName, Type\n| extend (Anomalies, Score, Baseline) = series_decompose_anomalies(FailedLogins, sensitivity, -1, 'linefit')\n| mv-expand FailedLogins to typeof(double), TimeGenerated to typeof(datetime), Anomalies to typeof(double), Score to typeof(double), Baseline to typeof(long) \n| where TimeGenerated >= ago(RunTime)\n| where Anomalies > 0 and Baseline > 0\n| join kind=inner (\n table(tableName) \n | where TimeGenerated between (ago(StartTime) .. ago(EndRunTime))\n | where AppDisplayName =~ \"GitHub.com\"\n | where ResultType != 0\n | summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), IPAddresses = make_set(IPAddress,100), Locations = make_set(LocationDetails,20), Devices = make_set(DeviceDetail,20) by UserPrincipalName \n ) on UserPrincipalName\n| extend timestamp = TimeGenerated, Name = tostring(split(UserPrincipalName,'@',0)[0]), UPNSuffix = tostring(split(UserPrincipalName,'@',1)[0])\n};\nlet aadSignin = aadFunc(\"SigninLogs\");\nlet aadNonInt = aadFunc(\"AADNonInteractiveUserSignInLogs\");\nunion isfuzzy=true aadSignin, aadNonInt\n", + "queryFrequency": "PT1H", + "queryPeriod": "P7D", "severity": "Medium", "suppressionDuration": "PT1H", "suppressionEnabled": false, @@ -7135,69 +6170,37 @@ "status": "Available", "requiredDataConnectors": [ { + "connectorId": "AzureActiveDirectory", "dataTypes": [ "SigninLogs" - ], - "connectorId": "AzureActiveDirectory" + ] }, { + "connectorId": "AzureActiveDirectory", "dataTypes": [ "AADNonInteractiveUserSignInLogs" - ], - "connectorId": "AzureActiveDirectory" - }, - { - "dataTypes": [ - "BehaviorAnalytics" - ], - "connectorId": "BehaviorAnalytics" - }, - { - "dataTypes": [ - "IdentityInfo" - ], - "connectorId": "IdentityInfo" + ] } ], "tactics": [ - "CredentialAccess", - "InitialAccess" + "CredentialAccess" ], "techniques": [ - "T1110", - "T1078" + "T1110" ], "entityMappings": [ { - "entityType": "Account", "fieldMappings": [ { - "identifier": "Name", - "columnName": "Name" + "columnName": "Name", + "identifier": "Name" }, { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" - } - ] - }, - { - "entityType": "IP", - "fieldMappings": [ - { - "identifier": "Address", - "columnName": "SuccessIPAddress" - } - ] - }, - { - "entityType": "IP", - "fieldMappings": [ - { - "identifier": "Address", - "columnName": "FailedIPAddress" + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" } - ] + ], + "entityType": "Account" } ] } @@ -7205,13 +6208,13 @@ { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId51'),'/'))))]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId11'),'/'))))]", "properties": { - "description": "Azure Active Directory Analytics Rule 51", - "parentId": "[variables('analyticRuleId51')]", - "contentId": "[variables('_analyticRulecontentId51')]", + "description": "Azure Active Directory Analytics Rule 11", + "parentId": "[variables('analyticRuleId11')]", + "contentId": "[variables('_analyticRulecontentId11')]", "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion51')]", + "version": "[variables('analyticRuleVersion11')]", "source": { "kind": "Solution", "name": "Azure Active Directory", @@ -7236,41 +6239,41 @@ "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId51')]", + "contentId": "[variables('_analyticRulecontentId11')]", "contentKind": "AnalyticsRule", - "displayName": "Successful logon from IP and failure from a different IP", - "contentProductId": "[variables('_analyticRulecontentProductId51')]", - "id": "[variables('_analyticRulecontentProductId51')]", - "version": "[variables('analyticRuleVersion51')]" + "displayName": "Brute Force Attack against GitHub Account", + "contentProductId": "[variables('_analyticRulecontentProductId11')]", + "id": "[variables('_analyticRulecontentProductId11')]", + "version": "[variables('analyticRuleVersion11')]" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName52')]", + "name": "[variables('analyticRuleTemplateSpecName12')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "SuspiciousAADJoinedDeviceUpdate_AnalyticalRules Analytics Rule with template version 3.0.4", + "description": "BruteForceCloudPC_AnalyticalRules Analytics Rule with template version 3.0.5", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion52')]", + "contentVersion": "[variables('analyticRuleVersion12')]", "parameters": {}, "variables": {}, "resources": [ { "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId52')]", + "name": "[variables('analyticRulecontentId12')]", "apiVersion": "2022-04-01-preview", "kind": "Scheduled", "location": "[parameters('workspace-location')]", "properties": { - "description": "This query looks for suspicious updates to an Azure AD joined device where the device name is changed and the device falls out of compliance.\nThis could occur when a threat actor updates the details of an Autopilot provisioned device using a stolen device ticket, in order to access certificates and keys.\nRef: https://dirkjanm.io/assets/raw/Insomnihack%20Breaking%20and%20fixing%20Azure%20AD%20device%20identity%20security.pdf", - "displayName": "Suspicious AAD Joined Device Update", + "description": "Identifies evidence of brute force activity against a Windows 365 Cloud PC by highlighting multiple authentication failures and by a successful authentication within a given time window.", + "displayName": "Brute force attack against a Cloud PC", "enabled": false, - "query": "AuditLogs\n| where OperationName =~ \"Update device\"\n| mv-apply TargetResource=TargetResources on (\n where TargetResource.type =~ \"Device\"\n | extend ModifiedProperties = TargetResource.modifiedProperties\n | extend DeviceId = TargetResource.id)\n| mv-apply Prop=ModifiedProperties on ( \n where Prop.displayName =~ \"CloudDisplayName\"\n | extend OldName = Prop.oldValue \n | extend NewName = Prop.newValue)\n| mv-apply Prop=ModifiedProperties on ( \n where Prop.displayName =~ \"IsCompliant\"\n | extend OldComplianceState = Prop.oldValue \n | extend NewComplianceState = Prop.newValue)\n| mv-apply Prop=ModifiedProperties on ( \n where Prop.displayName =~ \"TargetId.DeviceTrustType\"\n | extend OldTrustType = Prop.oldValue \n | extend NewTrustType = Prop.newValue)\n| mv-apply Prop=ModifiedProperties on ( \n where Prop.displayName =~ \"Included Updated Properties\" \n | extend UpdatedProperties = Prop.newValue)\n| extend OldDeviceName = tostring(parse_json(tostring(OldName))[0])\n| extend NewDeviceName = tostring(parse_json(tostring(NewName))[0])\n| extend OldComplianceState = tostring(parse_json(tostring(OldComplianceState))[0])\n| extend NewComplianceState = tostring(parse_json(tostring(NewComplianceState))[0])\n| extend InitiatedByUser = tostring(iff(isnotempty(InitiatedBy.user.userPrincipalName),InitiatedBy.user.userPrincipalName, InitiatedBy.app.displayName))\n| extend UpdatedPropertiesCount = array_length(split(UpdatedProperties, ','))\n| where OldDeviceName != NewDeviceName\n| where OldComplianceState =~ 'true' and NewComplianceState =~ 'false'\n// Most common is transferring from AAD Registered to AAD Joined - we just want AAD Joined devices\n| where NewTrustType == '\"AzureAd\"' and OldTrustType != '\"Workplace\"'\n// We can modify this value to tune FPs - more properties changed about the device beyond its name the more suspicious it could be\n| where UpdatedPropertiesCount > 1\n| project-reorder TimeGenerated, DeviceId, NewDeviceName, OldDeviceName, NewComplianceState, InitiatedByUser, AADOperationType, OldTrustType, NewTrustType, UpdatedProperties, UpdatedPropertiesCount\n", + "query": "let authenticationWindow = 20m;\nlet sensitivity = 2.5;\nSigninLogs\n| where AppDisplayName =~ \"Windows Sign In\"\n| extend FailureOrSuccess = iff(ResultType in (\"0\", \"50125\", \"50140\", \"70043\", \"70044\"), \"Success\", \"Failure\")\n| summarize FailureCount = countif(FailureOrSuccess==\"Failure\"), SuccessCount = countif(FailureOrSuccess==\"Success\"), IPAddresses = make_set(IPAddress,1000)\n by bin(TimeGenerated, authenticationWindow), UserDisplayName, UserPrincipalName\n| extend FailureSuccessDiff = FailureCount - SuccessCount\n| where FailureSuccessDiff > 0\n| summarize Diff = make_list(FailureSuccessDiff, 10000), TimeStamp = make_list(TimeGenerated, 10000) by UserDisplayName, UserPrincipalName//, tostring(IPAddresses)\n| extend (Anomalies, Score, Baseline) = series_decompose_anomalies(Diff, sensitivity, -1, 'linefit') \n| mv-expand Diff to typeof(double), TimeStamp to typeof(datetime), Anomalies to typeof(double), Score to typeof(double), Baseline to typeof(long)\n| where Anomalies > 0\n| summarize by UserDisplayName, UserPrincipalName\n| join kind=leftouter (\n SigninLogs\n | where AppDisplayName =~ \"Windows Sign In\"\n | extend OS = DeviceDetail.operatingSystem, Browser = DeviceDetail.browser\n | extend StatusCode = tostring(Status.errorCode), StatusDetails = tostring(Status.additionalDetails)\n | extend State = tostring(LocationDetails.state), City = tostring(LocationDetails.city)\n | summarize StartTime = min(TimeGenerated), \n EndTime = max(TimeGenerated), \n IPAddress = make_set(IPAddress,100), \n OS = make_set(OS,20), \n Browser = make_set(Browser,20), \n City = make_set(City,100), \n ResultType = make_set(ResultType,100)\n by UserDisplayName, UserPrincipalName\n ) on UserDisplayName, UserPrincipalName\n| extend IPAddressFirst = IPAddress[0]\n| extend timestamp = StartTime, Name = tostring(split(UserPrincipalName,'@',0)[0]), UPNSuffix = tostring(split(UserPrincipalName,'@',1)[0])\n", "queryFrequency": "P1D", "queryPeriod": "P1D", "severity": "Medium", @@ -7281,72 +6284,54 @@ "status": "Available", "requiredDataConnectors": [ { + "connectorId": "AzureActiveDirectory", "dataTypes": [ - "AuditLogs" - ], - "connectorId": "AzureActiveDirectory" + "SigninLogs" + ] } ], "tactics": [ "CredentialAccess" ], "techniques": [ - "T1528" + "T1110" ], "entityMappings": [ { - "entityType": "Host", - "fieldMappings": [ - { - "identifier": "HostName", - "columnName": "NewDeviceName" - } - ] - }, - { - "entityType": "Host", "fieldMappings": [ { - "identifier": "HostName", - "columnName": "OldDeviceName" - } - ] - }, - { - "entityType": "Host", - "fieldMappings": [ + "columnName": "Name", + "identifier": "Name" + }, { - "identifier": "AzureID", - "columnName": "DeviceId" + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" } - ] + ], + "entityType": "Account" }, { - "entityType": "Account", "fieldMappings": [ { - "identifier": "AadUserId", - "columnName": "InitiatedByUser" + "columnName": "IPAddressFirst", + "identifier": "Address" } - ] + ], + "entityType": "IP" } - ], - "alertDetailsOverride": { - "alertDescriptionFormat": "This query looks for suspicious updates to an Azure AD joined device where the device name is changed and the device falls out of compliance.\nIn this case {{OldDeviceName}} was renamed to {{NewDeviceName}} and {{UpdatedPropertiesCount}} properties were changed.\nThis could occur when a threat actor steals a Device ticket from an Autopilot provisioned device and uses it to AAD Join a new device.\nRef: https://dirkjanm.io/assets/raw/Insomnihack%20Breaking%20and%20fixing%20Azure%20AD%20device%20identity%20security.pdf\n", - "alertDisplayNameFormat": "Suspicious AAD Joined Device Update {{OldDeviceName}} renamed to {{NewDeviceName}} and {{UpdatedPropertiesCount}} properties changed" - } + ] } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId52'),'/'))))]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId12'),'/'))))]", "properties": { - "description": "Azure Active Directory Analytics Rule 52", - "parentId": "[variables('analyticRuleId52')]", - "contentId": "[variables('_analyticRulecontentId52')]", + "description": "Azure Active Directory Analytics Rule 12", + "parentId": "[variables('analyticRuleId12')]", + "contentId": "[variables('_analyticRulecontentId12')]", "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion52')]", + "version": "[variables('analyticRuleVersion12')]", "source": { "kind": "Solution", "name": "Azure Active Directory", @@ -7371,44 +6356,44 @@ "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId52')]", + "contentId": "[variables('_analyticRulecontentId12')]", "contentKind": "AnalyticsRule", - "displayName": "Suspicious AAD Joined Device Update", - "contentProductId": "[variables('_analyticRulecontentProductId52')]", - "id": "[variables('_analyticRulecontentProductId52')]", - "version": "[variables('analyticRuleVersion52')]" + "displayName": "Brute force attack against a Cloud PC", + "contentProductId": "[variables('_analyticRulecontentProductId12')]", + "id": "[variables('_analyticRulecontentProductId12')]", + "version": "[variables('analyticRuleVersion12')]" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName53')]", + "name": "[variables('analyticRuleTemplateSpecName13')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "SuspiciousOAuthApp_OfflineAccess_AnalyticalRules Analytics Rule with template version 3.0.4", + "description": "BulkChangestoPrivilegedAccountPermissions_AnalyticalRules Analytics Rule with template version 3.0.5", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion53')]", + "contentVersion": "[variables('analyticRuleVersion13')]", "parameters": {}, "variables": {}, "resources": [ { "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId53')]", + "name": "[variables('analyticRulecontentId13')]", "apiVersion": "2022-04-01-preview", "kind": "Scheduled", "location": "[parameters('workspace-location')]", "properties": { - "description": "This will alert when a user consents to provide a previously-unknown Azure application with offline access via OAuth.\nOffline access will provide the Azure App with access to the listed resources without requiring two-factor authentication.\nConsent to applications with offline access and read capabilities should be rare, especially as the knownApplications list is expanded. Public contributions to expand this filter are welcome!\nFor further information on AuditLogs please see https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-audit-activities.", - "displayName": "Suspicious application consent for offline access", + "description": "Identifies when changes to multiple users permissions are changed at once. Investigate immediately if not a planned change. This setting could enable an attacker access to Azure subscriptions in your environment.\nRef : https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-privileged-identity-management", + "displayName": "Bulk Changes to Privileged Account Permissions", "enabled": false, - "query": "let detectionTime = 1d;\nlet joinLookback = 14d;\nAuditLogs\n| where TimeGenerated > ago(detectionTime)\n| where LoggedByService =~ \"Core Directory\"\n| where Category =~ \"ApplicationManagement\"\n| where OperationName =~ \"Consent to application\"\n| where TargetResources has \"offline\"\n| mv-apply TargetResource=TargetResources on \n (\n where TargetResource.type =~ \"ServicePrincipal\"\n | extend ModifiedProperties = TargetResource.modifiedProperties,\n AppDisplayName = tostring(TargetResource.displayName),\n AppClientId = tolower(tostring(TargetResource.id))\n )\n| where AppClientId !in ((externaldata(knownAppClientId:string, knownAppDisplayName:string)[@\"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Sample%20Data/Feeds/Microsoft.OAuth.KnownApplications.csv\"] with (format=\"csv\")))\n| mv-apply Properties=ModifiedProperties on \n (\n where Properties.displayName =~ \"ConsentAction.Permissions\"\n | extend ConsentFull = tostring(Properties.newValue)\n | extend ConsentFull = trim(@'\"',tostring(ConsentFull))\n )\n| parse ConsentFull with * \"ConsentType: \" GrantConsentType \", Scope: \" GrantScope1 \"]\" *\n| where ConsentFull has \"offline_access\" and ConsentFull has_any (\"Files.Read\", \"Mail.Read\", \"Notes.Read\", \"ChannelMessage.Read\", \"Chat.Read\", \"TeamsActivity.Read\", \"Group.Read\", \"EWS.AccessAsUser.All\", \"EAS.AccessAsUser.All\")\n| where GrantConsentType != \"AllPrincipals\" // NOTE: we are ignoring if OAuth application was granted to all users via an admin - but admin due diligence should be audited occasionally\n| extend GrantIpAddress = tostring(iff(isnotempty(InitiatedBy.user.ipAddress), InitiatedBy.user.ipAddress, InitiatedBy.app.ipAddress))\n| extend GrantInitiatedBy = tostring(iff(isnotempty(InitiatedBy.user.userPrincipalName),InitiatedBy.user.userPrincipalName, InitiatedBy.app.displayName))\n| extend GrantUserAgent = tostring(iff(AdditionalDetails[0].key =~ \"User-Agent\", AdditionalDetails[0].value, \"\"))\n| project TimeGenerated, GrantConsentType, GrantScope1, GrantInitiatedBy, AppDisplayName, GrantIpAddress, GrantUserAgent, AppClientId, OperationName, ConsentFull, CorrelationId\n| join kind = leftouter (AuditLogs\n| where TimeGenerated > ago(joinLookback)\n| where LoggedByService =~ \"Core Directory\"\n| where Category =~ \"ApplicationManagement\"\n| where OperationName =~ \"Add service principal\"\n| mv-apply TargetResource=TargetResources on \n (\n where TargetResource.type =~ \"ServicePrincipal\"\n | extend ModifiedProperties = TargetResource.modifiedProperties,\n AppClientId = tolower(TargetResource.id)\n )\n| mv-apply ModifiedProperties=TargetResource.modifiedProperties on \n (\n where ModifiedProperties.displayName =~ \"AppAddress\" and ModifiedProperties.newValue has \"AddressType\"\n | extend AppReplyURLs = ModifiedProperties.newValue\n )\n | distinct AppClientId, tostring(AppReplyURLs)\n)\non AppClientId\n| join kind = innerunique (AuditLogs\n| where TimeGenerated > ago(joinLookback)\n| where LoggedByService =~ \"Core Directory\"\n| where Category =~ \"ApplicationManagement\"\n| where OperationName =~ \"Add OAuth2PermissionGrant\" or OperationName =~ \"Add delegated permission grant\"\n | mv-apply TargetResource=TargetResources on \n (\n where TargetResource.type =~ \"ServicePrincipal\" and array_length(TargetResource.modifiedProperties) > 0 and isnotnull(TargetResource.displayName)\n | extend GrantAuthentication = tostring(TargetResource.displayName)\n )\n| extend GrantOperation = OperationName\n| project GrantAuthentication, GrantOperation, CorrelationId\n) on CorrelationId\n| project TimeGenerated, GrantConsentType, GrantScope1, GrantInitiatedBy, AppDisplayName, AppReplyURLs, GrantIpAddress, GrantUserAgent, AppClientId, GrantAuthentication, OperationName, GrantOperation, CorrelationId, ConsentFull\n| extend timestamp = TimeGenerated, Name = tostring(split(GrantInitiatedBy,'@',0)[0]), UPNSuffix = tostring(split(GrantInitiatedBy,'@',1)[0])\n", - "queryFrequency": "P1D", - "queryPeriod": "P14D", - "severity": "Low", + "query": "let AdminRecords = AuditLogs\n| where Category =~ \"RoleManagement\"\n| where ActivityDisplayName has_any (\"Add eligible member to role\", \"Add member to role\")\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"User\"\n | extend Target = tostring(TargetResource.userPrincipalName),\n props = TargetResource.modifiedProperties\n )\n| mv-apply Property = props on \n (\n where Property.displayName =~ \"Role.DisplayName\"\n | extend RoleName = trim('\"',tostring(Property.newValue))\n )\n| where RoleName contains \"Admin\";\nAdminRecords\n| summarize dcount(Target) by bin(TimeGenerated, 1h)\n| where dcount_Target > 9\n| join kind=rightsemi (\n AdminRecords\n | extend TimeWindow = bin(TimeGenerated, 1h)\n) on $left.TimeGenerated == $right.TimeWindow\n| extend InitiatedByUser = iff(isnotempty(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.user.userPrincipalName), \"\")\n| extend TargetName = tostring(split(Target,'@',0)[0]), TargetUPNSuffix = tostring(split(Target,'@',1)[0]),\n InitiatedByUserName = tostring(split(InitiatedByUser,'@',0)[0]), InitiatedByUserUPNSuffix = tostring(split(InitiatedByUser,'@',1)[0])\n", + "queryFrequency": "PT2H", + "queryPeriod": "PT2H", + "severity": "High", "suppressionDuration": "PT1H", "suppressionEnabled": false, "triggerOperator": "GreaterThan", @@ -7416,54 +6401,62 @@ "status": "Available", "requiredDataConnectors": [ { + "connectorId": "AzureActiveDirectory", "dataTypes": [ "AuditLogs" - ], - "connectorId": "AzureActiveDirectory" + ] } ], "tactics": [ - "CredentialAccess" + "PrivilegeEscalation" ], "techniques": [ - "T1528" + "T1078" ], "entityMappings": [ { - "entityType": "Account", "fieldMappings": [ { - "identifier": "Name", - "columnName": "Name" + "columnName": "TargetName", + "identifier": "Name" }, { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" + "columnName": "TargetUPNSuffix", + "identifier": "UPNSuffix" } - ] + ], + "entityType": "Account" }, { - "entityType": "IP", "fieldMappings": [ { - "identifier": "Address", - "columnName": "GrantIpAddress" + "columnName": "InitiatedByUserName", + "identifier": "Name" + }, + { + "columnName": "InitiatedByUserUPNSuffix", + "identifier": "UPNSuffix" } - ] + ], + "entityType": "Account" } - ] + ], + "customDetails": { + "InitiatedByUser": "InitiatedByUser", + "TargetUser": "Target" + } } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId53'),'/'))))]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId13'),'/'))))]", "properties": { - "description": "Azure Active Directory Analytics Rule 53", - "parentId": "[variables('analyticRuleId53')]", - "contentId": "[variables('_analyticRulecontentId53')]", + "description": "Azure Active Directory Analytics Rule 13", + "parentId": "[variables('analyticRuleId13')]", + "contentId": "[variables('_analyticRulecontentId13')]", "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion53')]", + "version": "[variables('analyticRuleVersion13')]", "source": { "kind": "Solution", "name": "Azure Active Directory", @@ -7488,43 +6481,43 @@ "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId53')]", + "contentId": "[variables('_analyticRulecontentId13')]", "contentKind": "AnalyticsRule", - "displayName": "Suspicious application consent for offline access", - "contentProductId": "[variables('_analyticRulecontentProductId53')]", - "id": "[variables('_analyticRulecontentProductId53')]", - "version": "[variables('analyticRuleVersion53')]" + "displayName": "Bulk Changes to Privileged Account Permissions", + "contentProductId": "[variables('_analyticRulecontentProductId13')]", + "id": "[variables('_analyticRulecontentProductId13')]", + "version": "[variables('analyticRuleVersion13')]" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName54')]", + "name": "[variables('analyticRuleTemplateSpecName14')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "SuspiciousServicePrincipalcreationactivity_AnalyticalRules Analytics Rule with template version 3.0.4", + "description": "BypassCondAccessRule_AnalyticalRules Analytics Rule with template version 3.0.5", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion54')]", + "contentVersion": "[variables('analyticRuleVersion14')]", "parameters": {}, "variables": {}, "resources": [ { "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId54')]", + "name": "[variables('analyticRulecontentId14')]", "apiVersion": "2022-04-01-preview", "kind": "Scheduled", "location": "[parameters('workspace-location')]", "properties": { - "description": "This alert will detect creation of an SPN, permissions granted, credentials created, activity and deletion of the SPN in a time frame (default 10 minutes)", - "displayName": "Suspicious Service Principal creation activity", + "description": "Identifies an attempt to Bypass conditional access rule(s) in Azure Active Directory.\nThe ConditionalAccessStatus column value details if there was an attempt to bypass Conditional Access\nor if the Conditional access rule was not satisfied (ConditionalAccessStatus == 1).\nReferences:\nhttps://docs.microsoft.com/azure/active-directory/conditional-access/overview\nhttps://docs.microsoft.com/azure/active-directory/reports-monitoring/concept-sign-ins\nhttps://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-sign-ins-error-codes\nConditionalAccessStatus == 0 // Success\nConditionalAccessStatus == 1 // Failure\nConditionalAccessStatus == 2 // Not Applied\nConditionalAccessStatus == 3 // unknown", + "displayName": "Attempt to bypass conditional access rule in Azure AD", "enabled": false, - "query": "let queryfrequency = 1h;\nlet wait_for_deletion = 10m;\nlet account_created =\n AuditLogs \n | where ActivityDisplayName == \"Add service principal\"\n | where Result == \"success\"\n | extend AppID = tostring(AdditionalDetails[1].value)\n | extend creationTime = ActivityDateTime\n | extend userPrincipalName_creator = tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName)\n | extend ipAddress_creator = tostring(parse_json(tostring(InitiatedBy.user)).ipAddress);\nlet account_activity =\n AADServicePrincipalSignInLogs\n | extend Activities = pack(\"ActivityTime\", TimeGenerated ,\"IpAddress\", IPAddress, \"ResourceDisplayName\", ResourceDisplayName)\n | extend AppID = AppId\n | summarize make_list(Activities) by AppID;\nlet account_deleted =\n AuditLogs \n | where OperationName == \"Remove service principal\"\n | where Result == \"success\"\n | extend AppID = tostring(AdditionalDetails[1].value)\n | extend deletionTime = ActivityDateTime\n | extend userPrincipalName_deleter = tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName)\n | extend ipAddress_deleter = tostring(parse_json(tostring(InitiatedBy.user)).ipAddress);\nlet account_credentials =\n AuditLogs\n | where OperationName has_all (\"Update application\", \"Certificates and secrets management\")\n | where Result == \"success\"\n | extend AppID = tostring(AdditionalDetails[1].value)\n | extend credentialCreationTime = ActivityDateTime;\nlet roles_assigned =\n AuditLogs\n | where ActivityDisplayName == \"Add app role assignment to service principal\"\n | extend AppID = tostring(TargetResources[1].displayName)\n | extend AssignedRole = iff(tostring(parse_json(tostring(TargetResources[0].modifiedProperties))[1].displayName)==\"AppRole.Value\", tostring(parse_json(tostring(parse_json(tostring(TargetResources[0].modifiedProperties))[1].newValue))),\"\")\n | extend AssignedRoles = pack(\"Role\", AssignedRole)\n | summarize make_list(AssignedRoles) by AppID;\naccount_created\n| where TimeGenerated between (ago(wait_for_deletion+queryfrequency)..ago(wait_for_deletion))\n| join kind= inner (account_activity) on AppID\n| join kind= inner (account_deleted) on AppID\n| join kind= inner (account_credentials) on AppID\n| join kind= inner (roles_assigned) on AppID\n| where deletionTime - creationTime between (time(0s)..wait_for_deletion)\n| extend AliveTime = deletionTime - creationTime\n| project AADTenantId, AppID, creationTime, deletionTime, userPrincipalName_creator, userPrincipalName_deleter, ipAddress_creator, ipAddress_deleter, list_Activities, list_AssignedRoles, AliveTime\n", - "queryFrequency": "PT1H", - "queryPeriod": "PT70M", + "query": "let threshold = 1; // Modify this threshold value to reduce false positives based on your environment\nlet aadFunc = (tableName:string){\ntable(tableName)\n| where ConditionalAccessStatus == 1 or ConditionalAccessStatus =~ \"failure\"\n| mv-apply CAP = parse_json(ConditionalAccessPolicies) on (\n project ConditionalAccessPoliciesName = CAP.displayName, result = CAP.result\n | where result =~ \"failure\"\n)\n| extend DeviceDetail = todynamic(DeviceDetail), Status = todynamic(Status), LocationDetails = todynamic(LocationDetails)\n| extend OS = DeviceDetail.operatingSystem, Browser = DeviceDetail.browser\n| extend State = tostring(LocationDetails.state), City = tostring(LocationDetails.city), Region = tostring(LocationDetails.countryOrRegion)\n| extend StatusCode = tostring(Status.errorCode), StatusDetails = tostring(Status.additionalDetails)\n| extend Status = strcat(StatusCode, \": \", ResultDescription)\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), Status = make_list(Status,10), StatusDetails = make_list(StatusDetails,50), IPAddresses = make_list(IPAddress,100), IPAddressCount = dcount(IPAddress), CorrelationIds = make_list(CorrelationId,100), ConditionalAccessPoliciesName = make_list(ConditionalAccessPoliciesName,100)\nby UserPrincipalName, AppDisplayName, tostring(Browser), tostring(OS), City, State, Region, Type\n| where IPAddressCount > threshold and StatusDetails !has \"MFA successfully completed\"\n| mv-expand IPAddresses, Status, StatusDetails, CorrelationIds\n| extend Status = strcat(Status, \" \", StatusDetails)\n| summarize IPAddresses = make_set(IPAddresses,100), Status = make_set(Status,10), CorrelationIds = make_set(CorrelationIds,100), ConditionalAccessPoliciesName = make_set(ConditionalAccessPoliciesName,100)\nby StartTime, EndTime, UserPrincipalName, AppDisplayName, tostring(Browser), tostring(OS), City, State, Region, IPAddressCount, Type\n| extend timestamp = StartTime, IPAddresses = tostring(IPAddresses), Name = tostring(split(UserPrincipalName,'@',0)[0]), UPNSuffix = tostring(split(UserPrincipalName,'@',1)[0])\n};\nlet aadSignin = aadFunc(\"SigninLogs\");\nlet aadNonInt = aadFunc(\"AADNonInteractiveUserSignInLogs\");\nunion isfuzzy=true aadSignin, aadNonInt\n", + "queryFrequency": "P1D", + "queryPeriod": "P1D", "severity": "Low", "suppressionDuration": "PT1H", "suppressionEnabled": false, @@ -7533,58 +6526,48 @@ "status": "Available", "requiredDataConnectors": [ { + "connectorId": "AzureActiveDirectory", "dataTypes": [ - "AuditLogs", - "AADServicePrincipalSignInLogs" - ], - "connectorId": "AzureActiveDirectory" + "SigninLogs" + ] + }, + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "AADNonInteractiveUserSignInLogs" + ] } ], "tactics": [ - "CredentialAccess", - "PrivilegeEscalation", - "InitialAccess" + "InitialAccess", + "Persistence" ], "techniques": [ "T1078", - "T1528" + "T1098" ], "entityMappings": [ { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "FullName", - "columnName": "userPrincipalName_creator" - } - ] - }, - { - "entityType": "Account", "fieldMappings": [ { - "identifier": "FullName", - "columnName": "userPrincipalName_deleter" - } - ] - }, - { - "entityType": "IP", - "fieldMappings": [ + "columnName": "Name", + "identifier": "Name" + }, { - "identifier": "Address", - "columnName": "ipAddress_creator" + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" } - ] + ], + "entityType": "Account" }, { - "entityType": "IP", "fieldMappings": [ { - "identifier": "Address", - "columnName": "ipAddress_deleter" + "columnName": "IPAddresses", + "identifier": "Address" } - ] + ], + "entityType": "IP" } ] } @@ -7592,13 +6575,13 @@ { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId54'),'/'))))]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId14'),'/'))))]", "properties": { - "description": "Azure Active Directory Analytics Rule 54", - "parentId": "[variables('analyticRuleId54')]", - "contentId": "[variables('_analyticRulecontentId54')]", + "description": "Azure Active Directory Analytics Rule 14", + "parentId": "[variables('analyticRuleId14')]", + "contentId": "[variables('_analyticRulecontentId14')]", "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion54')]", + "version": "[variables('analyticRuleVersion14')]", "source": { "kind": "Solution", "name": "Azure Active Directory", @@ -7623,43 +6606,43 @@ "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId54')]", + "contentId": "[variables('_analyticRulecontentId14')]", "contentKind": "AnalyticsRule", - "displayName": "Suspicious Service Principal creation activity", - "contentProductId": "[variables('_analyticRulecontentProductId54')]", - "id": "[variables('_analyticRulecontentProductId54')]", - "version": "[variables('analyticRuleVersion54')]" + "displayName": "Attempt to bypass conditional access rule in Azure AD", + "contentProductId": "[variables('_analyticRulecontentProductId14')]", + "id": "[variables('_analyticRulecontentProductId14')]", + "version": "[variables('analyticRuleVersion14')]" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName55')]", + "name": "[variables('analyticRuleTemplateSpecName15')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "UnusualGuestActivity_AnalyticalRules Analytics Rule with template version 3.0.4", + "description": "CredentialAddedAfterAdminConsent_AnalyticalRules Analytics Rule with template version 3.0.5", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion55')]", + "contentVersion": "[variables('analyticRuleVersion15')]", "parameters": {}, "variables": {}, "resources": [ { "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId55')]", + "name": "[variables('analyticRulecontentId15')]", "apiVersion": "2022-04-01-preview", "kind": "Scheduled", "location": "[parameters('workspace-location')]", "properties": { - "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/", - "displayName": "External guest invitation followed by Azure AD PowerShell signin", + "description": "This query will identify instances where Service Principal credentials were added to an application by one user after the application was granted admin consent rights by another user.\n If a threat actor obtains access to an account with sufficient privileges and adds the alternate authentication material triggering this event, the threat actor can now authenticate as the Application or Service Principal using this credential.\n Additional information on OAuth Credential Grants can be found in RFC 6749 Section 4.4 or https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow.\n For further information on AuditLogs please see https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-audit-activities", + "displayName": "Credential added after admin consented to Application", "enabled": false, - "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", + "query": "let auditLookbackStart = 2d;\nlet auditLookbackEnd = 1d;\nAuditLogs\n| where TimeGenerated >= ago(auditLookbackStart)\n| where OperationName =~ \"Consent to application\" \n| where Result =~ \"success\"\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"ServicePrincipal\"\n | extend targetResourceName = tostring(TargetResource.displayName),\n targetResourceID = tostring(TargetResource.id),\n targetResourceType = tostring(TargetResource.type),\n targetModifiedProp = TargetResource.modifiedProperties\n )\n| mv-apply Property = targetModifiedProp on \n (\n where Property.displayName =~ \"ConsentContext.IsAdminConsent\"\n | extend isAdminConsent = trim(@'\"',tostring(Property.newValue))\n )\n| mv-apply Property = targetModifiedProp on \n (\n where Property.displayName =~ \"ConsentAction.Permissions\"\n | extend Consent_Permissions = trim(@'\"',tostring(Property.newValue))\n )\n| mv-apply Property = targetModifiedProp on \n (\n where Property.displayName =~ \"TargetId.ServicePrincipalNames\"\n | extend Consent_ServicePrincipalNames = tostring(extract_all(@\"([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})\",trim(@'\"',tostring(Property.newValue)))[0])\n )\n| extend Consent_InitiatingUserOrApp = iff(isnotempty(InitiatedBy.user.userPrincipalName),tostring(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.app.displayName))\n| extend Consent_InitiatingIpAddress = iff(isnotempty(InitiatedBy.user.ipAddress), tostring(InitiatedBy.user.ipAddress), tostring(InitiatedBy.app.ipAddress))\n| join ( \nAuditLogs\n| where TimeGenerated >= ago(auditLookbackEnd)\n| where OperationName =~ \"Add service principal credentials\"\n| where Result =~ \"success\"\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"ServicePrincipal\"\n | extend targetResourceName = tostring(TargetResource.displayName),\n targetResourceID = tostring(TargetResource.id),\n targetModifiedProp = TargetResource.modifiedProperties\n )\n| mv-apply Property = targetModifiedProp on \n (\n where Property.displayName =~ \"KeyDescription\"\n | extend Credential_KeyDescription = trim(@'\"',tostring(Property.newValue))\n )\n| mv-apply Property = targetModifiedProp on \n (\n where Property.displayName =~ \"Included Updated Properties\"\n | extend UpdatedProperties = trim(@'\"',tostring(Property.newValue))\n )\n| mv-apply Property = targetModifiedProp on \n (\n where Property.displayName =~ \"TargetId.ServicePrincipalNames\"\n | extend Credential_ServicePrincipalNames = tostring(extract_all(@\"([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})\",trim(@'\"',tostring(Property.newValue)))[0])\n )\n| extend Credential_InitiatingUserOrApp = iff(isnotempty(InitiatedBy.user.userPrincipalName),tostring(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.app.displayName))\n| extend Credential_InitiatingIpAddress = iff(isnotempty(InitiatedBy.user.ipAddress), tostring(InitiatedBy.user.ipAddress), tostring(InitiatedBy.app.ipAddress))\n) on targetResourceName, targetResourceID\n| extend TimeConsent = TimeGenerated, TimeCred = TimeGenerated1\n| where TimeConsent < TimeCred \n| project TimeConsent, TimeCred, Consent_InitiatingUserOrApp, Credential_InitiatingUserOrApp, targetResourceName, targetResourceType, isAdminConsent, Consent_ServicePrincipalNames, Credential_ServicePrincipalNames, Consent_Permissions, Credential_KeyDescription, Consent_InitiatingIpAddress, Credential_InitiatingIpAddress\n| extend timestamp = TimeConsent, Name = tostring(split(Credential_InitiatingUserOrApp,'@',0)[0]), UPNSuffix = tostring(split(Credential_InitiatingUserOrApp,'@',1)[0])\n", + "queryFrequency": "P1D", + "queryPeriod": "P2D", "severity": "Medium", "suppressionDuration": "PT1H", "suppressionEnabled": false, @@ -7668,63 +6651,37 @@ "status": "Available", "requiredDataConnectors": [ { + "connectorId": "AzureActiveDirectory", "dataTypes": [ "AuditLogs" - ], - "connectorId": "AzureActiveDirectory" - }, - { - "dataTypes": [ - "SigninLogs" - ], - "connectorId": "AzureActiveDirectory" + ] } ], "tactics": [ - "InitialAccess", - "Persistence", - "Discovery" - ], - "techniques": [ - "T1078", - "T1136", - "T1087" + "CredentialAccess" ], "entityMappings": [ { - "entityType": "Account", - "fieldMappings": [ - { - "identifier": "Name", - "columnName": "InvitedUserName" - }, - { - "identifier": "UPNSuffix", - "columnName": "InvitedUserUPNSuffix" - } - ] - }, - { - "entityType": "Account", "fieldMappings": [ { - "identifier": "Name", - "columnName": "InitiatedByName" + "columnName": "Name", + "identifier": "Name" }, { - "identifier": "UPNSuffix", - "columnName": "InitiatedByUPNSuffix" + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" } - ] + ], + "entityType": "Account" }, { - "entityType": "IP", "fieldMappings": [ { - "identifier": "Address", - "columnName": "IPAddress" + "columnName": "Consent_InitiatingIpAddress", + "identifier": "Address" } - ] + ], + "entityType": "IP" } ] } @@ -7732,13 +6689,13 @@ { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId55'),'/'))))]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId15'),'/'))))]", "properties": { - "description": "Azure Active Directory Analytics Rule 55", - "parentId": "[variables('analyticRuleId55')]", - "contentId": "[variables('_analyticRulecontentId55')]", + "description": "Azure Active Directory Analytics Rule 15", + "parentId": "[variables('analyticRuleId15')]", + "contentId": "[variables('_analyticRulecontentId15')]", "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion55')]", + "version": "[variables('analyticRuleVersion15')]", "source": { "kind": "Solution", "name": "Azure Active Directory", @@ -7763,43 +6720,43 @@ "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId55')]", + "contentId": "[variables('_analyticRulecontentId15')]", "contentKind": "AnalyticsRule", - "displayName": "External guest invitation followed by Azure AD PowerShell signin", - "contentProductId": "[variables('_analyticRulecontentProductId55')]", - "id": "[variables('_analyticRulecontentProductId55')]", - "version": "[variables('analyticRuleVersion55')]" + "displayName": "Credential added after admin consented to Application", + "contentProductId": "[variables('_analyticRulecontentProductId15')]", + "id": "[variables('_analyticRulecontentProductId15')]", + "version": "[variables('analyticRuleVersion15')]" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName56')]", + "name": "[variables('analyticRuleTemplateSpecName16')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "UserAccounts-CABlockedSigninSpikes_AnalyticalRules Analytics Rule with template version 3.0.4", + "description": "Cross-tenantAccessSettingsOrganizationAdded_AnalyticalRules Analytics Rule with template version 3.0.5", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion56')]", + "contentVersion": "[variables('analyticRuleVersion16')]", "parameters": {}, "variables": {}, "resources": [ { "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId56')]", + "name": "[variables('analyticRulecontentId16')]", "apiVersion": "2022-04-01-preview", "kind": "Scheduled", "location": "[parameters('workspace-location')]", "properties": { - "description": " Identifies spike in failed sign-ins from user accounts due to conditional access policied.\nSpike is determined based on Time series anomaly which will look at historical baseline values.\nRef : https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-user-accounts#monitoring-for-failed-unusual-sign-ins\nThis query has also been updated to include UEBA logs IdentityInfo and BehaviorAnalytics for contextual information around the results.", - "displayName": "User Accounts - Sign in Failure due to CA Spikes", + "description": "Organizations are added in the Cross-tenant Access Settings to control communication inbound or outbound for users and applications. This detection notifies when an Organization is added other than the list that is supposed to exist from the Azure AD Cross-tenant Access Settings.", + "displayName": "Cross-tenant Access Settings Organization Added", "enabled": false, - "query": "let riskScoreCutoff = 20; //Adjust this based on volume of results\nlet starttime = 14d;\nlet timeframe = 1d;\nlet scorethreshold = 3;\nlet baselinethreshold = 50;\nlet aadFunc = (tableName:string){\n // Failed Signins attempts with reasoning related to conditional access policies.\n table(tableName)\n | where TimeGenerated between (startofday(ago(starttime))..startofday(now()))\n | where ResultDescription has_any (\"conditional access\", \"CA\") or ResultType in (50005, 50131, 53000, 53001, 53002, 52003, 70044)\n | extend UserPrincipalName = tolower(UserPrincipalName)\n | extend timestamp = TimeGenerated, AccountCustomEntity = UserPrincipalName\n};\nlet aadSignin = aadFunc(\"SigninLogs\");\nlet aadNonInt = aadFunc(\"AADNonInteractiveUserSignInLogs\");\nlet allSignins = union isfuzzy=true aadSignin, aadNonInt;\nlet TimeSeriesAlerts = \nallSignins\n| make-series DailyCount=count() on TimeGenerated from startofday(ago(starttime)) to startofday(now()) step 1d by UserPrincipalName\n| extend (anomalies, score, baseline) = series_decompose_anomalies(DailyCount, scorethreshold, -1, 'linefit')\n| mv-expand DailyCount to typeof(double), TimeGenerated to typeof(datetime), anomalies to typeof(double), score to typeof(double), baseline to typeof(long)\n// Filtering low count events per baselinethreshold\n| where anomalies > 0 and baseline > baselinethreshold\n| extend AnomalyHour = TimeGenerated\n| project UserPrincipalName, AnomalyHour, TimeGenerated, DailyCount, baseline, anomalies, score;\n// Filter the alerts for specified timeframe\nTimeSeriesAlerts\n| where TimeGenerated > startofday(ago(timeframe))\n| join kind=inner ( \n allSignins\n | where TimeGenerated > startofday(ago(timeframe))\n // create a new column and round to hour\n | extend DateHour = bin(TimeGenerated, 1h)\n | summarize PartialFailedSignins = count(), LatestAnomalyTime = arg_max(TimeGenerated, *) by bin(TimeGenerated, 1h), OperationName, Category, ResultType, ResultDescription, UserPrincipalName, UserDisplayName, AppDisplayName, ClientAppUsed, IPAddress, ResourceDisplayName\n) on UserPrincipalName, $left.AnomalyHour == $right.DateHour\n| project LatestAnomalyTime, OperationName, Category, UserPrincipalName, UserDisplayName, ResultType, ResultDescription, AppDisplayName, ClientAppUsed, UserAgent, IPAddress, Location, AuthenticationRequirement, ConditionalAccessStatus, ResourceDisplayName, PartialFailedSignins, TotalFailedSignins = DailyCount, baseline, anomalies, score\n| extend timestamp = LatestAnomalyTime, Name = tostring(split(UserPrincipalName,'@',0)[0]), UPNSuffix = tostring(split(UserPrincipalName,'@',1)[0])\n| extend UserPrincipalName = tolower(UserPrincipalName)\n| join kind=leftouter (\n IdentityInfo\n | summarize LatestReportTime = arg_max(TimeGenerated, *) by AccountUPN\n | extend BlastRadiusInt = iif(BlastRadius == \"High\", 1, 0)\n | project AccountUPN, Tags, JobTitle, GroupMembership, AssignedRoles, UserType, IsAccountEnabled, BlastRadiusInt\n | summarize\n Tags = make_set(Tags, 1000),\n GroupMembership = make_set(GroupMembership, 1000),\n AssignedRoles = make_set(AssignedRoles, 1000),\n BlastRadiusInt = sum(BlastRadiusInt),\n UserType = make_set(UserType, 1000),\n UserAccountControl = make_set(UserType, 1000)\n by AccountUPN\n | extend UserPrincipalName=tolower(AccountUPN)\n) on UserPrincipalName\n| join kind=leftouter (\n BehaviorAnalytics\n | where ActivityType in (\"FailedLogOn\", \"LogOn\")\n | where isnotempty(SourceIPAddress)\n | project UsersInsights, DevicesInsights, ActivityInsights, InvestigationPriority, SourceIPAddress\n | project-rename IPAddress = SourceIPAddress\n | summarize\n UsersInsights = make_set(UsersInsights, 1000),\n DevicesInsights = make_set(DevicesInsights, 1000),\n IPInvestigationPriority = sum(InvestigationPriority)\n by IPAddress)\non IPAddress\n| extend UEBARiskScore = BlastRadiusInt + IPInvestigationPriority\n| where UEBARiskScore > riskScoreCutoff\n| sort by UEBARiskScore desc \n", - "queryFrequency": "P1D", - "queryPeriod": "P14D", + "query": "// Tenants IDs can be found by navigating to Azure Active Directory then from menu on the left, select External Identities, then from menu on the left, select Cross-tenant access settings and from the list shown of Tenants\nlet ExpectedTenantIDs = dynamic([\"List of expected tenant IDs\",\"Tenant ID 2\"]);\nAuditLogs\n| where OperationName has \"Add a partner to cross-tenant access setting\"\n| extend InitiatedByActionUserInformation = iff(isnotempty(InitiatedBy.user.userPrincipalName), InitiatedBy.user.userPrincipalName, InitiatedBy.app.displayName)\n| extend InitiatedByIPAdress = InitiatedBy.user.ipAddress\n| mv-apply TargetResource = TargetResources on\n (\n where TargetResource.type =~ \"Policy\"\n | extend Properties = TargetResource.modifiedProperties\n )\n| mv-apply Property = Properties on\n (\n where Property.displayName =~ \"tenantId\"\n | extend ExtTenantIDAdded = trim('\"',tostring(Property.newValue))\n )\n| where ExtTenantIDAdded !in (ExpectedTenantIDs)\n| extend Name = tostring(split(InitiatedByActionUserInformation,'@',0)[0]), UPNSuffix = tostring(split(InitiatedByActionUserInformation,'@',1)[0])\n", + "queryFrequency": "P2D", + "queryPeriod": "P2D", "severity": "Medium", "suppressionDuration": "PT1H", "suppressionEnabled": false, @@ -7808,58 +6765,44 @@ "status": "Available", "requiredDataConnectors": [ { + "connectorId": "AzureActiveDirectory", "dataTypes": [ - "SigninLogs" - ], - "connectorId": "AzureActiveDirectory" - }, - { - "dataTypes": [ - "AADNonInteractiveUserSignInLogs" - ], - "connectorId": "AzureActiveDirectory" - }, - { - "dataTypes": [ - "BehaviorAnalytics" - ], - "connectorId": "BehaviorAnalytics" - }, - { - "dataTypes": [ - "IdentityInfo" - ], - "connectorId": "IdentityInfo" + "AuditLogs" + ] } ], "tactics": [ - "InitialAccess" + "InitialAccess", + "Persistence", + "Discovery" ], "techniques": [ - "T1078" + "T1078", + "T1136", + "T1087" ], "entityMappings": [ { - "entityType": "Account", "fieldMappings": [ { - "identifier": "Name", - "columnName": "Name" + "columnName": "Name", + "identifier": "Name" }, { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" } - ] + ], + "entityType": "Account" }, { - "entityType": "IP", "fieldMappings": [ { - "identifier": "Address", - "columnName": "IPAddress" + "columnName": "InitiatedByIPAdress", + "identifier": "Address" } - ] + ], + "entityType": "IP" } ] } @@ -7867,13 +6810,13 @@ { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId56'),'/'))))]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId16'),'/'))))]", "properties": { - "description": "Azure Active Directory Analytics Rule 56", - "parentId": "[variables('analyticRuleId56')]", - "contentId": "[variables('_analyticRulecontentId56')]", + "description": "Azure Active Directory Analytics Rule 16", + "parentId": "[variables('analyticRuleId16')]", + "contentId": "[variables('_analyticRulecontentId16')]", "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion56')]", + "version": "[variables('analyticRuleVersion16')]", "source": { "kind": "Solution", "name": "Azure Active Directory", @@ -7898,43 +6841,43 @@ "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId56')]", + "contentId": "[variables('_analyticRulecontentId16')]", "contentKind": "AnalyticsRule", - "displayName": "User Accounts - Sign in Failure due to CA Spikes", - "contentProductId": "[variables('_analyticRulecontentProductId56')]", - "id": "[variables('_analyticRulecontentProductId56')]", - "version": "[variables('analyticRuleVersion56')]" + "displayName": "Cross-tenant Access Settings Organization Added", + "contentProductId": "[variables('_analyticRulecontentProductId16')]", + "id": "[variables('_analyticRulecontentProductId16')]", + "version": "[variables('analyticRuleVersion16')]" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName57')]", + "name": "[variables('analyticRuleTemplateSpecName17')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "UseraddedtoPrivilgedGroups_AnalyticalRules Analytics Rule with template version 3.0.4", + "description": "Cross-tenantAccessSettingsOrganizationDeleted_AnalyticalRules Analytics Rule with template version 3.0.5", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion57')]", + "contentVersion": "[variables('analyticRuleVersion17')]", "parameters": {}, "variables": {}, "resources": [ { "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId57')]", + "name": "[variables('analyticRulecontentId17')]", "apiVersion": "2022-04-01-preview", "kind": "Scheduled", "location": "[parameters('workspace-location')]", "properties": { - "description": "This will alert when a user is added to any of the Privileged Groups.\nFor further information on AuditLogs please see https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-audit-activities.\nFor Administrator role permissions in Azure Active Directory please see https://docs.microsoft.com/azure/active-directory/users-groups-roles/directory-assign-admin-roles", - "displayName": "User added to Azure Active Directory Privileged Groups", + "description": "Organizations are added in the Cross-tenant Access Settings to control communication inbound or outbound for users and applications. This detection notifies when an Organization is deleted from the Azure AD Cross-tenant Access Settings.", + "displayName": "Cross-tenant Access Settings Organization Deleted", "enabled": false, - "query": "let OperationList = dynamic([\"Add member to role\",\"Add member to role in PIM requested (permanent)\"]);\nlet PrivilegedGroups = dynamic([\"UserAccountAdmins\",\"PrivilegedRoleAdmins\",\"TenantAdmins\"]);\nAuditLogs\n//| where LoggedByService =~ \"Core Directory\"\n| where Category =~ \"RoleManagement\"\n| where OperationName in~ (OperationList)\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"User\"\n | extend TargetUserPrincipalName = tostring(TargetResource.userPrincipalName),\n modProps = TargetResource.modifiedProperties\n )\n| mv-apply Property = modProps on \n (\n where Property.displayName =~ \"Role.WellKnownObjectName\"\n | extend DisplayName = trim('\"',tostring(Property.displayName)),\n GroupName = trim('\"',tostring(Property.newValue))\n )\n| extend AppId = InitiatedBy.app.appId,\n InitiatedByDisplayName = case(isnotempty(InitiatedBy.app.displayName), InitiatedBy.app.displayName, isnotempty(InitiatedBy.user.displayName), InitiatedBy.user.displayName, \"not available\"),\n ServicePrincipalId = tostring(InitiatedBy.app.servicePrincipalId),\n ServicePrincipalName = tostring(InitiatedBy.app.servicePrincipalName),\n UserId = InitiatedBy.user.id,\n UserIPAddress = InitiatedBy.user.ipAddress,\n UserRoles = InitiatedBy.user.roles,\n UserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)\n| where GroupName in~ (PrivilegedGroups)\n// If you don't want to alert for operations from PIM, remove below filtering for MS-PIM.\n//| where InitiatedByDisplayName != \"MS-PIM\"\n| project TimeGenerated, AADOperationType, Category, OperationName, AADTenantId, AppId, InitiatedByDisplayName, ServicePrincipalId, ServicePrincipalName, DisplayName, GroupName, UserId, UserIPAddress, UserRoles, UserPrincipalName, TargetUserPrincipalName\n| extend AccountCustomEntity = case(isnotempty(ServicePrincipalName), ServicePrincipalName, \n isnotempty(UserPrincipalName), UserPrincipalName, \n \"\")\n| extend AccountName = tostring(split(AccountCustomEntity,'@',0)[0]), AccountUPNSuffix = tostring(split(AccountCustomEntity,'@',1)[0])\n| extend TargetName = tostring(split(TargetUserPrincipalName,'@',0)[0]), TargetUPNSuffix = tostring(split(TargetUserPrincipalName,'@',1)[0])\n", - "queryFrequency": "PT1H", - "queryPeriod": "PT1H", + "query": "AuditLogs\n| where OperationName has \"Delete partner specific cross-tenant access setting\"\n| extend InitiatedByActionUserInformation = iff(isnotempty(InitiatedBy.user.userPrincipalName), InitiatedBy.user.userPrincipalName, InitiatedBy.app.displayName)\n| extend InitiatedByIPAdress = InitiatedBy.user.ipAddress\n| mv-apply TargetResource = TargetResources on\n (\n where TargetResource.type =~ \"Policy\"\n | extend Properties = TargetResource.modifiedProperties\n )\n| mv-apply Property = Properties on\n (\n where Property.displayName =~ \"tenantId\"\n | extend ExtTenantDeleted = trim('\"',tostring(Property.oldValue))\n )\n| extend Name = tostring(split(InitiatedByActionUserInformation,'@',0)[0]), UPNSuffix = tostring(split(InitiatedByActionUserInformation,'@',1)[0])\n", + "queryFrequency": "P2D", + "queryPeriod": "P2D", "severity": "Medium", "suppressionDuration": "PT1H", "suppressionEnabled": false, @@ -7943,46 +6886,44 @@ "status": "Available", "requiredDataConnectors": [ { + "connectorId": "AzureActiveDirectory", "dataTypes": [ "AuditLogs" - ], - "connectorId": "AzureActiveDirectory" + ] } ], "tactics": [ + "InitialAccess", "Persistence", - "PrivilegeEscalation" + "Discovery" ], "techniques": [ - "T1098", - "T1078" + "T1078", + "T1136", + "T1087" ], "entityMappings": [ { - "entityType": "Account", "fieldMappings": [ { - "identifier": "Name", - "columnName": "AccountName" + "columnName": "Name", + "identifier": "Name" }, { - "identifier": "UPNSuffix", - "columnName": "AccountUPNSuffix" + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" } - ] + ], + "entityType": "Account" }, { - "entityType": "Account", "fieldMappings": [ { - "identifier": "Name", - "columnName": "TargetName" - }, - { - "identifier": "UPNSuffix", - "columnName": "TargetUPNSuffix" + "columnName": "InitiatedByIPAdress", + "identifier": "Address" } - ] + ], + "entityType": "IP" } ] } @@ -7990,13 +6931,13 @@ { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId57'),'/'))))]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId17'),'/'))))]", "properties": { - "description": "Azure Active Directory Analytics Rule 57", - "parentId": "[variables('analyticRuleId57')]", - "contentId": "[variables('_analyticRulecontentId57')]", + "description": "Azure Active Directory Analytics Rule 17", + "parentId": "[variables('analyticRuleId17')]", + "contentId": "[variables('_analyticRulecontentId17')]", "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion57')]", + "version": "[variables('analyticRuleVersion17')]", "source": { "kind": "Solution", "name": "Azure Active Directory", @@ -8021,44 +6962,44 @@ "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId57')]", + "contentId": "[variables('_analyticRulecontentId17')]", "contentKind": "AnalyticsRule", - "displayName": "User added to Azure Active Directory Privileged Groups", - "contentProductId": "[variables('_analyticRulecontentProductId57')]", - "id": "[variables('_analyticRulecontentProductId57')]", - "version": "[variables('analyticRuleVersion57')]" + "displayName": "Cross-tenant Access Settings Organization Deleted", + "contentProductId": "[variables('_analyticRulecontentProductId17')]", + "id": "[variables('_analyticRulecontentProductId17')]", + "version": "[variables('analyticRuleVersion17')]" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName58')]", + "name": "[variables('analyticRuleTemplateSpecName18')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "UserAssignedPrivilegedRole_AnalyticalRules Analytics Rule with template version 3.0.4", + "description": "Cross-tenantAccessSettingsOrganizationInboundCollaborationSettingsChanged_AnalyticalRules Analytics Rule with template version 3.0.5", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion58')]", + "contentVersion": "[variables('analyticRuleVersion18')]", "parameters": {}, "variables": {}, "resources": [ { "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId58')]", + "name": "[variables('analyticRulecontentId18')]", "apiVersion": "2022-04-01-preview", "kind": "Scheduled", "location": "[parameters('workspace-location')]", "properties": { - "description": "Identifies when a privileged role is assigned to a new user. Any account eligible for a role is now being given privileged access. If the assignment is unexpected or into a role that isn't the responsibility of the account holder, investigate.", - "displayName": "New User Assigned to Privileged Role", + "description": "Organizations are added in the Cross-tenant Access Settings to control communication inbound or outbound for users and applications. This detection notifies when Organization Inbound Collaboration Settings are changed for \"Users & Groups\" and for \"Applications\".", + "displayName": "Cross-tenant Access Settings Organization Inbound Collaboration Settings Changed", "enabled": false, - "query": "// Define the start and end times based on input values\nlet starttime = now()-1d;\nlet endtime = now();\n// Set a lookback period of 14 days\nlet lookback = starttime - 14d;\n// Define a reusable function to query audit logs\nlet awsFunc = (start:datetime, end:datetime) {\n AuditLogs\n | where TimeGenerated between (start..end)\n | where Category =~ \"RoleManagement\"\n | where AADOperationType in (\"Assign\", \"AssignEligibleRole\")\n | where ActivityDisplayName has_any (\"Add eligible member to role\", \"Add member to role\")\n | mv-apply TargetResource = TargetResources on\n (\n where TargetResource.type in~ (\"User\", \"ServicePrincipal\")\n | extend Target = iff(TargetResource.type =~ \"ServicePrincipal\", tostring(TargetResource.displayName), tostring(TargetResource.userPrincipalName)),\n props = TargetResource.modifiedProperties\n )\n | mv-apply Property = props on\n (\n where Property.displayName =~ \"Role.DisplayName\"\n | extend RoleName = trim('\"', tostring(Property.newValue))\n )\n | where RoleName contains \"Admin\" and Result == \"success\"\n};\n// Query for audit events in the current day\nlet EventInfo_CurrentDay = awsFunc(starttime, endtime);\n// Query for audit events in the historical period (lookback)\nlet EventInfo_historical = awsFunc(lookback, starttime);\n// Find unseen events by performing a left anti-join\nlet EventInfo_Unseen = (EventInfo_CurrentDay\n | join kind=leftanti(EventInfo_historical) on Target, RoleName, OperationName\n);\n// Extend and clean up the results\nEventInfo_Unseen\n| extend InitiatingApp = tostring(InitiatedBy.app.displayName)\n| extend Initiator = iif(isnotempty(InitiatingApp), InitiatingApp, tostring(InitiatedBy.user.userPrincipalName))\n// You can uncomment the lines below to filter out PIM activations\n// | where Initiator != \"MS-PIM\"\n// | summarize StartTime=min(TimeGenerated), EndTime=min(TimeGenerated) by OperationName, RoleName, Target, Initiator, Result\n// Project specific columns and split them for further analysis\n| project TimeGenerated, OperationName, RoleName, Target, Initiator, Result\n| extend TargetName = tostring(split(Target, '@', 0)[0]),\n TargetUPNSuffix = tostring(split(Target, '@', 1)[0]),\n InitiatorName = tostring(split(Initiator, '@', 0)[0]),\n InitiatorUPNSuffix = tostring(split(Initiator, '@', 1)[0])\n", - "queryFrequency": "PT1H", - "queryPeriod": "P14D", - "severity": "High", + "query": "//In User & Groups and in Applications, the following \"AccessType\" values in columns PremodifiedInboundSettings and ModifiedInboundSettings are interpreted accordingly:\n// When Access Type in premodified inbound settings value was 1 that means that the initial access was allowed. When Access Type in premodified inbound settings value was 2 that means that the initial access was blocked. \n// When Access Type in modified inbound settings value is 1 that means that now access is allowed. When Access Type in modified inbound settings value is 2 that means that now access is blocked. \nAuditLogs\n| where OperationName has \"Update a partner cross-tenant access setting\"\n| mv-apply TargetResource = TargetResources on\n (\n where TargetResource.type =~ \"Policy\"\n | extend Properties = TargetResource.modifiedProperties\n )\n| mv-apply Property = Properties on\n (\n where Property.displayName =~ \"b2bCollaborationInbound\"\n | extend PremodifiedInboundSettings = trim('\"',tostring(Property.oldValue)),\n ModifiedInboundSettings = trim(@'\"',tostring(Property.newValue))\n )\n| extend InitiatedByActionUserInformation = iff(isnotempty(InitiatedBy.user.userPrincipalName), InitiatedBy.user.userPrincipalName, InitiatedBy.app.displayName)\n| extend InitiatedByIPAdress = InitiatedBy.user.ipAddress\n| where PremodifiedInboundSettings != ModifiedInboundSettings\n| extend Name = tostring(split(InitiatedByActionUserInformation,'@',0)[0]), UPNSuffix = tostring(split(InitiatedByActionUserInformation,'@',1)[0])\n", + "queryFrequency": "P2D", + "queryPeriod": "P2D", + "severity": "Medium", "suppressionDuration": "PT1H", "suppressionEnabled": false, "triggerOperator": "GreaterThan", @@ -8066,44 +7007,44 @@ "status": "Available", "requiredDataConnectors": [ { + "connectorId": "AzureActiveDirectory", "dataTypes": [ "AuditLogs" - ], - "connectorId": "AzureActiveDirectory" + ] } ], "tactics": [ - "Persistence" + "InitialAccess", + "Persistence", + "Discovery" ], "techniques": [ - "T1078" + "T1078", + "T1136", + "T1087" ], "entityMappings": [ { - "entityType": "Account", "fieldMappings": [ { - "identifier": "Name", - "columnName": "TargetName" + "columnName": "Name", + "identifier": "Name" }, { - "identifier": "UPNSuffix", - "columnName": "TargetUPNSuffix" + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" } - ] + ], + "entityType": "Account" }, { - "entityType": "Account", "fieldMappings": [ { - "identifier": "Name", - "columnName": "InitiatorName" - }, - { - "identifier": "UPNSuffix", - "columnName": "InitiatorUPNSuffix" + "columnName": "InitiatedByIPAdress", + "identifier": "Address" } - ] + ], + "entityType": "IP" } ] } @@ -8111,13 +7052,13 @@ { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId58'),'/'))))]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId18'),'/'))))]", "properties": { - "description": "Azure Active Directory Analytics Rule 58", - "parentId": "[variables('analyticRuleId58')]", - "contentId": "[variables('_analyticRulecontentId58')]", + "description": "Azure Active Directory Analytics Rule 18", + "parentId": "[variables('analyticRuleId18')]", + "contentId": "[variables('_analyticRulecontentId18')]", "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion58')]", + "version": "[variables('analyticRuleVersion18')]", "source": { "kind": "Solution", "name": "Azure Active Directory", @@ -8142,43 +7083,43 @@ "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId58')]", + "contentId": "[variables('_analyticRulecontentId18')]", "contentKind": "AnalyticsRule", - "displayName": "New User Assigned to Privileged Role", - "contentProductId": "[variables('_analyticRulecontentProductId58')]", - "id": "[variables('_analyticRulecontentProductId58')]", - "version": "[variables('analyticRuleVersion58')]" + "displayName": "Cross-tenant Access Settings Organization Inbound Collaboration Settings Changed", + "contentProductId": "[variables('_analyticRulecontentProductId18')]", + "id": "[variables('_analyticRulecontentProductId18')]", + "version": "[variables('analyticRuleVersion18')]" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName59')]", + "name": "[variables('analyticRuleTemplateSpecName19')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "NewOnmicrosoftDomainAdded_AnalyticalRules Analytics Rule with template version 3.0.4", + "description": "Cross-tenantAccessSettingsOrganizationInboundDirectSettingsChanged_AnalyticalRules Analytics Rule with template version 3.0.5", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion59')]", + "contentVersion": "[variables('analyticRuleVersion19')]", "parameters": {}, "variables": {}, "resources": [ { "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId59')]", + "name": "[variables('analyticRulecontentId19')]", "apiVersion": "2022-04-01-preview", "kind": "Scheduled", "location": "[parameters('workspace-location')]", "properties": { - "description": "This detection looks for new onmicrosoft domains being added to a tenant. \nAn attacker who compromises a tenant may register a new onmicrosoft domain in order to masquerade as a service provider for launching phishing campaigns.\nDomain additions are not a common occurrence and users should validate that the domain was added by a legitimate user, with a legitimate purpose.", - "displayName": "New onmicrosoft domain added to tenant", + "description": "Organizations are added in the Cross-tenant Access Settings to control communication inbound or outbound for users and applications. This detection notifies when Organization Inbound Direct Settings are changed for \"Users & Groups\" and for \"Applications\".", + "displayName": "Cross-tenant Access Settings Organization Inbound Direct Settings Changed", "enabled": false, - "query": "AuditLogs\n| where AADOperationType == \"Add\"\n| where Result == \"success\"\n| where OperationName in (\"Add verified domain\", \"Add unverified domain\")\n| extend InitiatedBy = parse_json(InitiatedBy)\n| extend InitiatingUser = tostring(InitiatedBy.user.userPrincipalName)\n| extend InitiatingIp = tostring(InitiatedBy.user.ipAddress)\n| extend InitiatingApp = tostring(InitiatedBy.app.displayName)\n| extend InitiatingSPID = tostring(InitiatedBy.app.servicePrincipalId)\n| extend DomainAdded = tostring(TargetResources[0].displayName)\n| where DomainAdded has \"onmicrosoft\"\n| extend ActionInitiatedBy = case(isnotempty(InitiatingUser), InitiatingUser, strcat(InitiatingApp, \" - \", InitiatingSPID))\n| extend UserName = split(InitiatingUser, \"@\")[0]\n| extend UPNSuffix = split(InitiatingUser, \"@\")[1]\n| project-reorder TimeGenerated, OperationName, DomainAdded, ActionInitiatedBy, InitiatingIp\n", - "queryFrequency": "PT1H", - "queryPeriod": "PT1H", + "query": "//In User & Groups and in Applications, the following \"AccessType\" values in columns PremodifiedInboundSettings and ModifiedInboundSettings are interpreted accordingly:\n// When Access Type in premodified inbound settings value was 1 that means that the initial access was allowed. When Access Type in premodified inbound settings value was 2 that means that the initial access was blocked. \n// When Access Type in modified inbound settings value is 1 that means that now access is allowed. When Access Type in modified inbound settings value is 2 that means that now access is blocked. \nAuditLogs\n| where OperationName has \"Update a partner cross-tenant access setting\"\n| mv-apply TargetResource = TargetResources on\n (\n where TargetResource.type =~ \"Policy\"\n | extend Properties = TargetResource.modifiedProperties\n )\n| mv-apply Property = Properties on\n (\n where Property.displayName =~ \"b2bDirectConnectInbound\"\n | extend PremodifiedInboundSettings = trim('\"',tostring(Property.oldValue)),\n ModifiedInboundSettings = trim(@'\"',tostring(Property.newValue))\n )\n| extend InitiatedByActionUserInformation = iff(isnotempty(InitiatedBy.user.userPrincipalName), InitiatedBy.user.userPrincipalName, InitiatedBy.app.displayName)\n| extend InitiatedByIPAdress = InitiatedBy.user.ipAddress\n| where PremodifiedInboundSettings != ModifiedInboundSettings\n| extend Name = tostring(split(InitiatedByActionUserInformation,'@',0)[0]), UPNSuffix = tostring(split(InitiatedByActionUserInformation,'@',1)[0])\n", + "queryFrequency": "P2D", + "queryPeriod": "P2D", "severity": "Medium", "suppressionDuration": "PT1H", "suppressionEnabled": false, @@ -8187,74 +7128,58 @@ "status": "Available", "requiredDataConnectors": [ { + "connectorId": "AzureActiveDirectory", "dataTypes": [ "AuditLogs" - ], - "connectorId": "AzureActiveDirectory" + ] } ], "tactics": [ - "ResourceDevelopment" + "InitialAccess", + "Persistence", + "Discovery" ], "techniques": [ - "T1585" + "T1078", + "T1136", + "T1087" ], "entityMappings": [ { - "entityType": "Account", "fieldMappings": [ { - "identifier": "Name", - "columnName": "UserName" + "columnName": "Name", + "identifier": "Name" }, { - "identifier": "UPNSuffix", - "columnName": "UPNSuffix" - }, - { - "identifier": "AadUserId", - "columnName": "InitiatingSPID" + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" } - ] + ], + "entityType": "Account" }, { - "entityType": "IP", "fieldMappings": [ { - "identifier": "Address", - "columnName": "InitiatingIp" + "columnName": "InitiatedByIPAdress", + "identifier": "Address" } - ] - }, - { - "entityType": "DNS", - "fieldMappings": [ - { - "identifier": "DomainName", - "columnName": "DomainAdded" - } - ] + ], + "entityType": "IP" } - ], - "eventGroupingSettings": { - "aggregationKind": "SingleAlert" - }, - "alertDetailsOverride": { - "alertDescriptionFormat": "This detection looks for new onmicrosoft domains being added to a tenant. An attacker who compromises a tenant may register a new onmicrosoft domain in order to masquerade as a service provider for launching phishing accounts. Domain additions are not a common occurrence and users should validate that {{ActionInitiatedBy}} added {{DomainAdded}} with a legitimate purpose.", - "alertDisplayNameFormat": "{{DomainAdded}} added to tenant by {{ActionInitiatedBy}}" - } + ] } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId59'),'/'))))]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId19'),'/'))))]", "properties": { - "description": "Azure Active Directory Analytics Rule 59", - "parentId": "[variables('analyticRuleId59')]", - "contentId": "[variables('_analyticRulecontentId59')]", + "description": "Azure Active Directory Analytics Rule 19", + "parentId": "[variables('analyticRuleId19')]", + "contentId": "[variables('_analyticRulecontentId19')]", "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion59')]", + "version": "[variables('analyticRuleVersion19')]", "source": { "kind": "Solution", "name": "Azure Active Directory", @@ -8279,43 +7204,43 @@ "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId59')]", + "contentId": "[variables('_analyticRulecontentId19')]", "contentKind": "AnalyticsRule", - "displayName": "New onmicrosoft domain added to tenant", - "contentProductId": "[variables('_analyticRulecontentProductId59')]", - "id": "[variables('_analyticRulecontentProductId59')]", - "version": "[variables('analyticRuleVersion59')]" + "displayName": "Cross-tenant Access Settings Organization Inbound Direct Settings Changed", + "contentProductId": "[variables('_analyticRulecontentProductId19')]", + "id": "[variables('_analyticRulecontentProductId19')]", + "version": "[variables('analyticRuleVersion19')]" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('analyticRuleTemplateSpecName60')]", + "name": "[variables('analyticRuleTemplateSpecName20')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "SuspiciousSignInFollowedByMFAModification_AnalyticalRules Analytics Rule with template version 3.0.4", + "description": "Cross-tenantAccessSettingsOrganizationOutboundCollaborationSettingsChanged_AnalyticalRules Analytics Rule with template version 3.0.5", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('analyticRuleVersion60')]", + "contentVersion": "[variables('analyticRuleVersion20')]", "parameters": {}, "variables": {}, "resources": [ { "type": "Microsoft.SecurityInsights/AlertRuleTemplates", - "name": "[variables('analyticRulecontentId60')]", + "name": "[variables('analyticRulecontentId20')]", "apiVersion": "2022-04-01-preview", "kind": "Scheduled", "location": "[parameters('workspace-location')]", "properties": { - "description": "This query looks uses Microsoft Sentinel's UEBA features to look for suspicious logons followed by modifications to MFA settings by that user.", - "displayName": "Suspicious Sign In Followed by MFA Modification", + "description": "Organizations are added in the Cross-tenant Access Settings to control communication inbound or outbound for users and applications. This detection notifies when Organization Outbound Collaboration Settings are changed for \"Users & Groups\" and for \"Applications\".", + "displayName": "Cross-tenant Access Settings Organization Outbound Collaboration Settings Changed", "enabled": false, - "query": "let PriorityScore = 9;\nBehaviorAnalytics\n| where ActionType == \"Sign-in\"\n| where InvestigationPriority > PriorityScore\n| extend UserPrincipalName = tolower(UserPrincipalName)\n| extend LogOnTime = TimeGenerated\n| join kind=inner (AuditLogs\n| where Category =~ \"UserManagement\" \n| where OperationName in~ (\"Admin registered security info\", \"Admin updated security info\", \"Admin deleted security info\", \"User registered security info\", \"User changed default security info\", \"User deleted security info\",\"User registered all required security info\",\"User started security info registration\") \n| extend InitiatorUPN = tolower(tostring(InitiatedBy.user.userPrincipalName))\n| extend InitiatorID = tostring(InitiatedBy.user.id)\n| extend FromIP = tostring(InitiatedBy.user.ipAddress) \n| extend TargetUPN = tolower(tostring(TargetResources[0].userPrincipalName))\n| extend TargetId = tostring(TargetResources[0].id)\n| extend MFAModTime = TimeGenerated\n| where isnotempty(InitiatorUPN)) on $left.UserPrincipalName == $right.InitiatorUPN\n| where MFAModTime between((LogOnTime-30m)..(LogOnTime+1h))\n| extend InitiatorName = tostring(split(InitiatorUPN, \"@\")[0]), InitiatorSuffix = tostring(split(InitiatorUPN, \"@\")[1]), TargetName = tostring(split(TargetUPN, \"@\")[0]), TargetSuffix = tostring(split(TargetUPN, \"@\")[1])\n", - "queryFrequency": "P1D", - "queryPeriod": "P1D", + "query": "//In User & Groups and in Applications, the following \"AccessType\" values in columns PremodifiedOutboundSettings and ModifiedOutboundSettings are interpreted accordingly:\n// When Access Type in premodified outbound settings value was 1 that means that the initial access was allowed. When Access Type in premodified outbound settings value was 2 that means that the initial access was blocked. \n// When Access Type in modified outbound settings value is 1 that means that now access is allowed. When Access Type in modified outbound settings value is 2 that means that now access is blocked. \nAuditLogs\n| where OperationName has \"Update a partner cross-tenant access setting\"\n| mv-apply TargetResource = TargetResources on\n (\n where TargetResource.type =~ \"Policy\"\n | extend Properties = TargetResource.modifiedProperties\n )\n| mv-apply Property = Properties on\n (\n where Property.displayName =~ \"b2bCollaborationOutbound\"\n | extend PremodifiedOutboundSettings = trim('\"',tostring(Property.oldValue)),\n ModifiedOutboundSettings = trim(@'\"',tostring(Property.newValue))\n )\n| extend InitiatedByActionUserInformation = iff(isnotempty(InitiatedBy.user.userPrincipalName), InitiatedBy.user.userPrincipalName, InitiatedBy.app.displayName)\n| extend InitiatedByIPAdress = InitiatedBy.user.ipAddress\n| where PremodifiedOutboundSettings != ModifiedOutboundSettings\n| extend Name = tostring(split(InitiatedByActionUserInformation,'@',0)[0]), UPNSuffix = tostring(split(InitiatedByActionUserInformation,'@',1)[0])\n", + "queryFrequency": "P2D", + "queryPeriod": "P2D", "severity": "Medium", "suppressionDuration": "PT1H", "suppressionEnabled": false, @@ -8324,99 +7249,179 @@ "status": "Available", "requiredDataConnectors": [ { + "connectorId": "AzureActiveDirectory", "dataTypes": [ "AuditLogs" - ], - "connectorId": "AzureActiveDirectory" - }, - { - "dataTypes": [ - "BehaviorAnalytics" - ], - "connectorId": "BehaviorAnalytics" + ] } ], "tactics": [ "InitialAccess", - "DefenseEvasion" + "Persistence", + "Discovery" ], "techniques": [ "T1078", - "T1556" + "T1136", + "T1087" ], "entityMappings": [ { - "entityType": "Account", "fieldMappings": [ { - "identifier": "AadUserId", - "columnName": "InitiatorID" + "columnName": "Name", + "identifier": "Name" }, { - "identifier": "Name", - "columnName": "InitiatorName" - }, - { - "identifier": "UPNSuffix", - "columnName": "InitiatorSuffix" + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" } - ] + ], + "entityType": "Account" }, { - "entityType": "Account", "fieldMappings": [ { - "identifier": "AadUserId", - "columnName": "TargetId" - }, - { - "identifier": "Name", - "columnName": "TargetName" - }, - { - "identifier": "UPNSuffix", - "columnName": "TargetSuffix" + "columnName": "InitiatedByIPAdress", + "identifier": "Address" } + ], + "entityType": "IP" + } + ] + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId20'),'/'))))]", + "properties": { + "description": "Azure Active Directory Analytics Rule 20", + "parentId": "[variables('analyticRuleId20')]", + "contentId": "[variables('_analyticRulecontentId20')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion20')]", + "source": { + "kind": "Solution", + "name": "Azure Active Directory", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "Microsoft", + "email": "[variables('_email')]" + }, + "support": { + "tier": "Microsoft", + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "link": "https://support.microsoft.com/" + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_analyticRulecontentId20')]", + "contentKind": "AnalyticsRule", + "displayName": "Cross-tenant Access Settings Organization Outbound Collaboration Settings Changed", + "contentProductId": "[variables('_analyticRulecontentProductId20')]", + "id": "[variables('_analyticRulecontentProductId20')]", + "version": "[variables('analyticRuleVersion20')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleTemplateSpecName21')]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "Cross-tenantAccessSettingsOrganizationOutboundDirectSettingsChanged_AnalyticalRules Analytics Rule with template version 3.0.5", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleVersion21')]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId21')]", + "apiVersion": "2022-04-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", + "properties": { + "description": "Organizations are added in the Cross-tenant Access Settings to control communication inbound or outbound for users and applications. This detection notifies when Organization Outbound Direct Settings are changed for \"Users & Groups\" and for \"Applications\".", + "displayName": "Cross-tenant Access Settings Organization Outbound Direct Settings Changed", + "enabled": false, + "query": "//In User & Groups and in Applications, the following \"AccessType\" values in columns PremodifiedOutboundSettings and ModifiedOutboundSettings are interpreted accordingly:\n// When Access Type in premodified outbound settings value was 1 that means that the initial access was allowed. When Access Type in premodified outbound settings value was 2 that means that the initial access was blocked. \n// When Access Type in modified outbound settings value is 1 that means that now access is allowed. When Access Type in modified outbound settings value is 2 that means that now access is blocked. \nAuditLogs\n| where OperationName has \"Update a partner cross-tenant access setting\"\n| mv-apply TargetResource = TargetResources on\n (\n where TargetResource.type =~ \"Policy\"\n | extend Properties = TargetResource.modifiedProperties\n )\n| mv-apply Property = Properties on\n (\n where Property.displayName =~ \"b2bDirectConnectOutbound\"\n | extend PremodifiedOutboundSettings = trim('\"',tostring(Property.oldValue)),\n ModifiedOutboundSettings = trim(@'\"',tostring(Property.newValue))\n )\n| extend InitiatedByActionUserInformation = iff(isnotempty(InitiatedBy.user.userPrincipalName), InitiatedBy.user.userPrincipalName, InitiatedBy.app.displayName)\n| extend InitiatedByIPAdress = InitiatedBy.user.ipAddress\n| where PremodifiedOutboundSettings != ModifiedOutboundSettings\n| extend Name = tostring(split(InitiatedByActionUserInformation,'@',0)[0]), UPNSuffix = tostring(split(InitiatedByActionUserInformation,'@',1)[0])\n", + "queryFrequency": "P2D", + "queryPeriod": "P2D", + "severity": "Medium", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "AuditLogs" ] - }, + } + ], + "tactics": [ + "InitialAccess", + "Persistence", + "Discovery" + ], + "techniques": [ + "T1078", + "T1136", + "T1087" + ], + "entityMappings": [ { - "entityType": "IP", "fieldMappings": [ { - "identifier": "Address", - "columnName": "FromIP" + "columnName": "Name", + "identifier": "Name" + }, + { + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" } - ] + ], + "entityType": "Account" }, { - "entityType": "IP", "fieldMappings": [ { - "identifier": "Address", - "columnName": "SourceIPAddress" + "columnName": "InitiatedByIPAdress", + "identifier": "Address" } - ] + ], + "entityType": "IP" } - ], - "eventGroupingSettings": { - "aggregationKind": "AlertPerResult" - }, - "alertDetailsOverride": { - "alertDescriptionFormat": "This query looks uses Microsoft Sentinel's UEBA features to look for suspicious logons followed by modifications to MFA settings by that user.\nIn this case {{InitiatorUPN}} logged in followed by a modification to MFA settings for {{TargetUPN}}.\nThe sign in was from {{SourceIPAddress}}.\n", - "alertDisplayNameFormat": "Suspicious Sign In by {{InitiatorUPN}} Followed by MFA Modification to {{TargetUPN}}" - } + ] } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId60'),'/'))))]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId21'),'/'))))]", "properties": { - "description": "Azure Active Directory Analytics Rule 60", - "parentId": "[variables('analyticRuleId60')]", - "contentId": "[variables('_analyticRulecontentId60')]", + "description": "Azure Active Directory Analytics Rule 21", + "parentId": "[variables('analyticRuleId21')]", + "contentId": "[variables('_analyticRulecontentId21')]", "kind": "AnalyticsRule", - "version": "[variables('analyticRuleVersion60')]", + "version": "[variables('analyticRuleVersion21')]", "source": { "kind": "Solution", "name": "Azure Active Directory", @@ -8441,397 +7446,228 @@ "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_analyticRulecontentId60')]", + "contentId": "[variables('_analyticRulecontentId21')]", "contentKind": "AnalyticsRule", - "displayName": "Suspicious Sign In Followed by MFA Modification", - "contentProductId": "[variables('_analyticRulecontentProductId60')]", - "id": "[variables('_analyticRulecontentProductId60')]", - "version": "[variables('analyticRuleVersion60')]" + "displayName": "Cross-tenant Access Settings Organization Outbound Direct Settings Changed", + "contentProductId": "[variables('_analyticRulecontentProductId21')]", + "id": "[variables('_analyticRulecontentProductId21')]", + "version": "[variables('analyticRuleVersion21')]" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('playbookTemplateSpecName1')]", + "name": "[variables('analyticRuleTemplateSpecName22')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "Block-AADUser-Alert Playbook with template version 3.0.4", + "description": "DisabledAccountSigninsAcrossManyApplications_AnalyticalRules Analytics Rule with template version 3.0.5", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('playbookVersion1')]", - "parameters": { - "PlaybookName": { - "defaultValue": "Block-AADUser-Alert", - "type": "string" - } - }, - "variables": { - "AzureADConnectionName": "[[concat('azuread-', parameters('PlaybookName'))]", - "MicrosoftSentinelConnectionName": "[[concat('microsoftsentinel-', parameters('PlaybookName'))]", - "Office365ConnectionName": "[[concat('office365-', parameters('PlaybookName'))]", - "connection-1": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuread')]", - "_connection-1": "[[variables('connection-1')]", - "connection-2": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", - "_connection-2": "[[variables('connection-2')]", - "connection-3": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]", - "_connection-3": "[[variables('connection-3')]", - "workspace-location-inline": "[concat('[resourceGroup().locatio', 'n]')]", - "workspace-name": "[parameters('workspace')]", - "workspaceResourceId": "[[resourceId('microsoft.OperationalInsights/Workspaces', variables('workspace-name'))]" - }, + "contentVersion": "[variables('analyticRuleVersion22')]", + "parameters": {}, + "variables": {}, "resources": [ { - "type": "Microsoft.Web/connections", - "apiVersion": "2016-06-01", - "name": "[[variables('AzureADConnectionName')]", - "location": "[[variables('workspace-location-inline')]", - "properties": { - "displayName": "[[variables('AzureADConnectionName')]", - "api": { - "id": "[[variables('_connection-1')]" - } - } - }, - { - "type": "Microsoft.Web/connections", - "apiVersion": "2016-06-01", - "name": "[[variables('MicrosoftSentinelConnectionName')]", - "location": "[[variables('workspace-location-inline')]", - "kind": "V1", + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId22')]", + "apiVersion": "2022-04-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", "properties": { - "displayName": "[[variables('MicrosoftSentinelConnectionName')]", - "parameterValueType": "Alternative", - "api": { - "id": "[[variables('_connection-2')]" - } + "description": "Identifies failed attempts to sign in to disabled accounts across multiple Azure Applications.\nDefault threshold for Azure Applications attempted to sign in to is 3.\nReferences: https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-sign-ins-error-codes\n50057 - User account is disabled. The account has been disabled by an administrator.", + "displayName": "Attempts to sign in to disabled accounts", + "enabled": false, + "query": "let threshold = 3;\nlet aadFunc = (tableName:string){\ntable(tableName)\n| where ResultType == \"50057\"\n| where ResultDescription =~ \"User account is disabled. The account has been disabled by an administrator.\"\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), applicationCount = dcount(AppDisplayName),\napplicationSet = make_set(AppDisplayName), count() by UserPrincipalName, IPAddress, Type\n| where applicationCount >= threshold\n| extend timestamp = StartTime, Name = tostring(split(UserPrincipalName,'@',0)[0]), UPNSuffix = tostring(split(UserPrincipalName,'@',1)[0])\n};\nlet aadSignin = aadFunc(\"SigninLogs\");\nlet aadNonInt = aadFunc(\"AADNonInteractiveUserSignInLogs\");\nunion isfuzzy=true aadSignin, aadNonInt\n", + "queryFrequency": "P1D", + "queryPeriod": "P1D", + "severity": "Medium", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "SigninLogs" + ] + }, + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "AADNonInteractiveUserSignInLogs" + ] + } + ], + "tactics": [ + "InitialAccess" + ], + "techniques": [ + "T1078" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "Name", + "identifier": "Name" + }, + { + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" + } + ], + "entityType": "Account" + }, + { + "fieldMappings": [ + { + "columnName": "IPAddress", + "identifier": "Address" + } + ], + "entityType": "IP" + } + ] } }, { - "type": "Microsoft.Web/connections", - "apiVersion": "2016-06-01", - "name": "[[variables('Office365ConnectionName')]", - "location": "[[variables('workspace-location-inline')]", + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId22'),'/'))))]", "properties": { - "displayName": "[[variables('Office365ConnectionName')]", - "api": { - "id": "[[variables('_connection-3')]" + "description": "Azure Active Directory Analytics Rule 22", + "parentId": "[variables('analyticRuleId22')]", + "contentId": "[variables('_analyticRulecontentId22')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion22')]", + "source": { + "kind": "Solution", + "name": "Azure Active Directory", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "Microsoft", + "email": "[variables('_email')]" + }, + "support": { + "tier": "Microsoft", + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "link": "https://support.microsoft.com/" } } - }, + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_analyticRulecontentId22')]", + "contentKind": "AnalyticsRule", + "displayName": "Attempts to sign in to disabled accounts", + "contentProductId": "[variables('_analyticRulecontentProductId22')]", + "id": "[variables('_analyticRulecontentProductId22')]", + "version": "[variables('analyticRuleVersion22')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleTemplateSpecName23')]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "DistribPassCrackAttempt_AnalyticalRules Analytics Rule with template version 3.0.5", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleVersion23')]", + "parameters": {}, + "variables": {}, + "resources": [ { - "type": "Microsoft.Logic/workflows", - "apiVersion": "2017-07-01", - "name": "[[parameters('PlaybookName')]", - "location": "[[variables('workspace-location-inline')]", - "tags": { - "LogicAppsCategory": "security", - "hidden-SentinelTemplateName": "Block-AADUser_alert", - "hidden-SentinelTemplateVersion": "1.1", - "hidden-SentinelWorkspaceId": "[[variables('workspaceResourceId')]" - }, - "identity": { - "type": "SystemAssigned" - }, - "dependsOn": [ - "[[resourceId('Microsoft.Web/connections', variables('AzureADConnectionName'))]", - "[[resourceId('Microsoft.Web/connections', variables('MicrosoftSentinelConnectionName'))]", - "[[resourceId('Microsoft.Web/connections', variables('Office365ConnectionName'))]" - ], + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId23')]", + "apiVersion": "2022-04-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", "properties": { - "state": "Enabled", - "definition": { - "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "$connections": { - "type": "Object" - } + "description": "Identifies distributed password cracking attempts from the Azure Active Directory SigninLogs.\nThe query looks for unusually high number of failed password attempts coming from multiple locations for a user account.\nReferences: https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-sign-ins-error-codes\n50053 Account is locked because the user tried to sign in too many times with an incorrect user ID or password.\n50055 Invalid password, entered expired password.\n50056 Invalid or null password - Password does not exist in store for this user.\n50126 Invalid username or password, or invalid on-premises username or password.", + "displayName": "Distributed Password cracking attempts in AzureAD", + "enabled": false, + "query": "let s_threshold = 30;\nlet l_threshold = 3;\nlet aadFunc = (tableName:string){\ntable(tableName)\n| where OperationName =~ \"Sign-in activity\"\n// Error codes that we want to look at as they are related to the use of incorrect password.\n| where ResultType in (\"50126\", \"50053\" , \"50055\", \"50056\")\n| extend DeviceDetail = todynamic(DeviceDetail), Status = todynamic(DeviceDetail), LocationDetails = todynamic(LocationDetails)\n| extend OS = DeviceDetail.operatingSystem, Browser = DeviceDetail.browser\n| extend StatusCode = tostring(Status.errorCode), StatusDetails = tostring(Status.additionalDetails)\n| extend LocationString = strcat(tostring(LocationDetails.countryOrRegion), \"/\", tostring(LocationDetails.state), \"/\", tostring(LocationDetails.city))\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), LocationCount=dcount(LocationString), Location = make_set(LocationString,100),\nIPAddress = make_set(IPAddress,100), IPAddressCount = dcount(IPAddress), AppDisplayName = make_set(AppDisplayName,100), ResultDescription = make_set(ResultDescription,50),\nBrowser = make_set(Browser,20), OS = make_set(OS,20), SigninCount = count() by UserPrincipalName, Type\n// Setting a generic threshold - Can be different for different environment\n| where SigninCount > s_threshold and LocationCount >= l_threshold\n| extend Location = tostring(Location), IPAddress = tostring(IPAddress), AppDisplayName = tostring(AppDisplayName), ResultDescription = tostring(ResultDescription), Browser = tostring(Browser), OS = tostring(OS)\n| extend timestamp = StartTime, Name = tostring(split(UserPrincipalName,'@',0)[0]), UPNSuffix = tostring(split(UserPrincipalName,'@',1)[0])};\nlet aadSignin = aadFunc(\"SigninLogs\");\nlet aadNonInt = aadFunc(\"AADNonInteractiveUserSignInLogs\");\nunion isfuzzy=true aadSignin, aadNonInt\n", + "queryFrequency": "P1D", + "queryPeriod": "P1D", + "severity": "Medium", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "SigninLogs" + ] }, - "triggers": { - "Microsoft_Sentinel_alert": { - "type": "ApiConnectionWebhook", - "inputs": { - "body": { - "callback_url": "@{listCallbackUrl()}" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" - } - }, - "path": "/subscribe" + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "AADNonInteractiveUserSignInLogs" + ] + } + ], + "tactics": [ + "CredentialAccess" + ], + "techniques": [ + "T1110" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "Name", + "identifier": "Name" + }, + { + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" } - } + ], + "entityType": "Account" }, - "actions": { - "Alert_-_Get_incident": { - "type": "ApiConnection", - "inputs": { - "host": { - "connection": { - "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" - } - }, - "method": "get", - "path": "/Incidents/subscriptions/@{encodeURIComponent(triggerBody()?['WorkspaceSubscriptionId'])}/resourceGroups/@{encodeURIComponent(triggerBody()?['WorkspaceResourceGroup'])}/workspaces/@{encodeURIComponent(triggerBody()?['WorkspaceId'])}/alerts/@{encodeURIComponent(triggerBody()?['SystemAlertId'])}" - } - }, - "Entities_-_Get_Accounts": { - "runAfter": { - "Alert_-_Get_incident": [ - "Succeeded" - ] - }, - "type": "ApiConnection", - "inputs": { - "body": "@triggerBody()?['Entities']", - "host": { - "connection": { - "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" - } - }, - "method": "post", - "path": "/entities/account" + { + "fieldMappings": [ + { + "columnName": "IPAddress", + "identifier": "Address" } - }, - "For_each": { - "foreach": "@body('Entities_-_Get_Accounts')?['Accounts']", - "actions": { - "Condition": { - "actions": { - "Condition_-_if_user_have_manager": { - "actions": { - "Add_comment_to_incident_-_with_manager_-_no_admin": { - "runAfter": { - "Get_user_-_details": [ - "Succeeded" - ] - }, - "type": "ApiConnection", - "inputs": { - "body": { - "incidentArmId": "@body('Alert_-_Get_incident')?['id']", - "message": "

User @{items('For_each')?['Name']} (UPN - @{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])}) was disabled in AAD via playbook Block-AADUser. Manager (@{body('Parse_JSON_-_get_user_manager')?['userPrincipalName']}) is notified.

" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" - } - }, - "method": "post", - "path": "/Incidents/Comment" - } - }, - "Get_user_-_details": { - "type": "ApiConnection", - "inputs": { - "host": { - "connection": { - "name": "@parameters('$connections')['azuread']['connectionId']" - } - }, - "method": "get", - "path": "/v1.0/users/@{encodeURIComponent(concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix']))}" - } - }, - "Send_an_email_-_to_manager_-_no_admin": { - "runAfter": { - "Add_comment_to_incident_-_with_manager_-_no_admin": [ - "Succeeded" - ] - }, - "type": "ApiConnection", - "inputs": { - "body": { - "Body": "

Security notification! This is automated email sent by Microsoft Sentinel Automation!
\n
\nYour direct report @{items('For_each')?['Name']} has been disabled in Azure AD due to the security incident. Can you please notify the user and work with him to reach our support.
\n
\nDirect report details:
\nFirst name: @{body('Get_user_-_details')?['displayName']}
\nSurname: @{body('Get_user_-_details')?['surname']}
\nJob title: @{body('Get_user_-_details')?['jobTitle']}
\nOffice location: @{body('Get_user_-_details')?['officeLocation']}
\nBusiness phone: @{body('Get_user_-_details')?['businessPhones']}
\nMobile phone: @{body('Get_user_-_details')?['mobilePhone']}
\nMail: @{body('Get_user_-_details')?['mail']}
\n
\nThank you!

", - "Importance": "High", - "Subject": "@{items('For_each')?['Name']} has been disabled in Azure AD due to the security risk!", - "To": "@body('Parse_JSON_-_get_user_manager')?['userPrincipalName']" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['office365']['connectionId']" - } - }, - "method": "post", - "path": "/v2/Mail" - } - } - }, - "runAfter": { - "Parse_JSON_-_get_user_manager": [ - "Succeeded" - ] - }, - "else": { - "actions": { - "Add_comment_to_incident_-_no_manager_-_no_admin": { - "type": "ApiConnection", - "inputs": { - "body": { - "incidentArmId": "@body('Alert_-_Get_incident')?['id']", - "message": "

User @{items('For_each')?['Name']} (UPN - @{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])}) was disabled in AAD via playbook Block-AADUser. Manager has not been notified, since it is not found for this user!

" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" - } - }, - "method": "post", - "path": "/Incidents/Comment" - } - } - } - }, - "expression": { - "and": [ - { - "not": { - "equals": [ - "@body('Parse_JSON_-_get_user_manager')?['userPrincipalName']", - "@null" - ] - } - } - ] - }, - "type": "If" - }, - "HTTP_-_get_user_manager": { - "type": "Http", - "inputs": { - "authentication": { - "audience": "https://graph.microsoft.com/", - "type": "ManagedServiceIdentity" - }, - "method": "GET", - "uri": "https://graph.microsoft.com/v1.0/users/@{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])}/manager" - } - }, - "Parse_JSON_-_get_user_manager": { - "runAfter": { - "HTTP_-_get_user_manager": [ - "Succeeded", - "Failed" - ] - }, - "type": "ParseJson", - "inputs": { - "content": "@body('HTTP_-_get_user_manager')", - "schema": { - "properties": { - "userPrincipalName": { - "type": "string" - } - }, - "type": "object" - } - } - } - }, - "runAfter": { - "Update_user_-_disable_user": [ - "Succeeded", - "Failed" - ] - }, - "else": { - "actions": { - "Add_comment_to_incident_-_error_details": { - "type": "ApiConnection", - "inputs": { - "body": { - "incidentArmId": "@body('Alert_-_Get_incident')?['id']", - "message": "

Block-AADUser playbook could not disable user @{items('For_each')?['Name']}.
\nError message: @{body('Update_user_-_disable_user')['error']['message']}
\nNote: If user is admin, this playbook don't have privilages to block admin users!

" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" - } - }, - "method": "post", - "path": "/Incidents/Comment" - } - } - } - }, - "expression": { - "and": [ - { - "equals": [ - "@body('Update_user_-_disable_user')", - "@null" - ] - } - ] - }, - "type": "If" - }, - "Update_user_-_disable_user": { - "type": "ApiConnection", - "inputs": { - "body": { - "accountEnabled": false - }, - "host": { - "connection": { - "name": "@parameters('$connections')['azuread']['connectionId']" - } - }, - "method": "patch", - "path": "/v1.0/users/@{encodeURIComponent(concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix']))}" - } - } - }, - "runAfter": { - "Entities_-_Get_Accounts": [ - "Succeeded" - ] - }, - "type": "Foreach" - } - } - }, - "parameters": { - "$connections": { - "value": { - "azuread": { - "connectionId": "[[resourceId('Microsoft.Web/connections', variables('AzureADConnectionName'))]", - "connectionName": "[[variables('AzureADConnectionName')]", - "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuread')]" - }, - "microsoftsentinel": { - "connectionId": "[[resourceId('Microsoft.Web/connections', variables('MicrosoftSentinelConnectionName'))]", - "connectionName": "[[variables('MicrosoftSentinelConnectionName')]", - "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", - "connectionProperties": { - "authentication": { - "type": "ManagedServiceIdentity" - } - } - }, - "office365": { - "connectionId": "[[resourceId('Microsoft.Web/connections', variables('Office365ConnectionName'))]", - "connectionName": "[[variables('Office365ConnectionName')]", - "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]" - } - } + ], + "entityType": "IP" } - } + ] } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('Playbook-', last(split(variables('playbookId1'),'/'))))]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId23'),'/'))))]", "properties": { - "parentId": "[variables('playbookId1')]", - "contentId": "[variables('_playbookContentId1')]", - "kind": "Playbook", - "version": "[variables('playbookVersion1')]", + "description": "Azure Active Directory Analytics Rule 23", + "parentId": "[variables('analyticRuleId23')]", + "contentId": "[variables('_analyticRulecontentId23')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion23')]", "source": { "kind": "Solution", "name": "Azure Active Directory", @@ -8849,415 +7685,626 @@ } } } - ], - "metadata": { - "title": "Block AAD user - Alert", - "description": "For each account entity included in the alert, this playbook will disable the user in Azure Active Directoy, add a comment to the incident that contains this alert and notify manager if available. Note: This playbook will not disable admin user!", - "prerequisites": [ - "None" - ], - "postDeployment": [ - "1. Assign Microsoft Sentinel Responder role to the Playbook's managed identity.", - "2. Grant User.Read.All, User.ReadWrite.All, Directory.Read.All, Directory.ReadWrite.All permissions to the managed identity.", - "3. Authorize Azure AD and Office 365 Outlook Logic App connections." - ], - "lastUpdateTime": "2022-07-11T00:00:00Z", - "entities": [ - "Account" - ], - "tags": [ - "Remediation" - ], - "releaseNotes": [ - { - "version": "1.0.0", - "title": "Added manager notification action", - "notes": [ - "Initial version" - ] - } - ] - } + ] }, "packageKind": "Solution", "packageVersion": "[variables('_solutionVersion')]", "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_playbookContentId1')]", - "contentKind": "Playbook", - "displayName": "Block-AADUser-Alert", - "contentProductId": "[variables('_playbookcontentProductId1')]", - "id": "[variables('_playbookcontentProductId1')]", - "version": "[variables('playbookVersion1')]" + "contentId": "[variables('_analyticRulecontentId23')]", + "contentKind": "AnalyticsRule", + "displayName": "Distributed Password cracking attempts in AzureAD", + "contentProductId": "[variables('_analyticRulecontentProductId23')]", + "id": "[variables('_analyticRulecontentProductId23')]", + "version": "[variables('analyticRuleVersion23')]" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('playbookTemplateSpecName2')]", + "name": "[variables('analyticRuleTemplateSpecName24')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "Block-AADUser-Incident Playbook with template version 3.0.4", + "description": "ExplicitMFADeny_AnalyticalRules Analytics Rule with template version 3.0.5", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('playbookVersion2')]", - "parameters": { - "PlaybookName": { - "defaultValue": "Block-AADUser-Incident", - "type": "string" - } - }, - "variables": { - "AzureADConnectionName": "[[concat('azuread-', parameters('PlaybookName'))]", - "MicrosoftSentinelConnectionName": "[[concat('microsoftsentinel-', parameters('PlaybookName'))]", - "Office365ConnectionName": "[[concat('office365-', parameters('PlaybookName'))]", - "connection-1": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuread')]", - "_connection-1": "[[variables('connection-1')]", - "connection-2": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", - "_connection-2": "[[variables('connection-2')]", - "connection-3": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]", - "_connection-3": "[[variables('connection-3')]", - "workspace-location-inline": "[concat('[resourceGroup().locatio', 'n]')]", - "workspace-name": "[parameters('workspace')]", - "workspaceResourceId": "[[resourceId('microsoft.OperationalInsights/Workspaces', variables('workspace-name'))]" - }, + "contentVersion": "[variables('analyticRuleVersion24')]", + "parameters": {}, + "variables": {}, "resources": [ { - "type": "Microsoft.Web/connections", - "apiVersion": "2016-06-01", - "name": "[[variables('AzureADConnectionName')]", - "location": "[[variables('workspace-location-inline')]", + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId24')]", + "apiVersion": "2022-04-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", "properties": { - "displayName": "[[variables('AzureADConnectionName')]", - "api": { - "id": "[[variables('_connection-1')]" - } + "description": "User explicitly denies MFA push, indicating that login was not expected and the account's password may be compromised.", + "displayName": "Explicit MFA Deny", + "enabled": false, + "query": "let aadFunc = (tableName:string){\ntable(tableName)\n| where ResultType == 500121\n| where Status has \"MFA Denied; user declined the authentication\" or Status has \"MFA denied; Phone App Reported Fraud\"\n| extend Type = Type\n| extend timestamp = TimeGenerated, Name = tostring(split(UserPrincipalName,'@',0)[0]), UPNSuffix = tostring(split(UserPrincipalName,'@',1)[0])\n};\nlet aadSignin = aadFunc(\"SigninLogs\");\nlet aadNonInt = aadFunc(\"AADNonInteractiveUserSignInLogs\");\nunion isfuzzy=true aadSignin, aadNonInt\n", + "queryFrequency": "P1D", + "queryPeriod": "P1D", + "severity": "Medium", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "SigninLogs" + ] + }, + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "AADNonInteractiveUserSignInLogs" + ] + } + ], + "tactics": [ + "CredentialAccess" + ], + "techniques": [ + "T1110" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "Name", + "identifier": "Name" + }, + { + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" + } + ], + "entityType": "Account" + }, + { + "fieldMappings": [ + { + "columnName": "IPAddress", + "identifier": "Address" + } + ], + "entityType": "IP" + }, + { + "fieldMappings": [ + { + "columnName": "ClientAppUsed", + "identifier": "Url" + } + ], + "entityType": "URL" + } + ] } }, { - "type": "Microsoft.Web/connections", - "apiVersion": "2016-06-01", - "name": "[[variables('MicrosoftSentinelConnectionName')]", - "location": "[[variables('workspace-location-inline')]", - "kind": "V1", + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId24'),'/'))))]", "properties": { - "displayName": "[[variables('MicrosoftSentinelConnectionName')]", - "parameterValueType": "Alternative", - "api": { - "id": "[[variables('_connection-2')]" + "description": "Azure Active Directory Analytics Rule 24", + "parentId": "[variables('analyticRuleId24')]", + "contentId": "[variables('_analyticRulecontentId24')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion24')]", + "source": { + "kind": "Solution", + "name": "Azure Active Directory", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "Microsoft", + "email": "[variables('_email')]" + }, + "support": { + "tier": "Microsoft", + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "link": "https://support.microsoft.com/" } } - }, + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_analyticRulecontentId24')]", + "contentKind": "AnalyticsRule", + "displayName": "Explicit MFA Deny", + "contentProductId": "[variables('_analyticRulecontentProductId24')]", + "id": "[variables('_analyticRulecontentProductId24')]", + "version": "[variables('analyticRuleVersion24')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleTemplateSpecName25')]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "ExchangeFullAccessGrantedToApp_AnalyticalRules Analytics Rule with template version 3.0.5", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleVersion25')]", + "parameters": {}, + "variables": {}, + "resources": [ { - "type": "Microsoft.Web/connections", - "apiVersion": "2016-06-01", - "name": "[[variables('Office365ConnectionName')]", - "location": "[[variables('workspace-location-inline')]", + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId25')]", + "apiVersion": "2022-04-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", "properties": { - "displayName": "[[variables('Office365ConnectionName')]", - "api": { - "id": "[[variables('_connection-3')]" + "description": "This detection looks for the full_access_as_app permission being granted to an OAuth application with Admin Consent.\nThis permission provide access to all Exchange mailboxes via the EWS API can could be exploited to access sensitive data \nby being added to a compromised application. The application granted this permission should be reviewed to ensure that it \nis absolutely necessary for the applications function.\nRef: https://learn.microsoft.com/graph/auth-limit-mailbox-access", + "displayName": "full_access_as_app Granted To Application", + "enabled": false, + "query": "AuditLogs\n| where LoggedByService =~ \"Core Directory\"\n| where Category =~ \"ApplicationManagement\"\n| where OperationName =~ \"Consent to application\"\n| where TargetResources has \"full_access_as_app\"\n| mv-expand TargetResources\n| extend OAuthAppName = TargetResources.displayName\n| extend ModifiedProperties = TargetResources.modifiedProperties \n| mv-apply Property = ModifiedProperties on \n (\n where Property.displayName =~ \"ConsentContext.isAdminConsent\"\n | extend AdminConsent = tostring(Property.newValue)\n )\n| mv-apply Property = ModifiedProperties on \n (\n where Property.displayName =~ \"ConsentAction.Permissions\"\n | extend Permissions = tostring(Property.newValue)\n )\n| mv-apply Property = ModifiedProperties on \n (\n where Property.displayName =~ \"TargetId.ServicePrincipalNames\"\n | extend AppId = tostring(Property.newValue)\n )\n| mv-expand AdditionalDetails\n| extend GrantUserAgent = tostring(iff(AdditionalDetails.key =~ \"User-Agent\", AdditionalDetails.value, \"\"))\n| parse Permissions with * \"ConsentType: \" GrantConsentType \", Scope: \" GrantScope1 \",\" *\n| where GrantScope1 =~ \"full_access_as_app\"\n| extend GrantIpAddress = tostring(iff(isnotempty(InitiatedBy.user.ipAddress), InitiatedBy.user.ipAddress, InitiatedBy.app.ipAddress))\n| extend GrantInitiatedBy = tostring(iff(isnotempty(InitiatedBy.user.userPrincipalName),InitiatedBy.user.userPrincipalName, InitiatedBy.app.displayName))\n| project-reorder TimeGenerated, OAuthAppName, AppId, AdminConsent, Permissions, GrantIpAddress, GrantInitiatedBy, GrantUserAgent, GrantScope1, GrantConsentType\n| extend Name = split(GrantInitiatedBy, \"@\")[0], UPNSuffix = split(GrantInitiatedBy, \"@\")[1]\n", + "queryFrequency": "PT1H", + "queryPeriod": "PT1H", + "severity": "Medium", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "AuditLogs" + ] + } + ], + "tactics": [ + "DefenseEvasion" + ], + "techniques": [ + "T1550" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "Name", + "identifier": "Name" + }, + { + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" + } + ], + "entityType": "Account" + }, + { + "fieldMappings": [ + { + "columnName": "GrantIpAddress", + "identifier": "Address" + } + ], + "entityType": "IP" + } + ], + "customDetails": { + "OAuthApplication": "OAuthAppName", + "OAuthAppId": "AppId", + "UserAgent": "GrantUserAgent" + }, + "alertDetailsOverride": { + "alertDisplayNameFormat": "User {{GrantInitiatedBy}} granted full_access_as_app to {{OAuthAppName}}", + "alertDescriptionFormat": "This detection looks for the full_access_as_app permission being granted to an OAuth application with Admin Consent.\nThis permission provide access to all Exchange mailboxes via the EWS API can could be exploited to access sensitive data \nby being added to a compromised application. The application granted this permission should be reviewed to ensure that it \nis absolutely necessary for the applications function.\nIn this case {{GrantInitiatedBy}} granted full_access_as_app to {{OAuthAppName}} from {{GrantIpAddress}}\nRef: https://learn.microsoft.com/graph/auth-limit-mailbox-access\n" } } }, { - "type": "Microsoft.Logic/workflows", - "apiVersion": "2017-07-01", - "name": "[[parameters('PlaybookName')]", - "location": "[[variables('workspace-location-inline')]", - "tags": { - "LogicAppsCategory": "security", - "hidden-SentinelTemplateName": "Block-AADUser", - "hidden-SentinelTemplateVersion": "1.1", - "hidden-SentinelWorkspaceId": "[[variables('workspaceResourceId')]" - }, - "identity": { - "type": "SystemAssigned" - }, - "dependsOn": [ - "[[resourceId('Microsoft.Web/connections', variables('AzureADConnectionName'))]", - "[[resourceId('Microsoft.Web/connections', variables('MicrosoftSentinelConnectionName'))]", - "[[resourceId('Microsoft.Web/connections', variables('Office365ConnectionName'))]" - ], + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId25'),'/'))))]", "properties": { - "state": "Enabled", - "definition": { - "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "$connections": { - "type": "Object" - } - }, - "triggers": { - "Microsoft_Sentinel_incident": { - "type": "ApiConnectionWebhook", - "inputs": { - "body": { - "callback_url": "@{listCallbackUrl()}" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" - } - }, - "path": "/incident-creation" - } - } - }, - "actions": { - "Entities_-_Get_Accounts": { - "type": "ApiConnection", - "inputs": { - "body": "@triggerBody()?['object']?['properties']?['relatedEntities']", - "host": { - "connection": { - "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" - } - }, - "method": "post", - "path": "/entities/account" - } - }, - "For_each": { - "foreach": "@body('Entities_-_Get_Accounts')?['Accounts']", - "actions": { - "Condition": { - "actions": { - "Condition_-_if_user_have_manager": { - "actions": { - "Add_comment_to_incident_-_with_manager_-_no_admin": { - "runAfter": { - "Get_user_-_details": [ - "Succeeded" - ] - }, - "type": "ApiConnection", - "inputs": { - "body": { - "incidentArmId": "@triggerBody()?['object']?['id']", - "message": "

User @{items('For_each')?['Name']} (UPN - @{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])}) was disabled in AAD via playbook Block-AADUser. Manager (@{body('Parse_JSON_-_get_user_manager')?['userPrincipalName']}) is notified.

" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" - } - }, - "method": "post", - "path": "/Incidents/Comment" - } - }, - "Get_user_-_details": { - "type": "ApiConnection", - "inputs": { - "host": { - "connection": { - "name": "@parameters('$connections')['azuread']['connectionId']" - } - }, - "method": "get", - "path": "/v1.0/users/@{encodeURIComponent(concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix']))}" - } - }, - "Send_an_email_-_to_manager_-_no_admin": { - "runAfter": { - "Add_comment_to_incident_-_with_manager_-_no_admin": [ - "Succeeded" - ] - }, - "type": "ApiConnection", - "inputs": { - "body": { - "Body": "

Security notification! This is automated email sent by Microsoft Sentinel Automation!
\n
\nYour direct report @{items('For_each')?['Name']} has been disabled in Azure AD due to the security incident. Can you please notify the user and work with him to reach our support.
\n
\nDirect report details:
\nFirst name: @{body('Get_user_-_details')?['displayName']}
\nSurname: @{body('Get_user_-_details')?['surname']}
\nJob title: @{body('Get_user_-_details')?['jobTitle']}
\nOffice location: @{body('Get_user_-_details')?['officeLocation']}
\nBusiness phone: @{body('Get_user_-_details')?['businessPhones']}
\nMobile phone: @{body('Get_user_-_details')?['mobilePhone']}
\nMail: @{body('Get_user_-_details')?['mail']}
\n
\nThank you!

", - "Importance": "High", - "Subject": "@{items('For_each')?['Name']} has been disabled in Azure AD due to the security risk!", - "To": "@body('Parse_JSON_-_get_user_manager')?['userPrincipalName']" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['office365']['connectionId']" - } - }, - "method": "post", - "path": "/v2/Mail" - } - } - }, - "runAfter": { - "Parse_JSON_-_get_user_manager": [ - "Succeeded" - ] - }, - "else": { - "actions": { - "Add_comment_to_incident_-_no_manager_-_no_admin": { - "type": "ApiConnection", - "inputs": { - "body": { - "incidentArmId": "@triggerBody()?['object']?['id']", - "message": "

User @{items('For_each')?['Name']} (UPN - @{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])}) was disabled in AAD via playbook Block-AADUser. Manager has not been notified, since it is not found for this user!

" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" - } - }, - "method": "post", - "path": "/Incidents/Comment" - } - } - } - }, - "expression": { - "and": [ - { - "not": { - "equals": [ - "@body('Parse_JSON_-_get_user_manager')?['userPrincipalName']", - "@null" - ] - } - } - ] - }, - "type": "If" - }, - "HTTP_-_get_user_manager": { - "type": "Http", - "inputs": { - "authentication": { - "audience": "https://graph.microsoft.com/", - "type": "ManagedServiceIdentity" - }, - "method": "GET", - "uri": "https://graph.microsoft.com/v1.0/users/@{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])}/manager" - } - }, - "Parse_JSON_-_get_user_manager": { - "runAfter": { - "HTTP_-_get_user_manager": [ - "Succeeded", - "Failed" - ] - }, - "type": "ParseJson", - "inputs": { - "content": "@body('HTTP_-_get_user_manager')", - "schema": { - "properties": { - "userPrincipalName": { - "type": "string" - } - }, - "type": "object" - } - } - } - }, - "runAfter": { - "Update_user_-_disable_user": [ - "Succeeded", - "Failed" - ] - }, - "else": { - "actions": { - "Add_comment_to_incident_-_error_details": { - "type": "ApiConnection", - "inputs": { - "body": { - "incidentArmId": "@triggerBody()?['object']?['id']", - "message": "

Block-AADUser playbook could not disable user @{items('For_each')?['Name']}.
\nError message: @{body('Update_user_-_disable_user')['error']['message']}
\nNote: If user is admin, this playbook don't have privilages to block admin users!

" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" - } - }, - "method": "post", - "path": "/Incidents/Comment" - } - } - } - }, - "expression": { - "and": [ - { - "equals": [ - "@body('Update_user_-_disable_user')", - "@null" - ] - } - ] - }, - "type": "If" - }, - "Update_user_-_disable_user": { - "type": "ApiConnection", - "inputs": { - "body": { - "accountEnabled": false - }, - "host": { - "connection": { - "name": "@parameters('$connections')['azuread']['connectionId']" - } - }, - "method": "patch", - "path": "/v1.0/users/@{encodeURIComponent(concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix']))}" - } - } - }, - "runAfter": { - "Entities_-_Get_Accounts": [ - "Succeeded" - ] + "description": "Azure Active Directory Analytics Rule 25", + "parentId": "[variables('analyticRuleId25')]", + "contentId": "[variables('_analyticRulecontentId25')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion25')]", + "source": { + "kind": "Solution", + "name": "Azure Active Directory", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "Microsoft", + "email": "[variables('_email')]" + }, + "support": { + "tier": "Microsoft", + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "link": "https://support.microsoft.com/" + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_analyticRulecontentId25')]", + "contentKind": "AnalyticsRule", + "displayName": "full_access_as_app Granted To Application", + "contentProductId": "[variables('_analyticRulecontentProductId25')]", + "id": "[variables('_analyticRulecontentProductId25')]", + "version": "[variables('analyticRuleVersion25')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleTemplateSpecName26')]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "FailedLogonToAzurePortal_AnalyticalRules Analytics Rule with template version 3.0.5", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleVersion26')]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId26')]", + "apiVersion": "2022-04-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", + "properties": { + "description": "Identifies failed login attempts in the Azure Active Directory SigninLogs to the Azure Portal. Many failed logon\nattempts or some failed logon attempts from multiple IPs could indicate a potential brute force attack.\nThe following are excluded due to success and non-failure results:\nReferences: https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-sign-ins-error-codes\n0 - successful logon\n50125 - Sign-in was interrupted due to a password reset or password registration entry.\n50140 - This error occurred due to 'Keep me signed in' interrupt when the user was signing-in.", + "displayName": "Failed login attempts to Azure Portal", + "enabled": false, + "query": "let timeRange = 1d;\nlet lookBack = 7d;\nlet threshold_Failed = 5;\nlet threshold_FailedwithSingleIP = 20;\nlet threshold_IPAddressCount = 2;\nlet isGUID = \"[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}\";\nlet aadFunc = (tableName:string){\nlet azPortalSignins = materialize(table(tableName)\n| where TimeGenerated >= ago(lookBack)\n// Azure Portal only\n| where AppDisplayName =~ \"Azure Portal\")\n;\nlet successPortalSignins = azPortalSignins\n| where TimeGenerated >= ago(timeRange)\n// Azure Portal only and exclude non-failure Result Types\n| where ResultType in (\"0\", \"50125\", \"50140\")\n// Tagging identities not resolved to friendly names\n//| extend Unresolved = iff(Identity matches regex isGUID, true, false)\n| distinct TimeGenerated, UserPrincipalName\n;\nlet failPortalSignins = azPortalSignins\n| where TimeGenerated >= ago(timeRange)\n// Azure Portal only and exclude non-failure Result Types\n| where ResultType !in (\"0\", \"50125\", \"50140\", \"70044\", \"70043\")\n// Tagging identities not resolved to friendly names\n| extend Unresolved = iff(Identity matches regex isGUID, true, false)\n;\n// Verify there is no success for the same connection attempt after the fail\nlet failnoSuccess = failPortalSignins | join kind= leftouter (\n successPortalSignins\n) on UserPrincipalName\n| where TimeGenerated > TimeGenerated1 or isempty(TimeGenerated1)\n| project-away TimeGenerated1, UserPrincipalName1\n;\n// Lookup up resolved identities from last 7 days\nlet identityLookup = azPortalSignins\n| where TimeGenerated >= ago(lookBack)\n| where not(Identity matches regex isGUID)\n| summarize by UserId, lu_UserDisplayName = UserDisplayName, lu_UserPrincipalName = UserPrincipalName;\n// Join resolved names to unresolved list from portal signins\nlet unresolvedNames = failnoSuccess | where Unresolved == true | join kind= inner (\n identityLookup\n) on UserId\n| extend UserDisplayName = lu_UserDisplayName, UserPrincipalName = lu_UserPrincipalName\n| project-away lu_UserDisplayName, lu_UserPrincipalName;\n// Join Signins that had resolved names with list of unresolved that now have a resolved name\nlet u_azPortalSignins = failnoSuccess | where Unresolved == false | union unresolvedNames;\nu_azPortalSignins\n| extend DeviceDetail = todynamic(DeviceDetail), Status = todynamic(DeviceDetail), LocationDetails = todynamic(LocationDetails)\n| extend Status = strcat(ResultType, \": \", ResultDescription), OS = tostring(DeviceDetail.operatingSystem), Browser = tostring(DeviceDetail.browser)\n| extend State = tostring(LocationDetails.state), City = tostring(LocationDetails.city), Region = tostring(LocationDetails.countryOrRegion)\n| extend FullLocation = strcat(Region,'|', State, '|', City) \n| summarize TimeGenerated = make_list(TimeGenerated,100), Status = make_list(Status,100), IPAddresses = make_list(IPAddress,100), IPAddressCount = dcount(IPAddress), FailedLogonCount = count()\nby UserPrincipalName, UserId, UserDisplayName, AppDisplayName, Browser, OS, FullLocation, Type\n| mvexpand TimeGenerated, IPAddresses, Status\n| extend TimeGenerated = todatetime(tostring(TimeGenerated)), IPAddress = tostring(IPAddresses), Status = tostring(Status)\n| project-away IPAddresses\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserPrincipalName, UserId, UserDisplayName, Status, FailedLogonCount, IPAddress, IPAddressCount, AppDisplayName, Browser, OS, FullLocation, Type\n| where (IPAddressCount >= threshold_IPAddressCount and FailedLogonCount >= threshold_Failed) or FailedLogonCount >= threshold_FailedwithSingleIP\n| extend timestamp = StartTime, Name = tostring(split(UserPrincipalName,'@',0)[0]), UPNSuffix = tostring(split(UserPrincipalName,'@',1)[0])\n};\nlet aadSignin = aadFunc(\"SigninLogs\");\nlet aadNonInt = aadFunc(\"AADNonInteractiveUserSignInLogs\");\nunion isfuzzy=true aadSignin, aadNonInt\n", + "queryFrequency": "P1D", + "queryPeriod": "P7D", + "severity": "Low", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "SigninLogs" + ] + }, + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "AADNonInteractiveUserSignInLogs" + ] + } + ], + "tactics": [ + "CredentialAccess" + ], + "techniques": [ + "T1110" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "Name", + "identifier": "Name" }, - "type": "Foreach" - } + { + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" + } + ], + "entityType": "Account" + }, + { + "fieldMappings": [ + { + "columnName": "IPAddress", + "identifier": "Address" + } + ], + "entityType": "IP" } + ] + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId26'),'/'))))]", + "properties": { + "description": "Azure Active Directory Analytics Rule 26", + "parentId": "[variables('analyticRuleId26')]", + "contentId": "[variables('_analyticRulecontentId26')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion26')]", + "source": { + "kind": "Solution", + "name": "Azure Active Directory", + "sourceId": "[variables('_solutionId')]" }, - "parameters": { - "$connections": { - "value": { - "azuread": { - "connectionId": "[[resourceId('Microsoft.Web/connections', variables('AzureADConnectionName'))]", - "connectionName": "[[variables('AzureADConnectionName')]", - "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuread')]" + "author": { + "name": "Microsoft", + "email": "[variables('_email')]" + }, + "support": { + "tier": "Microsoft", + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "link": "https://support.microsoft.com/" + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_analyticRulecontentId26')]", + "contentKind": "AnalyticsRule", + "displayName": "Failed login attempts to Azure Portal", + "contentProductId": "[variables('_analyticRulecontentProductId26')]", + "id": "[variables('_analyticRulecontentProductId26')]", + "version": "[variables('analyticRuleVersion26')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleTemplateSpecName27')]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "FirstAppOrServicePrincipalCredential_AnalyticalRules Analytics Rule with template version 3.0.5", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleVersion27')]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId27')]", + "apiVersion": "2022-04-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", + "properties": { + "description": "This will alert when an admin or app owner account adds a new credential to an Application or Service Principal where there was no previous verify KeyCredential associated.\nIf a threat actor obtains access to an account with sufficient privileges and adds the alternate authentication material triggering this event, the threat actor can now authenticate as the Application or Service Principal using this credential.\nAdditional information on OAuth Credential Grants can be found in RFC 6749 Section 4.4 or https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow\nFor further information on AuditLogs please see https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-audit-activities.", + "displayName": "First access credential added to Application or Service Principal where no credential was present", + "enabled": false, + "query": "AuditLogs\n| where OperationName has (\"Certificates and secrets management\")\n| where Result =~ \"success\"\n| where tostring(InitiatedBy.user.userPrincipalName) has \"@\" or tostring(InitiatedBy.app.displayName) has \"@\"\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"Application\"\n | extend targetDisplayName = tostring(TargetResource.displayName),\n targetId = tostring(TargetResource.id),\n targetType = tostring(TargetResource.type),\n keyEvents = TargetResource.modifiedProperties\n )\n| mv-apply Property = keyEvents on \n (\n where Property.displayName =~ \"KeyDescription\"\n | extend new_value_set = parse_json(tostring(Property.newValue)),\n old_value_set = parse_json(tostring(Property.oldValue))\n )\n| where old_value_set == \"[]\" \n| mv-expand new_value_set\n| parse new_value_set with * \"KeyIdentifier=\" keyIdentifier:string \",KeyType=\" keyType:string \",KeyUsage=\" keyUsage:string \",DisplayName=\" keyDisplayName:string \"]\" *\n| where keyUsage =~ \"Verify\"\n| mv-apply AdditionalDetail = AdditionalDetails on \n (\n where AdditionalDetail.key =~ \"User-Agent\"\n | extend UserAgent = tostring(AdditionalDetail.value)\n )\n| extend InitiatingUserOrApp = iff(isnotempty(InitiatedBy.user.userPrincipalName),tostring(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.app.displayName))\n| extend InitiatingIpAddress = iff(isnotempty(InitiatedBy.user.ipAddress), tostring(InitiatedBy.user.ipAddress), tostring(InitiatedBy.app.ipAddress))\n| project-away new_value_set, old_value_set\n| project-reorder TimeGenerated, OperationName, InitiatingUserOrApp, InitiatingIpAddress, UserAgent, targetDisplayName, targetId, targetType, keyDisplayName, keyType, keyUsage, keyIdentifier, CorrelationId, TenantId\n| extend timestamp = TimeGenerated, Name = tostring(split(InitiatingUserOrApp,'@',0)[0]), UPNSuffix = tostring(split(InitiatingUserOrApp,'@',1)[0])\n", + "queryFrequency": "PT1H", + "queryPeriod": "PT1H", + "severity": "High", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "AuditLogs" + ] + } + ], + "tactics": [ + "DefenseEvasion" + ], + "techniques": [ + "T1550" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "Name", + "identifier": "Name" }, - "microsoftsentinel": { - "connectionId": "[[resourceId('Microsoft.Web/connections', variables('MicrosoftSentinelConnectionName'))]", - "connectionName": "[[variables('MicrosoftSentinelConnectionName')]", - "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", - "connectionProperties": { - "authentication": { - "type": "ManagedServiceIdentity" - } - } + { + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" + } + ], + "entityType": "Account" + }, + { + "fieldMappings": [ + { + "columnName": "InitiatingIpAddress", + "identifier": "Address" + } + ], + "entityType": "IP" + }, + { + "fieldMappings": [ + { + "columnName": "targetDisplayName", + "identifier": "Name" + } + ], + "entityType": "CloudApplication" + } + ] + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId27'),'/'))))]", + "properties": { + "description": "Azure Active Directory Analytics Rule 27", + "parentId": "[variables('analyticRuleId27')]", + "contentId": "[variables('_analyticRulecontentId27')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion27')]", + "source": { + "kind": "Solution", + "name": "Azure Active Directory", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "Microsoft", + "email": "[variables('_email')]" + }, + "support": { + "tier": "Microsoft", + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "link": "https://support.microsoft.com/" + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_analyticRulecontentId27')]", + "contentKind": "AnalyticsRule", + "displayName": "First access credential added to Application or Service Principal where no credential was present", + "contentProductId": "[variables('_analyticRulecontentProductId27')]", + "id": "[variables('_analyticRulecontentProductId27')]", + "version": "[variables('analyticRuleVersion27')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleTemplateSpecName28')]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "GuestAccountsAddedinAADGroupsOtherThanTheOnesSpecified_AnalyticalRules Analytics Rule with template version 3.0.5", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleVersion28')]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId28')]", + "apiVersion": "2022-04-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", + "properties": { + "description": "Guest Accounts are added in the Organization Tenants to perform various tasks i.e projects execution, support etc.. This detection notifies when guest users are added to Azure AD Groups other than the ones specified and poses a risk to gain access to sensitive apps or data.", + "displayName": "Guest accounts added in AAD Groups other than the ones specified", + "enabled": false, + "query": "// OBJECT ID of AAD Groups can be found by navigating to Azure Active Directory then from menu on the left, select Groups and from the list shown of AAD Groups, the Second Column shows the ObjectID of each\nlet GroupIDs = dynamic([\"List with Custom AAD GROUP OBJECT ID 1\",\"Custom AAD GROUP OBJECT ID 2\"]);\nAuditLogs\n| where OperationName in ('Add member to group', 'Add owner to group')\n| extend InitiatedByActionUserInformation = iff(isnotempty(InitiatedBy.user.userPrincipalName), InitiatedBy.user.userPrincipalName, InitiatedBy.app.displayName)\n| extend InitiatedByIPAdress = InitiatedBy.user.ipAddress \n// Uncomment the following line to filter events where the inviting user was a guest user\n//| where InitiatedBy has_any (\"CUSTOM DOMAIN NAME#\", \"#EXT#\")\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"User\"\n | extend InvitedUser = trim(@'\"',tostring(TargetResource.userPrincipalName)),\n Properties = TargetResource.modifiedProperties\n )\n| mv-apply Property = Properties on \n (\n where Property.displayName =~ \"Group.DisplayName\"\n | extend AADGroup = trim('\"',tostring(Property.newValue))\n )\n| where InvitedUser has_any (\"CUSTOM DOMAIN NAME#\", \"#EXT#\")\n| mv-apply Property = Properties on\n (\n where Property.displayName =~ \"Group.ObjectID\"\n | extend AADGroupId = trim('\"',tostring(Property.newValue))\n )\n| where AADGroupId !in (GroupIDs)\n| extend Name = tostring(split(InitiatedByActionUserInformation,'@',0)[0]), UPNSuffix = tostring(split(InitiatedByActionUserInformation,'@',1)[0])\n", + "queryFrequency": "P1D", + "queryPeriod": "P1D", + "severity": "High", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "AuditLogs" + ] + } + ], + "tactics": [ + "InitialAccess", + "Persistence", + "Discovery" + ], + "techniques": [ + "T1078", + "T1136", + "T1087" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "InvitedUser", + "identifier": "Name" + } + ], + "entityType": "Account" + }, + { + "fieldMappings": [ + { + "columnName": "Name", + "identifier": "Name" }, - "office365": { - "connectionId": "[[resourceId('Microsoft.Web/connections', variables('Office365ConnectionName'))]", - "connectionName": "[[variables('Office365ConnectionName')]", - "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]" + { + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" } - } + ], + "entityType": "Account" + }, + { + "fieldMappings": [ + { + "columnName": "InitiatedByIPAdress", + "identifier": "Address" + } + ], + "entityType": "IP" } - } + ] } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('Playbook-', last(split(variables('playbookId2'),'/'))))]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId28'),'/'))))]", "properties": { - "parentId": "[variables('playbookId2')]", - "contentId": "[variables('_playbookContentId2')]", - "kind": "Playbook", - "version": "[variables('playbookVersion2')]", + "description": "Azure Active Directory Analytics Rule 28", + "parentId": "[variables('analyticRuleId28')]", + "contentId": "[variables('_analyticRulecontentId28')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion28')]", "source": { "kind": "Solution", "name": "Azure Active Directory", @@ -9275,426 +8322,234 @@ } } } - ], - "metadata": { - "title": "Block AAD user - Incident", - "description": "For each account entity included in the incident, this playbook will disable the user in Azure Active Directoy, add a comment to the incident that contains this alert and notify manager if available. Note: This playbook will not disable admin user!", - "prerequisites": [ - "None" - ], - "postDeployment": [ - "1. Assign Microsoft Sentinel Responder role to the Playbook's managed identity.", - "2. Grant User.Read.All, User.ReadWrite.All, Directory.Read.All, Directory.ReadWrite.All permissions to the managed identity.", - "3. Authorize Azure AD and Office 365 Outlook Logic App connections." - ], - "lastUpdateTime": "2022-07-11T00:00:00Z", - "entities": [ - "Account" - ], - "tags": [ - "Remediation" - ], - "releaseNotes": [ - { - "version": "1.0.0", - "title": "Added manager notification action", - "notes": [ - "Initial version" - ] - } - ] - } + ] }, "packageKind": "Solution", "packageVersion": "[variables('_solutionVersion')]", "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_playbookContentId2')]", - "contentKind": "Playbook", - "displayName": "Block-AADUser-Incident", - "contentProductId": "[variables('_playbookcontentProductId2')]", - "id": "[variables('_playbookcontentProductId2')]", - "version": "[variables('playbookVersion2')]" + "contentId": "[variables('_analyticRulecontentId28')]", + "contentKind": "AnalyticsRule", + "displayName": "Guest accounts added in AAD Groups other than the ones specified", + "contentProductId": "[variables('_analyticRulecontentProductId28')]", + "id": "[variables('_analyticRulecontentProductId28')]", + "version": "[variables('analyticRuleVersion28')]" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('playbookTemplateSpecName3')]", + "name": "[variables('analyticRuleTemplateSpecName29')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "Prompt-User-Alert Playbook with template version 3.0.4", + "description": "MailPermissionsAddedToApplication_AnalyticalRules Analytics Rule with template version 3.0.5", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('playbookVersion3')]", - "parameters": { - "PlaybookName": { - "defaultValue": "Prompt-User-Alert", - "type": "string" - }, - "TeamsId": { - "metadata": { - "description": "Enter the Teams Group ID" - }, - "type": "string" - }, - "TeamsChannelId": { - "metadata": { - "description": "Enter the Teams Channel ID" - }, - "type": "string" - } - }, - "variables": { - "AzureADConnectionName": "[[concat('azuread-', parameters('PlaybookName'))]", - "AzureSentinelConnectionName": "[[concat('azuresentinel-', parameters('PlaybookName'))]", - "Office365ConnectionName": "[[concat('office365-', parameters('PlaybookName'))]", - "TeamsConnectionName": "[[concat('teams-', parameters('PlaybookName'))]", - "connection-1": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuread')]", - "_connection-1": "[[variables('connection-1')]", - "connection-2": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", - "_connection-2": "[[variables('connection-2')]", - "connection-3": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]", - "_connection-3": "[[variables('connection-3')]", - "connection-4": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/teams')]", - "_connection-4": "[[variables('connection-4')]", - "workspace-location-inline": "[concat('[resourceGroup().locatio', 'n]')]", - "workspace-name": "[parameters('workspace')]", - "workspaceResourceId": "[[resourceId('microsoft.OperationalInsights/Workspaces', variables('workspace-name'))]" - }, + "contentVersion": "[variables('analyticRuleVersion29')]", + "parameters": {}, + "variables": {}, "resources": [ { - "type": "Microsoft.Web/connections", - "apiVersion": "2016-06-01", - "name": "[[variables('AzureADConnectionName')]", - "location": "[[variables('workspace-location-inline')]", - "properties": { - "displayName": "[[variables('AzureADConnectionName')]", - "api": { - "id": "[[variables('_connection-1')]" - } - } - }, - { - "type": "Microsoft.Web/connections", - "apiVersion": "2016-06-01", - "name": "[[variables('AzureSentinelConnectionName')]", - "location": "[[variables('workspace-location-inline')]", - "kind": "V1", - "properties": { - "displayName": "[[variables('AzureSentinelConnectionName')]", - "parameterValueType": "Alternative", - "api": { - "id": "[[variables('_connection-2')]" - } - } - }, - { - "type": "Microsoft.Web/connections", - "apiVersion": "2016-06-01", - "name": "[[variables('Office365ConnectionName')]", - "location": "[[variables('workspace-location-inline')]", + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId29')]", + "apiVersion": "2022-04-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", "properties": { - "displayName": "[[variables('Office365ConnectionName')]", - "api": { - "id": "[[variables('_connection-3')]" - } + "description": "This query look for applications that have been granted (Delegated or App/Role) permissions to Read Mail (Permissions field has Mail.Read) and subsequently has been consented to. This can help identify applications that have been abused to gain access to mailboxes.", + "displayName": "Mail.Read Permissions Granted to Application", + "enabled": false, + "query": "AuditLogs\n| where Category =~ \"ApplicationManagement\"\n| where ActivityDisplayName has_any (\"Add delegated permission grant\",\"Add app role assignment to service principal\") \n| where Result =~ \"success\"\n| where tostring(InitiatedBy.user.userPrincipalName) has \"@\" or tostring(InitiatedBy.app.displayName) has \"@\"\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"ServicePrincipal\" and array_length(TargetResource.modifiedProperties) > 0 and isnotnull(TargetResource.displayName)\n | extend props = TargetResource.modifiedProperties,\n Type = tostring(TargetResource.type),\n PermissionsAddedTo = tostring(TargetResource.displayName)\n )\n| mv-apply Property = props on \n (\n where Property.displayName =~ \"DelegatedPermissionGrant.Scope\"\n | extend DisplayName = tostring(Property.displayName), Permissions = trim('\"',tostring(Property.newValue))\n )\n| where Permissions has_any (\"Mail.Read\", \"Mail.ReadWrite\")\n| mv-apply AdditionalDetail = AdditionalDetails on \n (\n where AdditionalDetail.key =~ \"User-Agent\"\n | extend UserAgent = tostring(AdditionalDetail.value)\n )\n| extend InitiatingUser = tostring(InitiatedBy.user.userPrincipalName)\n| extend UserIPAddress = tostring(InitiatedBy.user.ipAddress) \n| project-away props, TargetResource*, AdditionalDetail*, Property, InitiatedBy\n| join kind=leftouter(\n AuditLogs\n | where ActivityDisplayName has \"Consent to application\"\n | mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"ServicePrincipal\"\n | extend AppName = tostring(TargetResource.displayName),\n AppId = tostring(TargetResource.id)\n )\n | project AppName, AppId, CorrelationId) on CorrelationId\n| project-reorder TimeGenerated, OperationName, InitiatingUser, UserIPAddress, UserAgent, PermissionsAddedTo, Permissions, AppName, AppId, CorrelationId\n| extend timestamp = TimeGenerated, Name = tostring(split(InitiatingUser,'@',0)[0]), UPNSuffix = tostring(split(InitiatingUser,'@',1)[0])\n", + "queryFrequency": "P1D", + "queryPeriod": "P1D", + "severity": "Medium", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "AuditLogs" + ] + } + ], + "tactics": [ + "Persistence" + ], + "techniques": [ + "T1098" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "Name", + "identifier": "Name" + }, + { + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" + } + ], + "entityType": "Account" + }, + { + "fieldMappings": [ + { + "columnName": "UserIPAddress", + "identifier": "Address" + } + ], + "entityType": "IP" + } + ] } }, { - "type": "Microsoft.Web/connections", - "apiVersion": "2016-06-01", - "name": "[[variables('TeamsConnectionName')]", - "location": "[[variables('workspace-location-inline')]", + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId29'),'/'))))]", "properties": { - "displayName": "[[variables('TeamsConnectionName')]", - "api": { - "id": "[[variables('_connection-4')]" + "description": "Azure Active Directory Analytics Rule 29", + "parentId": "[variables('analyticRuleId29')]", + "contentId": "[variables('_analyticRulecontentId29')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion29')]", + "source": { + "kind": "Solution", + "name": "Azure Active Directory", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "Microsoft", + "email": "[variables('_email')]" + }, + "support": { + "tier": "Microsoft", + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "link": "https://support.microsoft.com/" } } - }, + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_analyticRulecontentId29')]", + "contentKind": "AnalyticsRule", + "displayName": "Mail.Read Permissions Granted to Application", + "contentProductId": "[variables('_analyticRulecontentProductId29')]", + "id": "[variables('_analyticRulecontentProductId29')]", + "version": "[variables('analyticRuleVersion29')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleTemplateSpecName30')]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "MaliciousOAuthApp_O365AttackToolkit_AnalyticalRules Analytics Rule with template version 3.0.5", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleVersion30')]", + "parameters": {}, + "variables": {}, + "resources": [ { - "type": "Microsoft.Logic/workflows", - "apiVersion": "2017-07-01", - "name": "[[parameters('PlaybookName')]", - "location": "[[variables('workspace-location-inline')]", - "tags": { - "LogicAppsCategory": "security", - "hidden-SentinelTemplateName": "Prompt-User_alert", - "hidden-SentinelTemplateVersion": "1.1", - "hidden-SentinelWorkspaceId": "[[variables('workspaceResourceId')]" - }, - "identity": { - "type": "SystemAssigned" - }, - "dependsOn": [ - "[[resourceId('Microsoft.Web/connections', variables('AzureADConnectionName'))]", - "[[resourceId('Microsoft.Web/connections', variables('AzureSentinelConnectionName'))]", - "[[resourceId('Microsoft.Web/connections', variables('Office365ConnectionName'))]", - "[[resourceId('Microsoft.Web/connections', variables('TeamsConnectionName'))]" - ], + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId30')]", + "apiVersion": "2022-04-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", "properties": { - "state": "Enabled", - "definition": { - "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", - "actions": { - "Alert_-_Get_incident": { - "inputs": { - "host": { - "connection": { - "name": "@parameters('$connections')['azuresentinel']['connectionId']" - } - }, - "method": "get", - "path": "/Incidents/subscriptions/@{encodeURIComponent(triggerBody()?['WorkspaceSubscriptionId'])}/resourceGroups/@{encodeURIComponent(triggerBody()?['WorkspaceResourceGroup'])}/workspaces/@{encodeURIComponent(triggerBody()?['WorkspaceId'])}/alerts/@{encodeURIComponent(triggerBody()?['SystemAlertId'])}" - }, - "type": "ApiConnection" - }, - "Entities_-_Get_Accounts": { - "inputs": { - "body": "@triggerBody()?['Entities']", - "host": { - "connection": { - "name": "@parameters('$connections')['azuresentinel']['connectionId']" - } - }, - "method": "post", - "path": "/entities/account" - }, - "runAfter": { - "Alert_-_Get_incident": [ - "Succeeded" - ] - }, - "type": "ApiConnection" - }, - "For_each": { - "actions": { - "Condition_2": { - "actions": { - "Add_comment_to_incident_(V3)": { - "inputs": { - "body": { - "incidentArmId": "@body('Alert_-_Get_incident')?['id']", - "message": "

@{body('Get_user')?['displayName']} confirms they completed the action that triggered the alert.  Closing the incident.

" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['azuresentinel']['connectionId']" - } - }, - "method": "post", - "path": "/Incidents/Comment" - }, - "type": "ApiConnection" - }, - "Update_incident": { - "inputs": { - "body": { - "classification": { - "ClassificationAndReason": "BenignPositive - SuspiciousButExpected", - "ClassificationReasonText": "User Confirmed it was them" - }, - "incidentArmId": "@body('Alert_-_Get_incident')?['id']", - "status": "Closed" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['azuresentinel']['connectionId']" - } - }, - "method": "put", - "path": "/Incidents" - }, - "runAfter": { - "Add_comment_to_incident_(V3)": [ - "Succeeded" - ] - }, - "type": "ApiConnection" - } - }, - "else": { - "actions": { - "Add_comment_to_incident_(V3)_2": { - "inputs": { - "body": { - "incidentArmId": "@body('Alert_-_Get_incident')?['id']", - "message": "

@{body('Get_user')?['displayName']} confirms they did not complete the action. Further investigation is needed.

" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['azuresentinel']['connectionId']" - } - }, - "method": "post", - "path": "/Incidents/Comment" - }, - "type": "ApiConnection" - }, - "Post_message_in_a_chat_or_channel": { - "inputs": { - "body": { - "messageBody": "

New alert from Microsoft Sentinel.
\nPlease investigate ASAP.
\nSeverity : @{body('Alert_-_Get_incident')?['properties']?['severity']}
\nDescription: @{body('Alert_-_Get_incident')?['properties']?['description']}
\n
\n@{body('Get_user')?['displayName']} user confirmed they did not complete the action.

", - "recipient": { - "channelId": "[[parameters('TeamsChannelId')]", - "groupId": "[[parameters('TeamsId')]" - }, - "subject": "Incident @{body('Alert_-_Get_incident')?['properties']?['incidentNumber']} - @{body('Alert_-_Get_incident')?['properties']?['title']}" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['teams']['connectionId']" - } - }, - "method": "post", - "path": "/beta/teams/conversation/message/poster/@{encodeURIComponent('User')}/location/@{encodeURIComponent('Channel')}" - }, - "runAfter": { - "Add_comment_to_incident_(V3)_2": [ - "Succeeded" - ] - }, - "type": "ApiConnection" - } - } - }, - "expression": { - "and": [ - { - "equals": [ - "", - "This was me" - ] - } - ] - }, - "runAfter": { - "Send_approval_email": [ - "Succeeded" - ] - }, - "type": "If" - }, - "Get_user": { - "inputs": { - "host": { - "connection": { - "name": "@parameters('$connections')['azuread']['connectionId']" - } - }, - "method": "get", - "path": "/v1.0/users/@{encodeURIComponent(concat(items('For_each')?['Name'], '@' ,items('For_each')?['UPNSuffix']))}" - }, - "type": "ApiConnection" - }, - "Send_approval_email": { - "inputs": { - "body": { - "Message": { - "Body": "New Alert from Microsoft Sentinel.\nPlease respond ASAP.\nSeverity: @{triggerBody()?['Severity']}\nName: @{triggerBody()?['AlertDisplayName']}\nDescription: @{triggerBody()?['Description']}", - "HideHTMLMessage": false, - "Importance": "High", - "Options": "This was me, This was not me", - "ShowHTMLConfirmationDialog": false, - "Subject": "Security Alert: @{body('Alert_-_Get_incident')?['properties']?['title']}", - "To": "@body('Get_user')?['mail']" - }, - "NotificationUrl": "@{listCallbackUrl()}" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['office365']['connectionId']" - } - }, - "path": "/approvalmail/$subscriptions" - }, - "runAfter": { - "Get_user": [ - "Succeeded" - ] - }, - "type": "ApiConnectionWebhook" - } - }, - "foreach": "@body('Entities_-_Get_Accounts')?['Accounts']", - "runAfter": { - "Entities_-_Get_Accounts": [ - "Succeeded" - ] + "description": "This will alert when a user consents to provide a previously-unknown Azure application with the same OAuth permissions used by the MDSec O365 Attack Toolkit (https://github.com/mdsecactivebreach/o365-attack-toolkit).\nThe default permissions/scope for the MDSec O365 Attack toolkit change sometimes but often include contacts.read, user.read, mail.read, notes.read.all, mailboxsettings.readwrite, files.readwrite.all, mail.send, files.read, and files.read.all.\nConsent to applications with these permissions should be rare, especially as the knownApplications list is expanded, especially as the knownApplications list is expanded. Public contributions to expand this filter are welcome!\nFor further information on AuditLogs please see https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-audit-activities.", + "displayName": "Suspicious application consent similar to O365 Attack Toolkit", + "enabled": false, + "query": "let detectionTime = 1d;\nlet joinLookback = 14d;\nlet threshold = 5;\nlet o365_attack_regex = \"contacts.read|user.read|mail.read|notes.read.all|mailboxsettings.readwrite|Files.ReadWrite.All|mail.send|files.read|files.read.all\";\nlet o365_attack = dynamic([\"contacts.read\", \"user.read\", \"mail.read\", \"notes.read.all\", \"mailboxsettings.readwrite\", \"Files.ReadWrite.All\", \"mail.send\", \"files.read\", \"files.read.all\"]);\nAuditLogs\n| where TimeGenerated > ago(detectionTime)\n| where LoggedByService =~ \"Core Directory\"\n| where Category =~ \"ApplicationManagement\"\n| where OperationName =~ \"Consent to application\"\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"ServicePrincipal\"\n | extend AppDisplayName = tostring(TargetResource.displayName),\n AppClientId = tostring(TargetResource.id),\n props = TargetResource.modifiedProperties\n )\n| where AppClientId !in ((externaldata(knownAppClientId:string, knownAppDisplayName:string)[@\"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Sample%20Data/Feeds/Microsoft.OAuth.KnownApplications.csv\"] with (format=\"csv\"))) // NOTE: a MATCH from this list will cause the alert to NOT fire - please modify for your environment!\n| mv-apply ConsentFull = props on \n (\n where ConsentFull.displayName =~ \"ConsentAction.Permissions\"\n )\n| parse ConsentFull with * \"ConsentType: \" GrantConsentType \", Scope: \" GrantScope1 \", CreatedDateTime\" * \"]\" *\n| where GrantConsentType != \"AllPrincipals\" // NOTE: we are ignoring if OAuth application was granted to all users via an admin - but admin due diligence should be audited occasionally\n| where ConsentFull has_any (o365_attack) \n| extend GrantScopeCount = countof(tolower(GrantScope1), o365_attack_regex, 'regex')\n| where GrantScopeCount > threshold\n| extend GrantIpAddress = iff(isnotempty(InitiatedBy.user.ipAddress), tostring(InitiatedBy.user.ipAddress), tostring(InitiatedBy.app.ipAddress))\n| extend GrantInitiatedBy = iff(isnotempty(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.app.displayName))\n| mv-apply AdditionalDetail = AdditionalDetails on \n (\n where AdditionalDetail.key =~ \"User-Agent\"\n | extend GrantUserAgent = AdditionalDetail.value\n )\n| project TimeGenerated, GrantConsentType, GrantScope1, GrantInitiatedBy, AppDisplayName, GrantIpAddress, GrantUserAgent, AppClientId, OperationName, ConsentFull, CorrelationId\n| join kind = leftouter (AuditLogs\n | where TimeGenerated > ago(joinLookback)\n | where LoggedByService =~ \"Core Directory\"\n | where Category =~ \"ApplicationManagement\"\n | where OperationName =~ \"Add service principal\"\n | mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"ServicePrincipal\"\n | extend props = TargetResource.modifiedProperties,\n AppClientId = tostring(TargetResource.id)\n )\n | mv-apply Property = props on \n (\n where Property.displayName =~ \"AppAddress\" and Property.newValue has \"AddressType\"\n | extend AppReplyURLs = trim('\"',tostring(Property.newValue))\n )\n | distinct AppClientId, tostring(AppReplyURLs)\n) on AppClientId\n| join kind = innerunique (AuditLogs\n | where TimeGenerated > ago(joinLookback)\n | where LoggedByService =~ \"Core Directory\"\n | where Category =~ \"ApplicationManagement\"\n | where OperationName =~ \"Add OAuth2PermissionGrant\" or OperationName =~ \"Add delegated permission grant\"\n | mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"ServicePrincipal\" and array_length(TargetResource.modifiedProperties) > 0 and isnotnull(TargetResource.displayName)\n | extend GrantAuthentication = tostring(TargetResource.displayName)\n )\n | extend GrantOperation = OperationName\n | project GrantAuthentication, GrantOperation, CorrelationId\n ) on CorrelationId\n| project TimeGenerated, GrantConsentType, GrantScope1, GrantInitiatedBy, AppDisplayName, AppReplyURLs, GrantIpAddress, GrantUserAgent, AppClientId, GrantAuthentication, OperationName, GrantOperation, CorrelationId, ConsentFull\n| extend timestamp = TimeGenerated, Name = tostring(split(GrantInitiatedBy,'@',0)[0]), UPNSuffix = tostring(split(GrantInitiatedBy,'@',1)[0])\n", + "queryFrequency": "P1D", + "queryPeriod": "P14D", + "severity": "High", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "AuditLogs" + ] + } + ], + "tactics": [ + "CredentialAccess", + "DefenseEvasion" + ], + "techniques": [ + "T1528", + "T1550" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "Name", + "identifier": "Name" }, - "type": "Foreach" - } + { + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" + } + ], + "entityType": "Account" }, - "contentVersion": "1.0.0.0", - "parameters": { - "$connections": { - "type": "Object" - } + { + "fieldMappings": [ + { + "columnName": "GrantIpAddress", + "identifier": "Address" + } + ], + "entityType": "IP" }, - "triggers": { - "Microsoft_Sentinel_alert": { - "inputs": { - "body": { - "callback_url": "@{listCallbackUrl()}" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['azuresentinel']['connectionId']" - } - }, - "path": "/subscribe" - }, - "type": "ApiConnectionWebhook" - } - } - }, - "parameters": { - "$connections": { - "value": { - "azuread": { - "connectionId": "[[resourceId('Microsoft.Web/connections', variables('AzureADConnectionName'))]", - "connectionName": "[[variables('AzureADConnectionName')]", - "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuread')]" - }, - "azuresentinel": { - "connectionId": "[[resourceId('Microsoft.Web/connections', variables('AzureSentinelConnectionName'))]", - "connectionName": "[[variables('AzureSentinelConnectionName')]", - "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", - "connectionProperties": { - "authentication": { - "type": "ManagedServiceIdentity" - } - } - }, - "office365": { - "connectionId": "[[resourceId('Microsoft.Web/connections', variables('Office365ConnectionName'))]", - "connectionName": "[[variables('Office365ConnectionName')]", - "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]" - }, - "teams": { - "connectionId": "[[resourceId('Microsoft.Web/connections', variables('TeamsConnectionName'))]", - "connectionName": "[[variables('TeamsConnectionName')]", - "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/teams')]" + { + "fieldMappings": [ + { + "columnName": "AppDisplayName", + "identifier": "Name" } - } + ], + "entityType": "CloudApplication" } - } + ] } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('Playbook-', last(split(variables('playbookId3'),'/'))))]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId30'),'/'))))]", "properties": { - "parentId": "[variables('playbookId3')]", - "contentId": "[variables('_playbookContentId3')]", - "kind": "Playbook", - "version": "[variables('playbookVersion3')]", + "description": "Azure Active Directory Analytics Rule 30", + "parentId": "[variables('analyticRuleId30')]", + "contentId": "[variables('_analyticRulecontentId30')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion30')]", "source": { "kind": "Solution", "name": "Azure Active Directory", @@ -9712,408 +8567,576 @@ } } } - ], - "metadata": { - "title": "Prompt User - Alert", - "description": "This playbook will ask the user if they completed the action from the alert in Microsoft Sentinel. If so, it will close the incident and add a comment. If not, it will post a message to teams for the SOC to investigate and add a comment to the incident.", - "prerequisites": [ - "1. You will need the Team Id and Channel Id." - ], - "postDeployment": [ - "1. Assign Microsoft Sentinel Responder role to the Playbook's managed identity.", - "2. Authorize Azure AD, Microsoft Teams, and Office 365 Outlook Logic App connections." - ], - "lastUpdateTime": "2022-07-11T00:00:00Z", - "entities": [ - "Account" - ], - "tags": [ - "Remediation" - ], - "releaseNotes": [ - { - "version": "1.0.0", - "title": "Added new Post a Teams message action", - "notes": [ - "Initial version" - ] - } - ] - } + ] }, "packageKind": "Solution", "packageVersion": "[variables('_solutionVersion')]", "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_playbookContentId3')]", - "contentKind": "Playbook", - "displayName": "Prompt-User-Alert", - "contentProductId": "[variables('_playbookcontentProductId3')]", - "id": "[variables('_playbookcontentProductId3')]", - "version": "[variables('playbookVersion3')]" + "contentId": "[variables('_analyticRulecontentId30')]", + "contentKind": "AnalyticsRule", + "displayName": "Suspicious application consent similar to O365 Attack Toolkit", + "contentProductId": "[variables('_analyticRulecontentProductId30')]", + "id": "[variables('_analyticRulecontentProductId30')]", + "version": "[variables('analyticRuleVersion30')]" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('playbookTemplateSpecName4')]", + "name": "[variables('analyticRuleTemplateSpecName31')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "Prompt-User-Incident Playbook with template version 3.0.4", + "description": "MaliciousOAuthApp_PwnAuth_AnalyticalRules Analytics Rule with template version 3.0.5", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('playbookVersion4')]", - "parameters": { - "PlaybookName": { - "defaultValue": "Prompt-User-Incident", - "type": "string" - }, - "TeamsId": { - "metadata": { - "description": "Enter the Teams Group ID" - }, - "type": "string" - }, - "TeamsChannelId": { - "metadata": { - "description": "Enter the Teams Channel ID" - }, - "type": "string" - } - }, - "variables": { - "AzureADConnectionName": "[[concat('azuread-', parameters('PlaybookName'))]", - "AzureSentinelConnectionName": "[[concat('azuresentinel-', parameters('PlaybookName'))]", - "Office365ConnectionName": "[[concat('office365-', parameters('PlaybookName'))]", - "TeamsConnectionName": "[[concat('teams-', parameters('PlaybookName'))]", - "connection-1": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuread')]", - "_connection-1": "[[variables('connection-1')]", - "connection-2": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", - "_connection-2": "[[variables('connection-2')]", - "connection-3": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]", - "_connection-3": "[[variables('connection-3')]", - "connection-4": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/teams')]", - "_connection-4": "[[variables('connection-4')]", - "workspace-location-inline": "[concat('[resourceGroup().locatio', 'n]')]", - "workspace-name": "[parameters('workspace')]", - "workspaceResourceId": "[[resourceId('microsoft.OperationalInsights/Workspaces', variables('workspace-name'))]" - }, + "contentVersion": "[variables('analyticRuleVersion31')]", + "parameters": {}, + "variables": {}, "resources": [ { - "type": "Microsoft.Web/connections", - "apiVersion": "2016-06-01", - "name": "[[variables('AzureADConnectionName')]", - "location": "[[variables('workspace-location-inline')]", - "properties": { - "displayName": "[[variables('AzureADConnectionName')]", - "api": { - "id": "[[variables('_connection-1')]" - } - } - }, - { - "type": "Microsoft.Web/connections", - "apiVersion": "2016-06-01", - "name": "[[variables('AzureSentinelConnectionName')]", - "location": "[[variables('workspace-location-inline')]", - "kind": "V1", - "properties": { - "displayName": "[[variables('AzureSentinelConnectionName')]", - "parameterValueType": "Alternative", - "api": { - "id": "[[variables('_connection-2')]" - } - } - }, - { - "type": "Microsoft.Web/connections", - "apiVersion": "2016-06-01", - "name": "[[variables('Office365ConnectionName')]", - "location": "[[variables('workspace-location-inline')]", + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId31')]", + "apiVersion": "2022-04-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", "properties": { - "displayName": "[[variables('Office365ConnectionName')]", - "api": { - "id": "[[variables('_connection-3')]" - } + "description": "This will alert when a user consents to provide a previously-unknown Azure application with the same OAuth permissions used by the FireEye PwnAuth toolkit (https://github.com/fireeye/PwnAuth).\nThe default permissions/scope for the PwnAuth toolkit are user.read, offline_access, mail.readwrite, mail.send, and files.read.all.\nConsent to applications with these permissions should be rare, especially as the knownApplications list is expanded. Public contributions to expand this filter are welcome!\nFor further information on AuditLogs please see https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-audit-activities.", + "displayName": "Suspicious application consent similar to PwnAuth", + "enabled": false, + "query": "let detectionTime = 1d;\nlet joinLookback = 14d;\nAuditLogs\n| where TimeGenerated > ago(detectionTime)\n| where LoggedByService =~ \"Core Directory\"\n| where Category =~ \"ApplicationManagement\"\n| where OperationName =~ \"Consent to application\"\n| where TargetResources has \"offline\"\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"ServicePrincipal\"\n | extend AppDisplayName = tostring(TargetResource.displayName),\n AppClientId = tostring(TargetResource.id),\n props = TargetResource.modifiedProperties\n )\n| where AppClientId !in ((externaldata(knownAppClientId:string, knownAppDisplayName:string)[@\"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Sample%20Data/Feeds/Microsoft.OAuth.KnownApplications.csv\"] with (format=\"csv\")))\n| mv-apply ConsentFull = props on \n (\n where ConsentFull.displayName =~ \"ConsentAction.Permissions\"\n )\n| parse ConsentFull with * \"ConsentType: \" GrantConsentType \", Scope: \" GrantScope1 \"]\" *\n| where ConsentFull has_all (\"user.read\", \"offline_access\", \"mail.readwrite\", \"mail.send\", \"files.read.all\")\n| where GrantConsentType != \"AllPrincipals\" // NOTE: we are ignoring if OAuth application was granted to all users via an admin - but admin due diligence should be audited occasionally\n| extend GrantIpAddress = iff(isnotempty(InitiatedBy.user.ipAddress), tostring(InitiatedBy.user.ipAddress), tostring(InitiatedBy.app.ipAddress))\n| extend GrantInitiatedBy = iff(isnotempty(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.app.displayName))\n| mv-apply AdditionalDetail = AdditionalDetails on \n (\n where AdditionalDetail.key =~ \"User-Agent\"\n | extend GrantUserAgent = AdditionalDetail.value\n )\n| project TimeGenerated, GrantConsentType, GrantScope1, GrantInitiatedBy, AppDisplayName, GrantIpAddress, GrantUserAgent, AppClientId, OperationName, ConsentFull, CorrelationId\n| join kind = leftouter (AuditLogs\n| where TimeGenerated > ago(joinLookback)\n| where LoggedByService =~ \"Core Directory\"\n| where Category =~ \"ApplicationManagement\"\n| where OperationName =~ \"Add service principal\"\n | mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"ServicePrincipal\"\n | extend props = TargetResource.modifiedProperties,\n AppClientId = tostring(TargetResource.id)\n )\n | mv-apply Property = props on \n (\n where Property.displayName =~ \"AppAddress\" and Property.newValue has \"AddressType\"\n | extend AppReplyURLs = trim('\"',tostring(Property.newValue))\n )\n| distinct AppClientId, tostring(AppReplyURLs)\n)\non AppClientId\n| join kind = innerunique (AuditLogs\n| where TimeGenerated > ago(joinLookback)\n| where LoggedByService =~ \"Core Directory\"\n| where Category =~ \"ApplicationManagement\"\n| where OperationName =~ \"Add OAuth2PermissionGrant\" or OperationName =~ \"Add delegated permission grant\"\n | mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"ServicePrincipal\" and array_length(TargetResource.modifiedProperties) > 0 and isnotnull(TargetResource.displayName)\n | extend GrantAuthentication = tostring(TargetResource.displayName)\n )\n| extend GrantOperation = OperationName\n| project GrantAuthentication, GrantOperation, CorrelationId\n) on CorrelationId\n| project TimeGenerated, GrantConsentType, GrantScope1, GrantInitiatedBy, AppDisplayName, AppReplyURLs, GrantIpAddress, GrantUserAgent, AppClientId, GrantAuthentication, OperationName, GrantOperation, CorrelationId, ConsentFull\n| extend timestamp = TimeGenerated, Name = tostring(split(GrantInitiatedBy,'@',0)[0]), UPNSuffix = tostring(split(GrantInitiatedBy,'@',1)[0])\n", + "queryFrequency": "P1D", + "queryPeriod": "P14D", + "severity": "Medium", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "AuditLogs" + ] + } + ], + "tactics": [ + "CredentialAccess", + "DefenseEvasion" + ], + "techniques": [ + "T1528", + "T1550" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "Name", + "identifier": "Name" + }, + { + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" + } + ], + "entityType": "Account" + }, + { + "fieldMappings": [ + { + "columnName": "GrantIpAddress", + "identifier": "Address" + } + ], + "entityType": "IP" + } + ] } }, { - "type": "Microsoft.Web/connections", - "apiVersion": "2016-06-01", - "name": "[[variables('TeamsConnectionName')]", - "location": "[[variables('workspace-location-inline')]", + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId31'),'/'))))]", "properties": { - "displayName": "[[variables('TeamsConnectionName')]", - "api": { - "id": "[[variables('_connection-4')]" + "description": "Azure Active Directory Analytics Rule 31", + "parentId": "[variables('analyticRuleId31')]", + "contentId": "[variables('_analyticRulecontentId31')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion31')]", + "source": { + "kind": "Solution", + "name": "Azure Active Directory", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "Microsoft", + "email": "[variables('_email')]" + }, + "support": { + "tier": "Microsoft", + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "link": "https://support.microsoft.com/" } } - }, + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_analyticRulecontentId31')]", + "contentKind": "AnalyticsRule", + "displayName": "Suspicious application consent similar to PwnAuth", + "contentProductId": "[variables('_analyticRulecontentProductId31')]", + "id": "[variables('_analyticRulecontentProductId31')]", + "version": "[variables('analyticRuleVersion31')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleTemplateSpecName32')]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "MFARejectedbyUser_AnalyticalRules Analytics Rule with template version 3.0.5", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleVersion32')]", + "parameters": {}, + "variables": {}, + "resources": [ { - "type": "Microsoft.Logic/workflows", - "apiVersion": "2017-07-01", - "name": "[[parameters('PlaybookName')]", - "location": "[[variables('workspace-location-inline')]", - "tags": { - "LogicAppsCategory": "security", - "hidden-SentinelTemplateName": "Prompt-User", - "hidden-SentinelTemplateVersion": "1.1", - "hidden-SentinelWorkspaceId": "[[variables('workspaceResourceId')]" - }, - "identity": { - "type": "SystemAssigned" - }, - "dependsOn": [ - "[[resourceId('Microsoft.Web/connections', variables('AzureADConnectionName'))]", - "[[resourceId('Microsoft.Web/connections', variables('AzureSentinelConnectionName'))]", - "[[resourceId('Microsoft.Web/connections', variables('Office365ConnectionName'))]", - "[[resourceId('Microsoft.Web/connections', variables('TeamsConnectionName'))]" - ], + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId32')]", + "apiVersion": "2022-04-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", "properties": { - "state": "Enabled", - "definition": { - "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", - "actions": { - "Entities_-_Get_Accounts": { - "inputs": { - "body": "@triggerBody()?['object']?['properties']?['relatedEntities']", - "host": { - "connection": { - "name": "@parameters('$connections')['azuresentinel']['connectionId']" - } - }, - "method": "post", - "path": "/entities/account" - }, - "type": "ApiConnection" - }, - "For_each": { - "actions": { - "Condition_2": { - "actions": { - "Add_comment_to_incident_(V3)": { - "inputs": { - "body": { - "incidentArmId": "@triggerBody()?['object']?['id']", - "message": "

@{body('Get_user')?['displayName']} confirms they completed the action that triggered the alert.  Closing the incident.

" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['azuresentinel']['connectionId']" - } - }, - "method": "post", - "path": "/Incidents/Comment" - }, - "type": "ApiConnection" - }, - "Update_incident": { - "inputs": { - "body": { - "classification": { - "ClassificationAndReason": "BenignPositive - SuspiciousButExpected", - "ClassificationReasonText": "User Confirmed it was them" - }, - "incidentArmId": "@triggerBody()?['object']?['id']", - "status": "Closed" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['azuresentinel']['connectionId']" - } - }, - "method": "put", - "path": "/Incidents" - }, - "runAfter": { - "Add_comment_to_incident_(V3)": [ - "Succeeded" - ] - }, - "type": "ApiConnection" - } - }, - "else": { - "actions": { - "Add_comment_to_incident_(V3)_2": { - "inputs": { - "body": { - "incidentArmId": "@triggerBody()?['object']?['id']", - "message": "

@{body('Get_user')?['displayName']} confirms they did not complete the action. Further investigation is needed.

" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['azuresentinel']['connectionId']" - } - }, - "method": "post", - "path": "/Incidents/Comment" - }, - "type": "ApiConnection" - }, - "Post_message_in_a_chat_or_channel": { - "inputs": { - "body": { - "messageBody": "

New alert from Microsoft Sentinel.
\nPlease investigate ASAP.
\nSeverity : @{triggerBody()?['object']?['properties']?['severity']}
\nDescription: @{triggerBody()?['object']?['properties']?['description']}
\n
\n@{body('Get_user')?['displayName']} user confirmed they did not complete the action.

", - "recipient": { - "channelId": "[[parameters('TeamsChannelId')]", - "groupId": "[[parameters('TeamsId')]" - }, - "subject": "Incident @{triggerBody()?['object']?['properties']?['incidentNumber']} - @{triggerBody()?['object']?['properties']?['title']}" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['teams']['connectionId']" - } - }, - "method": "post", - "path": "/beta/teams/conversation/message/poster/@{encodeURIComponent('User')}/location/@{encodeURIComponent('Channel')}" - }, - "runAfter": { - "Add_comment_to_incident_(V3)_2": [ - "Succeeded" - ] - }, - "type": "ApiConnection" - } - } - }, - "expression": { - "and": [ - { - "equals": [ - "@body('Send_approval_email')?['SelectedOption']", - "This was me" - ] - } - ] - }, - "runAfter": { - "Send_approval_email": [ - "Succeeded" - ] - }, - "type": "If" - }, - "Get_user": { - "inputs": { - "host": { - "connection": { - "name": "@parameters('$connections')['azuread']['connectionId']" - } - }, - "method": "get", - "path": "/v1.0/users/@{encodeURIComponent(concat(items('For_each')?['Name'], '@' ,items('For_each')?['UPNSuffix']))}" - }, - "type": "ApiConnection" - }, - "Send_approval_email": { - "inputs": { - "body": { - "Message": { - "Body": "New Alert from Microsoft Sentinel.\nPlease respond ASAP.\nSeverity: @{triggerBody()?['object']?['properties']?['severity']}\nName: @{triggerBody()?['object']?['properties']?['title']}\nDescription: @{triggerBody()?['object']?['properties']?['description']}", - "HideHTMLMessage": false, - "Importance": "High", - "Options": "This was me, This was not me", - "ShowHTMLConfirmationDialog": false, - "Subject": "Security Alert: @{triggerBody()?['object']?['properties']?['title']}", - "To": "@body('Get_user')?['mail']" - }, - "NotificationUrl": "@{listCallbackUrl()}" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['office365']['connectionId']" - } - }, - "path": "/approvalmail/$subscriptions" - }, - "runAfter": { - "Get_user": [ - "Succeeded" - ] - }, - "type": "ApiConnectionWebhook" - } + "description": "Identifies occurances where a user has rejected an MFA prompt. This could be an indicator that a threat actor has compromised the username and password of this user account and is using it to try and log into the account.\nRef : https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-user-accounts#monitoring-for-failed-unusual-sign-ins\nThis query has also been updated to include UEBA logs IdentityInfo and BehaviorAnalytics for contextual information around the results.", + "displayName": "MFA Rejected by User", + "enabled": false, + "query": "let riskScoreCutoff = 20; //Adjust this based on volume of results\nSigninLogs\n| where ResultType == 500121\n| extend additionalDetails_ = tostring(Status.additionalDetails)\n| extend UserPrincipalName = tolower(UserPrincipalName)\n| where additionalDetails_ =~ \"MFA denied; user declined the authentication\" or additionalDetails_ has \"fraud\"\n| summarize StartTime = min(TimeGenerated), EndTIme = max(TimeGenerated) by UserPrincipalName, UserId, AADTenantId, IPAddress\n| extend Name = tostring(split(UserPrincipalName,'@',0)[0]), UPNSuffix = tostring(split(UserPrincipalName,'@',1)[0])\n| join kind=leftouter (\n IdentityInfo\n | summarize LatestReportTime = arg_max(TimeGenerated, *) by AccountUPN\n | extend BlastRadiusInt = iif(BlastRadius == \"High\", 1, 0)\n | project AccountUPN, Tags, JobTitle, GroupMembership, AssignedRoles, UserType, IsAccountEnabled, BlastRadiusInt\n | summarize\n Tags = make_set(Tags, 1000),\n GroupMembership = make_set(GroupMembership, 1000),\n AssignedRoles = make_set(AssignedRoles, 1000),\n BlastRadiusInt = sum(BlastRadiusInt),\n UserType = make_set(UserType, 1000),\n UserAccountControl = make_set(UserType, 1000)\n by AccountUPN\n | extend UserPrincipalName=tolower(AccountUPN)\n) on UserPrincipalName\n| join kind=leftouter (\n BehaviorAnalytics\n | where ActivityType in (\"FailedLogOn\", \"LogOn\")\n | where isnotempty(SourceIPAddress)\n | project UsersInsights, DevicesInsights, ActivityInsights, InvestigationPriority, SourceIPAddress\n | project-rename IPAddress = SourceIPAddress\n | summarize\n UsersInsights = make_set(UsersInsights, 1000),\n DevicesInsights = make_set(DevicesInsights, 1000),\n IPInvestigationPriority = sum(InvestigationPriority)\n by IPAddress)\non IPAddress\n| extend UEBARiskScore = BlastRadiusInt + IPInvestigationPriority\n| where UEBARiskScore > riskScoreCutoff\n| sort by UEBARiskScore desc \n", + "queryFrequency": "PT1H", + "queryPeriod": "PT1H", + "severity": "Medium", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "SigninLogs" + ] + }, + { + "connectorId": "BehaviorAnalytics", + "dataTypes": [ + "BehaviorAnalytics" + ] + }, + { + "connectorId": "IdentityInfo", + "dataTypes": [ + "IdentityInfo" + ] + } + ], + "tactics": [ + "InitialAccess" + ], + "techniques": [ + "T1078" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "Name", + "identifier": "Name" }, - "foreach": "@body('Entities_-_Get_Accounts')?['Accounts']", - "runAfter": { - "Entities_-_Get_Accounts": [ - "Succeeded" - ] + { + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" }, - "type": "Foreach" - } - }, - "contentVersion": "1.0.0.0", - "parameters": { - "$connections": { - "type": "Object" - } + { + "columnName": "UserId", + "identifier": "AadUserId" + } + ], + "entityType": "Account" }, - "triggers": { - "Microsoft_Sentinel_incident": { - "inputs": { - "body": { - "callback_url": "@{listCallbackUrl()}" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['azuresentinel']['connectionId']" - } - }, - "path": "/incident-creation" + { + "fieldMappings": [ + { + "columnName": "IPAddress", + "identifier": "Address" + } + ], + "entityType": "IP" + } + ] + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId32'),'/'))))]", + "properties": { + "description": "Azure Active Directory Analytics Rule 32", + "parentId": "[variables('analyticRuleId32')]", + "contentId": "[variables('_analyticRulecontentId32')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion32')]", + "source": { + "kind": "Solution", + "name": "Azure Active Directory", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "Microsoft", + "email": "[variables('_email')]" + }, + "support": { + "tier": "Microsoft", + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "link": "https://support.microsoft.com/" + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_analyticRulecontentId32')]", + "contentKind": "AnalyticsRule", + "displayName": "MFA Rejected by User", + "contentProductId": "[variables('_analyticRulecontentProductId32')]", + "id": "[variables('_analyticRulecontentProductId32')]", + "version": "[variables('analyticRuleVersion32')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleTemplateSpecName33')]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "MultipleAdmin_membership_removals_from_NewAdmin_AnalyticalRules Analytics Rule with template version 3.0.5", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleVersion33')]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId33')]", + "apiVersion": "2022-04-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", + "properties": { + "description": "This query detects when newly created Global admin removes multiple existing global admins which can be an attempt by adversaries to lock down organization and retain sole access. \n Investigate reasoning and intention of multiple membership removal by new Global admins and take necessary actions accordingly.", + "displayName": "Multiple admin membership removals from newly created admin.", + "enabled": false, + "query": "let lookback = 7d; \nlet timeframe = 1h; \nlet GlobalAdminsRemoved = AuditLogs \n| where TimeGenerated > ago(timeframe) \n| where Category =~ \"RoleManagement\" \n| where AADOperationType in (\"Unassign\", \"RemoveEligibleRole\") \n| where ActivityDisplayName has_any (\"Remove member from role\", \"Remove eligible member from role\") \n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"User\"\n | extend Target = tostring(TargetResource.userPrincipalName),\n props = TargetResource.modifiedProperties\n )\n| mv-apply Property = props on \n (\n where Property.displayName =~ \"Role.DisplayName\"\n | extend RoleName = trim('\"',tostring(Property.oldValue))\n )\n| where RoleName =~ \"Global Administrator\" // Add other Privileged role if applicable \n| extend InitiatingApp = tostring(InitiatedBy.app.displayName) \n| extend Initiator = iif(isnotempty(InitiatingApp), InitiatingApp, tostring(InitiatedBy.user.userPrincipalName)) \n| where Initiator != \"MS-PIM\" // Filtering PIM events \n| summarize RemovedGlobalAdminTime = max(TimeGenerated), TargetAdmins = make_set(Target,100) by OperationName, RoleName, Initiator, Result; \nlet GlobalAdminsAdded = AuditLogs \n| where TimeGenerated > ago(lookback) \n| where Category =~ \"RoleManagement\" \n| where AADOperationType in (\"Assign\", \"AssignEligibleRole\") \n| where ActivityDisplayName has_any (\"Add eligible member to role\", \"Add member to role\") and Result == \"success\" \n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"User\"\n | extend Target = tostring(TargetResource.userPrincipalName),\n props = TargetResource.modifiedProperties\n )\n| mv-apply Property = props on \n (\n where Property.displayName =~ \"Role.DisplayName\"\n | extend RoleName = trim('\"',tostring(Property.newValue))\n )\n| where RoleName =~ \"Global Administrator\" // Add other Privileged role if applicable \n| extend InitiatingApp = tostring(InitiatedBy.app.displayName) \n| extend Initiator = iif(isnotempty(InitiatingApp), InitiatingApp, tostring(InitiatedBy.user.userPrincipalName)) \n| where Initiator != \"MS-PIM\" // Filtering PIM events \n| summarize AddedGlobalAdminTime = max(TimeGenerated) by OperationName, RoleName, Target, Initiator, Result \n| extend AccountCustomEntity = Target; \nGlobalAdminsAdded \n| join kind= inner GlobalAdminsRemoved on $left.Target == $right.Initiator \n| where AddedGlobalAdminTime < RemovedGlobalAdminTime \n| extend NoofAdminsRemoved = array_length(TargetAdmins) \n| where NoofAdminsRemoved > 1\n| project AddedGlobalAdminTime, Initiator, Target, AccountCustomEntity, RemovedGlobalAdminTime, TargetAdmins, NoofAdminsRemoved\n| extend Name = tostring(split(AccountCustomEntity,'@',0)[0]), UPNSuffix = tostring(split(AccountCustomEntity,'@',1)[0])\n", + "queryFrequency": "PT1H", + "queryPeriod": "P7D", + "severity": "Medium", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "AuditLogs" + ] + } + ], + "tactics": [ + "Impact" + ], + "techniques": [ + "T1531" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "Name", + "identifier": "Name" + }, + { + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" + } + ], + "entityType": "Account" + } + ] + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId33'),'/'))))]", + "properties": { + "description": "Azure Active Directory Analytics Rule 33", + "parentId": "[variables('analyticRuleId33')]", + "contentId": "[variables('_analyticRulecontentId33')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion33')]", + "source": { + "kind": "Solution", + "name": "Azure Active Directory", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "Microsoft", + "email": "[variables('_email')]" + }, + "support": { + "tier": "Microsoft", + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "link": "https://support.microsoft.com/" + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_analyticRulecontentId33')]", + "contentKind": "AnalyticsRule", + "displayName": "Multiple admin membership removals from newly created admin.", + "contentProductId": "[variables('_analyticRulecontentProductId33')]", + "id": "[variables('_analyticRulecontentProductId33')]", + "version": "[variables('analyticRuleVersion33')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleTemplateSpecName34')]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "NewAppOrServicePrincipalCredential_AnalyticalRules Analytics Rule with template version 3.0.5", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleVersion34')]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId34')]", + "apiVersion": "2022-04-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", + "properties": { + "description": "This will alert when an admin or app owner account adds a new credential to an Application or Service Principal where a verify KeyCredential was already present for the app.\nIf a threat actor obtains access to an account with sufficient privileges and adds the alternate authentication material triggering this event, the threat actor can now authenticate as the Application or Service Principal using this credential.\nAdditional information on OAuth Credential Grants can be found in RFC 6749 Section 4.4 or https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow\nFor further information on AuditLogs please see https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-audit-activities.", + "displayName": "New access credential added to Application or Service Principal", + "enabled": false, + "query": "AuditLogs\n| where OperationName has_any (\"Add service principal\", \"Certificates and secrets management\") // captures \"Add service principal\", \"Add service principal credentials\", and \"Update application - Certificates and secrets management\" events\n| where Result =~ \"success\"\n| where tostring(InitiatedBy.user.userPrincipalName) has \"@\" or tostring(InitiatedBy.app.displayName) has \"@\"\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"Application\"\n | extend targetDisplayName = tostring(TargetResource.displayName),\n targetId = tostring(TargetResource.id),\n targetType = tostring(TargetResource.type),\n keyEvents = TargetResource.modifiedProperties\n )\n| mv-apply Property = keyEvents on \n (\n where Property.displayName =~ \"KeyDescription\"\n | extend new_value_set = parse_json(tostring(Property.newValue)),\n old_value_set = parse_json(tostring(Property.oldValue))\n )\n| where old_value_set != \"[]\"\n| extend diff = set_difference(new_value_set, old_value_set)\n| where isnotempty(diff)\n| parse diff with * \"KeyIdentifier=\" keyIdentifier:string \",KeyType=\" keyType:string \",KeyUsage=\" keyUsage:string \",DisplayName=\" keyDisplayName:string \"]\" *\n| where keyUsage =~ \"Verify\"\n| mv-apply AdditionalDetail = AdditionalDetails on \n (\n where AdditionalDetail.key =~ \"User-Agent\"\n | extend UserAgent = tostring(AdditionalDetail.value)\n )\n| extend InitiatingUserOrApp = iff(isnotempty(InitiatedBy.user.userPrincipalName),tostring(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.app.displayName))\n| extend InitiatingIpAddress = iff(isnotempty(InitiatedBy.user.ipAddress), tostring(InitiatedBy.user.ipAddress), tostring(InitiatedBy.app.ipAddress))\n// The below line is currently commented out but Microsoft Sentinel users can modify this query to show only Application or only Service Principal events in their environment\n//| where targetType =~ \"Application\" // or targetType =~ \"ServicePrincipal\"\n| project-away diff, new_value_set, old_value_set\n| project-reorder TimeGenerated, OperationName, InitiatingUserOrApp, InitiatingIpAddress, UserAgent, targetDisplayName, targetId, targetType, keyDisplayName, keyType, keyUsage, keyIdentifier, CorrelationId, TenantId\n| extend timestamp = TimeGenerated, Name = tostring(split(InitiatingUserOrApp,'@',0)[0]), UPNSuffix = tostring(split(InitiatingUserOrApp,'@',1)[0])\n", + "queryFrequency": "PT1H", + "queryPeriod": "PT1H", + "severity": "Medium", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "AuditLogs" + ] + } + ], + "tactics": [ + "DefenseEvasion" + ], + "techniques": [ + "T1550" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "Name", + "identifier": "Name" }, - "type": "ApiConnectionWebhook" - } + { + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" + } + ], + "entityType": "Account" + }, + { + "fieldMappings": [ + { + "columnName": "InitiatingIpAddress", + "identifier": "Address" + } + ], + "entityType": "IP" } + ] + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId34'),'/'))))]", + "properties": { + "description": "Azure Active Directory Analytics Rule 34", + "parentId": "[variables('analyticRuleId34')]", + "contentId": "[variables('_analyticRulecontentId34')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion34')]", + "source": { + "kind": "Solution", + "name": "Azure Active Directory", + "sourceId": "[variables('_solutionId')]" }, - "parameters": { - "$connections": { - "value": { - "azuread": { - "connectionId": "[[resourceId('Microsoft.Web/connections', variables('AzureADConnectionName'))]", - "connectionName": "[[variables('AzureADConnectionName')]", - "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuread')]" - }, - "azuresentinel": { - "connectionId": "[[resourceId('Microsoft.Web/connections', variables('AzureSentinelConnectionName'))]", - "connectionName": "[[variables('AzureSentinelConnectionName')]", - "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", - "connectionProperties": { - "authentication": { - "type": "ManagedServiceIdentity" - } - } - }, - "office365": { - "connectionId": "[[resourceId('Microsoft.Web/connections', variables('Office365ConnectionName'))]", - "connectionName": "[[variables('Office365ConnectionName')]", - "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]" + "author": { + "name": "Microsoft", + "email": "[variables('_email')]" + }, + "support": { + "tier": "Microsoft", + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "link": "https://support.microsoft.com/" + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_analyticRulecontentId34')]", + "contentKind": "AnalyticsRule", + "displayName": "New access credential added to Application or Service Principal", + "contentProductId": "[variables('_analyticRulecontentProductId34')]", + "id": "[variables('_analyticRulecontentProductId34')]", + "version": "[variables('analyticRuleVersion34')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleTemplateSpecName35')]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "NRT_ADFSDomainTrustMods_AnalyticalRules Analytics Rule with template version 3.0.5", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleVersion35')]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId35')]", + "apiVersion": "2022-04-01-preview", + "kind": "NRT", + "location": "[parameters('workspace-location')]", + "properties": { + "description": "This will alert when a user or application modifies the federation settings on the domain or Update domain authentication from Managed to Federated.\nFor example, this alert will trigger when a new Active Directory Federated Service (ADFS) TrustedRealm object, such as a signing certificate, is added to the domain.\nModification to domain federation settings should be rare. Confirm the added or modified target domain/URL is legitimate administrator behavior.\nTo understand why an authorized user may update settings for a federated domain in Office 365, Azure, or Intune, see: https://docs.microsoft.com/office365/troubleshoot/active-directory/update-federated-domain-office-365.\nFor details on security realms that accept security tokens, see the ADFS Proxy Protocol (MS-ADFSPP) specification: https://docs.microsoft.com/openspecs/windows_protocols/ms-adfspp/e7b9ea73-1980-4318-96a6-da559486664b.\nFor further information on AuditLogs please see https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-audit-activities.", + "displayName": "NRT Modified domain federation trust settings", + "enabled": false, + "query": "AuditLogs\n| where OperationName =~ \"Set federation settings on domain\" or OperationName =~ \"Set domain authentication\"\n//| where Result =~ \"success\" // commenting out, as it may be interesting to capture failed attempts\n| mv-expand TargetResources\n| extend modifiedProperties = parse_json(TargetResources).modifiedProperties\n| mv-apply Property = modifiedProperties on \n (\n where Property.displayName =~ \"LiveType\"\n | extend targetDisplayName = tostring(Property.displayName),\n NewDomainValue = tostring(Property.newValue)\n )\n| extend Federated = iif(OperationName =~ \"Set domain authentication\", iif(NewDomainValue has \"Federated\", True, False), True)\n| where Federated == True\n| mv-expand AdditionalDetails\n| mv-apply AdditionalDetail = AdditionalDetails on \n (\n where AdditionalDetail.key =~ \"User-Agent\"\n | extend UserAgent = tostring(AdditionalDetail.value)\n )\n| extend InitiatingUserOrApp = iff(isnotempty(InitiatedBy.user.userPrincipalName),tostring(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.app.displayName))\n| extend InitiatingIpAddress = iff(isnotempty(InitiatedBy.user.ipAddress), tostring(InitiatedBy.user.ipAddress), tostring(InitiatedBy.app.ipAddress))\n| project-reorder TimeGenerated, OperationName, InitiatingUserOrApp, AADOperationType, targetDisplayName, Result, InitiatingIpAddress, UserAgent, CorrelationId, TenantId, AADTenantId\n| extend Name = tostring(split(InitiatingUserOrApp,'@',0)[0]), UPNSuffix = tostring(split(InitiatingUserOrApp,'@',1)[0])\n", + "severity": "High", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "AuditLogs" + ] + } + ], + "tactics": [ + "CredentialAccess" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "Name", + "identifier": "Name" }, - "teams": { - "connectionId": "[[resourceId('Microsoft.Web/connections', variables('TeamsConnectionName'))]", - "connectionName": "[[variables('TeamsConnectionName')]", - "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/teams')]" + { + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" } - } + ], + "entityType": "Account" + }, + { + "fieldMappings": [ + { + "columnName": "InitiatingIpAddress", + "identifier": "Address" + } + ], + "entityType": "IP" } - } + ] } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('Playbook-', last(split(variables('playbookId4'),'/'))))]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId35'),'/'))))]", "properties": { - "parentId": "[variables('playbookId4')]", - "contentId": "[variables('_playbookContentId4')]", - "kind": "Playbook", - "version": "[variables('playbookVersion4')]", + "description": "Azure Active Directory Analytics Rule 35", + "parentId": "[variables('analyticRuleId35')]", + "contentId": "[variables('_analyticRulecontentId35')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion35')]", "source": { "kind": "Solution", "name": "Azure Active Directory", @@ -10131,388 +9154,454 @@ } } } - ], - "metadata": { - "title": "Prompt User - Incident", - "description": "This playbook will ask the user if they completed the action from the Incident in Microsoft Sentinel. If so, it will close the incident and add a comment. If not, it will post a message to teams for the SOC to investigate and add a comment to the incident.", - "prerequisites": [ - "1. You will need the Team Id and Channel Id." - ], - "postDeployment": [ - "1. Assign Microsoft Sentinel Responder role to the Playbook's managed identity.", - "2. Authorize Azure AD, Microsoft Teams, and Office 365 Outlook Logic App connections." - ], - "lastUpdateTime": "2022-07-11T00:00:00Z", - "entities": [ - "Account" - ], - "tags": [ - "Remediation" - ], - "releaseNotes": [ - { - "version": "1.0.0", - "title": "Added new Post a Teams message action", - "notes": [ - "Initial version" + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_analyticRulecontentId35')]", + "contentKind": "AnalyticsRule", + "displayName": "NRT Modified domain federation trust settings", + "contentProductId": "[variables('_analyticRulecontentProductId35')]", + "id": "[variables('_analyticRulecontentProductId35')]", + "version": "[variables('analyticRuleVersion35')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleTemplateSpecName36')]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "NRT_AuthenticationMethodsChangedforVIPUsers_AnalyticalRules Analytics Rule with template version 3.0.5", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleVersion36')]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId36')]", + "apiVersion": "2022-04-01-preview", + "kind": "NRT", + "location": "[parameters('workspace-location')]", + "properties": { + "description": "Identifies authentication methods being changed for a list of VIP users watchlist. This could be an indication of an attacker adding an auth method to the account so they can have continued access.", + "displayName": "NRT Authentication Methods Changed for VIP Users", + "enabled": false, + "query": "let security_info_actions = dynamic([\"User registered security info\", \"User changed default security info\", \"User deleted security info\", \"Admin updated security info\", \"User reviewed security info\", \"Admin deleted security info\", \"Admin registered security info\"]);\nlet VIPUsers = (_GetWatchlist('VIPUsers') | distinct \"User Principal Name\");\nAuditLogs\n| where Category =~ \"UserManagement\"\n| where ActivityDisplayName in (security_info_actions)\n| extend Initiator = tostring(InitiatedBy.user.userPrincipalName)\n| extend IP = tostring(InitiatedBy.user.ipAddress)\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"User\"\n | extend Target = trim(@'\"',tolower(tostring(TargetResource.userPrincipalName)))\n )\n| where Target in~ (VIPUsers)\n| summarize Start=min(TimeGenerated), End=max(TimeGenerated), Actions = make_set(ResultReason) by Initiator, IP, Result, Target\n| extend Name = tostring(split(Target,'@',0)[0]), UPNSuffix = tostring(split(Target,'@',1)[0])\n", + "severity": "Medium", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "AuditLogs" + ] + } + ], + "tactics": [ + "Persistence" + ], + "techniques": [ + "T1098" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "Name", + "identifier": "Name" + }, + { + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" + } + ], + "entityType": "Account" + }, + { + "fieldMappings": [ + { + "columnName": "IP", + "identifier": "Address" + } + ], + "entityType": "IP" + } ] } - ] - } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId36'),'/'))))]", + "properties": { + "description": "Azure Active Directory Analytics Rule 36", + "parentId": "[variables('analyticRuleId36')]", + "contentId": "[variables('_analyticRulecontentId36')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion36')]", + "source": { + "kind": "Solution", + "name": "Azure Active Directory", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "Microsoft", + "email": "[variables('_email')]" + }, + "support": { + "tier": "Microsoft", + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "link": "https://support.microsoft.com/" + } + } + } + ] }, "packageKind": "Solution", "packageVersion": "[variables('_solutionVersion')]", "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_playbookContentId4')]", - "contentKind": "Playbook", - "displayName": "Prompt-User-Incident", - "contentProductId": "[variables('_playbookcontentProductId4')]", - "id": "[variables('_playbookcontentProductId4')]", - "version": "[variables('playbookVersion4')]" + "contentId": "[variables('_analyticRulecontentId36')]", + "contentKind": "AnalyticsRule", + "displayName": "NRT Authentication Methods Changed for VIP Users", + "contentProductId": "[variables('_analyticRulecontentProductId36')]", + "id": "[variables('_analyticRulecontentProductId36')]", + "version": "[variables('analyticRuleVersion36')]" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('playbookTemplateSpecName5')]", + "name": "[variables('analyticRuleTemplateSpecName37')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "Reset-AADPassword-AlertTrigger Playbook with template version 3.0.4", - "mainTemplate": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('playbookVersion5')]", - "parameters": { - "PlaybookName": { - "defaultValue": "Reset-AADPassword-AlertTrigger", - "type": "string" - } - }, - "variables": { - "MicrosoftSentinelConnectionName": "[[concat('microsoftsentinel-', parameters('PlaybookName'))]", - "office365ConnectionName": "[[concat('office365-', parameters('PlaybookName'))]", - "connection-2": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", - "_connection-2": "[[variables('connection-2')]", - "connection-3": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]", - "_connection-3": "[[variables('connection-3')]", - "workspace-location-inline": "[concat('[resourceGroup().locatio', 'n]')]", - "workspace-name": "[parameters('workspace')]", - "workspaceResourceId": "[[resourceId('microsoft.OperationalInsights/Workspaces', variables('workspace-name'))]" - }, - "resources": [ - { - "properties": { - "provisioningState": "Succeeded", - "state": "Enabled", - "definition": { - "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "$connections": { - "type": "Object" - } - }, - "triggers": { - "Microsoft_Sentinel_alert": { - "type": "ApiConnectionWebhook", - "inputs": { - "body": { - "callback_url": "@{listCallbackUrl()}" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" - } - }, - "path": "/subscribe" - } - } - }, - "actions": { - "Alert_-_Get_incident": { - "runAfter": { - "Set_variable_-_password": [ - "Succeeded" - ] - }, - "type": "ApiConnection", - "inputs": { - "host": { - "connection": { - "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" - } - }, - "method": "get", - "path": "/Incidents/subscriptions/@{encodeURIComponent(triggerBody()?['WorkspaceSubscriptionId'])}/resourceGroups/@{encodeURIComponent(triggerBody()?['WorkspaceResourceGroup'])}/workspaces/@{encodeURIComponent(triggerBody()?['WorkspaceId'])}/alerts/@{encodeURIComponent(triggerBody()?['SystemAlertId'])}" - } - }, - "Entities_-_Get_Accounts": { - "runAfter": { - "Alert_-_Get_incident": [ - "Succeeded" - ] - }, - "type": "ApiConnection", - "inputs": { - "body": "@triggerBody()?['Entities']", - "host": { - "connection": { - "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" - } - }, - "method": "post", - "path": "/entities/account" - } - }, - "For_each": { - "foreach": "@body('Entities_-_Get_Accounts')?['Accounts']", - "actions": { - "Condition_-_is_manager_available": { - "actions": { - "Add_comment_to_incident_-_manager_available": { - "runAfter": { - "Send_an_email_-_to_manager_with_password_details": [ - "Succeeded" - ] - }, - "type": "ApiConnection", - "inputs": { - "body": { - "incidentArmId": "@body('Alert_-_Get_incident')?['id']", - "message": "

User @{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])} password was reset in AAD and their manager @{body('Parse_JSON_-_HTTP_-_get_manager')?['userPrincipalName']} was contacted using playbook.

" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" - } - }, - "method": "post", - "path": "/Incidents/Comment" - } - }, - "Parse_JSON_-_HTTP_-_get_manager": { - "type": "ParseJson", - "inputs": { - "content": "@body('HTTP_-_get_manager')", - "schema": { - "properties": { - "userPrincipalName": { - "type": "string" - } - }, - "type": "object" - } - } - }, - "Send_an_email_-_to_manager_with_password_details": { - "runAfter": { - "Parse_JSON_-_HTTP_-_get_manager": [ - "Succeeded" - ] - }, - "type": "ApiConnection", - "inputs": { - "body": { - "Body": "

User, @{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])}, was involved in part of a security incident.  As part of remediation, the user password has been reset.
\n
\nThe temporary password is: @{variables('Password')}
\n
\nThe user will be required to reset this password upon login.

", - "Subject": "A user password was reset due to security incident.", - "To": "@body('Parse_JSON_-_HTTP_-_get_manager')?['userPrincipalName']" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['office365']['connectionId']" - } - }, - "method": "post", - "path": "/v2/Mail" - } - } - }, - "runAfter": { - "HTTP_-_get_manager": [ - "Succeeded", - "Failed" - ] - }, - "else": { - "actions": { - "Add_comment_to_incident_-_manager_not_available": { - "type": "ApiConnection", - "inputs": { - "body": { - "incidentArmId": "@body('Alert_-_Get_incident')?['id']", - "message": "

User @{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])} password was reset in AAD but the user doesn't have a manager.
\n
\nThe temporary password is: @{variables('Password')}
\n
\nThe user will be required to reset this password upon login.

" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" - } - }, - "method": "post", - "path": "/Incidents/Comment" - } - } - } - }, - "expression": { - "and": [ - { - "equals": [ - "@outputs('HTTP_-_get_manager')['statusCode']", - 200 - ] - } - ] - }, - "type": "If" - }, - "HTTP_-_get_manager": { - "runAfter": { - "HTTP_-_reset_a_password": [ - "Succeeded" - ] - }, - "type": "Http", - "inputs": { - "authentication": { - "audience": "https://graph.microsoft.com", - "type": "ManagedServiceIdentity" - }, - "method": "GET", - "uri": "https://graph.microsoft.com/v1.0/users/@{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])}/manager" - } - }, - "HTTP_-_reset_a_password": { - "type": "Http", - "inputs": { - "authentication": { - "audience": "https://graph.microsoft.com", - "type": "ManagedServiceIdentity" - }, - "body": { - "passwordProfile": { - "forceChangePasswordNextSignIn": true, - "forceChangePasswordNextSignInWithMfa": false, - "password": "@{variables('Password')}" - } - }, - "method": "PATCH", - "uri": "https://graph.microsoft.com/v1.0/users/@{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])}" - } - } + "description": "nrt_FirstAppOrServicePrincipalCredential_AnalyticalRules Analytics Rule with template version 3.0.5", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleVersion37')]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId37')]", + "apiVersion": "2022-04-01-preview", + "kind": "NRT", + "location": "[parameters('workspace-location')]", + "properties": { + "description": "This will alert when an admin or app owner account adds a new credential to an Application or Service Principal where there was no previous verify KeyCredential associated.\nIf a threat actor obtains access to an account with sufficient privileges and adds the alternate authentication material triggering this event, the threat actor can now authenticate as the Application or Service Principal using this credential.\nAdditional information on OAuth Credential Grants can be found in RFC 6749 Section 4.4 or https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow\nFor further information on AuditLogs please see https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-audit-activities.", + "displayName": "NRT First access credential added to Application or Service Principal where no credential was present", + "enabled": false, + "query": "AuditLogs\n| where OperationName has_any (\"Add service principal\", \"Certificates and secrets management\")\n| where Result =~ \"success\"\n| where tostring(InitiatedBy.user.userPrincipalName) has \"@\" or tostring(InitiatedBy.app.displayName) has \"@\"\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"Application\"\n | extend targetDisplayName = tostring(TargetResource.displayName),\n targetId = tostring(TargetResource.id),\n targetType = tostring(TargetResource.type),\n keyEvents = TargetResource.modifiedProperties\n )\n| mv-apply Property = keyEvents on \n (\n where Property.displayName =~ \"KeyDescription\"\n | extend new_value_set = parse_json(tostring(Property.newValue)),\n old_value_set = parse_json(tostring(Property.oldValue))\n )\n| where old_value_set == \"[]\"\n| mv-expand new_value_set\n| parse new_value_set with * \"KeyIdentifier=\" keyIdentifier:string \",KeyType=\" keyType:string \",KeyUsage=\" keyUsage:string \",DisplayName=\" keyDisplayName:string \"]\" *\n| where keyUsage == \"Verify\"\n | mv-apply AdditionalDetail = AdditionalDetails on \n (\n where AdditionalDetail.key =~ \"User-Agent\"\n | extend UserAgent = tostring(AdditionalDetail.value)\n )\n| extend InitiatingUserOrApp = iff(isnotempty(InitiatedBy.user.userPrincipalName),tostring(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.app.displayName))\n| extend InitiatingIpAddress = iff(isnotempty(InitiatedBy.user.ipAddress), tostring(InitiatedBy.user.ipAddress), tostring(InitiatedBy.app.ipAddress))\n//| where targetType =~ \"Application\" // or targetType =~ \"ServicePrincipal\"\n| project-away new_value_set, old_value_set\n| project-reorder TimeGenerated, OperationName, InitiatingUserOrApp, InitiatingIpAddress, UserAgent, targetDisplayName, targetId, targetType, keyDisplayName, keyType, keyUsage, keyIdentifier, CorrelationId, TenantId\n| extend timestamp = TimeGenerated, Name = tostring(split(InitiatingUserOrApp,'@',0)[0]), UPNSuffix = tostring(split(InitiatingUserOrApp,'@',1)[0])\n", + "severity": "Medium", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "AuditLogs" + ] + } + ], + "tactics": [ + "DefenseEvasion" + ], + "techniques": [ + "T1550" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "Name", + "identifier": "Name" }, - "runAfter": { - "Entities_-_Get_Accounts": [ - "Succeeded" - ] + { + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" + } + ], + "entityType": "Account" + }, + { + "fieldMappings": [ + { + "columnName": "InitiatingIpAddress", + "identifier": "Address" + } + ], + "entityType": "IP" + } + ] + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId37'),'/'))))]", + "properties": { + "description": "Azure Active Directory Analytics Rule 37", + "parentId": "[variables('analyticRuleId37')]", + "contentId": "[variables('_analyticRulecontentId37')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion37')]", + "source": { + "kind": "Solution", + "name": "Azure Active Directory", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "Microsoft", + "email": "[variables('_email')]" + }, + "support": { + "tier": "Microsoft", + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "link": "https://support.microsoft.com/" + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_analyticRulecontentId37')]", + "contentKind": "AnalyticsRule", + "displayName": "NRT First access credential added to Application or Service Principal where no credential was present", + "contentProductId": "[variables('_analyticRulecontentProductId37')]", + "id": "[variables('_analyticRulecontentProductId37')]", + "version": "[variables('analyticRuleVersion37')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleTemplateSpecName38')]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "NRT_NewAppOrServicePrincipalCredential_AnalyticalRules Analytics Rule with template version 3.0.5", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleVersion38')]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId38')]", + "apiVersion": "2022-04-01-preview", + "kind": "NRT", + "location": "[parameters('workspace-location')]", + "properties": { + "description": "This will alert when an admin or app owner account adds a new credential to an Application or Service Principal where a verify KeyCredential was already present for the app.\nIf a threat actor obtains access to an account with sufficient privileges and adds the alternate authentication material triggering this event, the threat actor can now authenticate as the Application or Service Principal using this credential.\nAdditional information on OAuth Credential Grants can be found in RFC 6749 Section 4.4 or https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow\nFor further information on AuditLogs please see https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-audit-activities.", + "displayName": "NRT New access credential added to Application or Service Principal", + "enabled": false, + "query": "AuditLogs\n| where OperationName has_any (\"Add service principal\", \"Certificates and secrets management\") // captures \"Add service principal\", \"Add service principal credentials\", and \"Update application - Certificates and secrets management\" events\n| where Result =~ \"success\"\n| where tostring(InitiatedBy.user.userPrincipalName) has \"@\" or tostring(InitiatedBy.app.displayName) has \"@\"\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"Application\"\n | extend targetDisplayName = tostring(TargetResource.displayName),\n targetId = tostring(TargetResource.id),\n targetType = tostring(TargetResource.type),\n keyEvents = TargetResource.modifiedProperties\n )\n| mv-apply Property = keyEvents on \n (\n where Property.displayName =~ \"KeyDescription\"\n | extend new_value_set = parse_json(tostring(Property.newValue)),\n old_value_set = parse_json(tostring(Property.oldValue))\n )\n| where old_value_set != \"[]\"\n| extend diff = set_difference(new_value_set, old_value_set)\n| where diff != \"[]\"\n| parse diff with * \"KeyIdentifier=\" keyIdentifier:string \",KeyType=\" keyType:string \",KeyUsage=\" keyUsage:string \",DisplayName=\" keyDisplayName:string \"]\" *\n| where keyUsage =~ \"Verify\"\n| mv-apply AdditionalDetail = AdditionalDetails on \n (\n where AdditionalDetail.key =~ \"User-Agent\"\n | extend UserAgent = tostring(AdditionalDetail.value)\n )\n| extend InitiatingUserOrApp = iff(isnotempty(InitiatedBy.user.userPrincipalName),tostring(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.app.displayName))\n| extend InitiatingIpAddress = iff(isnotempty(InitiatedBy.user.ipAddress), tostring(InitiatedBy.user.ipAddress), tostring(InitiatedBy.app.ipAddress))\n// The below line is currently commented out but Microsoft Sentinel users can modify this query to show only Application or only Service Principal events in their environment\n//| where targetType =~ \"Application\" // or targetType =~ \"ServicePrincipal\"\n| project-away diff, new_value_set, old_value_set\n| project-reorder TimeGenerated, OperationName, InitiatingUserOrApp, InitiatingIpAddress, UserAgent, targetDisplayName, targetId, targetType, keyDisplayName, keyType, keyUsage, keyIdentifier, CorrelationId, TenantId\n| extend timestamp = TimeGenerated, Name = tostring(split(InitiatingUserOrApp,'@',0)[0]), UPNSuffix = tostring(split(InitiatingUserOrApp,'@',1)[0])\n", + "severity": "Medium", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "AuditLogs" + ] + } + ], + "tactics": [ + "DefenseEvasion" + ], + "techniques": [ + "T1550" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "Name", + "identifier": "Name" }, - "type": "Foreach" - }, - "Initialize_variable": { - "type": "InitializeVariable", - "inputs": { - "variables": [ - { - "name": "Password", - "type": "String", - "value": "null" - } - ] + { + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" } - }, - "Set_variable_-_password": { - "runAfter": { - "Initialize_variable": [ - "Succeeded" - ] + ], + "entityType": "Account" + }, + { + "fieldMappings": [ + { + "columnName": "InitiatingIpAddress", + "identifier": "Address" + } + ], + "entityType": "IP" + } + ] + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId38'),'/'))))]", + "properties": { + "description": "Azure Active Directory Analytics Rule 38", + "parentId": "[variables('analyticRuleId38')]", + "contentId": "[variables('_analyticRulecontentId38')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion38')]", + "source": { + "kind": "Solution", + "name": "Azure Active Directory", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "Microsoft", + "email": "[variables('_email')]" + }, + "support": { + "tier": "Microsoft", + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "link": "https://support.microsoft.com/" + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_analyticRulecontentId38')]", + "contentKind": "AnalyticsRule", + "displayName": "NRT New access credential added to Application or Service Principal", + "contentProductId": "[variables('_analyticRulecontentProductId38')]", + "id": "[variables('_analyticRulecontentProductId38')]", + "version": "[variables('analyticRuleVersion38')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleTemplateSpecName39')]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "NRT_PIMElevationRequestRejected_AnalyticalRules Analytics Rule with template version 3.0.5", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleVersion39')]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId39')]", + "apiVersion": "2022-04-01-preview", + "kind": "NRT", + "location": "[parameters('workspace-location')]", + "properties": { + "description": "Identifies when a user is rejected for a privileged role elevation via PIM. Monitor rejections for indicators of attacker compromise of the requesting account.\nRef : https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-privileged-identity-management", + "displayName": "NRT PIM Elevation Request Rejected", + "enabled": false, + "query": "AuditLogs\n| where ActivityDisplayName =~'Add member to role completed (PIM activation)'\n| where Result =~ \"failure\"\n| mv-apply ResourceItem = TargetResources on \n (\n where ResourceItem.type =~ \"Role\"\n | extend Role = trim(@'\"',tostring(ResourceItem.displayName))\n )\n| mv-apply ResourceItem = TargetResources on \n (\n where ResourceItem.type =~ \"User\"\n | extend User = trim(@'\"',tostring(ResourceItem.userPrincipalName))\n )\n| project-reorder TimeGenerated, User, Role, OperationName, Result, ResultDescription\n| where isnotempty(InitiatedBy.user)\n| extend InitiatingUser = tostring(InitiatedBy.user.userPrincipalName), InitiatingIpAddress = tostring(InitiatedBy.user.ipAddress)\n| extend InitiatingName = tostring(split(InitiatingUser,'@',0)[0]), InitiatingUPNSuffix = tostring(split(InitiatingUser,'@',1)[0])\n| extend UserName = tostring(split(User,'@',0)[0]), UserUPNSuffix = tostring(split(User,'@',1)[0])\n", + "severity": "High", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "AuditLogs" + ] + } + ], + "tactics": [ + "Persistence" + ], + "techniques": [ + "T1078" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "InitiatingName", + "identifier": "Name" }, - "type": "SetVariable", - "inputs": { - "name": "Password", - "value": "@{substring(guid(), 0, 10)}" + { + "columnName": "InitiatingUPNSuffix", + "identifier": "UPNSuffix" } - } - } - }, - "parameters": { - "$connections": { - "value": { - "microsoftsentinel": { - "connectionId": "[[resourceId('Microsoft.Web/connections', variables('MicrosoftSentinelConnectionName'))]", - "connectionName": "[[variables('MicrosoftSentinelConnectionName')]", - "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", - "connectionProperties": { - "authentication": { - "type": "ManagedServiceIdentity" - } - } + ], + "entityType": "Account" + }, + { + "fieldMappings": [ + { + "columnName": "UserName", + "identifier": "Name" }, - "office365": { - "connectionId": "[[resourceId('Microsoft.Web/connections', variables('office365ConnectionName'))]", - "connectionName": "[[variables('office365ConnectionName')]", - "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]" + { + "columnName": "UserUPNSuffix", + "identifier": "UPNSuffix" } - } + ], + "entityType": "Account" + }, + { + "fieldMappings": [ + { + "columnName": "InitiatingIpAddress", + "identifier": "Address" + } + ], + "entityType": "IP" } - } - }, - "name": "[[parameters('PlaybookName')]", - "type": "Microsoft.Logic/workflows", - "location": "[[variables('workspace-location-inline')]", - "tags": { - "LogicAppsCategory": "security", - "hidden-SentinelTemplateName": "Reset-AADUserPassword_alert", - "hidden-SentinelTemplateVersion": "1.1", - "hidden-SentinelWorkspaceId": "[[variables('workspaceResourceId')]" - }, - "identity": { - "type": "SystemAssigned" - }, - "apiVersion": "2017-07-01", - "dependsOn": [ - "[[resourceId('Microsoft.Web/connections', variables('MicrosoftSentinelConnectionName'))]", - "[[resourceId('Microsoft.Web/connections', variables('office365ConnectionName'))]" - ] - }, - { - "type": "Microsoft.Web/connections", - "apiVersion": "2016-06-01", - "name": "[[variables('MicrosoftSentinelConnectionName')]", - "location": "[[variables('workspace-location-inline')]", - "kind": "V1", - "properties": { - "displayName": "[[variables('MicrosoftSentinelConnectionName')]", - "parameterValueType": "Alternative", - "api": { - "id": "[[variables('_connection-2')]" - } - } - }, - { - "type": "Microsoft.Web/connections", - "apiVersion": "2016-06-01", - "name": "[[variables('office365ConnectionName')]", - "location": "[[variables('workspace-location-inline')]", - "kind": "V1", - "properties": { - "displayName": "[[variables('office365ConnectionName')]", - "api": { - "id": "[[variables('_connection-3')]" - } + ] } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('Playbook-', last(split(variables('playbookId5'),'/'))))]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId39'),'/'))))]", "properties": { - "parentId": "[variables('playbookId5')]", - "contentId": "[variables('_playbookContentId5')]", - "kind": "Playbook", - "version": "[variables('playbookVersion5')]", + "description": "Azure Active Directory Analytics Rule 39", + "parentId": "[variables('analyticRuleId39')]", + "contentId": "[variables('_analyticRulecontentId39')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion39')]", "source": { "kind": "Solution", "name": "Azure Active Directory", @@ -10530,372 +9619,474 @@ } } } - ], - "metadata": { - "title": "Reset Azure AD User Password - Alert Trigger", - "description": "This playbook will reset the user password using Graph API. It will send the password (which is a random guid substring) to the user's manager. The user will have to reset the password upon login.", - "prerequisites": [ - "None" - ], - "postDeployment": [ - "1. Assign Password Administrator permission to managed identity.", - "2. Assign Microsoft Sentinel Responder permission to managed identity.", - "3. Authorize Office 365 Outlook connection" - ], - "lastUpdateTime": "2022-07-11T00:00:00Z", - "entities": [ - "Account" - ], - "tags": [ - "Remediation" - ], - "releaseNotes": [ - { - "version": "1.0.0", - "title": " Added manager notification action", - "notes": [ - "Initial version" - ] - } - ] - } + ] }, "packageKind": "Solution", "packageVersion": "[variables('_solutionVersion')]", "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_playbookContentId5')]", - "contentKind": "Playbook", - "displayName": "Reset-AADPassword-AlertTrigger", - "contentProductId": "[variables('_playbookcontentProductId5')]", - "id": "[variables('_playbookcontentProductId5')]", - "version": "[variables('playbookVersion5')]" + "contentId": "[variables('_analyticRulecontentId39')]", + "contentKind": "AnalyticsRule", + "displayName": "NRT PIM Elevation Request Rejected", + "contentProductId": "[variables('_analyticRulecontentProductId39')]", + "id": "[variables('_analyticRulecontentProductId39')]", + "version": "[variables('analyticRuleVersion39')]" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('playbookTemplateSpecName6')]", + "name": "[variables('analyticRuleTemplateSpecName40')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "Reset-AADPassword-IncidentTrigger Playbook with template version 3.0.4", + "description": "NRT_PrivlegedRoleAssignedOutsidePIM_AnalyticalRules Analytics Rule with template version 3.0.5", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('playbookVersion6')]", - "parameters": { - "PlaybookName": { - "defaultValue": "Reset-AADPassword-IncidentTrigger", - "type": "string" + "contentVersion": "[variables('analyticRuleVersion40')]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId40')]", + "apiVersion": "2022-04-01-preview", + "kind": "NRT", + "location": "[parameters('workspace-location')]", + "properties": { + "description": "Identifies a privileged role being assigned to a user outside of PIM\nRef : https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-privileged-accounts#things-to-monitor-1", + "displayName": "NRT Privileged Role Assigned Outside PIM", + "enabled": false, + "query": "AuditLogs\n| where Category =~ \"RoleManagement\"\n| where OperationName has \"Add member to role outside of PIM\"\n or (LoggedByService =~ \"Core Directory\" and OperationName =~ \"Add member to role\" and Identity != \"MS-PIM\")\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"User\"\n | extend UserPrincipalName = tostring(TargetResource.userPrincipalName)\n )\n| extend IpAddress = tostring(InitiatedBy.user.ipAddress), Name = tostring(split(UserPrincipalName,'@',0)[0]), UPNSuffix = tostring(split(UserPrincipalName,'@',1)[0])\n", + "severity": "Low", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "AuditLogs" + ] + } + ], + "tactics": [ + "PrivilegeEscalation" + ], + "techniques": [ + "T1078" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "Name", + "identifier": "Name" + }, + { + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" + } + ], + "entityType": "Account" + }, + { + "fieldMappings": [ + { + "columnName": "IpAddress", + "identifier": "Address" + } + ], + "entityType": "IP" + } + ] + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId40'),'/'))))]", + "properties": { + "description": "Azure Active Directory Analytics Rule 40", + "parentId": "[variables('analyticRuleId40')]", + "contentId": "[variables('_analyticRulecontentId40')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion40')]", + "source": { + "kind": "Solution", + "name": "Azure Active Directory", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "Microsoft", + "email": "[variables('_email')]" + }, + "support": { + "tier": "Microsoft", + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "link": "https://support.microsoft.com/" + } + } } - }, - "variables": { - "MicrosoftSentinelConnectionName": "[[concat('microsoftsentinel-', parameters('PlaybookName'))]", - "office365ConnectionName": "[[concat('office365-', parameters('PlaybookName'))]", - "connection-2": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", - "_connection-2": "[[variables('connection-2')]", - "connection-3": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]", - "_connection-3": "[[variables('connection-3')]", - "workspace-location-inline": "[concat('[resourceGroup().locatio', 'n]')]", - "workspace-name": "[parameters('workspace')]", - "workspaceResourceId": "[[resourceId('microsoft.OperationalInsights/Workspaces', variables('workspace-name'))]" - }, + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_analyticRulecontentId40')]", + "contentKind": "AnalyticsRule", + "displayName": "NRT Privileged Role Assigned Outside PIM", + "contentProductId": "[variables('_analyticRulecontentProductId40')]", + "id": "[variables('_analyticRulecontentProductId40')]", + "version": "[variables('analyticRuleVersion40')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleTemplateSpecName41')]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "NRT_UseraddedtoPrivilgedGroups_AnalyticalRules Analytics Rule with template version 3.0.5", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleVersion41')]", + "parameters": {}, + "variables": {}, "resources": [ { + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId41')]", + "apiVersion": "2022-04-01-preview", + "kind": "NRT", + "location": "[parameters('workspace-location')]", "properties": { - "provisioningState": "Succeeded", - "state": "Enabled", - "definition": { - "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "$connections": { - "type": "Object" - } - }, - "triggers": { - "Microsoft_Sentinel_incident": { - "type": "ApiConnectionWebhook", - "inputs": { - "body": { - "callback_url": "@{listCallbackUrl()}" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" - } - }, - "path": "/incident-creation" - } - } - }, - "actions": { - "Entities_-_Get_Accounts": { - "runAfter": { - "Set_variable_-_password": [ - "Succeeded" - ] - }, - "type": "ApiConnection", - "inputs": { - "body": "@triggerBody()?['object']?['properties']?['relatedEntities']", - "host": { - "connection": { - "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" - } - }, - "method": "post", - "path": "/entities/account" - } - }, - "For_each": { - "foreach": "@body('Entities_-_Get_Accounts')?['Accounts']", - "actions": { - "Condition_-_is_manager_available": { - "actions": { - "Add_comment_to_incident_-_manager_available": { - "runAfter": { - "Send_an_email_-_to_manager_with_password_details": [ - "Succeeded" - ] - }, - "type": "ApiConnection", - "inputs": { - "body": { - "incidentArmId": "@triggerBody()?['object']?['id']", - "message": "

User @{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])} password was reset in AAD and their manager @{body('Parse_JSON_-_HTTP_-_get_manager')?['userPrincipalName']} was contacted using playbook.

" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" - } - }, - "method": "post", - "path": "/Incidents/Comment" - } - }, - "Parse_JSON_-_HTTP_-_get_manager": { - "type": "ParseJson", - "inputs": { - "content": "@body('HTTP_-_get_manager')", - "schema": { - "properties": { - "userPrincipalName": { - "type": "string" - } - }, - "type": "object" - } - } - }, - "Send_an_email_-_to_manager_with_password_details": { - "runAfter": { - "Parse_JSON_-_HTTP_-_get_manager": [ - "Succeeded" - ] - }, - "type": "ApiConnection", - "inputs": { - "body": { - "Body": "

User, @{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])}, was involved in part of a security incident.  As part of remediation, the user password has been reset.
\n
\nThe temporary password is: @{variables('Password')}
\n
\nThe user will be required to reset this password upon login.

", - "Subject": "A user password was reset due to security incident.", - "To": "@body('Parse_JSON_-_HTTP_-_get_manager')?['userPrincipalName']" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['office365']['connectionId']" - } - }, - "method": "post", - "path": "/v2/Mail" - } - } - }, - "runAfter": { - "HTTP_-_get_manager": [ - "Succeeded", - "Failed" - ] - }, - "else": { - "actions": { - "Add_comment_to_incident_-_manager_not_available": { - "type": "ApiConnection", - "inputs": { - "body": { - "incidentArmId": "@triggerBody()?['object']?['id']", - "message": "

User @{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])} password was reset in AAD but the user doesn't have a manager.
\n
\nThe temporary password is: @{variables('Password')}
\n
\nThe user will be required to reset this password upon login.

" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" - } - }, - "method": "post", - "path": "/Incidents/Comment" - } - } - } - }, - "expression": { - "and": [ - { - "equals": [ - "@outputs('HTTP_-_get_manager')['statusCode']", - 200 - ] - } - ] - }, - "type": "If" - }, - "HTTP_-_get_manager": { - "runAfter": { - "HTTP_-_reset_a_password": [ - "Succeeded" - ] - }, - "type": "Http", - "inputs": { - "authentication": { - "audience": "https://graph.microsoft.com", - "type": "ManagedServiceIdentity" - }, - "method": "GET", - "uri": "https://graph.microsoft.com/v1.0/users/@{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])}/manager" - } - }, - "HTTP_-_reset_a_password": { - "type": "Http", - "inputs": { - "authentication": { - "audience": "https://graph.microsoft.com", - "type": "ManagedServiceIdentity" - }, - "body": { - "passwordProfile": { - "forceChangePasswordNextSignIn": true, - "forceChangePasswordNextSignInWithMfa": false, - "password": "@{variables('Password')}" - } - }, - "method": "PATCH", - "uri": "https://graph.microsoft.com/v1.0/users/@{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])}" - } - } - }, - "runAfter": { - "Entities_-_Get_Accounts": [ - "Succeeded" - ] + "description": "This will alert when a user is added to any of the Privileged Groups.\nFor further information on AuditLogs please see https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-audit-activities.\nFor Administrator role permissions in Azure Active Directory please see https://docs.microsoft.com/azure/active-directory/users-groups-roles/directory-assign-admin-roles", + "displayName": "NRT User added to Azure Active Directory Privileged Groups", + "enabled": false, + "query": "let OperationList = dynamic([\"Add member to role\",\"Add member to role in PIM requested (permanent)\"]);\nlet PrivilegedGroups = dynamic([\"UserAccountAdmins\",\"PrivilegedRoleAdmins\",\"TenantAdmins\"]);\nAuditLogs\n//| where LoggedByService =~ \"Core Directory\"\n| where Category =~ \"RoleManagement\"\n| where OperationName in~ (OperationList)\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"User\"\n | extend TargetUserPrincipalName = tostring(TargetResource.userPrincipalName),\n modProps = TargetResource.modifiedProperties\n )\n| mv-apply Property = modProps on \n (\n where Property.displayName =~ \"Role.WellKnownObjectName\"\n | extend DisplayName = trim('\"',tostring(Property.displayName)),\n GroupName = trim('\"',tostring(Property.newValue))\n )\n| extend AppId = InitiatedBy.app.appId,\n InitiatedByDisplayName = case(isnotempty(InitiatedBy.app.displayName), InitiatedBy.app.displayName, isnotempty(InitiatedBy.user.displayName), InitiatedBy.user.displayName, \"not available\"),\n ServicePrincipalId = tostring(InitiatedBy.app.servicePrincipalId),\n ServicePrincipalName = tostring(InitiatedBy.app.servicePrincipalName),\n UserId = InitiatedBy.user.id,\n UserIPAddress = InitiatedBy.user.ipAddress,\n UserRoles = InitiatedBy.user.roles,\n UserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)\n| where GroupName in~ (PrivilegedGroups)\n// If you don't want to alert for operations from PIM, remove below filtering for MS-PIM.\n//| where InitiatedByDisplayName != \"MS-PIM\"\n| project TimeGenerated, AADOperationType, Category, OperationName, AADTenantId, AppId, InitiatedByDisplayName, ServicePrincipalId, ServicePrincipalName, DisplayName, GroupName, UserId, UserIPAddress, UserRoles, UserPrincipalName, TargetUserPrincipalName\n| extend AccountCustomEntity = case(isnotempty(ServicePrincipalName), ServicePrincipalName, \n isnotempty(UserPrincipalName), UserPrincipalName, \n \"\")\n| extend AccountName = tostring(split(AccountCustomEntity,'@',0)[0]), AccountUPNSuffix = tostring(split(AccountCustomEntity,'@',1)[0])\n| extend TargetName = tostring(split(TargetUserPrincipalName,'@',0)[0]), TargetUPNSuffix = tostring(split(TargetUserPrincipalName,'@',1)[0])\n", + "severity": "Medium", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "AuditLogs" + ] + } + ], + "tactics": [ + "Persistence", + "PrivilegeEscalation" + ], + "techniques": [ + "T1098", + "T1078" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "AccountName", + "identifier": "Name" }, - "type": "Foreach" - }, - "Initialize_variable": { - "type": "InitializeVariable", - "inputs": { - "variables": [ - { - "name": "Password", - "type": "String", - "value": "null" - } - ] + { + "columnName": "AccountUPNSuffix", + "identifier": "UPNSuffix" } - }, - "Set_variable_-_password": { - "runAfter": { - "Initialize_variable": [ - "Succeeded" - ] - }, - "type": "SetVariable", - "inputs": { - "name": "Password", - "value": "@{substring(guid(), 0, 10)}" + ], + "entityType": "Account" + }, + { + "fieldMappings": [ + { + "columnName": "TargetName", + "identifier": "Name" + }, + { + "columnName": "TargetUPNSuffix", + "identifier": "UPNSuffix" } - } + ], + "entityType": "Account" } + ] + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId41'),'/'))))]", + "properties": { + "description": "Azure Active Directory Analytics Rule 41", + "parentId": "[variables('analyticRuleId41')]", + "contentId": "[variables('_analyticRulecontentId41')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion41')]", + "source": { + "kind": "Solution", + "name": "Azure Active Directory", + "sourceId": "[variables('_solutionId')]" }, - "parameters": { - "$connections": { - "value": { - "microsoftsentinel": { - "connectionId": "[[resourceId('Microsoft.Web/connections', variables('MicrosoftSentinelConnectionName'))]", - "connectionName": "[[variables('MicrosoftSentinelConnectionName')]", - "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", - "connectionProperties": { - "authentication": { - "type": "ManagedServiceIdentity" - } - } + "author": { + "name": "Microsoft", + "email": "[variables('_email')]" + }, + "support": { + "tier": "Microsoft", + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "link": "https://support.microsoft.com/" + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_analyticRulecontentId41')]", + "contentKind": "AnalyticsRule", + "displayName": "NRT User added to Azure Active Directory Privileged Groups", + "contentProductId": "[variables('_analyticRulecontentProductId41')]", + "id": "[variables('_analyticRulecontentProductId41')]", + "version": "[variables('analyticRuleVersion41')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleTemplateSpecName42')]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "PIMElevationRequestRejected_AnalyticalRules Analytics Rule with template version 3.0.5", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleVersion42')]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId42')]", + "apiVersion": "2022-04-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", + "properties": { + "description": "Identifies when a user is rejected for a privileged role elevation via PIM. Monitor rejections for indicators of attacker compromise of the requesting account.\nRef : https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-privileged-identity-management", + "displayName": "PIM Elevation Request Rejected", + "enabled": false, + "query": "AuditLogs\n| where ActivityDisplayName =~'Add member to role request denied (PIM activation)'\n| mv-apply ResourceItem = TargetResources on \n (\n where ResourceItem.type =~ \"Role\"\n | extend Role = trim(@'\"',tostring(ResourceItem.displayName))\n )\n| mv-apply ResourceItem = TargetResources on \n (\n where ResourceItem.type =~ \"User\"\n | extend User = trim(@'\"',tostring(ResourceItem.userPrincipalName))\n )\n| project-reorder TimeGenerated, User, Role, OperationName, Result, ResultDescription\n| where isnotempty(InitiatedBy.user)\n| extend InitiatingUser = tostring(InitiatedBy.user.userPrincipalName), InitiatingIpAddress = tostring(InitiatedBy.user.ipAddress)\n| extend InitiatingName = tostring(split(InitiatingUser,'@',0)[0]), InitiatingUPNSuffix = tostring(split(InitiatingUser,'@',1)[0])\n| extend UserName = tostring(split(User,'@',0)[0]), UserUPNSuffix = tostring(split(User,'@',1)[0])\n", + "queryFrequency": "PT2H", + "queryPeriod": "PT2H", + "severity": "High", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "AuditLogs" + ] + } + ], + "tactics": [ + "Persistence" + ], + "techniques": [ + "T1078" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "InitiatingName", + "identifier": "Name" }, - "office365": { - "connectionId": "[[resourceId('Microsoft.Web/connections', variables('office365ConnectionName'))]", - "connectionName": "[[variables('office365ConnectionName')]", - "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]" + { + "columnName": "InitiatingUPNSuffix", + "identifier": "UPNSuffix" } - } + ], + "entityType": "Account" + }, + { + "fieldMappings": [ + { + "columnName": "UserName", + "identifier": "Name" + }, + { + "columnName": "UserUPNSuffix", + "identifier": "UPNSuffix" + } + ], + "entityType": "Account" + }, + { + "fieldMappings": [ + { + "columnName": "InitiatingIpAddress", + "identifier": "Address" + } + ], + "entityType": "IP" } - } - }, - "name": "[[parameters('PlaybookName')]", - "type": "Microsoft.Logic/workflows", - "location": "[[variables('workspace-location-inline')]", - "tags": { - "LogicAppsCategory": "security", - "hidden-SentinelTemplateName": "Reset-AADUserPassword", - "hidden-SentinelTemplateVersion": "1.1", - "hidden-SentinelWorkspaceId": "[[variables('workspaceResourceId')]" - }, - "identity": { - "type": "SystemAssigned" - }, - "apiVersion": "2017-07-01", - "dependsOn": [ - "[[resourceId('Microsoft.Web/connections', variables('MicrosoftSentinelConnectionName'))]", - "[[resourceId('Microsoft.Web/connections', variables('office365ConnectionName'))]" - ] + ] + } }, { - "type": "Microsoft.Web/connections", - "apiVersion": "2016-06-01", - "name": "[[variables('MicrosoftSentinelConnectionName')]", - "location": "[[variables('workspace-location-inline')]", - "kind": "V1", + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId42'),'/'))))]", "properties": { - "displayName": "[[variables('MicrosoftSentinelConnectionName')]", - "parameterValueType": "Alternative", - "api": { - "id": "[[variables('_connection-2')]" + "description": "Azure Active Directory Analytics Rule 42", + "parentId": "[variables('analyticRuleId42')]", + "contentId": "[variables('_analyticRulecontentId42')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion42')]", + "source": { + "kind": "Solution", + "name": "Azure Active Directory", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "Microsoft", + "email": "[variables('_email')]" + }, + "support": { + "tier": "Microsoft", + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "link": "https://support.microsoft.com/" } } - }, + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_analyticRulecontentId42')]", + "contentKind": "AnalyticsRule", + "displayName": "PIM Elevation Request Rejected", + "contentProductId": "[variables('_analyticRulecontentProductId42')]", + "id": "[variables('_analyticRulecontentProductId42')]", + "version": "[variables('analyticRuleVersion42')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleTemplateSpecName43')]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "PrivilegedAccountsSigninFailureSpikes_AnalyticalRules Analytics Rule with template version 3.0.5", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleVersion43')]", + "parameters": {}, + "variables": {}, + "resources": [ { - "type": "Microsoft.Web/connections", - "apiVersion": "2016-06-01", - "name": "[[variables('office365ConnectionName')]", - "location": "[[variables('workspace-location-inline')]", - "kind": "V1", + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId43')]", + "apiVersion": "2022-04-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", "properties": { - "displayName": "[[variables('office365ConnectionName')]", - "api": { - "id": "[[variables('_connection-3')]" - } + "description": " Identifies spike in failed sign-ins from Privileged accounts. Privileged accounts list can be based on IdentityInfo UEBA table.\nSpike is determined based on Time series anomaly which will look at historical baseline values.\nRef : https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-privileged-accounts#things-to-monitor", + "displayName": "Privileged Accounts - Sign in Failure Spikes", + "enabled": false, + "query": "let starttime = 14d;\nlet timeframe = 1d;\nlet scorethreshold = 3;\nlet baselinethreshold = 5;\nlet aadFunc = (tableName:string){\n IdentityInfo\n | where TimeGenerated > ago(starttime)\n | summarize arg_max(TimeGenerated, *) by AccountUPN\n | mv-expand AssignedRoles\n | where AssignedRoles contains 'Admin'\n | summarize Roles = make_list(AssignedRoles) by AccountUPN = tolower(AccountUPN)\n | join kind=inner (\n table(tableName)\n | where TimeGenerated between (startofday(ago(starttime))..startofday(now()))\n | where ResultType != 0\n | extend UserPrincipalName = tolower(UserPrincipalName)\n ) on $left.AccountUPN == $right.UserPrincipalName\n | extend timestamp = TimeGenerated, AccountCustomEntity = UserPrincipalName, Roles = tostring(Roles)\n};\nlet aadSignin = aadFunc(\"SigninLogs\");\nlet aadNonInt = aadFunc(\"AADNonInteractiveUserSignInLogs\");\nlet allSignins = union isfuzzy=true aadSignin, aadNonInt;\nlet TimeSeriesAlerts = \n allSignins\n | make-series HourlyCount=count() on TimeGenerated from startofday(ago(starttime)) to startofday(now()) step 1h by UserPrincipalName, Roles\n | extend (anomalies, score, baseline) = series_decompose_anomalies(HourlyCount, scorethreshold, -1, 'linefit')\n | mv-expand HourlyCount to typeof(double), TimeGenerated to typeof(datetime), anomalies to typeof(double), score to typeof(double), baseline to typeof(long)\n // Filtering low count events per baselinethreshold\n | where anomalies > 0 and baseline > baselinethreshold\n | extend AnomalyHour = TimeGenerated\n | project UserPrincipalName, Roles, AnomalyHour, TimeGenerated, HourlyCount, baseline, anomalies, score;\n// Filter the alerts for specified timeframe\nTimeSeriesAlerts\n| where TimeGenerated > startofday(ago(timeframe))\n| join kind=inner ( \n allSignins\n | where TimeGenerated > startofday(ago(timeframe))\n // create a new column and round to hour\n | extend DateHour = bin(TimeGenerated, 1h)\n | summarize PartialFailedSignins = count(), LatestAnomalyTime = arg_max(TimeGenerated, *) by bin(TimeGenerated, 1h), OperationName, Category, ResultType, ResultDescription, UserPrincipalName, Roles, UserDisplayName, AppDisplayName, ClientAppUsed, IPAddress, ResourceDisplayName\n) on UserPrincipalName, $left.AnomalyHour == $right.DateHour\n| project LatestAnomalyTime, OperationName, Category, UserPrincipalName, Roles = todynamic(Roles), UserDisplayName, ResultType, ResultDescription, AppDisplayName, ClientAppUsed, UserAgent, IPAddress, Location, AuthenticationRequirement, ConditionalAccessStatus, ResourceDisplayName, PartialFailedSignins, TotalFailedSignins = HourlyCount, baseline, anomalies, score\n| extend timestamp = LatestAnomalyTime, Name = tostring(split(UserPrincipalName,'@',0)[0]), UPNSuffix = tostring(split(UserPrincipalName,'@',1)[0])\n", + "queryFrequency": "P1D", + "queryPeriod": "P14D", + "severity": "High", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "SigninLogs" + ] + }, + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "AADNonInteractiveUserSignInLogs" + ] + } + ], + "tactics": [ + "InitialAccess" + ], + "techniques": [ + "T1078" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "Name", + "identifier": "Name" + }, + { + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" + } + ], + "entityType": "Account" + }, + { + "fieldMappings": [ + { + "columnName": "IPAddress", + "identifier": "Address" + } + ], + "entityType": "IP" + } + ] } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('Playbook-', last(split(variables('playbookId6'),'/'))))]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId43'),'/'))))]", "properties": { - "parentId": "[variables('playbookId6')]", - "contentId": "[variables('_playbookContentId6')]", - "kind": "Playbook", - "version": "[variables('playbookVersion6')]", + "description": "Azure Active Directory Analytics Rule 43", + "parentId": "[variables('analyticRuleId43')]", + "contentId": "[variables('_analyticRulecontentId43')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion43')]", "source": { "kind": "Solution", "name": "Azure Active Directory", @@ -10913,453 +10104,820 @@ } } } - ], - "metadata": { - "title": "Reset Azure AD User Password - Incident Trigger", - "description": "This playbook will reset the user password using Graph API. It will send the password (which is a random guid substring) to the user's manager. The user will have to reset the password upon login.", - "prerequisites": [ - "None" - ], - "postDeployment": [ - "1. Assign Password Administrator permission to managed identity.", - "2. Assign Microsoft Sentinel Responder permission to managed identity.", - "3. Authorize Office 365 Outlook connection" - ], - "lastUpdateTime": "2022-07-11T00:00:00Z", - "entities": [ - "Account" - ], - "tags": [ - "Remediation" - ], - "releaseNotes": [ - { - "version": "1.0.0", - "title": " Added manager notification action", - "notes": [ - "Initial version" - ] - } - ] - } + ] }, "packageKind": "Solution", "packageVersion": "[variables('_solutionVersion')]", "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_playbookContentId6')]", - "contentKind": "Playbook", - "displayName": "Reset-AADPassword-IncidentTrigger", - "contentProductId": "[variables('_playbookcontentProductId6')]", - "id": "[variables('_playbookcontentProductId6')]", - "version": "[variables('playbookVersion6')]" + "contentId": "[variables('_analyticRulecontentId43')]", + "contentKind": "AnalyticsRule", + "displayName": "Privileged Accounts - Sign in Failure Spikes", + "contentProductId": "[variables('_analyticRulecontentProductId43')]", + "id": "[variables('_analyticRulecontentProductId43')]", + "version": "[variables('analyticRuleVersion43')]" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('playbookTemplateSpecName7')]", + "name": "[variables('analyticRuleTemplateSpecName44')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "Block-AADUser-EntityTrigger Playbook with template version 3.0.4", + "description": "PrivlegedRoleAssignedOutsidePIM_AnalyticalRules Analytics Rule with template version 3.0.5", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('playbookVersion7')]", - "parameters": { - "PlaybookName": { - "defaultValue": "Block-AADUser-EntityTrigger", - "type": "string" - } - }, - "variables": { - "AzureADConnectionName": "[[concat('azuread-', parameters('PlaybookName'))]", - "MicrosoftSentinelConnectionName": "[[concat('microsoftsentinel-', parameters('PlaybookName'))]", - "Office365ConnectionName": "[[concat('office365-', parameters('PlaybookName'))]", - "connection-1": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuread')]", - "_connection-1": "[[variables('connection-1')]", - "connection-2": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", - "_connection-2": "[[variables('connection-2')]", - "connection-3": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]", - "_connection-3": "[[variables('connection-3')]", - "workspace-location-inline": "[concat('[resourceGroup().locatio', 'n]')]", - "workspace-name": "[parameters('workspace')]", - "workspaceResourceId": "[[resourceId('microsoft.OperationalInsights/Workspaces', variables('workspace-name'))]" - }, + "contentVersion": "[variables('analyticRuleVersion44')]", + "parameters": {}, + "variables": {}, "resources": [ { - "type": "Microsoft.Web/connections", - "apiVersion": "2016-06-01", - "name": "[[variables('AzureADConnectionName')]", - "location": "[[variables('workspace-location-inline')]", - "properties": { - "displayName": "[[variables('AzureADConnectionName')]", - "api": { - "id": "[[variables('_connection-1')]" - } - } - }, - { - "type": "Microsoft.Web/connections", - "apiVersion": "2016-06-01", - "name": "[[variables('MicrosoftSentinelConnectionName')]", - "location": "[[variables('workspace-location-inline')]", - "kind": "V1", + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId44')]", + "apiVersion": "2022-04-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", "properties": { - "displayName": "[[variables('MicrosoftSentinelConnectionName')]", - "parameterValueType": "Alternative", - "api": { - "id": "[[variables('_connection-2')]" - } + "description": "Identifies a privileged role being assigned to a user outside of PIM\nRef : https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-privileged-accounts#things-to-monitor-1", + "displayName": "Privileged Role Assigned Outside PIM", + "enabled": false, + "query": "AuditLogs\n| where Category =~ \"RoleManagement\"\n| where OperationName has \"Add member to role outside of PIM\"\n or (LoggedByService =~ \"Core Directory\" and OperationName =~ \"Add member to role\" and Identity != \"MS-PIM\")\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"User\"\n | extend UserPrincipalName = tostring(TargetResource.userPrincipalName)\n )\n| extend IpAddress = tostring(InitiatedBy.user.ipAddress), Name = tostring(split(UserPrincipalName,'@',0)[0]), UPNSuffix = tostring(split(UserPrincipalName,'@',1)[0])\n", + "queryFrequency": "P1D", + "queryPeriod": "P1D", + "severity": "Low", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "AuditLogs" + ] + } + ], + "tactics": [ + "PrivilegeEscalation" + ], + "techniques": [ + "T1078" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "Name", + "identifier": "Name" + }, + { + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" + } + ], + "entityType": "Account" + }, + { + "fieldMappings": [ + { + "columnName": "IpAddress", + "identifier": "Address" + } + ], + "entityType": "IP" + } + ] } }, { - "type": "Microsoft.Web/connections", - "apiVersion": "2016-06-01", - "name": "[[variables('Office365ConnectionName')]", - "location": "[[variables('workspace-location-inline')]", + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId44'),'/'))))]", "properties": { - "displayName": "[[variables('Office365ConnectionName')]", - "api": { - "id": "[[variables('_connection-3')]" + "description": "Azure Active Directory Analytics Rule 44", + "parentId": "[variables('analyticRuleId44')]", + "contentId": "[variables('_analyticRulecontentId44')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion44')]", + "source": { + "kind": "Solution", + "name": "Azure Active Directory", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "Microsoft", + "email": "[variables('_email')]" + }, + "support": { + "tier": "Microsoft", + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "link": "https://support.microsoft.com/" } } - }, + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_analyticRulecontentId44')]", + "contentKind": "AnalyticsRule", + "displayName": "Privileged Role Assigned Outside PIM", + "contentProductId": "[variables('_analyticRulecontentProductId44')]", + "id": "[variables('_analyticRulecontentProductId44')]", + "version": "[variables('analyticRuleVersion44')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleTemplateSpecName45')]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "RareApplicationConsent_AnalyticalRules Analytics Rule with template version 3.0.5", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleVersion45')]", + "parameters": {}, + "variables": {}, + "resources": [ { - "type": "Microsoft.Logic/workflows", - "apiVersion": "2017-07-01", - "name": "[[parameters('PlaybookName')]", - "location": "[[variables('workspace-location-inline')]", - "tags": { - "LogicAppsCategory": "security", - "hidden-SentinelTemplateName": "Block-AADUser-EntityTrigger", - "hidden-SentinelTemplateVersion": "1.1", - "hidden-SentinelWorkspaceId": "[[variables('workspaceResourceId')]" - }, - "identity": { - "type": "SystemAssigned" - }, - "dependsOn": [ - "[[resourceId('Microsoft.Web/connections', variables('AzureADConnectionName'))]", - "[[resourceId('Microsoft.Web/connections', variables('MicrosoftSentinelConnectionName'))]", - "[[resourceId('Microsoft.Web/connections', variables('Office365ConnectionName'))]" - ], - "properties": { - "state": "Enabled", - "definition": { - "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "$connections": { - "type": "Object" - } + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId45')]", + "apiVersion": "2022-04-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", + "properties": { + "description": "This will alert when the \"Consent to application\" operation occurs by a user that has not done this operation before or rarely does this.\nThis could indicate that permissions to access the listed Azure App were provided to a malicious actor.\nConsent to application, Add service principal and Add OAuth2PermissionGrant should typically be rare events.\nThis may help detect the Oauth2 attack that can be initiated by this publicly available tool - https://github.com/fireeye/PwnAuth\nFor further information on AuditLogs please see https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-audit-activities.", + "displayName": "Rare application consent", + "enabled": false, + "query": "let current = 1d;\nlet auditLookback = 7d;\n// Setting threshold to 3 as a default, change as needed.\n// Any operation that has been initiated by a user or app more than 3 times in the past 7 days will be excluded\nlet threshold = 3;\n// Gather initial data from lookback period, excluding current, adjust current to more than a single day if no results\nlet AuditTrail = AuditLogs | where TimeGenerated >= ago(auditLookback) and TimeGenerated < ago(current)\n// 2 other operations that can be part of malicious activity in this situation are\n// \"Add OAuth2PermissionGrant\" and \"Add service principal\", extend the filter below to capture these too\n| where OperationName has \"Consent to application\"\n| extend InitiatedBy = iff(isnotempty(tostring(InitiatedBy.user.userPrincipalName)),\n tostring(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.app.displayName))\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"ServicePrincipal\"\n | extend TargetResourceName = tolower(tostring(TargetResource.displayName))\n )\n| summarize max(TimeGenerated), OperationCount = count() by OperationName, InitiatedBy, TargetResourceName\n// only including operations initiated by a user or app that is above the threshold so we produce only rare and has not occurred in last 7 days\n| where OperationCount > threshold;\n// Gather current period of audit data\nlet RecentConsent = AuditLogs | where TimeGenerated >= ago(current)\n| where OperationName has \"Consent to application\"\n| extend IpAddress = case(\n isnotempty(tostring(InitiatedBy.user.ipAddress)) and tostring(InitiatedBy.user.ipAddress) != 'null', tostring(InitiatedBy.user.ipAddress),\n isnotempty(tostring(InitiatedBy.app.ipAddress)) and tostring(InitiatedBy.app.ipAddress) != 'null', tostring(InitiatedBy.app.ipAddress),\n 'Not Available')\n| extend InitiatedBy = iff(isnotempty(tostring(InitiatedBy.user.userPrincipalName)),\n tostring(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.app.displayName))\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"ServicePrincipal\"\n | extend TargetResourceName = tolower(tostring(TargetResource.displayName)),\n props = TargetResource.modifiedProperties\n )\n| parse props with * \"ConsentType: \" ConsentType \"]\" *\n| mv-apply AdditionalDetail = AdditionalDetails on \n (\n where AdditionalDetail.key =~ \"User-Agent\"\n | extend UserAgent = tostring(AdditionalDetail.value)\n )\n| project TimeGenerated, InitiatedBy, IpAddress, TargetResourceName, Category, OperationName, ConsentType, UserAgent, CorrelationId, Type;\n// Exclude previously seen audit activity for \"Consent to application\" that was seen in the lookback period\n// First for rare InitiatedBy\nlet RareConsentBy = RecentConsent | join kind= leftanti AuditTrail on OperationName, InitiatedBy\n| extend Reason = \"Previously unseen user consenting\";\n// Second for rare TargetResourceName\nlet RareConsentApp = RecentConsent | join kind= leftanti AuditTrail on OperationName, TargetResourceName\n| extend Reason = \"Previously unseen app granted consent\";\nRareConsentBy | union RareConsentApp\n| summarize Reason = make_set(Reason,100) by TimeGenerated, InitiatedBy, IpAddress, TargetResourceName, Category, OperationName, ConsentType, UserAgent, CorrelationId, Type\n| extend timestamp = TimeGenerated, Name = tolower(tostring(split(InitiatedBy,'@',0)[0])), UPNSuffix = tolower(tostring(split(InitiatedBy,'@',1)[0]))\n", + "queryFrequency": "P1D", + "queryPeriod": "P7D", + "severity": "Medium", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 3, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "AuditLogs" + ] + } + ], + "tactics": [ + "Persistence", + "PrivilegeEscalation" + ], + "techniques": [ + "T1136", + "T1068" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "Name", + "identifier": "Name" + }, + { + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" + } + ], + "entityType": "Account" }, - "triggers": { - "Microsoft_Sentinel_entity": { - "type": "ApiConnectionWebhook", - "inputs": { - "body": { - "callback_url": "@{listCallbackUrl()}" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" - } - }, - "path": "/entity/@{encodeURIComponent('Account')}" + { + "fieldMappings": [ + { + "columnName": "TargetResourceName", + "identifier": "Name" } - } + ], + "entityType": "CloudApplication" }, - "actions": { - "Condition": { - "actions": { - "Condition_-_if_user_have_manager": { - "actions": { - "Condition_2": { - "actions": { - "Add_comment_to_incident_-_with_manager_-_no_admin": { - "type": "ApiConnection", - "inputs": { - "body": { - "incidentArmId": "@triggerBody()?['IncidentArmID']", - "message": "

User @{triggerBody()?['Entity']?['properties']?['Name']}  (UPN - @{variables('AccountDetails')}) was disabled in AAD via playbook Block-AADUser. Manager (@{body('Parse_JSON_-_get_user_manager')?['userPrincipalName']}) is notified.

" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" - } - }, - "method": "post", - "path": "/Incidents/Comment" - } - } - }, - "runAfter": { - "Get_user_-_details": [ - "Succeeded" - ] - }, - "expression": { - "and": [ - { - "not": { - "equals": [ - "@triggerBody()?['IncidentArmID']", - "@null" - ] - } - } - ] - }, - "type": "If" - }, - "Get_user_-_details": { - "type": "ApiConnection", - "inputs": { - "host": { - "connection": { - "name": "@parameters('$connections')['azuread']['connectionId']" - } - }, - "method": "get", - "path": "/v1.0/users/@{encodeURIComponent(variables('AccountDetails'))}" - } - }, - "Send_an_email_-_to_manager_-_no_admin": { - "runAfter": { - "Condition_2": [ - "Succeeded" - ] - }, - "type": "ApiConnection", - "inputs": { - "body": { - "Body": "

Security notification! This is automated email sent by Microsoft Sentinel Automation!
\n
\nYour direct report @{triggerBody()?['Entity']?['properties']?['Name']} has been disabled in Azure AD due to the security incident. Can you please notify the user and work with him to reach our support.
\n
\nDirect report details:
\nFirst name: @{body('Get_user_-_details')?['displayName']}
\nSurname: @{body('Get_user_-_details')?['surname']}
\nJob title: @{body('Get_user_-_details')?['jobTitle']}
\nOffice location: @{body('Get_user_-_details')?['officeLocation']}
\nBusiness phone: @{body('Get_user_-_details')?['businessPhones']}
\nMobile phone: @{body('Get_user_-_details')?['mobilePhone']}
\nMail: @{body('Get_user_-_details')?['mail']}
\n
\nThank you!

", - "Importance": "High", - "Subject": "@{triggerBody()?['Entity']?['properties']?['Name']} has been disabled in Azure AD due to the security risk!", - "To": "@body('Parse_JSON_-_get_user_manager')?['userPrincipalName']" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['office365']['connectionId']" - } - }, - "method": "post", - "path": "/v2/Mail" - } - } - }, - "runAfter": { - "Parse_JSON_-_get_user_manager": [ - "Succeeded" - ] - }, - "else": { - "actions": { - "Condition_3": { - "actions": { - "Add_comment_to_incident_-_no_manager_-_no_admin": { - "type": "ApiConnection", - "inputs": { - "body": { - "incidentArmId": "@triggerBody()?['IncidentArmID']", - "message": "

User @{triggerBody()?['Entity']?['properties']?['Name']} (UPN - @{variables('AccountDetails')}) was disabled in AAD via playbook Block-AADUser. Manager has not been notified, since it is not found for this user!

" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" - } - }, - "method": "post", - "path": "/Incidents/Comment" - } - } - }, - "expression": { - "and": [ - { - "not": { - "equals": [ - "@triggerBody()?['IncidentArmID']", - "@null" - ] - } - } - ] - }, - "type": "If" - } - } - }, - "expression": { - "and": [ - { - "not": { - "equals": [ - "@body('Parse_JSON_-_get_user_manager')?['userPrincipalName']", - "@null" - ] - } - } - ] - }, - "type": "If" - }, - "HTTP_-_get_user_manager": { - "type": "Http", - "inputs": { - "authentication": { - "audience": "https://graph.microsoft.com/", - "type": "ManagedServiceIdentity" - }, - "method": "GET", - "uri": "https://graph.microsoft.com/v1.0/users/@{variables('AccountDetails')}/manager" - } - }, - "Parse_JSON_-_get_user_manager": { - "runAfter": { - "HTTP_-_get_user_manager": [ - "Succeeded", - "Failed" - ] - }, - "type": "ParseJson", - "inputs": { - "content": "@body('HTTP_-_get_user_manager')", - "schema": { - "properties": { - "userPrincipalName": { - "type": "string" - } - }, - "type": "object" - } - } - } - }, - "runAfter": { - "Update_user_-_disable_user": [ - "Succeeded", - "Failed" - ] - }, - "else": { - "actions": { - "Add_comment_to_incident_-_error_details": { - "type": "ApiConnection", - "inputs": { - "body": { - "incidentArmId": "@triggerBody()?['IncidentArmID']", - "message": "

Block-AADUser playbook could not disable user @{triggerBody()?['Entity']?['properties']?['Name']}.
\nError message: @{body('Update_user_-_disable_user')['error']['message']}
\nNote: If user is admin, this playbook don't have privilages to block admin users!

" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" - } - }, - "method": "post", - "path": "/Incidents/Comment" - } - } - } + { + "fieldMappings": [ + { + "columnName": "IpAddress", + "identifier": "Address" + } + ], + "entityType": "IP" + } + ] + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId45'),'/'))))]", + "properties": { + "description": "Azure Active Directory Analytics Rule 45", + "parentId": "[variables('analyticRuleId45')]", + "contentId": "[variables('_analyticRulecontentId45')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion45')]", + "source": { + "kind": "Solution", + "name": "Azure Active Directory", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "Microsoft", + "email": "[variables('_email')]" + }, + "support": { + "tier": "Microsoft", + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "link": "https://support.microsoft.com/" + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_analyticRulecontentId45')]", + "contentKind": "AnalyticsRule", + "displayName": "Rare application consent", + "contentProductId": "[variables('_analyticRulecontentProductId45')]", + "id": "[variables('_analyticRulecontentProductId45')]", + "version": "[variables('analyticRuleVersion45')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleTemplateSpecName46')]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "SeamlessSSOPasswordSpray_AnalyticalRules Analytics Rule with template version 3.0.5", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleVersion46')]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId46')]", + "apiVersion": "2022-04-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", + "properties": { + "description": "This query detects when there is a spike in Azure AD Seamless SSO errors. They may not be caused by a Password Spray attack, but the cause of the errors might need to be investigated.\nAzure AD only logs the requests that matched existing accounts, thus there might have been unlogged requests for non-existing accounts.", + "displayName": "Password spray attack against Azure AD Seamless SSO", + "enabled": false, + "query": "let account_threshold = 5;\nAADNonInteractiveUserSignInLogs\n//| where ResultType == \"81016\"\n| where ResultType startswith \"81\"\n| summarize DistinctAccounts = dcount(UserPrincipalName), DistinctAddresses = make_set(IPAddress,100) by ResultType\n| where DistinctAccounts > account_threshold\n| mv-expand IPAddress = DistinctAddresses\n| extend IPAddress = tostring(IPAddress)\n| join kind=leftouter (union isfuzzy=true SigninLogs, AADNonInteractiveUserSignInLogs) on IPAddress\n| summarize\n StartTime = min(TimeGenerated),\n EndTime = max(TimeGenerated),\n UserPrincipalName = make_set(UserPrincipalName,100),\n UserAgent = make_set(UserAgent,100),\n ResultDescription = take_any(ResultDescription),\n ResultSignature = take_any(ResultSignature)\n by IPAddress, Type, ResultType\n| project Type, StartTime, EndTime, IPAddress, ResultType, ResultDescription, ResultSignature, UserPrincipalName, UserAgent = iff(array_length(UserAgent) == 1, UserAgent[0], UserAgent)\n| extend Name = tostring(split(UserPrincipalName[0],'@',0)[0]), UPNSuffix = tostring(split(UserPrincipalName[0],'@',1)[0])\n", + "queryFrequency": "PT1H", + "queryPeriod": "PT1H", + "severity": "Medium", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "AADNonInteractiveUserSignInLogs" + ] + } + ], + "tactics": [ + "CredentialAccess" + ], + "techniques": [ + "T1110" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "Name", + "identifier": "Name" }, - "expression": { - "and": [ - { - "equals": [ - "@body('Update_user_-_disable_user')", - "@null" - ] - } - ] + { + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" + } + ], + "entityType": "Account" + }, + { + "fieldMappings": [ + { + "columnName": "IPAddress", + "identifier": "Address" + } + ], + "entityType": "IP" + } + ] + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId46'),'/'))))]", + "properties": { + "description": "Azure Active Directory Analytics Rule 46", + "parentId": "[variables('analyticRuleId46')]", + "contentId": "[variables('_analyticRulecontentId46')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion46')]", + "source": { + "kind": "Solution", + "name": "Azure Active Directory", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "Microsoft", + "email": "[variables('_email')]" + }, + "support": { + "tier": "Microsoft", + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "link": "https://support.microsoft.com/" + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_analyticRulecontentId46')]", + "contentKind": "AnalyticsRule", + "displayName": "Password spray attack against Azure AD Seamless SSO", + "contentProductId": "[variables('_analyticRulecontentProductId46')]", + "id": "[variables('_analyticRulecontentProductId46')]", + "version": "[variables('analyticRuleVersion46')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleTemplateSpecName47')]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "Sign-in Burst from Multiple Locations_AnalyticalRules Analytics Rule with template version 3.0.5", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleVersion47')]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId47')]", + "apiVersion": "2022-04-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", + "properties": { + "description": "This detection triggers when there is a Signin burst from multiple locations in GitHub (AAD SSO).\n This detection is based on configurable threshold which can be prone to false positives. To view the anomaly based equivalent of thie detection, please see here https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Azure%20Active%20Directory/Analytic%20Rules/AnomalousUserAppSigninLocationIncrease-detection.yaml. ", + "displayName": "GitHub Signin Burst from Multiple Locations", + "enabled": false, + "query": "let locationThreshold = 1;\nlet aadFunc = (tableName:string){\ntable(tableName)\n| where AppDisplayName =~ \"GitHub.com\"\n| where ResultType == 0\n| summarize CountOfLocations = dcount(Location), Locations = make_set(Location,100), BurstStartTime = min(TimeGenerated), BurstEndTime = max(TimeGenerated) by UserPrincipalName, Type\n| where CountOfLocations > locationThreshold\n| extend timestamp = BurstStartTime\n};\nlet aadSignin = aadFunc(\"SigninLogs\");\nlet aadNonInt = aadFunc(\"AADNonInteractiveUserSignInLogs\");\nunion isfuzzy=true aadSignin, aadNonInt\n| extend Name = tostring(split(UserPrincipalName,'@',0)[0]), UPNSuffix = tostring(split(UserPrincipalName,'@',1)[0])\n", + "queryFrequency": "PT1H", + "queryPeriod": "PT1H", + "severity": "Medium", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "SigninLogs" + ] + }, + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "AADNonInteractiveUserSignInLogs" + ] + } + ], + "tactics": [ + "CredentialAccess" + ], + "techniques": [ + "T1110" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "Name", + "identifier": "Name" }, - "type": "If" - }, - "Initialize_variable_Account_Details": { - "type": "InitializeVariable", - "inputs": { - "variables": [ - { - "name": "AccountDetails", - "type": "string" - } - ] + { + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" + } + ], + "entityType": "Account" + } + ] + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId47'),'/'))))]", + "properties": { + "description": "Azure Active Directory Analytics Rule 47", + "parentId": "[variables('analyticRuleId47')]", + "contentId": "[variables('_analyticRulecontentId47')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion47')]", + "source": { + "kind": "Solution", + "name": "Azure Active Directory", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "Microsoft", + "email": "[variables('_email')]" + }, + "support": { + "tier": "Microsoft", + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "link": "https://support.microsoft.com/" + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_analyticRulecontentId47')]", + "contentKind": "AnalyticsRule", + "displayName": "GitHub Signin Burst from Multiple Locations", + "contentProductId": "[variables('_analyticRulecontentProductId47')]", + "id": "[variables('_analyticRulecontentProductId47')]", + "version": "[variables('analyticRuleVersion47')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleTemplateSpecName48')]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "SigninAttemptsByIPviaDisabledAccounts_AnalyticalRules Analytics Rule with template version 3.0.5", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleVersion48')]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId48')]", + "apiVersion": "2022-04-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", + "properties": { + "description": "Identifies IPs with failed attempts to sign in to one or more disabled accounts using the IP through which successful signins from other accounts have happened.\nThis could indicate an attacker who obtained credentials for a list of accounts and is attempting to login with those accounts, some of which may have already been disabled.\nReferences: https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-sign-ins-error-codes\n50057 - User account is disabled. The account has been disabled by an administrator.\nThis query has also been updated to include UEBA logs IdentityInfo and BehaviorAnalytics for contextual information around the results.", + "displayName": "Sign-ins from IPs that attempt sign-ins to disabled accounts", + "enabled": false, + "query": "let aadFunc = (tableName: string) {\nlet failed_signins = table(tableName)\n| where ResultType == \"50057\"\n| where ResultDescription == \"User account is disabled. The account has been disabled by an administrator.\";\nlet disabled_users = failed_signins | summarize by UserPrincipalName;\ntable(tableName)\n | where ResultType == 0\n | where isnotempty(UserPrincipalName)\n | where UserPrincipalName !in (disabled_users)\n| summarize\n successfulAccountsTargettedCount = dcount(UserPrincipalName),\n successfulAccountSigninSet = make_set(UserPrincipalName, 100),\n successfulApplicationSet = make_set(AppDisplayName, 100)\n by IPAddress, Type\n // Assume IPs associated with sign-ins from 100+ distinct user accounts are safe\n | where successfulAccountsTargettedCount < 50\n | where isnotempty(successfulAccountsTargettedCount)\n | join kind=inner (failed_signins\n| summarize\n StartTime = min(TimeGenerated),\n EndTime = max(TimeGenerated),\n totalDisabledAccountLoginAttempts = count(),\n disabledAccountsTargettedCount = dcount(UserPrincipalName),\n applicationsTargeted = dcount(AppDisplayName),\n disabledAccountSet = make_set(UserPrincipalName, 100),\n disabledApplicationSet = make_set(AppDisplayName, 100)\nby IPAddress, Type\n| order by totalDisabledAccountLoginAttempts desc) on IPAddress\n| project StartTime, EndTime, IPAddress, totalDisabledAccountLoginAttempts, disabledAccountsTargettedCount, disabledAccountSet, disabledApplicationSet, successfulApplicationSet, successfulAccountsTargettedCount, successfulAccountSigninSet, Type\n| order by totalDisabledAccountLoginAttempts};\nlet aadSignin = aadFunc(\"SigninLogs\");\nlet aadNonInt = aadFunc(\"AADNonInteractiveUserSignInLogs\");\nunion isfuzzy=true aadSignin, aadNonInt\n| join kind=leftouter (\n BehaviorAnalytics\n | where ActivityType in (\"FailedLogOn\", \"LogOn\")\n | where EventSource =~ \"Azure AD\"\n | project UsersInsights, DevicesInsights, ActivityInsights, InvestigationPriority, SourceIPAddress, UserPrincipalName\n | project-rename IPAddress = SourceIPAddress\n | summarize\n Users = make_set(UserPrincipalName, 100),\n UsersInsights = make_set(UsersInsights, 100),\n DevicesInsights = make_set(DevicesInsights, 100),\n IPInvestigationPriority = sum(InvestigationPriority)\n by IPAddress\n) on IPAddress\n| extend SFRatio = toreal(toreal(disabledAccountsTargettedCount)/toreal(successfulAccountsTargettedCount))\n| where SFRatio >= 0.5\n| sort by IPInvestigationPriority desc\n", + "queryFrequency": "P1D", + "queryPeriod": "P1D", + "severity": "Medium", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "SigninLogs" + ] + }, + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "AADNonInteractiveUserSignInLogs" + ] + }, + { + "connectorId": "BehaviorAnalytics", + "dataTypes": [ + "BehaviorAnalytics" + ] + } + ], + "tactics": [ + "InitialAccess", + "Persistence" + ], + "techniques": [ + "T1078", + "T1098" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "IPAddress", + "identifier": "Address" } - }, - "Set_variable": { - "runAfter": { - "Initialize_variable_Account_Details": [ - "Succeeded" - ] + ], + "entityType": "IP" + } + ] + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId48'),'/'))))]", + "properties": { + "description": "Azure Active Directory Analytics Rule 48", + "parentId": "[variables('analyticRuleId48')]", + "contentId": "[variables('_analyticRulecontentId48')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion48')]", + "source": { + "kind": "Solution", + "name": "Azure Active Directory", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "Microsoft", + "email": "[variables('_email')]" + }, + "support": { + "tier": "Microsoft", + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "link": "https://support.microsoft.com/" + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_analyticRulecontentId48')]", + "contentKind": "AnalyticsRule", + "displayName": "Sign-ins from IPs that attempt sign-ins to disabled accounts", + "contentProductId": "[variables('_analyticRulecontentProductId48')]", + "id": "[variables('_analyticRulecontentProductId48')]", + "version": "[variables('analyticRuleVersion48')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleTemplateSpecName49')]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "SigninBruteForce-AzurePortal_AnalyticalRules Analytics Rule with template version 3.0.5", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleVersion49')]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId49')]", + "apiVersion": "2022-04-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", + "properties": { + "description": "Detects Azure Portal brute force attacks by monitoring for multiple authentication failures and a successful login within a 20-minute window. Default settings: 10 failures, 25 deviations.\nRef: https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-sign-ins-error-codes.", + "displayName": "Brute force attack against Azure Portal", + "enabled": false, + "query": "// Set threshold value for deviation\nlet threshold = 25;\n// Set the time range for the query\nlet timeRange = 24h;\n// Set the authentication window duration\nlet authenticationWindow = 20m;\n// Define a reusable function 'aadFunc' that takes a table name as input\nlet aadFunc = (tableName: string) {\n // Query the specified table\n table(tableName)\n // Filter data within the last 24 hours\n | where TimeGenerated > ago(1d)\n // Filter records related to \"Azure Portal\" applications\n | where AppDisplayName has \"Azure Portal\"\n // Extract and transform some fields\n | extend\n DeviceDetail = todynamic(DeviceDetail),\n LocationDetails = todynamic(LocationDetails)\n | extend\n OS = tostring(DeviceDetail.operatingSystem),\n Browser = tostring(DeviceDetail.browser),\n State = tostring(LocationDetails.state),\n City = tostring(LocationDetails.city),\n Region = tostring(LocationDetails.countryOrRegion)\n // Categorize records as Success or Failure based on ResultType\n | extend FailureOrSuccess = iff(ResultType in (\"0\", \"50125\", \"50140\", \"70043\", \"70044\"), \"Success\", \"Failure\")\n // Sort and identify sessions\n | sort by UserPrincipalName asc, TimeGenerated asc\n | extend SessionStartedUtc = row_window_session(TimeGenerated, timeRange, authenticationWindow, UserPrincipalName != prev(UserPrincipalName) or prev(FailureOrSuccess) == \"Success\")\n // Summarize data\n | summarize FailureOrSuccessCount = count() by FailureOrSuccess, UserId, UserDisplayName, AppDisplayName, IPAddress, Browser, OS, State, City, Region, Type, CorrelationId, bin(TimeGenerated, authenticationWindow), ResultType, UserPrincipalName, SessionStartedUtc\n | summarize FailureCountBeforeSuccess = sumif(FailureOrSuccessCount, FailureOrSuccess == \"Failure\"), StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), makelist(FailureOrSuccess), IPAddress = make_set(IPAddress, 15), make_set(Browser, 15), make_set(City, 15), make_set(State, 15), make_set(Region, 15), make_set(ResultType, 15) by SessionStartedUtc, UserPrincipalName, CorrelationId, AppDisplayName, UserId, Type\n // Filter records where \"Success\" occurs in the middle of a session\n | where array_index_of(list_FailureOrSuccess, \"Success\") != 0\n | where array_index_of(list_FailureOrSuccess, \"Success\") == array_length(list_FailureOrSuccess) - 1\n // Remove unnecessary columns from the output\n | project-away SessionStartedUtc, list_FailureOrSuccess\n // Join with another table and calculate deviation\n | join kind=inner (\n table(tableName)\n | where TimeGenerated > ago(7d)\n | where AppDisplayName has \"Azure Portal\"\n | extend FailureOrSuccess = iff(ResultType in (\"0\", \"50125\", \"50140\", \"70043\", \"70044\"), \"Success\", \"Failure\")\n | summarize avgFailures = avg(todouble(FailureOrSuccess == \"Failure\")) by UserPrincipalName\n ) on UserPrincipalName\n | extend Deviation = abs(FailureCountBeforeSuccess - avgFailures) / avgFailures\n // Filter records based on deviation and failure count criteria\n | where Deviation > threshold and FailureCountBeforeSuccess >= 10\n // Expand the IPAddress array\n | mv-expand IPAddress\n | extend IPAddress = tostring(IPAddress)\n | extend timestamp = StartTime\n};\n// Call 'aadFunc' with different table names and union the results\nlet aadSignin = aadFunc(\"SigninLogs\");\nlet aadNonInt = aadFunc(\"AADNonInteractiveUserSignInLogs\");\nunion isfuzzy=true aadSignin, aadNonInt\n// Additional transformation: Split UserPrincipalName\n| extend Name = tostring(split(UserPrincipalName,'@',0)[0]), UPNSuffix = tostring(split(UserPrincipalName,'@',1)[0])\n", + "queryFrequency": "P1D", + "queryPeriod": "P7D", + "severity": "Medium", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "SigninLogs" + ] + }, + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "AADNonInteractiveUserSignInLogs" + ] + } + ], + "tactics": [ + "CredentialAccess" + ], + "techniques": [ + "T1110" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "Name", + "identifier": "Name" }, - "type": "SetVariable", - "inputs": { - "name": "AccountDetails", - "value": "@{concat(triggerBody()?['Entity']?['properties']?['Name'],'@',triggerBody()?['Entity']?['properties']?['UPNSuffix'])}" - } - }, - "Update_user_-_disable_user": { - "runAfter": { - "Set_variable": [ - "Succeeded" - ] + { + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" }, - "type": "ApiConnection", - "inputs": { - "body": { - "accountEnabled": false - }, - "host": { - "connection": { - "name": "@parameters('$connections')['azuread']['connectionId']" - } - }, - "method": "patch", - "path": "/v1.0/users/@{encodeURIComponent(variables('AccountDetails'))}" + { + "columnName": "UserId", + "identifier": "AadUserId" } - } + ], + "entityType": "Account" + }, + { + "fieldMappings": [ + { + "columnName": "IPAddress", + "identifier": "Address" + } + ], + "entityType": "IP" + } + ] + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId49'),'/'))))]", + "properties": { + "description": "Azure Active Directory Analytics Rule 49", + "parentId": "[variables('analyticRuleId49')]", + "contentId": "[variables('_analyticRulecontentId49')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion49')]", + "source": { + "kind": "Solution", + "name": "Azure Active Directory", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "Microsoft", + "email": "[variables('_email')]" + }, + "support": { + "tier": "Microsoft", + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "link": "https://support.microsoft.com/" + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_analyticRulecontentId49')]", + "contentKind": "AnalyticsRule", + "displayName": "Brute force attack against Azure Portal", + "contentProductId": "[variables('_analyticRulecontentProductId49')]", + "id": "[variables('_analyticRulecontentProductId49')]", + "version": "[variables('analyticRuleVersion49')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleTemplateSpecName50')]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "SigninPasswordSpray_AnalyticalRules Analytics Rule with template version 3.0.5", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleVersion50')]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId50')]", + "apiVersion": "2022-04-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", + "properties": { + "description": "Identifies evidence of password spray activity against Azure AD applications by looking for failures from multiple accounts from the same\nIP address within a time window. If the number of accounts breaches the threshold just once, all failures from the IP address within the time range\nare bought into the result. Details on whether there were successful authentications by the IP address within the time window are also included.\nThis can be an indicator that an attack was successful.\nThe default failure acccount threshold is 5, Default time window for failures is 20m and default look back window is 3 days\nNote: Due to the number of possible accounts involved in a password spray it is not possible to map identities to a custom entity.\nReferences: https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-sign-ins-error-codes.", + "displayName": "Password spray attack against Azure AD application", + "enabled": false, + "query": "let timeRange = 3d;\nlet lookBack = 7d;\nlet authenticationWindow = 20m;\nlet authenticationThreshold = 5;\nlet isGUID = \"[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}\";\nlet failureCodes = dynamic([50053, 50126, 50055]); // invalid password, account is locked - too many sign ins, expired password\nlet successCodes = dynamic([0, 50055, 50057, 50155, 50105, 50133, 50005, 50076, 50079, 50173, 50158, 50072, 50074, 53003, 53000, 53001, 50129]);\n// Lookup up resolved identities from last 7 days\nlet aadFunc = (tableName:string){\nlet identityLookup = table(tableName)\n| where TimeGenerated >= ago(lookBack)\n| where not(Identity matches regex isGUID)\n| where isnotempty(UserId)\n| summarize by UserId, lu_UserDisplayName = UserDisplayName, lu_UserPrincipalName = UserPrincipalName, Type;\n// collect window threshold breaches\ntable(tableName)\n| where TimeGenerated > ago(timeRange)\n| where ResultType in(failureCodes)\n| summarize FailedPrincipalCount = dcount(UserPrincipalName) by bin(TimeGenerated, authenticationWindow), IPAddress, AppDisplayName, Type\n| where FailedPrincipalCount >= authenticationThreshold\n| summarize WindowThresholdBreaches = count() by IPAddress, Type\n| join kind= inner (\n// where we breached a threshold, join the details back on all failure data\ntable(tableName)\n| where TimeGenerated > ago(timeRange)\n| where ResultType in(failureCodes)\n| extend LocationDetails = todynamic(LocationDetails)\n| extend FullLocation = strcat(LocationDetails.countryOrRegion,'|', LocationDetails.state, '|', LocationDetails.city)\n| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), make_set(ClientAppUsed,20), make_set(FullLocation,20), FailureCount = count() by IPAddress, AppDisplayName, UserPrincipalName, UserDisplayName, Identity, UserId, Type\n// lookup any unresolved identities\n| extend UnresolvedUserId = iff(Identity matches regex isGUID, UserId, \"\")\n| join kind= leftouter (\n identityLookup\n) on $left.UnresolvedUserId==$right.UserId\n| extend UserDisplayName=iff(isempty(lu_UserDisplayName), UserDisplayName, lu_UserDisplayName)\n| extend UserPrincipalName=iff(isempty(lu_UserPrincipalName), UserPrincipalName, lu_UserPrincipalName)\n| summarize StartTime = min(StartTime), EndTime = max(EndTime), make_set(UserPrincipalName,20), make_set(UserDisplayName,20), make_set(set_ClientAppUsed,20), make_set(set_FullLocation,20), make_list(FailureCount,20) by IPAddress, AppDisplayName, Type\n| extend FailedPrincipalCount = array_length(set_UserPrincipalName)\n) on IPAddress\n| project IPAddress, StartTime, EndTime, TargetedApplication=AppDisplayName, FailedPrincipalCount, UserPrincipalNames=set_UserPrincipalName, UserDisplayNames=set_UserDisplayName, ClientAppsUsed=set_set_ClientAppUsed, Locations=set_set_FullLocation, FailureCountByPrincipal=list_FailureCount, WindowThresholdBreaches, Type\n| join kind= inner (\ntable(tableName) // get data on success vs. failure history for each IP\n| where TimeGenerated > ago(timeRange)\n| where ResultType in(successCodes) or ResultType in(failureCodes) // success or failure types\n| summarize GlobalSuccessPrincipalCount = dcountif(UserPrincipalName, (ResultType in (successCodes))), ResultTypeSuccesses = make_set_if(ResultType, (ResultType in (successCodes))), GlobalFailPrincipalCount = dcountif(UserPrincipalName, (ResultType in (failureCodes))), ResultTypeFailures = make_set_if(ResultType, (ResultType in (failureCodes))) by IPAddress, Type\n| where GlobalFailPrincipalCount > GlobalSuccessPrincipalCount // where the number of failed principals is greater than success - eliminates FPs from IPs who authenticate successfully alot and as a side effect have alot of failures\n) on IPAddress\n| project-away IPAddress1\n| extend timestamp=StartTime\n};\nlet aadSignin = aadFunc(\"SigninLogs\");\nlet aadNonInt = aadFunc(\"AADNonInteractiveUserSignInLogs\");\nunion isfuzzy=true aadSignin, aadNonInt\n", + "queryFrequency": "P1D", + "queryPeriod": "P7D", + "severity": "Medium", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "SigninLogs" + ] + }, + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "AADNonInteractiveUserSignInLogs" + ] } - }, - "parameters": { - "$connections": { - "value": { - "azuread": { - "connectionId": "[[resourceId('Microsoft.Web/connections', variables('AzureADConnectionName'))]", - "connectionName": "[[variables('AzureADConnectionName')]", - "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuread')]" - }, - "microsoftsentinel": { - "connectionId": "[[resourceId('Microsoft.Web/connections', variables('MicrosoftSentinelConnectionName'))]", - "connectionName": "[[variables('MicrosoftSentinelConnectionName')]", - "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", - "connectionProperties": { - "authentication": { - "type": "ManagedServiceIdentity" - } - } - }, - "office365": { - "connectionId": "[[resourceId('Microsoft.Web/connections', variables('Office365ConnectionName'))]", - "connectionName": "[[variables('Office365ConnectionName')]", - "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]" + ], + "tactics": [ + "CredentialAccess" + ], + "techniques": [ + "T1110" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "IPAddress", + "identifier": "Address" } - } + ], + "entityType": "IP" } - } + ] } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('Playbook-', last(split(variables('playbookId7'),'/'))))]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId50'),'/'))))]", "properties": { - "parentId": "[variables('playbookId7')]", - "contentId": "[variables('_playbookContentId7')]", - "kind": "Playbook", - "version": "[variables('playbookVersion7')]", + "description": "Azure Active Directory Analytics Rule 50", + "parentId": "[variables('analyticRuleId50')]", + "contentId": "[variables('_analyticRulecontentId50')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion50')]", "source": { "kind": "Solution", "name": "Azure Active Directory", @@ -11377,396 +10935,662 @@ } } } - ], - "metadata": { - "title": "Block AAD user - Entity trigger", - "description": "This playbook disables the selected user (account entity) in Azure Active Directoy. If this playbook triggered from an incident context, it will add a comment to the incident. This playbook will notify the disabled user manager if available. Note: This playbook will not disable admin user!", - "postDeployment": [ - "1. Assign Microsoft Sentinel Responder role to the Playbook's managed identity.", - "2. Grant User.Read.All, User.ReadWrite.All, Directory.Read.All, Directory.ReadWrite.All permissions to the managed identity.", - "3. Authorize Azure AD and Office 365 Outlook Logic App connections." - ], - "lastUpdateTime": "2022-12-08T00:00:00Z", - "entities": [ - "Account" - ], - "tags": [ - "Remediation" - ], - "releaseNotes": [ - { - "version": "1.0.0", - "title": "Added manager notification action", - "notes": [ - "Initial version" + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_analyticRulecontentId50')]", + "contentKind": "AnalyticsRule", + "displayName": "Password spray attack against Azure AD application", + "contentProductId": "[variables('_analyticRulecontentProductId50')]", + "id": "[variables('_analyticRulecontentProductId50')]", + "version": "[variables('analyticRuleVersion50')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleTemplateSpecName51')]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "SuccessThenFail_DiffIP_SameUserandApp_AnalyticalRules Analytics Rule with template version 3.0.5", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleVersion51')]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId51')]", + "apiVersion": "2022-04-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", + "properties": { + "description": "Identifies when a user account successfully logs onto an Azure App from one IP and within 10 mins failed to logon to the same App via a different IP (may indicate a malicious attempt at password guessing with known account). UEBA added for context.", + "displayName": "Successful logon from IP and failure from a different IP", + "enabled": false, + "query": "let riskScoreCutoff = 20; //Adjust this based on volume of results\nlet logonDiff = 10m; let aadFunc = (tableName:string){ table(tableName)\n| where ResultType == \"0\"\n| where AppDisplayName !in (\"Office 365 Exchange Online\", \"Skype for Business Online\") // To remove false-positives, add more Apps to this array\n// ---------- Fix for SuccessBlock to also consider IPv6\n| extend SuccessIPv6Block = strcat(split(IPAddress, \":\")[0], \":\", split(IPAddress, \":\")[1], \":\", split(IPAddress, \":\")[2], \":\", split(IPAddress, \":\")[3])\n| extend SuccessIPv4Block = strcat(split(IPAddress, \".\")[0], \".\", split(IPAddress, \".\")[1])\n// ------------------\n| project SuccessLogonTime = TimeGenerated, UserPrincipalName, SuccessIPAddress = IPAddress, SuccessLocation = Location, AppDisplayName, SuccessIPBlock = iff(IPAddress contains \":\", strcat(split(IPAddress, \":\")[0], \":\", split(IPAddress, \":\")[1]), strcat(split(IPAddress, \".\")[0], \".\", split(IPAddress, \".\")[1])), Type\n| join kind= inner (\n table(tableName)\n | where ResultType !in (\"0\", \"50140\")\n | where ResultDescription !~ \"Other\"\n | where AppDisplayName !in (\"Office 365 Exchange Online\", \"Skype for Business Online\")\n | project FailedLogonTime = TimeGenerated, UserPrincipalName, FailedIPAddress = IPAddress, FailedLocation = Location, AppDisplayName, ResultType, ResultDescription, Type \n) on UserPrincipalName, AppDisplayName\n| where SuccessLogonTime < FailedLogonTime and FailedLogonTime - SuccessLogonTime <= logonDiff and FailedIPAddress !startswith SuccessIPBlock\n| summarize FailedLogonTime = max(FailedLogonTime), SuccessLogonTime = max(SuccessLogonTime) by UserPrincipalName, SuccessIPAddress, SuccessLocation, AppDisplayName, FailedIPAddress, FailedLocation, ResultType, ResultDescription, Type\n| extend timestamp = SuccessLogonTime\n| extend UserPrincipalName = tolower(UserPrincipalName)};\nlet aadSignin = aadFunc(\"SigninLogs\");\nlet aadNonInt = aadFunc(\"AADNonInteractiveUserSignInLogs\");\nunion isfuzzy=true aadSignin, aadNonInt\n| extend Name = tostring(split(UserPrincipalName,'@',0)[0]), UPNSuffix = tostring(split(UserPrincipalName,'@',1)[0])\n// UEBA context below - make sure you have these 2 datatypes, otherwise the query will not work. If so, comment all that is below.\n| join kind=leftouter (\n IdentityInfo\n | summarize LatestReportTime = arg_max(TimeGenerated, *) by AccountUPN\n | extend BlastRadiusInt = iif(BlastRadius == \"High\", 1, 0)\n | project AccountUPN, Tags, JobTitle, GroupMembership, AssignedRoles, UserType, IsAccountEnabled, BlastRadiusInt\n | summarize\n Tags = make_set(Tags, 1000),\n GroupMembership = make_set(GroupMembership, 1000),\n AssignedRoles = make_set(AssignedRoles, 1000),\n BlastRadiusInt = sum(BlastRadiusInt),\n UserType = make_set(UserType, 1000),\n UserAccountControl = make_set(UserType, 1000)\n by AccountUPN\n | extend UserPrincipalName=tolower(AccountUPN)\n) on UserPrincipalName\n| join kind=leftouter (\n BehaviorAnalytics\n | where ActivityType in (\"FailedLogOn\", \"LogOn\")\n | where isnotempty(SourceIPAddress)\n | project UsersInsights, DevicesInsights, ActivityInsights, InvestigationPriority, SourceIPAddress\n | project-rename FailedIPAddress = SourceIPAddress\n | summarize\n UsersInsights = make_set(UsersInsights, 1000),\n DevicesInsights = make_set(DevicesInsights, 1000),\n IPInvestigationPriority = sum(InvestigationPriority)\n by FailedIPAddress)\non FailedIPAddress\n| extend UEBARiskScore = BlastRadiusInt + IPInvestigationPriority\n| where UEBARiskScore > riskScoreCutoff\n| sort by UEBARiskScore desc \n", + "queryFrequency": "P1D", + "queryPeriod": "P1D", + "severity": "Medium", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "SigninLogs" + ] + }, + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "AADNonInteractiveUserSignInLogs" + ] + }, + { + "connectorId": "BehaviorAnalytics", + "dataTypes": [ + "BehaviorAnalytics" + ] + }, + { + "connectorId": "IdentityInfo", + "dataTypes": [ + "IdentityInfo" + ] + } + ], + "tactics": [ + "CredentialAccess", + "InitialAccess" + ], + "techniques": [ + "T1110", + "T1078" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "Name", + "identifier": "Name" + }, + { + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" + } + ], + "entityType": "Account" + }, + { + "fieldMappings": [ + { + "columnName": "SuccessIPAddress", + "identifier": "Address" + } + ], + "entityType": "IP" + }, + { + "fieldMappings": [ + { + "columnName": "FailedIPAddress", + "identifier": "Address" + } + ], + "entityType": "IP" + } ] } - ] - } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId51'),'/'))))]", + "properties": { + "description": "Azure Active Directory Analytics Rule 51", + "parentId": "[variables('analyticRuleId51')]", + "contentId": "[variables('_analyticRulecontentId51')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion51')]", + "source": { + "kind": "Solution", + "name": "Azure Active Directory", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "Microsoft", + "email": "[variables('_email')]" + }, + "support": { + "tier": "Microsoft", + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "link": "https://support.microsoft.com/" + } + } + } + ] }, "packageKind": "Solution", "packageVersion": "[variables('_solutionVersion')]", "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_playbookContentId7')]", - "contentKind": "Playbook", - "displayName": "Block-AADUser-EntityTrigger", - "contentProductId": "[variables('_playbookcontentProductId7')]", - "id": "[variables('_playbookcontentProductId7')]", - "version": "[variables('playbookVersion7')]" + "contentId": "[variables('_analyticRulecontentId51')]", + "contentKind": "AnalyticsRule", + "displayName": "Successful logon from IP and failure from a different IP", + "contentProductId": "[variables('_analyticRulecontentProductId51')]", + "id": "[variables('_analyticRulecontentProductId51')]", + "version": "[variables('analyticRuleVersion51')]" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('playbookTemplateSpecName8')]", + "name": "[variables('analyticRuleTemplateSpecName52')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "Reset-AADUserPassword-EntityTrigger Playbook with template version 3.0.4", + "description": "SuspiciousAADJoinedDeviceUpdate_AnalyticalRules Analytics Rule with template version 3.0.5", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('playbookVersion8')]", - "parameters": { - "PlaybookName": { - "defaultValue": "Reset-AADUserPassword-EntityTrigger", - "type": "string" - } - }, - "variables": { - "MicrosoftSentinelConnectionName": "[[concat('microsoftsentinel-', parameters('PlaybookName'))]", - "office365ConnectionName": "[[concat('office365-', parameters('PlaybookName'))]", - "connection-2": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", - "_connection-2": "[[variables('connection-2')]", - "connection-3": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]", - "_connection-3": "[[variables('connection-3')]", - "workspace-location-inline": "[concat('[resourceGroup().locatio', 'n]')]", - "workspace-name": "[parameters('workspace')]", - "workspaceResourceId": "[[resourceId('microsoft.OperationalInsights/Workspaces', variables('workspace-name'))]" - }, + "contentVersion": "[variables('analyticRuleVersion52')]", + "parameters": {}, + "variables": {}, "resources": [ { + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId52')]", + "apiVersion": "2022-04-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", "properties": { - "provisioningState": "Succeeded", - "state": "Enabled", - "definition": { - "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "$connections": { - "type": "Object" - } + "description": "This query looks for suspicious updates to an Azure AD joined device where the device name is changed and the device falls out of compliance.\nThis could occur when a threat actor updates the details of an Autopilot provisioned device using a stolen device ticket, in order to access certificates and keys.\nRef: https://dirkjanm.io/assets/raw/Insomnihack%20Breaking%20and%20fixing%20Azure%20AD%20device%20identity%20security.pdf", + "displayName": "Suspicious AAD Joined Device Update", + "enabled": false, + "query": "AuditLogs\n| where OperationName =~ \"Update device\"\n| mv-apply TargetResource=TargetResources on (\n where TargetResource.type =~ \"Device\"\n | extend ModifiedProperties = TargetResource.modifiedProperties\n | extend DeviceId = TargetResource.id)\n| mv-apply Prop=ModifiedProperties on ( \n where Prop.displayName =~ \"CloudDisplayName\"\n | extend OldName = Prop.oldValue \n | extend NewName = Prop.newValue)\n| mv-apply Prop=ModifiedProperties on ( \n where Prop.displayName =~ \"IsCompliant\"\n | extend OldComplianceState = Prop.oldValue \n | extend NewComplianceState = Prop.newValue)\n| mv-apply Prop=ModifiedProperties on ( \n where Prop.displayName =~ \"TargetId.DeviceTrustType\"\n | extend OldTrustType = Prop.oldValue \n | extend NewTrustType = Prop.newValue)\n| mv-apply Prop=ModifiedProperties on ( \n where Prop.displayName =~ \"Included Updated Properties\" \n | extend UpdatedProperties = Prop.newValue)\n| extend OldDeviceName = tostring(parse_json(tostring(OldName))[0])\n| extend NewDeviceName = tostring(parse_json(tostring(NewName))[0])\n| extend OldComplianceState = tostring(parse_json(tostring(OldComplianceState))[0])\n| extend NewComplianceState = tostring(parse_json(tostring(NewComplianceState))[0])\n| extend InitiatedByUser = tostring(iff(isnotempty(InitiatedBy.user.userPrincipalName),InitiatedBy.user.userPrincipalName, InitiatedBy.app.displayName))\n| extend UpdatedPropertiesCount = array_length(split(UpdatedProperties, ','))\n| where OldDeviceName != NewDeviceName\n| where OldComplianceState =~ 'true' and NewComplianceState =~ 'false'\n// Most common is transferring from AAD Registered to AAD Joined - we just want AAD Joined devices\n| where NewTrustType == '\"AzureAd\"' and OldTrustType != '\"Workplace\"'\n// We can modify this value to tune FPs - more properties changed about the device beyond its name the more suspicious it could be\n| where UpdatedPropertiesCount > 1\n| project-reorder TimeGenerated, DeviceId, NewDeviceName, OldDeviceName, NewComplianceState, InitiatedByUser, AADOperationType, OldTrustType, NewTrustType, UpdatedProperties, UpdatedPropertiesCount\n", + "queryFrequency": "P1D", + "queryPeriod": "P1D", + "severity": "Medium", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "AuditLogs" + ] + } + ], + "tactics": [ + "CredentialAccess" + ], + "techniques": [ + "T1528" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "NewDeviceName", + "identifier": "HostName" + } + ], + "entityType": "Host" }, - "triggers": { - "Microsoft_Sentinel_entity": { - "type": "ApiConnectionWebhook", - "inputs": { - "body": { - "callback_url": "@{listCallbackUrl()}" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" - } - }, - "path": "/entity/@{encodeURIComponent('Account')}" + { + "fieldMappings": [ + { + "columnName": "OldDeviceName", + "identifier": "HostName" } - } + ], + "entityType": "Host" }, - "actions": { - "Condition_-_is_manager_available": { - "actions": { - "Condition_2": { - "actions": { - "Add_comment_to_incident_-_manager_available": { - "type": "ApiConnection", - "inputs": { - "body": { - "incidentArmId": "@triggerBody()?['IncidentArmID']", - "message": "

User @{variables('AccountDetails')} password was reset in AAD and their manager @{body('Parse_JSON_-_HTTP_-_get_manager')?['userPrincipalName']} was contacted using playbook.

" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" - } - }, - "method": "post", - "path": "/Incidents/Comment" - } - } - }, - "runAfter": { - "Send_an_email_-_to_manager_with_password_details": [ - "Succeeded" - ] - }, - "expression": { - "and": [ - { - "not": { - "equals": [ - "@triggerBody()?['IncidentArmID']", - "@null" - ] - } - } - ] - }, - "type": "If" - }, - "Parse_JSON_-_HTTP_-_get_manager": { - "type": "ParseJson", - "inputs": { - "content": "@body('HTTP_-_get_manager')", - "schema": { - "properties": { - "userPrincipalName": { - "type": "string" - } - }, - "type": "object" - } - } - }, - "Send_an_email_-_to_manager_with_password_details": { - "runAfter": { - "Parse_JSON_-_HTTP_-_get_manager": [ - "Succeeded" - ] - }, - "type": "ApiConnection", - "inputs": { - "body": { - "Body": "

User, @{variables('AccountDetails')}, was involved in part of a security incident.  As part of remediation, the user password has been reset.
\n
\nThe temporary password is: @{variables('Password')}
\n
\nThe user will be required to reset this password upon login.

", - "Subject": "A user password was reset due to security incident.", - "To": "@body('Parse_JSON_-_HTTP_-_get_manager')?['userPrincipalName']" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['office365']['connectionId']" - } - }, - "method": "post", - "path": "/v2/Mail" - } - } - }, - "runAfter": { - "HTTP_-_get_manager": [ - "Succeeded", - "Failed" - ] - }, - "else": { - "actions": { - "Condition": { - "actions": { - "Add_comment_to_incident_-_manager_not_available": { - "type": "ApiConnection", - "inputs": { - "body": { - "incidentArmId": "@triggerBody()?['IncidentArmID']", - "message": "

User @{variables('AccountDetails')} password was reset in AAD but the user doesn't have a manager.
\n
\nThe temporary password is: @{variables('Password')}
\n
\nThe user will be required to reset this password upon login.

" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" - } - }, - "method": "post", - "path": "/Incidents/Comment" - } - } - }, - "expression": { - "and": [ - { - "not": { - "equals": [ - "@triggerBody()?['IncidentArmID']", - "@null" - ] - } - } - ] - }, - "type": "If" - } - } - }, - "expression": { - "and": [ - { - "equals": [ - "@outputs('HTTP_-_get_manager')['statusCode']", - 200 - ] - } - ] - }, - "type": "If" - }, - "HTTP_-_get_manager": { - "runAfter": { - "HTTP_-_reset_a_password": [ - "Succeeded" - ] - }, - "type": "Http", - "inputs": { - "authentication": { - "audience": "https://graph.microsoft.com", - "type": "ManagedServiceIdentity" - }, - "method": "GET", - "uri": "https://graph.microsoft.com/v1.0/users/@{variables('AccountDetails')}/manager" + { + "fieldMappings": [ + { + "columnName": "DeviceId", + "identifier": "AzureID" + } + ], + "entityType": "Host" + }, + { + "fieldMappings": [ + { + "columnName": "InitiatedByUser", + "identifier": "AadUserId" } - }, - "HTTP_-_reset_a_password": { - "runAfter": { - "Initialize_variable_Account": [ - "Succeeded" - ] + ], + "entityType": "Account" + } + ], + "alertDetailsOverride": { + "alertDisplayNameFormat": "Suspicious AAD Joined Device Update {{OldDeviceName}} renamed to {{NewDeviceName}} and {{UpdatedPropertiesCount}} properties changed", + "alertDescriptionFormat": "This query looks for suspicious updates to an Azure AD joined device where the device name is changed and the device falls out of compliance.\nIn this case {{OldDeviceName}} was renamed to {{NewDeviceName}} and {{UpdatedPropertiesCount}} properties were changed.\nThis could occur when a threat actor steals a Device ticket from an Autopilot provisioned device and uses it to AAD Join a new device.\nRef: https://dirkjanm.io/assets/raw/Insomnihack%20Breaking%20and%20fixing%20Azure%20AD%20device%20identity%20security.pdf\n" + } + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId52'),'/'))))]", + "properties": { + "description": "Azure Active Directory Analytics Rule 52", + "parentId": "[variables('analyticRuleId52')]", + "contentId": "[variables('_analyticRulecontentId52')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion52')]", + "source": { + "kind": "Solution", + "name": "Azure Active Directory", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "Microsoft", + "email": "[variables('_email')]" + }, + "support": { + "tier": "Microsoft", + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "link": "https://support.microsoft.com/" + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_analyticRulecontentId52')]", + "contentKind": "AnalyticsRule", + "displayName": "Suspicious AAD Joined Device Update", + "contentProductId": "[variables('_analyticRulecontentProductId52')]", + "id": "[variables('_analyticRulecontentProductId52')]", + "version": "[variables('analyticRuleVersion52')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleTemplateSpecName53')]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "SuspiciousOAuthApp_OfflineAccess_AnalyticalRules Analytics Rule with template version 3.0.5", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleVersion53')]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId53')]", + "apiVersion": "2022-04-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", + "properties": { + "description": "This will alert when a user consents to provide a previously-unknown Azure application with offline access via OAuth.\nOffline access will provide the Azure App with access to the listed resources without requiring two-factor authentication.\nConsent to applications with offline access and read capabilities should be rare, especially as the knownApplications list is expanded. Public contributions to expand this filter are welcome!\nFor further information on AuditLogs please see https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-audit-activities.", + "displayName": "Suspicious application consent for offline access", + "enabled": false, + "query": "let detectionTime = 1d;\nlet joinLookback = 14d;\nAuditLogs\n| where TimeGenerated > ago(detectionTime)\n| where LoggedByService =~ \"Core Directory\"\n| where Category =~ \"ApplicationManagement\"\n| where OperationName =~ \"Consent to application\"\n| where TargetResources has \"offline\"\n| mv-apply TargetResource=TargetResources on \n (\n where TargetResource.type =~ \"ServicePrincipal\"\n | extend ModifiedProperties = TargetResource.modifiedProperties,\n AppDisplayName = tostring(TargetResource.displayName),\n AppClientId = tolower(tostring(TargetResource.id))\n )\n| where AppClientId !in ((externaldata(knownAppClientId:string, knownAppDisplayName:string)[@\"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Sample%20Data/Feeds/Microsoft.OAuth.KnownApplications.csv\"] with (format=\"csv\")))\n| mv-apply Properties=ModifiedProperties on \n (\n where Properties.displayName =~ \"ConsentAction.Permissions\"\n | extend ConsentFull = tostring(Properties.newValue)\n | extend ConsentFull = trim(@'\"',tostring(ConsentFull))\n )\n| parse ConsentFull with * \"ConsentType: \" GrantConsentType \", Scope: \" GrantScope1 \"]\" *\n| where ConsentFull has \"offline_access\" and ConsentFull has_any (\"Files.Read\", \"Mail.Read\", \"Notes.Read\", \"ChannelMessage.Read\", \"Chat.Read\", \"TeamsActivity.Read\", \"Group.Read\", \"EWS.AccessAsUser.All\", \"EAS.AccessAsUser.All\")\n| where GrantConsentType != \"AllPrincipals\" // NOTE: we are ignoring if OAuth application was granted to all users via an admin - but admin due diligence should be audited occasionally\n| extend GrantIpAddress = tostring(iff(isnotempty(InitiatedBy.user.ipAddress), InitiatedBy.user.ipAddress, InitiatedBy.app.ipAddress))\n| extend GrantInitiatedBy = tostring(iff(isnotempty(InitiatedBy.user.userPrincipalName),InitiatedBy.user.userPrincipalName, InitiatedBy.app.displayName))\n| extend GrantUserAgent = tostring(iff(AdditionalDetails[0].key =~ \"User-Agent\", AdditionalDetails[0].value, \"\"))\n| project TimeGenerated, GrantConsentType, GrantScope1, GrantInitiatedBy, AppDisplayName, GrantIpAddress, GrantUserAgent, AppClientId, OperationName, ConsentFull, CorrelationId\n| join kind = leftouter (AuditLogs\n| where TimeGenerated > ago(joinLookback)\n| where LoggedByService =~ \"Core Directory\"\n| where Category =~ \"ApplicationManagement\"\n| where OperationName =~ \"Add service principal\"\n| mv-apply TargetResource=TargetResources on \n (\n where TargetResource.type =~ \"ServicePrincipal\"\n | extend ModifiedProperties = TargetResource.modifiedProperties,\n AppClientId = tolower(TargetResource.id)\n )\n| mv-apply ModifiedProperties=TargetResource.modifiedProperties on \n (\n where ModifiedProperties.displayName =~ \"AppAddress\" and ModifiedProperties.newValue has \"AddressType\"\n | extend AppReplyURLs = ModifiedProperties.newValue\n )\n | distinct AppClientId, tostring(AppReplyURLs)\n)\non AppClientId\n| join kind = innerunique (AuditLogs\n| where TimeGenerated > ago(joinLookback)\n| where LoggedByService =~ \"Core Directory\"\n| where Category =~ \"ApplicationManagement\"\n| where OperationName =~ \"Add OAuth2PermissionGrant\" or OperationName =~ \"Add delegated permission grant\"\n | mv-apply TargetResource=TargetResources on \n (\n where TargetResource.type =~ \"ServicePrincipal\" and array_length(TargetResource.modifiedProperties) > 0 and isnotnull(TargetResource.displayName)\n | extend GrantAuthentication = tostring(TargetResource.displayName)\n )\n| extend GrantOperation = OperationName\n| project GrantAuthentication, GrantOperation, CorrelationId\n) on CorrelationId\n| project TimeGenerated, GrantConsentType, GrantScope1, GrantInitiatedBy, AppDisplayName, AppReplyURLs, GrantIpAddress, GrantUserAgent, AppClientId, GrantAuthentication, OperationName, GrantOperation, CorrelationId, ConsentFull\n| extend timestamp = TimeGenerated, Name = tostring(split(GrantInitiatedBy,'@',0)[0]), UPNSuffix = tostring(split(GrantInitiatedBy,'@',1)[0])\n", + "queryFrequency": "P1D", + "queryPeriod": "P14D", + "severity": "Low", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "AuditLogs" + ] + } + ], + "tactics": [ + "CredentialAccess" + ], + "techniques": [ + "T1528" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "Name", + "identifier": "Name" }, - "type": "Http", - "inputs": { - "authentication": { - "audience": "https://graph.microsoft.com", - "type": "ManagedServiceIdentity" - }, - "body": { - "passwordProfile": { - "forceChangePasswordNextSignIn": true, - "forceChangePasswordNextSignInWithMfa": false, - "password": "@{variables('Password')}" - } - }, - "method": "PATCH", - "uri": "https://graph.microsoft.com/v1.0/users/@{variables('AccountDetails')}" + { + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" } - }, - "Initialize_variable": { - "type": "InitializeVariable", - "inputs": { - "variables": [ - { - "name": "Password", - "type": "String", - "value": "null" - } - ] + ], + "entityType": "Account" + }, + { + "fieldMappings": [ + { + "columnName": "GrantIpAddress", + "identifier": "Address" } - }, - "Initialize_variable_Account": { - "runAfter": { - "Set_variable_-_password": [ - "Succeeded" - ] - }, - "type": "InitializeVariable", - "inputs": { - "variables": [ - { - "name": "AccountDetails", - "type": "string", - "value": "@{concat(triggerBody()?['Entity']?['properties']?['Name'],'@',triggerBody()?['Entity']?['properties']?['UPNSuffix'])}" - } - ] + ], + "entityType": "IP" + } + ] + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId53'),'/'))))]", + "properties": { + "description": "Azure Active Directory Analytics Rule 53", + "parentId": "[variables('analyticRuleId53')]", + "contentId": "[variables('_analyticRulecontentId53')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion53')]", + "source": { + "kind": "Solution", + "name": "Azure Active Directory", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "Microsoft", + "email": "[variables('_email')]" + }, + "support": { + "tier": "Microsoft", + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "link": "https://support.microsoft.com/" + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_analyticRulecontentId53')]", + "contentKind": "AnalyticsRule", + "displayName": "Suspicious application consent for offline access", + "contentProductId": "[variables('_analyticRulecontentProductId53')]", + "id": "[variables('_analyticRulecontentProductId53')]", + "version": "[variables('analyticRuleVersion53')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleTemplateSpecName54')]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "SuspiciousServicePrincipalcreationactivity_AnalyticalRules Analytics Rule with template version 3.0.5", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleVersion54')]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId54')]", + "apiVersion": "2022-04-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", + "properties": { + "description": "This alert will detect creation of an SPN, permissions granted, credentials created, activity and deletion of the SPN in a time frame (default 10 minutes)", + "displayName": "Suspicious Service Principal creation activity", + "enabled": false, + "query": "let queryfrequency = 1h;\nlet wait_for_deletion = 10m;\nlet account_created =\n AuditLogs \n | where ActivityDisplayName == \"Add service principal\"\n | where Result == \"success\"\n | extend AppID = tostring(AdditionalDetails[1].value)\n | extend creationTime = ActivityDateTime\n | extend userPrincipalName_creator = tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName)\n | extend ipAddress_creator = tostring(parse_json(tostring(InitiatedBy.user)).ipAddress);\nlet account_activity =\n AADServicePrincipalSignInLogs\n | extend Activities = pack(\"ActivityTime\", TimeGenerated ,\"IpAddress\", IPAddress, \"ResourceDisplayName\", ResourceDisplayName)\n | extend AppID = AppId\n | summarize make_list(Activities) by AppID;\nlet account_deleted =\n AuditLogs \n | where OperationName == \"Remove service principal\"\n | where Result == \"success\"\n | extend AppID = tostring(AdditionalDetails[1].value)\n | extend deletionTime = ActivityDateTime\n | extend userPrincipalName_deleter = tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName)\n | extend ipAddress_deleter = tostring(parse_json(tostring(InitiatedBy.user)).ipAddress);\nlet account_credentials =\n AuditLogs\n | where OperationName has_all (\"Update application\", \"Certificates and secrets management\")\n | where Result == \"success\"\n | extend AppID = tostring(AdditionalDetails[1].value)\n | extend credentialCreationTime = ActivityDateTime;\nlet roles_assigned =\n AuditLogs\n | where ActivityDisplayName == \"Add app role assignment to service principal\"\n | extend AppID = tostring(TargetResources[1].displayName)\n | extend AssignedRole = iff(tostring(parse_json(tostring(TargetResources[0].modifiedProperties))[1].displayName)==\"AppRole.Value\", tostring(parse_json(tostring(parse_json(tostring(TargetResources[0].modifiedProperties))[1].newValue))),\"\")\n | extend AssignedRoles = pack(\"Role\", AssignedRole)\n | summarize make_list(AssignedRoles) by AppID;\naccount_created\n| where TimeGenerated between (ago(wait_for_deletion+queryfrequency)..ago(wait_for_deletion))\n| join kind= inner (account_activity) on AppID\n| join kind= inner (account_deleted) on AppID\n| join kind= inner (account_credentials) on AppID\n| join kind= inner (roles_assigned) on AppID\n| where deletionTime - creationTime between (time(0s)..wait_for_deletion)\n| extend AliveTime = deletionTime - creationTime\n| project AADTenantId, AppID, creationTime, deletionTime, userPrincipalName_creator, userPrincipalName_deleter, ipAddress_creator, ipAddress_deleter, list_Activities, list_AssignedRoles, AliveTime\n", + "queryFrequency": "PT1H", + "queryPeriod": "PT70M", + "severity": "Low", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "AuditLogs", + "AADServicePrincipalSignInLogs" + ] + } + ], + "tactics": [ + "CredentialAccess", + "PrivilegeEscalation", + "InitialAccess" + ], + "techniques": [ + "T1078", + "T1528" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "userPrincipalName_creator", + "identifier": "FullName" } - }, - "Set_variable_-_password": { - "runAfter": { - "Initialize_variable": [ - "Succeeded" - ] - }, - "type": "SetVariable", - "inputs": { - "name": "Password", - "value": "@{substring(guid(), 0, 10)}" + ], + "entityType": "Account" + }, + { + "fieldMappings": [ + { + "columnName": "userPrincipalName_deleter", + "identifier": "FullName" } - } - } - }, - "parameters": { - "$connections": { - "value": { - "microsoftsentinel": { - "connectionId": "[[resourceId('Microsoft.Web/connections', variables('MicrosoftSentinelConnectionName'))]", - "connectionName": "[[variables('MicrosoftSentinelConnectionName')]", - "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", - "connectionProperties": { - "authentication": { - "type": "ManagedServiceIdentity" - } - } - }, - "office365": { - "connectionId": "[[resourceId('Microsoft.Web/connections', variables('office365ConnectionName'))]", - "connectionName": "[[variables('office365ConnectionName')]", - "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]" + ], + "entityType": "Account" + }, + { + "fieldMappings": [ + { + "columnName": "ipAddress_creator", + "identifier": "Address" } - } + ], + "entityType": "IP" + }, + { + "fieldMappings": [ + { + "columnName": "ipAddress_deleter", + "identifier": "Address" + } + ], + "entityType": "IP" } - } - }, - "name": "[[parameters('PlaybookName')]", - "type": "Microsoft.Logic/workflows", - "location": "[[variables('workspace-location-inline')]", - "tags": { - "LogicAppsCategory": "security", - "hidden-SentinelTemplateName": "Reset-AADUserPassword-EntityTrigger", - "hidden-SentinelTemplateVersion": "1.1", - "hidden-SentinelWorkspaceId": "[[variables('workspaceResourceId')]" - }, - "identity": { - "type": "SystemAssigned" - }, - "apiVersion": "2017-07-01", - "dependsOn": [ - "[[resourceId('Microsoft.Web/connections', variables('MicrosoftSentinelConnectionName'))]", - "[[resourceId('Microsoft.Web/connections', variables('office365ConnectionName'))]" - ] + ] + } }, { - "type": "Microsoft.Web/connections", - "apiVersion": "2016-06-01", - "name": "[[variables('MicrosoftSentinelConnectionName')]", - "location": "[[variables('workspace-location-inline')]", - "kind": "V1", + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId54'),'/'))))]", "properties": { - "displayName": "[[variables('MicrosoftSentinelConnectionName')]", - "parameterValueType": "Alternative", - "api": { - "id": "[[variables('_connection-2')]" + "description": "Azure Active Directory Analytics Rule 54", + "parentId": "[variables('analyticRuleId54')]", + "contentId": "[variables('_analyticRulecontentId54')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion54')]", + "source": { + "kind": "Solution", + "name": "Azure Active Directory", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "Microsoft", + "email": "[variables('_email')]" + }, + "support": { + "tier": "Microsoft", + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "link": "https://support.microsoft.com/" } } - }, + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_analyticRulecontentId54')]", + "contentKind": "AnalyticsRule", + "displayName": "Suspicious Service Principal creation activity", + "contentProductId": "[variables('_analyticRulecontentProductId54')]", + "id": "[variables('_analyticRulecontentProductId54')]", + "version": "[variables('analyticRuleVersion54')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleTemplateSpecName55')]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "UnusualGuestActivity_AnalyticalRules Analytics Rule with template version 3.0.5", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleVersion55')]", + "parameters": {}, + "variables": {}, + "resources": [ { - "type": "Microsoft.Web/connections", - "apiVersion": "2016-06-01", - "name": "[[variables('office365ConnectionName')]", - "location": "[[variables('workspace-location-inline')]", - "kind": "V1", + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId55')]", + "apiVersion": "2022-04-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", "properties": { - "displayName": "[[variables('office365ConnectionName')]", - "api": { - "id": "[[variables('_connection-3')]" - } + "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/", + "displayName": "External guest invitation followed by Azure AD PowerShell signin", + "enabled": false, + "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", + "severity": "Medium", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "AuditLogs" + ] + }, + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "SigninLogs" + ] + } + ], + "tactics": [ + "InitialAccess", + "Persistence", + "Discovery" + ], + "techniques": [ + "T1078", + "T1136", + "T1087" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "InvitedUserName", + "identifier": "Name" + }, + { + "columnName": "InvitedUserUPNSuffix", + "identifier": "UPNSuffix" + } + ], + "entityType": "Account" + }, + { + "fieldMappings": [ + { + "columnName": "InitiatedByName", + "identifier": "Name" + }, + { + "columnName": "InitiatedByUPNSuffix", + "identifier": "UPNSuffix" + } + ], + "entityType": "Account" + }, + { + "fieldMappings": [ + { + "columnName": "IPAddress", + "identifier": "Address" + } + ], + "entityType": "IP" + } + ] } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('Playbook-', last(split(variables('playbookId8'),'/'))))]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId55'),'/'))))]", "properties": { - "parentId": "[variables('playbookId8')]", - "contentId": "[variables('_playbookContentId8')]", - "kind": "Playbook", - "version": "[variables('playbookVersion8')]", + "description": "Azure Active Directory Analytics Rule 55", + "parentId": "[variables('analyticRuleId55')]", + "contentId": "[variables('_analyticRulecontentId55')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion55')]", "source": { "kind": "Solution", "name": "Azure Active Directory", @@ -11784,317 +11608,368 @@ } } } - ], - "metadata": { - "title": "Reset Azure AD User Password - Entity trigger", - "description": "This playbook will reset the user password using Graph API. It will send the password (which is a random guid substring) to the user's manager. The user will have to reset the password upon login.", - "postDeployment": [ - "1. Assign Password Administrator permission to managed identity.", - "2. Assign Microsoft Sentinel Responder permission to managed identity.", - "3. Authorize Office 365 Outlook connection" - ], - "lastUpdateTime": "2022-12-06T00:00:00Z", - "entities": [ - "Account" - ], - "tags": [ - "Remediation" - ], - "releaseNotes": { - "version": "1.1", - "title": "[variables('blanks')]", - "notes": [ - "Initial version" - ] - } - } + ] }, - "packageKind": "Solution", - "packageVersion": "[variables('_solutionVersion')]", - "packageName": "[variables('_solutionName')]", - "packageId": "[variables('_solutionId')]", - "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_playbookContentId8')]", - "contentKind": "Playbook", - "displayName": "Reset-AADUserPassword-EntityTrigger", - "contentProductId": "[variables('_playbookcontentProductId8')]", - "id": "[variables('_playbookcontentProductId8')]", - "version": "[variables('playbookVersion8')]" + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_analyticRulecontentId55')]", + "contentKind": "AnalyticsRule", + "displayName": "External guest invitation followed by Azure AD PowerShell signin", + "contentProductId": "[variables('_analyticRulecontentProductId55')]", + "id": "[variables('_analyticRulecontentProductId55')]", + "version": "[variables('analyticRuleVersion55')]" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('playbookTemplateSpecName9')]", + "name": "[variables('analyticRuleTemplateSpecName56')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "Revoke-AADSignInSessions-alert Playbook with template version 3.0.4", + "description": "UserAccounts-CABlockedSigninSpikes_AnalyticalRules Analytics Rule with template version 3.0.5", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('playbookVersion9')]", - "parameters": { - "PlaybookName": { - "defaultValue": "Revoke-AADSignInSessions-alert", - "type": "string" - }, - "UserName": { - "defaultValue": "@", - "type": "string" - } - }, - "variables": { - "AzureSentinelConnectionName": "[[concat('azuresentinel-', parameters('PlaybookName'))]", - "Office365ConnectionName": "[[concat('office365-', parameters('PlaybookName'))]", - "Office365UsersConnectionName": "[[concat('office365users-', parameters('PlaybookName'))]", - "connection-1": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", - "_connection-1": "[[variables('connection-1')]", - "connection-2": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]", - "_connection-2": "[[variables('connection-2')]", - "connection-3": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365users')]", - "_connection-3": "[[variables('connection-3')]", - "workspace-location-inline": "[concat('[resourceGroup().locatio', 'n]')]", - "workspace-name": "[parameters('workspace')]", - "workspaceResourceId": "[[resourceId('microsoft.OperationalInsights/Workspaces', variables('workspace-name'))]" - }, + "contentVersion": "[variables('analyticRuleVersion56')]", + "parameters": {}, + "variables": {}, "resources": [ { - "type": "Microsoft.Web/connections", - "apiVersion": "2016-06-01", - "name": "[[variables('AzureSentinelConnectionName')]", - "location": "[[variables('workspace-location-inline')]", - "kind": "V1", - "properties": { - "displayName": "[[parameters('PlaybookName')]", - "parameterValueType": "Alternative", - "api": { - "id": "[[variables('_connection-1')]" - } - } - }, - { - "type": "Microsoft.Web/connections", - "apiVersion": "2016-06-01", - "name": "[[variables('Office365ConnectionName')]", - "location": "[[variables('workspace-location-inline')]", - "properties": { - "displayName": "[[parameters('UserName')]", - "api": { - "id": "[[variables('_connection-2')]" - } - } - }, - { - "type": "Microsoft.Web/connections", - "apiVersion": "2016-06-01", - "name": "[[variables('Office365UsersConnectionName')]", - "location": "[[variables('workspace-location-inline')]", - "properties": { - "displayName": "[[parameters('UserName')]", - "api": { - "id": "[[variables('_connection-3')]" - } - } - }, - { - "type": "Microsoft.Logic/workflows", - "apiVersion": "2017-07-01", - "name": "[[parameters('PlaybookName')]", - "location": "[[variables('workspace-location-inline')]", - "tags": { - "LogicAppsCategory": "security", - "hidden-SentinelTemplateName": "Revoke-AADSigninSessions_alert", - "hidden-SentinelTemplateVersion": "1.0", - "hidden-SentinelWorkspaceId": "[[variables('workspaceResourceId')]" - }, - "identity": { - "type": "SystemAssigned" - }, - "dependsOn": [ - "[[resourceId('Microsoft.Web/connections', variables('AzureSentinelConnectionName'))]", - "[[resourceId('Microsoft.Web/connections', variables('Office365ConnectionName'))]", - "[[resourceId('Microsoft.Web/connections', variables('Office365UsersConnectionName'))]" - ], + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId56')]", + "apiVersion": "2022-04-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", "properties": { - "state": "Enabled", - "definition": { - "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", - "actions": { - "Alert_-_Get_incident": { - "inputs": { - "host": { - "connection": { - "name": "@parameters('$connections')['azuresentinel']['connectionId']" - } - }, - "method": "get", - "path": "/Incidents/subscriptions/@{encodeURIComponent(triggerBody()?['WorkspaceSubscriptionId'])}/resourceGroups/@{encodeURIComponent(triggerBody()?['WorkspaceResourceGroup'])}/workspaces/@{encodeURIComponent(triggerBody()?['WorkspaceId'])}/alerts/@{encodeURIComponent(triggerBody()?['SystemAlertId'])}" - }, - "type": "ApiConnection" - }, - "Entities_-_Get_Accounts": { - "inputs": { - "body": "@triggerBody()?['Entities']", - "host": { - "connection": { - "name": "@parameters('$connections')['azuresentinel']['connectionId']" - } - }, - "method": "post", - "path": "/entities/account" - }, - "runAfter": { - "Alert_-_Get_incident": [ - "Succeeded" - ] - }, - "type": "ApiConnection" - }, - "For_each": { - "actions": { - "Add_comment_to_incident_(V3)": { - "inputs": { - "body": { - "incidentArmId": "@body('Alert_-_Get_incident')?['id']", - "message": "

User @{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])} singin sessions were revoked in AAD and their manager @{body('Get_manager_(V2)')?['displayName']} was contacted using playbook.

" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['azuresentinel']['connectionId']" - } - }, - "method": "post", - "path": "/Incidents/Comment" - }, - "runAfter": { - "Send_an_email_(V2)": [ - "Succeeded" - ] - }, - "type": "ApiConnection" - }, - "Get_manager_(V2)": { - "inputs": { - "host": { - "connection": { - "name": "@parameters('$connections')['office365users']['connectionId']" - } - }, - "method": "get", - "path": "/codeless/v1.0/users/@{encodeURIComponent(concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix']))}/manager" - }, - "runAfter": { - "HTTP": [ - "Succeeded" - ] - }, - "type": "ApiConnection" - }, - "HTTP": { - "inputs": { - "authentication": { - "audience": "https://graph.microsoft.com", - "type": "ManagedServiceIdentity" - }, - "method": "POST", - "uri": "https://graph.microsoft.com/v1.0/users/@{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])}/revokeSignInSessions" - }, - "type": "Http" - }, - "Send_an_email_(V2)": { - "inputs": { - "body": { - "Body": "

User, @{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])}, was involved in part of a security incident.  As part of remediation, the user signin sessions have been revoked.  The user will need to reauthenticate in all applications.

", - "Subject": "User signin sessions were reset due to security incident.", - "To": "@body('Get_manager_(V2)')?['mail']" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['office365']['connectionId']" - } - }, - "method": "post", - "path": "/v2/Mail" - }, - "runAfter": { - "Get_manager_(V2)": [ - "Succeeded" - ] - }, - "type": "ApiConnection" - } - }, - "foreach": "@body('Entities_-_Get_Accounts')?['Accounts']", - "runAfter": { - "Entities_-_Get_Accounts": [ - "Succeeded" - ] + "description": " Identifies spike in failed sign-ins from user accounts due to conditional access policied.\nSpike is determined based on Time series anomaly which will look at historical baseline values.\nRef : https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-user-accounts#monitoring-for-failed-unusual-sign-ins\nThis query has also been updated to include UEBA logs IdentityInfo and BehaviorAnalytics for contextual information around the results.", + "displayName": "User Accounts - Sign in Failure due to CA Spikes", + "enabled": false, + "query": "let riskScoreCutoff = 20; //Adjust this based on volume of results\nlet starttime = 14d;\nlet timeframe = 1d;\nlet scorethreshold = 3;\nlet baselinethreshold = 50;\nlet aadFunc = (tableName:string){\n // Failed Signins attempts with reasoning related to conditional access policies.\n table(tableName)\n | where TimeGenerated between (startofday(ago(starttime))..startofday(now()))\n | where ResultDescription has_any (\"conditional access\", \"CA\") or ResultType in (50005, 50131, 53000, 53001, 53002, 52003, 70044)\n | extend UserPrincipalName = tolower(UserPrincipalName)\n | extend timestamp = TimeGenerated, AccountCustomEntity = UserPrincipalName\n};\nlet aadSignin = aadFunc(\"SigninLogs\");\nlet aadNonInt = aadFunc(\"AADNonInteractiveUserSignInLogs\");\nlet allSignins = union isfuzzy=true aadSignin, aadNonInt;\nlet TimeSeriesAlerts = \nallSignins\n| make-series DailyCount=count() on TimeGenerated from startofday(ago(starttime)) to startofday(now()) step 1d by UserPrincipalName\n| extend (anomalies, score, baseline) = series_decompose_anomalies(DailyCount, scorethreshold, -1, 'linefit')\n| mv-expand DailyCount to typeof(double), TimeGenerated to typeof(datetime), anomalies to typeof(double), score to typeof(double), baseline to typeof(long)\n// Filtering low count events per baselinethreshold\n| where anomalies > 0 and baseline > baselinethreshold\n| extend AnomalyHour = TimeGenerated\n| project UserPrincipalName, AnomalyHour, TimeGenerated, DailyCount, baseline, anomalies, score;\n// Filter the alerts for specified timeframe\nTimeSeriesAlerts\n| where TimeGenerated > startofday(ago(timeframe))\n| join kind=inner ( \n allSignins\n | where TimeGenerated > startofday(ago(timeframe))\n // create a new column and round to hour\n | extend DateHour = bin(TimeGenerated, 1h)\n | summarize PartialFailedSignins = count(), LatestAnomalyTime = arg_max(TimeGenerated, *) by bin(TimeGenerated, 1h), OperationName, Category, ResultType, ResultDescription, UserPrincipalName, UserDisplayName, AppDisplayName, ClientAppUsed, IPAddress, ResourceDisplayName\n) on UserPrincipalName, $left.AnomalyHour == $right.DateHour\n| project LatestAnomalyTime, OperationName, Category, UserPrincipalName, UserDisplayName, ResultType, ResultDescription, AppDisplayName, ClientAppUsed, UserAgent, IPAddress, Location, AuthenticationRequirement, ConditionalAccessStatus, ResourceDisplayName, PartialFailedSignins, TotalFailedSignins = DailyCount, baseline, anomalies, score\n| extend timestamp = LatestAnomalyTime, Name = tostring(split(UserPrincipalName,'@',0)[0]), UPNSuffix = tostring(split(UserPrincipalName,'@',1)[0])\n| extend UserPrincipalName = tolower(UserPrincipalName)\n| join kind=leftouter (\n IdentityInfo\n | summarize LatestReportTime = arg_max(TimeGenerated, *) by AccountUPN\n | extend BlastRadiusInt = iif(BlastRadius == \"High\", 1, 0)\n | project AccountUPN, Tags, JobTitle, GroupMembership, AssignedRoles, UserType, IsAccountEnabled, BlastRadiusInt\n | summarize\n Tags = make_set(Tags, 1000),\n GroupMembership = make_set(GroupMembership, 1000),\n AssignedRoles = make_set(AssignedRoles, 1000),\n BlastRadiusInt = sum(BlastRadiusInt),\n UserType = make_set(UserType, 1000),\n UserAccountControl = make_set(UserType, 1000)\n by AccountUPN\n | extend UserPrincipalName=tolower(AccountUPN)\n) on UserPrincipalName\n| join kind=leftouter (\n BehaviorAnalytics\n | where ActivityType in (\"FailedLogOn\", \"LogOn\")\n | where isnotempty(SourceIPAddress)\n | project UsersInsights, DevicesInsights, ActivityInsights, InvestigationPriority, SourceIPAddress\n | project-rename IPAddress = SourceIPAddress\n | summarize\n UsersInsights = make_set(UsersInsights, 1000),\n DevicesInsights = make_set(DevicesInsights, 1000),\n IPInvestigationPriority = sum(InvestigationPriority)\n by IPAddress)\non IPAddress\n| extend UEBARiskScore = BlastRadiusInt + IPInvestigationPriority\n| where UEBARiskScore > riskScoreCutoff\n| sort by UEBARiskScore desc \n", + "queryFrequency": "P1D", + "queryPeriod": "P14D", + "severity": "Medium", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "SigninLogs" + ] + }, + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "AADNonInteractiveUserSignInLogs" + ] + }, + { + "connectorId": "BehaviorAnalytics", + "dataTypes": [ + "BehaviorAnalytics" + ] + }, + { + "connectorId": "IdentityInfo", + "dataTypes": [ + "IdentityInfo" + ] + } + ], + "tactics": [ + "InitialAccess" + ], + "techniques": [ + "T1078" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "Name", + "identifier": "Name" }, - "type": "Foreach" - } + { + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" + } + ], + "entityType": "Account" }, - "contentVersion": "1.0.0.0", - "parameters": { - "$connections": { - "type": "Object" - } + { + "fieldMappings": [ + { + "columnName": "IPAddress", + "identifier": "Address" + } + ], + "entityType": "IP" + } + ] + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId56'),'/'))))]", + "properties": { + "description": "Azure Active Directory Analytics Rule 56", + "parentId": "[variables('analyticRuleId56')]", + "contentId": "[variables('_analyticRulecontentId56')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion56')]", + "source": { + "kind": "Solution", + "name": "Azure Active Directory", + "sourceId": "[variables('_solutionId')]" + }, + "author": { + "name": "Microsoft", + "email": "[variables('_email')]" + }, + "support": { + "tier": "Microsoft", + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "link": "https://support.microsoft.com/" + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_analyticRulecontentId56')]", + "contentKind": "AnalyticsRule", + "displayName": "User Accounts - Sign in Failure due to CA Spikes", + "contentProductId": "[variables('_analyticRulecontentProductId56')]", + "id": "[variables('_analyticRulecontentProductId56')]", + "version": "[variables('analyticRuleVersion56')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleTemplateSpecName57')]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "UseraddedtoPrivilgedGroups_AnalyticalRules Analytics Rule with template version 3.0.5", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleVersion57')]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId57')]", + "apiVersion": "2022-04-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", + "properties": { + "description": "This will alert when a user is added to any of the Privileged Groups.\nFor further information on AuditLogs please see https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-audit-activities.\nFor Administrator role permissions in Azure Active Directory please see https://docs.microsoft.com/azure/active-directory/users-groups-roles/directory-assign-admin-roles", + "displayName": "User added to Azure Active Directory Privileged Groups", + "enabled": false, + "query": "let OperationList = dynamic([\"Add member to role\",\"Add member to role in PIM requested (permanent)\"]);\nlet PrivilegedGroups = dynamic([\"UserAccountAdmins\",\"PrivilegedRoleAdmins\",\"TenantAdmins\"]);\nAuditLogs\n//| where LoggedByService =~ \"Core Directory\"\n| where Category =~ \"RoleManagement\"\n| where OperationName in~ (OperationList)\n| mv-apply TargetResource = TargetResources on \n (\n where TargetResource.type =~ \"User\"\n | extend TargetUserPrincipalName = tostring(TargetResource.userPrincipalName),\n modProps = TargetResource.modifiedProperties\n )\n| mv-apply Property = modProps on \n (\n where Property.displayName =~ \"Role.WellKnownObjectName\"\n | extend DisplayName = trim('\"',tostring(Property.displayName)),\n GroupName = trim('\"',tostring(Property.newValue))\n )\n| extend AppId = InitiatedBy.app.appId,\n InitiatedByDisplayName = case(isnotempty(InitiatedBy.app.displayName), InitiatedBy.app.displayName, isnotempty(InitiatedBy.user.displayName), InitiatedBy.user.displayName, \"not available\"),\n ServicePrincipalId = tostring(InitiatedBy.app.servicePrincipalId),\n ServicePrincipalName = tostring(InitiatedBy.app.servicePrincipalName),\n UserId = InitiatedBy.user.id,\n UserIPAddress = InitiatedBy.user.ipAddress,\n UserRoles = InitiatedBy.user.roles,\n UserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)\n| where GroupName in~ (PrivilegedGroups)\n// If you don't want to alert for operations from PIM, remove below filtering for MS-PIM.\n//| where InitiatedByDisplayName != \"MS-PIM\"\n| project TimeGenerated, AADOperationType, Category, OperationName, AADTenantId, AppId, InitiatedByDisplayName, ServicePrincipalId, ServicePrincipalName, DisplayName, GroupName, UserId, UserIPAddress, UserRoles, UserPrincipalName, TargetUserPrincipalName\n| extend AccountCustomEntity = case(isnotempty(ServicePrincipalName), ServicePrincipalName, \n isnotempty(UserPrincipalName), UserPrincipalName, \n \"\")\n| extend AccountName = tostring(split(AccountCustomEntity,'@',0)[0]), AccountUPNSuffix = tostring(split(AccountCustomEntity,'@',1)[0])\n| extend TargetName = tostring(split(TargetUserPrincipalName,'@',0)[0]), TargetUPNSuffix = tostring(split(TargetUserPrincipalName,'@',1)[0])\n", + "queryFrequency": "PT1H", + "queryPeriod": "PT1H", + "severity": "Medium", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "AuditLogs" + ] + } + ], + "tactics": [ + "Persistence", + "PrivilegeEscalation" + ], + "techniques": [ + "T1098", + "T1078" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "AccountName", + "identifier": "Name" + }, + { + "columnName": "AccountUPNSuffix", + "identifier": "UPNSuffix" + } + ], + "entityType": "Account" }, - "triggers": { - "Microsoft_Sentinel_alert": { - "inputs": { - "body": { - "callback_url": "@{listCallbackUrl()}" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['azuresentinel']['connectionId']" - } - }, - "path": "/subscribe" + { + "fieldMappings": [ + { + "columnName": "TargetName", + "identifier": "Name" }, - "type": "ApiConnectionWebhook" - } + { + "columnName": "TargetUPNSuffix", + "identifier": "UPNSuffix" + } + ], + "entityType": "Account" } + ] + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", + "apiVersion": "2022-01-01-preview", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId57'),'/'))))]", + "properties": { + "description": "Azure Active Directory Analytics Rule 57", + "parentId": "[variables('analyticRuleId57')]", + "contentId": "[variables('_analyticRulecontentId57')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion57')]", + "source": { + "kind": "Solution", + "name": "Azure Active Directory", + "sourceId": "[variables('_solutionId')]" }, - "parameters": { - "$connections": { - "value": { - "azuresentinel": { - "connectionId": "[[resourceId('Microsoft.Web/connections', variables('AzureSentinelConnectionName'))]", - "connectionName": "[[variables('AzureSentinelConnectionName')]", - "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", - "connectionProperties": { - "authentication": { - "type": "ManagedServiceIdentity" - } - } + "author": { + "name": "Microsoft", + "email": "[variables('_email')]" + }, + "support": { + "tier": "Microsoft", + "name": "Microsoft Corporation", + "email": "support@microsoft.com", + "link": "https://support.microsoft.com/" + } + } + } + ] + }, + "packageKind": "Solution", + "packageVersion": "[variables('_solutionVersion')]", + "packageName": "[variables('_solutionName')]", + "packageId": "[variables('_solutionId')]", + "contentSchemaVersion": "3.0.0", + "contentId": "[variables('_analyticRulecontentId57')]", + "contentKind": "AnalyticsRule", + "displayName": "User added to Azure Active Directory Privileged Groups", + "contentProductId": "[variables('_analyticRulecontentProductId57')]", + "id": "[variables('_analyticRulecontentProductId57')]", + "version": "[variables('analyticRuleVersion57')]" + } + }, + { + "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", + "apiVersion": "2023-04-01-preview", + "name": "[variables('analyticRuleTemplateSpecName58')]", + "location": "[parameters('workspace-location')]", + "dependsOn": [ + "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" + ], + "properties": { + "description": "UserAssignedPrivilegedRole_AnalyticalRules Analytics Rule with template version 3.0.5", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleVersion58')]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId58')]", + "apiVersion": "2022-04-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", + "properties": { + "description": "Identifies when a privileged role is assigned to a new user. Any account eligible for a role is now being given privileged access. If the assignment is unexpected or into a role that isn't the responsibility of the account holder, investigate.", + "displayName": "New User Assigned to Privileged Role", + "enabled": false, + "query": "// Define the start and end times based on input values\nlet starttime = now()-1d;\nlet endtime = now();\n// Set a lookback period of 14 days\nlet lookback = starttime - 14d;\n// Define a reusable function to query audit logs\nlet awsFunc = (start:datetime, end:datetime) {\n AuditLogs\n | where TimeGenerated between (start..end)\n | where Category =~ \"RoleManagement\"\n | where AADOperationType in (\"Assign\", \"AssignEligibleRole\")\n | where ActivityDisplayName has_any (\"Add eligible member to role\", \"Add member to role\")\n | mv-apply TargetResource = TargetResources on\n (\n where TargetResource.type in~ (\"User\", \"ServicePrincipal\")\n | extend Target = iff(TargetResource.type =~ \"ServicePrincipal\", tostring(TargetResource.displayName), tostring(TargetResource.userPrincipalName)),\n props = TargetResource.modifiedProperties\n )\n | mv-apply Property = props on\n (\n where Property.displayName =~ \"Role.DisplayName\"\n | extend RoleName = trim('\"', tostring(Property.newValue))\n )\n | where RoleName contains \"Admin\" and Result == \"success\"\n};\n// Query for audit events in the current day\nlet EventInfo_CurrentDay = awsFunc(starttime, endtime);\n// Query for audit events in the historical period (lookback)\nlet EventInfo_historical = awsFunc(lookback, starttime);\n// Find unseen events by performing a left anti-join\nlet EventInfo_Unseen = (EventInfo_CurrentDay\n | join kind=leftanti(EventInfo_historical) on Target, RoleName, OperationName\n);\n// Extend and clean up the results\nEventInfo_Unseen\n| extend InitiatingApp = tostring(InitiatedBy.app.displayName)\n| extend Initiator = iif(isnotempty(InitiatingApp), InitiatingApp, tostring(InitiatedBy.user.userPrincipalName))\n// You can uncomment the lines below to filter out PIM activations\n// | where Initiator != \"MS-PIM\"\n// | summarize StartTime=min(TimeGenerated), EndTime=min(TimeGenerated) by OperationName, RoleName, Target, Initiator, Result\n// Project specific columns and split them for further analysis\n| project TimeGenerated, OperationName, RoleName, Target, Initiator, Result\n| extend TargetName = tostring(split(Target, '@', 0)[0]),\n TargetUPNSuffix = tostring(split(Target, '@', 1)[0]),\n InitiatorName = tostring(split(Initiator, '@', 0)[0]),\n InitiatorUPNSuffix = tostring(split(Initiator, '@', 1)[0])\n", + "queryFrequency": "PT1H", + "queryPeriod": "P14D", + "severity": "High", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "AuditLogs" + ] + } + ], + "tactics": [ + "Persistence" + ], + "techniques": [ + "T1078" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "TargetName", + "identifier": "Name" }, - "office365": { - "connectionId": "[[resourceId('Microsoft.Web/connections', variables('Office365ConnectionName'))]", - "connectionName": "[[variables('Office365ConnectionName')]", - "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]" + { + "columnName": "TargetUPNSuffix", + "identifier": "UPNSuffix" + } + ], + "entityType": "Account" + }, + { + "fieldMappings": [ + { + "columnName": "InitiatorName", + "identifier": "Name" }, - "office365users": { - "connectionId": "[[resourceId('Microsoft.Web/connections', variables('Office365UsersConnectionName'))]", - "connectionName": "[[variables('Office365UsersConnectionName')]", - "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365users')]" + { + "columnName": "InitiatorUPNSuffix", + "identifier": "UPNSuffix" } - } + ], + "entityType": "Account" } - } + ] } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('Playbook-', last(split(variables('playbookId9'),'/'))))]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId58'),'/'))))]", "properties": { - "parentId": "[variables('playbookId9')]", - "contentId": "[variables('_playbookContentId9')]", - "kind": "Playbook", - "version": "[variables('playbookVersion9')]", + "description": "Azure Active Directory Analytics Rule 58", + "parentId": "[variables('analyticRuleId58')]", + "contentId": "[variables('_analyticRulecontentId58')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion58')]", "source": { "kind": "Solution", "name": "Azure Active Directory", @@ -12112,317 +11987,126 @@ } } } - ], - "metadata": { - "title": "Revoke-AADSignInSessions alert trigger", - "description": "This playbook will revoke all signin sessions for the user using Graph API. It will send an email to the user's manager.", - "prerequisites": [ - "1. You must create an app registration for graph api with appropriate permissions.", - "2. You will need to add the managed identity that is created by the logic app to the Password Administrator role in Azure AD." - ], - "comments": "This playbook will revoke all signin sessions for the user using Graph API using a Beta API. It will send and email to the user's manager.", - "lastUpdateTime": "2021-07-14T00:00:00Z", - "entities": [ - "Account" - ], - "tags": [ - "Remediation" - ], - "releaseNotes": { - "version": "1.0", - "title": "[variables('blanks')]", - "notes": [ - "Initial version" - ] - } - } + ] }, "packageKind": "Solution", "packageVersion": "[variables('_solutionVersion')]", "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_playbookContentId9')]", - "contentKind": "Playbook", - "displayName": "Revoke-AADSignInSessions-alert", - "contentProductId": "[variables('_playbookcontentProductId9')]", - "id": "[variables('_playbookcontentProductId9')]", - "version": "[variables('playbookVersion9')]" + "contentId": "[variables('_analyticRulecontentId58')]", + "contentKind": "AnalyticsRule", + "displayName": "New User Assigned to Privileged Role", + "contentProductId": "[variables('_analyticRulecontentProductId58')]", + "id": "[variables('_analyticRulecontentProductId58')]", + "version": "[variables('analyticRuleVersion58')]" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('playbookTemplateSpecName10')]", + "name": "[variables('analyticRuleTemplateSpecName59')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], - "properties": { - "description": "Revoke-AADSignInSessions-incident Playbook with template version 3.0.4", - "mainTemplate": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('playbookVersion10')]", - "parameters": { - "PlaybookName": { - "defaultValue": "Revoke-AADSignInSessions-incident", - "type": "string" - }, - "UserName": { - "defaultValue": "@", - "type": "string" - } - }, - "variables": { - "AzureSentinelConnectionName": "[[concat('azuresentinel-', parameters('PlaybookName'))]", - "Office365ConnectionName": "[[concat('office365-', parameters('PlaybookName'))]", - "Office365UsersConnectionName": "[[concat('office365users-', parameters('PlaybookName'))]", - "connection-1": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", - "_connection-1": "[[variables('connection-1')]", - "connection-2": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]", - "_connection-2": "[[variables('connection-2')]", - "connection-3": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365users')]", - "_connection-3": "[[variables('connection-3')]", - "workspace-location-inline": "[concat('[resourceGroup().locatio', 'n]')]", - "workspace-name": "[parameters('workspace')]", - "workspaceResourceId": "[[resourceId('microsoft.OperationalInsights/Workspaces', variables('workspace-name'))]" - }, - "resources": [ - { - "type": "Microsoft.Web/connections", - "apiVersion": "2016-06-01", - "name": "[[variables('AzureSentinelConnectionName')]", - "location": "[[variables('workspace-location-inline')]", - "kind": "V1", - "properties": { - "displayName": "[[parameters('PlaybookName')]", - "parameterValueType": "Alternative", - "api": { - "id": "[[variables('_connection-1')]" - } - } - }, - { - "type": "Microsoft.Web/connections", - "apiVersion": "2016-06-01", - "name": "[[variables('Office365ConnectionName')]", - "location": "[[variables('workspace-location-inline')]", - "properties": { - "displayName": "[[parameters('UserName')]", - "api": { - "id": "[[variables('_connection-2')]" - } - } - }, - { - "type": "Microsoft.Web/connections", - "apiVersion": "2016-06-01", - "name": "[[variables('Office365UsersConnectionName')]", - "location": "[[variables('workspace-location-inline')]", - "properties": { - "displayName": "[[parameters('UserName')]", - "api": { - "id": "[[variables('_connection-3')]" - } - } - }, - { - "type": "Microsoft.Logic/workflows", - "apiVersion": "2017-07-01", - "name": "[[parameters('PlaybookName')]", - "location": "[[variables('workspace-location-inline')]", - "tags": { - "LogicAppsCategory": "security", - "hidden-SentinelTemplateName": "Revoke-AADSigninSessions", - "hidden-SentinelTemplateVersion": "1.0", - "hidden-SentinelWorkspaceId": "[[variables('workspaceResourceId')]" - }, - "identity": { - "type": "SystemAssigned" - }, - "dependsOn": [ - "[[resourceId('Microsoft.Web/connections', variables('AzureSentinelConnectionName'))]", - "[[resourceId('Microsoft.Web/connections', variables('Office365ConnectionName'))]", - "[[resourceId('Microsoft.Web/connections', variables('Office365UsersConnectionName'))]" - ], - "properties": { - "state": "Enabled", - "definition": { - "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", - "actions": { - "Alert_-_Get_incident": { - "inputs": { - "host": { - "connection": { - "name": "@parameters('$connections')['azuresentinel']['connectionId']" - } - }, - "method": "get", - "path": "/Incidents/subscriptions/@{encodeURIComponent(triggerBody()?['WorkspaceSubscriptionId'])}/resourceGroups/@{encodeURIComponent(triggerBody()?['WorkspaceResourceGroup'])}/workspaces/@{encodeURIComponent(triggerBody()?['WorkspaceId'])}/alerts/@{encodeURIComponent(triggerBody()?['SystemAlertId'])}" - }, - "type": "ApiConnection" - }, - "Entities_-_Get_Accounts": { - "inputs": { - "body": "@triggerBody()?['Entities']", - "host": { - "connection": { - "name": "@parameters('$connections')['azuresentinel']['connectionId']" - } - }, - "method": "post", - "path": "/entities/account" - }, - "runAfter": { - "Alert_-_Get_incident": [ - "Succeeded" - ] - }, - "type": "ApiConnection" - }, - "For_each": { - "actions": { - "Add_comment_to_incident_(V3)": { - "inputs": { - "body": { - "incidentArmId": "@body('Alert_-_Get_incident')?['id']", - "message": "

User @{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])} singin sessions were revoked in AAD and their manager @{body('Get_manager_(V2)')?['displayName']} was contacted using playbook.

" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['azuresentinel']['connectionId']" - } - }, - "method": "post", - "path": "/Incidents/Comment" - }, - "runAfter": { - "Send_an_email_(V2)": [ - "Succeeded" - ] - }, - "type": "ApiConnection" - }, - "Get_manager_(V2)": { - "inputs": { - "host": { - "connection": { - "name": "@parameters('$connections')['office365users']['connectionId']" - } - }, - "method": "get", - "path": "/codeless/v1.0/users/@{encodeURIComponent(concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix']))}/manager" - }, - "runAfter": { - "HTTP": [ - "Succeeded" - ] - }, - "type": "ApiConnection" - }, - "HTTP": { - "inputs": { - "authentication": { - "audience": "https://graph.microsoft.com", - "type": "ManagedServiceIdentity" - }, - "method": "POST", - "uri": "https://graph.microsoft.com/v1.0/users/@{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])}/revokeSignInSessions" - }, - "type": "Http" - }, - "Send_an_email_(V2)": { - "inputs": { - "body": { - "Body": "

User, @{concat(items('For_each')?['Name'], '@', items('for_each')?['UPNSuffix'])}, was involved in part of a security incident.  As part of remediation, the user signin sessions have been revoked.  The user will need to reauthenticate in all applications.

", - "Subject": "User signin sessions were reset due to security incident.", - "To": "@body('Get_manager_(V2)')?['mail']" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['office365']['connectionId']" - } - }, - "method": "post", - "path": "/v2/Mail" - }, - "runAfter": { - "Get_manager_(V2)": [ - "Succeeded" - ] - }, - "type": "ApiConnection" - } + "properties": { + "description": "NewOnmicrosoftDomainAdded_AnalyticalRules Analytics Rule with template version 3.0.5", + "mainTemplate": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "[variables('analyticRuleVersion59')]", + "parameters": {}, + "variables": {}, + "resources": [ + { + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId59')]", + "apiVersion": "2022-04-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", + "properties": { + "description": "This detection looks for new onmicrosoft domains being added to a tenant. \nAn attacker who compromises a tenant may register a new onmicrosoft domain in order to masquerade as a service provider for launching phishing campaigns.\nDomain additions are not a common occurrence and users should validate that the domain was added by a legitimate user, with a legitimate purpose.", + "displayName": "New onmicrosoft domain added to tenant", + "enabled": false, + "query": "AuditLogs\n| where AADOperationType == \"Add\"\n| where Result == \"success\"\n| where OperationName in (\"Add verified domain\", \"Add unverified domain\")\n| extend InitiatedBy = parse_json(InitiatedBy)\n| extend InitiatingUser = tostring(InitiatedBy.user.userPrincipalName)\n| extend InitiatingIp = tostring(InitiatedBy.user.ipAddress)\n| extend InitiatingApp = tostring(InitiatedBy.app.displayName)\n| extend InitiatingSPID = tostring(InitiatedBy.app.servicePrincipalId)\n| extend DomainAdded = tostring(TargetResources[0].displayName)\n| where DomainAdded has \"onmicrosoft\"\n| extend ActionInitiatedBy = case(isnotempty(InitiatingUser), InitiatingUser, strcat(InitiatingApp, \" - \", InitiatingSPID))\n| extend UserName = split(InitiatingUser, \"@\")[0]\n| extend UPNSuffix = split(InitiatingUser, \"@\")[1]\n| project-reorder TimeGenerated, OperationName, DomainAdded, ActionInitiatedBy, InitiatingIp\n", + "queryFrequency": "PT1H", + "queryPeriod": "PT1H", + "severity": "Medium", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "AuditLogs" + ] + } + ], + "tactics": [ + "ResourceDevelopment" + ], + "techniques": [ + "T1585" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "UserName", + "identifier": "Name" }, - "foreach": "@body('Entities_-_Get_Accounts')?['Accounts']", - "runAfter": { - "Entities_-_Get_Accounts": [ - "Succeeded" - ] + { + "columnName": "UPNSuffix", + "identifier": "UPNSuffix" }, - "type": "Foreach" - } + { + "columnName": "InitiatingSPID", + "identifier": "AadUserId" + } + ], + "entityType": "Account" }, - "contentVersion": "1.0.0.0", - "parameters": { - "$connections": { - "type": "Object" - } + { + "fieldMappings": [ + { + "columnName": "InitiatingIp", + "identifier": "Address" + } + ], + "entityType": "IP" }, - "triggers": { - "Microsoft_Sentinel_alert": { - "inputs": { - "body": { - "callback_url": "@{listCallbackUrl()}" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['azuresentinel']['connectionId']" - } - }, - "path": "/subscribe" - }, - "type": "ApiConnectionWebhook" - } - } - }, - "parameters": { - "$connections": { - "value": { - "azuresentinel": { - "connectionId": "[[resourceId('Microsoft.Web/connections', variables('AzureSentinelConnectionName'))]", - "connectionName": "[[variables('AzureSentinelConnectionName')]", - "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/azuresentinel')]", - "connectionProperties": { - "authentication": { - "type": "ManagedServiceIdentity" - } - } - }, - "office365": { - "connectionId": "[[resourceId('Microsoft.Web/connections', variables('Office365ConnectionName'))]", - "connectionName": "[[variables('Office365ConnectionName')]", - "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365')]" - }, - "office365users": { - "connectionId": "[[resourceId('Microsoft.Web/connections', variables('Office365UsersConnectionName'))]", - "connectionName": "[[variables('Office365UsersConnectionName')]", - "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/office365users')]" + { + "fieldMappings": [ + { + "columnName": "DomainAdded", + "identifier": "DomainName" } - } + ], + "entityType": "DNS" } + ], + "eventGroupingSettings": { + "aggregationKind": "SingleAlert" + }, + "alertDetailsOverride": { + "alertDisplayNameFormat": "{{DomainAdded}} added to tenant by {{ActionInitiatedBy}}", + "alertDescriptionFormat": "This detection looks for new onmicrosoft domains being added to a tenant. An attacker who compromises a tenant may register a new onmicrosoft domain in order to masquerade as a service provider for launching phishing accounts. Domain additions are not a common occurrence and users should validate that {{ActionInitiatedBy}} added {{DomainAdded}} with a legitimate purpose." } } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('Playbook-', last(split(variables('playbookId10'),'/'))))]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId59'),'/'))))]", "properties": { - "parentId": "[variables('playbookId10')]", - "contentId": "[variables('_playbookContentId10')]", - "kind": "Playbook", - "version": "[variables('playbookVersion10')]", + "description": "Azure Active Directory Analytics Rule 59", + "parentId": "[variables('analyticRuleId59')]", + "contentId": "[variables('_analyticRulecontentId59')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion59')]", "source": { "kind": "Solution", "name": "Azure Active Directory", @@ -12440,204 +12124,151 @@ } } } - ], - "metadata": { - "title": "Revoke AAD SignIn Sessions - incident trigger", - "description": "This playbook will revoke all signin sessions for the user using Graph API. It will send an email to the user's manager.", - "prerequisites": "1. You will need to grant User.ReadWrite.All permissions to the managed identity.", - "lastUpdateTime": "2021-07-14T00:00:00Z", - "entities": [ - "Account" - ], - "tags": [ - "Remediation" - ], - "releaseNotes": { - "version": "1.0", - "title": "[variables('blanks')]", - "notes": [ - "Initial version" - ] - } - } + ] }, "packageKind": "Solution", "packageVersion": "[variables('_solutionVersion')]", "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_playbookContentId10')]", - "contentKind": "Playbook", - "displayName": "Revoke-AADSignInSessions-incident", - "contentProductId": "[variables('_playbookcontentProductId10')]", - "id": "[variables('_playbookcontentProductId10')]", - "version": "[variables('playbookVersion10')]" + "contentId": "[variables('_analyticRulecontentId59')]", + "contentKind": "AnalyticsRule", + "displayName": "New onmicrosoft domain added to tenant", + "contentProductId": "[variables('_analyticRulecontentProductId59')]", + "id": "[variables('_analyticRulecontentProductId59')]", + "version": "[variables('analyticRuleVersion59')]" } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/contentTemplates", "apiVersion": "2023-04-01-preview", - "name": "[variables('playbookTemplateSpecName11')]", + "name": "[variables('analyticRuleTemplateSpecName60')]", "location": "[parameters('workspace-location')]", "dependsOn": [ "[extensionResourceId(resourceId('Microsoft.OperationalInsights/workspaces', parameters('workspace')), 'Microsoft.SecurityInsights/contentPackages', variables('_solutionId'))]" ], "properties": { - "description": "Revoke-AADSignIn-Session-entityTrigger Playbook with template version 3.0.4", + "description": "SuspiciousSignInFollowedByMFAModification_AnalyticalRules Analytics Rule with template version 3.0.5", "mainTemplate": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "[variables('playbookVersion11')]", - "parameters": { - "PlaybookName": { - "defaultValue": "Revoke-AADSignIn-Session-entityTrigger", - "type": "string" - } - }, - "variables": { - "MicrosoftSentinelConnectionName": "[[concat('MicrosoftSentinel-', parameters('PlaybookName'))]", - "connection-2": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/Azuresentinel')]", - "_connection-2": "[[variables('connection-2')]", - "workspace-location-inline": "[concat('[resourceGroup().locatio', 'n]')]", - "workspace-name": "[parameters('workspace')]", - "workspaceResourceId": "[[resourceId('microsoft.OperationalInsights/Workspaces', variables('workspace-name'))]" - }, + "contentVersion": "[variables('analyticRuleVersion60')]", + "parameters": {}, + "variables": {}, "resources": [ { + "type": "Microsoft.SecurityInsights/AlertRuleTemplates", + "name": "[variables('analyticRulecontentId60')]", + "apiVersion": "2022-04-01-preview", + "kind": "Scheduled", + "location": "[parameters('workspace-location')]", "properties": { - "provisioningState": "Succeeded", - "state": "Enabled", - "definition": { - "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "$connections": { - "type": "Object" - } - }, - "triggers": { - "Microsoft_Sentinel_entity": { - "type": "ApiConnectionWebhook", - "inputs": { - "body": { - "callback_url": "@{listCallbackUrl()}" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" - } - }, - "path": "/entity/@{encodeURIComponent('Account')}" - } - } + "description": "This query looks uses Microsoft Sentinel's UEBA features to look for suspicious logons followed by modifications to MFA settings by that user.", + "displayName": "Suspicious Sign In Followed by MFA Modification", + "enabled": false, + "query": "let PriorityScore = 9;\nBehaviorAnalytics\n| where ActionType == \"Sign-in\"\n| where InvestigationPriority > PriorityScore\n| extend UserPrincipalName = tolower(UserPrincipalName)\n| extend LogOnTime = TimeGenerated\n| join kind=inner (AuditLogs\n| where Category =~ \"UserManagement\" \n| where OperationName in~ (\"Admin registered security info\", \"Admin updated security info\", \"Admin deleted security info\", \"User registered security info\", \"User changed default security info\", \"User deleted security info\",\"User registered all required security info\",\"User started security info registration\") \n| extend InitiatorUPN = tolower(tostring(InitiatedBy.user.userPrincipalName))\n| extend InitiatorID = tostring(InitiatedBy.user.id)\n| extend FromIP = tostring(InitiatedBy.user.ipAddress) \n| extend TargetUPN = tolower(tostring(TargetResources[0].userPrincipalName))\n| extend TargetId = tostring(TargetResources[0].id)\n| extend MFAModTime = TimeGenerated\n| where isnotempty(InitiatorUPN)) on $left.UserPrincipalName == $right.InitiatorUPN\n| where MFAModTime between((LogOnTime-30m)..(LogOnTime+1h))\n| extend InitiatorName = tostring(split(InitiatorUPN, \"@\")[0]), InitiatorSuffix = tostring(split(InitiatorUPN, \"@\")[1]), TargetName = tostring(split(TargetUPN, \"@\")[0]), TargetSuffix = tostring(split(TargetUPN, \"@\")[1])\n", + "queryFrequency": "P1D", + "queryPeriod": "P1D", + "severity": "Medium", + "suppressionDuration": "PT1H", + "suppressionEnabled": false, + "triggerOperator": "GreaterThan", + "triggerThreshold": 0, + "status": "Available", + "requiredDataConnectors": [ + { + "connectorId": "AzureActiveDirectory", + "dataTypes": [ + "AuditLogs" + ] }, - "actions": { - "Condition": { - "actions": { - "Add_comment_to_incident_(V3)_-_session_revoked": { - "type": "ApiConnection", - "inputs": { - "body": { - "incidentArmId": "@triggerBody()?['IncidentArmID']", - "message": "

Sign-in session revoked for the user - @{concat(triggerBody()?['Entity']?['properties']?['Name'], '@', triggerBody()?['Entity']?['properties']?['upnSuffix'])}

" - }, - "host": { - "connection": { - "name": "@parameters('$connections')['microsoftsentinel']['connectionId']" - } - }, - "method": "post", - "path": "/Incidents/Comment" - } - } + { + "connectorId": "BehaviorAnalytics", + "dataTypes": [ + "BehaviorAnalytics" + ] + } + ], + "tactics": [ + "InitialAccess", + "DefenseEvasion" + ], + "techniques": [ + "T1078", + "T1556" + ], + "entityMappings": [ + { + "fieldMappings": [ + { + "columnName": "InitiatorID", + "identifier": "AadUserId" }, - "runAfter": { - "HTTP_-_revoke_sign-in_session": [ - "Succeeded" - ] + { + "columnName": "InitiatorName", + "identifier": "Name" }, - "expression": { - "and": [ - { - "not": { - "equals": [ - "@triggerBody()?['IncidentArmID']", - "@null" - ] - } - } - ] + { + "columnName": "InitiatorSuffix", + "identifier": "UPNSuffix" + } + ], + "entityType": "Account" + }, + { + "fieldMappings": [ + { + "columnName": "TargetId", + "identifier": "AadUserId" }, - "type": "If" - }, - "HTTP_-_revoke_sign-in_session": { - "type": "Http", - "inputs": { - "authentication": { - "audience": "https://graph.microsoft.com", - "type": "ManagedServiceIdentity" - }, - "method": "POST", - "uri": "https://graph.microsoft.com/v1.0/users/@{concat(triggerBody()?['Entity']?['properties']?['Name'], '@', triggerBody()?['Entity']?['properties']?['upnSuffix'])}/revokeSignInSessions" + { + "columnName": "TargetName", + "identifier": "Name" + }, + { + "columnName": "TargetSuffix", + "identifier": "UPNSuffix" } - } - } - }, - "parameters": { - "$connections": { - "value": { - "microsoftsentinel": { - "connectionId": "[[resourceId('Microsoft.Web/connections', variables('MicrosoftSentinelConnectionName'))]", - "connectionName": "[[variables('MicrosoftSentinelConnectionName')]", - "id": "[[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Web/locations/', variables('workspace-location-inline'), '/managedApis/Azuresentinel')]", - "connectionProperties": { - "authentication": { - "type": "ManagedServiceIdentity" - } - } + ], + "entityType": "Account" + }, + { + "fieldMappings": [ + { + "columnName": "FromIP", + "identifier": "Address" } - } + ], + "entityType": "IP" + }, + { + "fieldMappings": [ + { + "columnName": "SourceIPAddress", + "identifier": "Address" + } + ], + "entityType": "IP" } - } - }, - "name": "[[parameters('PlaybookName')]", - "type": "Microsoft.Logic/workflows", - "location": "[[variables('workspace-location-inline')]", - "tags": { - "hidden-SentinelTemplateName": "Revoke-AADSignIn-Session-entityTrigger", - "hidden-SentinelTemplateVersion": "1.0", - "hidden-SentinelWorkspaceId": "[[variables('workspaceResourceId')]" - }, - "identity": { - "type": "SystemAssigned" - }, - "apiVersion": "2017-07-01", - "dependsOn": [ - "[[resourceId('Microsoft.Web/connections', variables('MicrosoftSentinelConnectionName'))]" - ] - }, - { - "type": "Microsoft.Web/connections", - "apiVersion": "2016-06-01", - "name": "[[variables('MicrosoftSentinelConnectionName')]", - "location": "[[variables('workspace-location-inline')]", - "kind": "V1", - "properties": { - "displayName": "[[variables('MicrosoftSentinelConnectionName')]", - "parameterValueType": "Alternative", - "api": { - "id": "[[variables('_connection-2')]" + ], + "eventGroupingSettings": { + "aggregationKind": "AlertPerResult" + }, + "alertDetailsOverride": { + "alertDisplayNameFormat": "Suspicious Sign In by {{InitiatorUPN}} Followed by MFA Modification to {{TargetUPN}}", + "alertDescriptionFormat": "This query looks uses Microsoft Sentinel's UEBA features to look for suspicious logons followed by modifications to MFA settings by that user.\nIn this case {{InitiatorUPN}} logged in followed by a modification to MFA settings for {{TargetUPN}}.\nThe sign in was from {{SourceIPAddress}}.\n" } } }, { "type": "Microsoft.OperationalInsights/workspaces/providers/metadata", "apiVersion": "2022-01-01-preview", - "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('Playbook-', last(split(variables('playbookId11'),'/'))))]", + "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/',concat('AnalyticsRule-', last(split(variables('analyticRuleId60'),'/'))))]", "properties": { - "parentId": "[variables('playbookId11')]", - "contentId": "[variables('_playbookContentId11')]", - "kind": "Playbook", - "version": "[variables('playbookVersion11')]", + "description": "Azure Active Directory Analytics Rule 60", + "parentId": "[variables('analyticRuleId60')]", + "contentId": "[variables('_analyticRulecontentId60')]", + "kind": "AnalyticsRule", + "version": "[variables('analyticRuleVersion60')]", "source": { "kind": "Solution", "name": "Azure Active Directory", @@ -12655,38 +12286,19 @@ } } } - ], - "metadata": { - "title": "Revoke AAD Sign-in session using entity trigger", - "description": "This playbook will revoke user's sign-in sessions and user will have to perform authentication again. It invalidates all the refresh tokens issued to applications for a user (as well as session cookies in a user's browser), by resetting the signInSessionsValidFromDateTime user property to the current date-time.", - "postDeployment": [ - "1. Add Microsoft Sentinel Responder role to the managed identity.", - "2. Assign User.ReadWrite.All and Directory.ReadWrite.All API permissions to the managed identity." - ], - "lastUpdateTime": "2022-12-22T00:00:00Z", - "entities": [ - "Account" - ], - "releaseNotes": { - "version": "1.0", - "title": "[variables('blanks')]", - "notes": [ - "Initial version" - ] - } - } + ] }, "packageKind": "Solution", "packageVersion": "[variables('_solutionVersion')]", "packageName": "[variables('_solutionName')]", "packageId": "[variables('_solutionId')]", "contentSchemaVersion": "3.0.0", - "contentId": "[variables('_playbookContentId11')]", - "contentKind": "Playbook", - "displayName": "Revoke-AADSignIn-Session-entityTrigger", - "contentProductId": "[variables('_playbookcontentProductId11')]", - "id": "[variables('_playbookcontentProductId11')]", - "version": "[variables('playbookVersion11')]" + "contentId": "[variables('_analyticRulecontentId60')]", + "contentKind": "AnalyticsRule", + "displayName": "Suspicious Sign In Followed by MFA Modification", + "contentProductId": "[variables('_analyticRulecontentProductId60')]", + "id": "[variables('_analyticRulecontentProductId60')]", + "version": "[variables('analyticRuleVersion60')]" } }, { @@ -12694,12 +12306,12 @@ "apiVersion": "2023-04-01-preview", "location": "[parameters('workspace-location')]", "properties": { - "version": "3.0.4", + "version": "3.0.5", "kind": "Solution", "contentSchemaVersion": "3.0.0", "displayName": "Azure Active Directory", "publisherDisplayName": "Microsoft Sentinel, Microsoft Corporation", - "descriptionHtml": "

Note: There may be known issues pertaining to this Solution, please refer to them before installing.

\n

The Azure Active Directory solution for Microsoft Sentinel enables you to ingest Azure Active Directory Audit, Sign-in, Provisioning, Risk Events and Risky User/Service Principal logs using Diagnostic Settings into Microsoft Sentinel.

\n

Data Connectors: 1, Workbooks: 2, Analytic Rules: 60, Playbooks: 11

\n

Learn more about Microsoft Sentinel | Learn more about Solutions

\n", + "descriptionHtml": "

Note: There may be known issues pertaining to this Solution, please refer to them before installing.

\n

The Azure Active Directory solution for Microsoft Sentinel enables you to ingest Azure Active Directory Audit, Sign-in, Provisioning, Risk Events and Risky User/Service Principal logs using Diagnostic Settings into Microsoft Sentinel.

\n

Workbooks: 2, Analytic Rules: 60, Playbooks: 11

\n

Learn more about Microsoft Sentinel | Learn more about Solutions

\n", "contentKind": "Solution", "contentProductId": "[variables('_solutioncontentProductId')]", "id": "[variables('_solutioncontentProductId')]", @@ -12725,9 +12337,59 @@ "operator": "AND", "criteria": [ { - "kind": "DataConnector", - "contentId": "[variables('_dataConnectorContentId1')]", - "version": "[variables('dataConnectorVersion1')]" + "kind": "Playbook", + "contentId": "[variables('_Block-AADUser-alert-trigger')]", + "version": "[variables('playbookVersion1')]" + }, + { + "kind": "Playbook", + "contentId": "[variables('_Block-AADUser-entity-trigger')]", + "version": "[variables('playbookVersion2')]" + }, + { + "kind": "Playbook", + "contentId": "[variables('_Block-AADUser-incident-trigger')]", + "version": "[variables('playbookVersion3')]" + }, + { + "kind": "Playbook", + "contentId": "[variables('_Prompt-User-alert-trigger')]", + "version": "[variables('playbookVersion4')]" + }, + { + "kind": "Playbook", + "contentId": "[variables('_Prompt-User-incident-trigger')]", + "version": "[variables('playbookVersion5')]" + }, + { + "kind": "Playbook", + "contentId": "[variables('_Reset-AADUserPassword-alert-trigger')]", + "version": "[variables('playbookVersion6')]" + }, + { + "kind": "Playbook", + "contentId": "[variables('_Reset-AADUserPassword-entity-trigger')]", + "version": "[variables('playbookVersion7')]" + }, + { + "kind": "Playbook", + "contentId": "[variables('_Reset-AADUserPassword-incident-trigger')]", + "version": "[variables('playbookVersion8')]" + }, + { + "kind": "Playbook", + "contentId": "[variables('_Revoke-AADSignInSessions-alert-trigger')]", + "version": "[variables('playbookVersion9')]" + }, + { + "kind": "Playbook", + "contentId": "[variables('_Revoke-AADSignInSessions-entity-trigger')]", + "version": "[variables('playbookVersion10')]" + }, + { + "kind": "Playbook", + "contentId": "[variables('_Revoke-AADSignInSessions-incident-trigger')]", + "version": "[variables('playbookVersion11')]" }, { "kind": "Workbook", @@ -13038,61 +12700,6 @@ "kind": "AnalyticsRule", "contentId": "[variables('analyticRulecontentId60')]", "version": "[variables('analyticRuleVersion60')]" - }, - { - "kind": "Playbook", - "contentId": "[variables('_Block-AADUser-alert-trigger')]", - "version": "[variables('playbookVersion1')]" - }, - { - "kind": "Playbook", - "contentId": "[variables('_Block-AADUser-incident-trigger')]", - "version": "[variables('playbookVersion2')]" - }, - { - "kind": "Playbook", - "contentId": "[variables('_Prompt-User-alert-trigger')]", - "version": "[variables('playbookVersion3')]" - }, - { - "kind": "Playbook", - "contentId": "[variables('_Prompt-User-incident-trigger')]", - "version": "[variables('playbookVersion4')]" - }, - { - "kind": "Playbook", - "contentId": "[variables('_Reset-AADUserPassword-alert-trigger')]", - "version": "[variables('playbookVersion5')]" - }, - { - "kind": "Playbook", - "contentId": "[variables('_Reset-AADUserPassword-incident-trigger')]", - "version": "[variables('playbookVersion6')]" - }, - { - "kind": "Playbook", - "contentId": "[variables('_Block-AADUser-entity-trigger')]", - "version": "[variables('playbookVersion7')]" - }, - { - "kind": "Playbook", - "contentId": "[variables('_Reset-AADUserPassword-entity-trigger')]", - "version": "[variables('playbookVersion8')]" - }, - { - "kind": "Playbook", - "contentId": "[variables('_Revoke-AADSignInSessions-alert-trigger')]", - "version": "[variables('playbookVersion9')]" - }, - { - "kind": "Playbook", - "contentId": "[variables('_Revoke-AADSignInSessions-incident-trigger')]", - "version": "[variables('playbookVersion10')]" - }, - { - "kind": "Playbook", - "contentId": "[variables('_Revoke-AADSignInSessions-entity-trigger')]", - "version": "[variables('playbookVersion11')]" } ] }, @@ -13111,4 +12718,4 @@ } ], "outputs": {} -} \ No newline at end of file +} From 29157478a4dd27c74924ed96f0d3eebd6c846af9 Mon Sep 17 00:00:00 2001 From: v-rbajaj Date: Thu, 19 Oct 2023 13:11:13 +0530 Subject: [PATCH 4/6] added release notes in create ui --- .../Azure Active Directory/Package/3.0.5.zip | Bin 83601 -> 83844 bytes .../Package/createUiDefinition.json | 2 +- .../Azure Active Directory/ReleaseNotes.md | 1 + 3 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Solutions/Azure Active Directory/Package/3.0.5.zip b/Solutions/Azure Active Directory/Package/3.0.5.zip index a26b39064a232a1725a87171ed47a9a41e05aa27..17c7a00cd921f4ae9462f02487f6785c5f80be70 100644 GIT binary patch delta 10452 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 K2I@uu0000m7b;%> delta 10221 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 diff --git a/Solutions/Azure Active Directory/Package/createUiDefinition.json b/Solutions/Azure Active Directory/Package/createUiDefinition.json index 5711d301db7..32c8a51d799 100644 --- a/Solutions/Azure Active Directory/Package/createUiDefinition.json +++ b/Solutions/Azure Active Directory/Package/createUiDefinition.json @@ -6,7 +6,7 @@ "config": { "isWizard": false, "basics": { - "description": "\n\n**Note:** _There may be [known issues](https://aka.ms/sentinelsolutionsknownissues) pertaining to this Solution, please refer to them before installing._\n\nThe [ Azure Active Directory](https://docs.microsoft.com/azure/active-directory/fundamentals/active-directory-whatis) solution for Microsoft Sentinel enables you to ingest Azure Active Directory [Audit](https://docs.microsoft.com/azure/active-directory/reports-monitoring/concept-audit-logs), [Sign-in](https://docs.microsoft.com/azure/active-directory/reports-monitoring/concept-sign-ins), [Provisioning](https://docs.microsoft.com/azure/active-directory/reports-monitoring/concept-provisioning-logs), [Risk Events and Risky User/Service Principal](https://docs.microsoft.com/azure/active-directory/identity-protection/howto-identity-protection-investigate-risk#risky-users) logs using Diagnostic Settings into Microsoft Sentinel.\n\n**Workbooks:** 2, **Analytic Rules:** 60, **Playbooks:** 11\n\n[Learn more about Microsoft Sentinel](https://aka.ms/azuresentinel) | [Learn more about Solutions](https://aka.ms/azuresentinelsolutionsdoc)", + "description": ""\n\n**Note:** Please refer to the following before installing the solution: \r \n • Review the solution [Release Notes](https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Azure%20Active%20Directory/ReleaseNotes.md)\r \n • There may be [known issues](https://aka.ms/sentinelsolutionsknownissues) pertaining to this Solution, please refer to them before installing._\n\nThe [ Azure Active Directory](https://docs.microsoft.com/azure/active-directory/fundamentals/active-directory-whatis) solution for Microsoft Sentinel enables you to ingest Azure Active Directory [Audit](https://docs.microsoft.com/azure/active-directory/reports-monitoring/concept-audit-logs), [Sign-in](https://docs.microsoft.com/azure/active-directory/reports-monitoring/concept-sign-ins), [Provisioning](https://docs.microsoft.com/azure/active-directory/reports-monitoring/concept-provisioning-logs), [Risk Events and Risky User/Service Principal](https://docs.microsoft.com/azure/active-directory/identity-protection/howto-identity-protection-investigate-risk#risky-users) logs using Diagnostic Settings into Microsoft Sentinel.\n\n**Data Connectors:** 1, **Workbooks:** 2, **Analytic Rules:** 60, **Playbooks:** 11\n\n[Learn more about Microsoft Sentinel](https://aka.ms/azuresentinel) | [Learn more about Solutions](https://aka.ms/azuresentinelsolutionsdoc)", "subscription": { "resourceProviders": [ "Microsoft.OperationsManagement/solutions", diff --git a/Solutions/Azure Active Directory/ReleaseNotes.md b/Solutions/Azure Active Directory/ReleaseNotes.md index 7ca68e32ca2..289c4c88429 100644 --- a/Solutions/Azure Active Directory/ReleaseNotes.md +++ b/Solutions/Azure Active Directory/ReleaseNotes.md @@ -1,5 +1,6 @@ | **Version** | **Date Modified (DD-MM-YYYY)** | **Change History** | |-------------|--------------------------------|----------------------------------------------------------------------------------------------------------------------------------------| +| 3.0.5 | 19-10-2023 | 1 **Analytic Rules** updated in the solution (PIMElevationRequestRejected) | | 3.0.4 | 16-10-2023 | 1 **Analytic Rules** got added in the solution (SuspiciousSignInFollowedByMFAModification), modified workbook query to fix duplicate locations for the query. | | 3.0.3 | 22-09-2023 | 2 **Analytic Rules** updated in the solution (PIM Elevation Request Rejected),(NRT Authentication Methods Changed for VIP Users) | | 3.0.2 | 08-08-2023 | 1 **Analytic Rules** updated in the solution (Credential added after admin consented to Application) | From b08d4161d2f81d188f4c75b440308b1fec9b7ffa Mon Sep 17 00:00:00 2001 From: v-rbajaj Date: Thu, 19 Oct 2023 13:13:28 +0530 Subject: [PATCH 5/6] create ui --- .../Azure Active Directory/Package/3.0.5.zip | Bin 83844 -> 83844 bytes .../Package/createUiDefinition.json | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/Solutions/Azure Active Directory/Package/3.0.5.zip b/Solutions/Azure Active Directory/Package/3.0.5.zip index 17c7a00cd921f4ae9462f02487f6785c5f80be70..ac6e25ba53a64a1fa7174c9ebfb6e907da4ea438 100644 GIT binary patch delta 10345 zcmV-vD3;fRj|GH}1s70D0|XQR000O8rD;=FUV_r57AOD!@sSrQ6?pE}cF^j!oy2+I zvV)GDWQ<8BhV7A6Gk@5|f9QB3GQRPcZA^?Q^y6O7KIvvW=VOtH+;sULRVli$%G^8M z+v)Ch_oAW{=Tcns4obm|cyn|pMlzR1s=WKEN{#$I>;6rv{HKi$%{Ae9l8O@NdL`ph zX*Dw4KEVzkxWVV5)Bp$v&rIfC7rf+|Ffa&4{E3g?VXX3z9Dg?t;E~jCWw?-LW*2YFKGe!i)wfgtVcR*#AbS z@KEL=?E$d>$=+L4ejFso+|$QjA2&jACXY*hr6g2`MPo~HN&-)ogtxYoyPP_jYJ{_lVOmz@xqXI`^+C&EI<$@KdzPYg?l%U3^4 z)zFjR)B)3W(0}gj^l9Pn!=Yb$&&@;AbhBi;LF;TH0Du3CPhlzS-N#&AiU{>Yx41Hm-|mB#S*DSM-l$whfCW5JFAN-PVWehEG@ z!M!w7oZY}Pn7%hr7e+-(-T)EKVT0uu^k-B8CVxNSf2I*?Ctw%EnN=FO{ZR68u3%^k z%wm99;El|IMHZQ;YgNl3H=G@)JSW67YMI>*yK|@3X82?epY(H{P7(4+1-yrk_jmC5 zamuIl$lYB8`|hRSWzI4bDLzz{Su+2ENE4;JTyL{~utg}fe!2SNS}DMOY;SY|-LI=* zsDJzevj8svfU3$^5U(ZH?7Ry{u+XTz1|`F3mRGeE?bS1fvtITgPmgkq>R$IQfZDp? zF<6bl&)(x;NDUGD3TQJRXdA8=3>HboG;#zsLvMrw-#5Q}4oQ}(m@g$4m}Z^;_sqXQ zFF+>1#b{lBkqPpp2hw2|f{le?(y&pfGJi5bz`r14mbo;mNil=n=b1%qpumC#^cMdT z)cuCOC{#`Vj9TF4HLK~5PKr-iGQO3 zBO)*j#y2)1nSl+OFp=ILdN(FNt=vjQJ~orB86s|NcX5T=ot^FX8?&VTJ6K+`j7cU6 zJ+qA$&(3B!6Z|_fp&3yVbF&o+Crl)h&SoGDHx;0tc_Aa`Sw7j@+1rVB9!5L6n}G1L z-K|ktwu=`x+`t2sfnn($mZ~@eH-BVibjpV!#o^1jp-AD$M5T#!nonte7-yGEJ;wzJ z%$T5?bRpA}rMT}ZPXm?+I6~i&CA2BQhcbF$Pf2h@@;gsq%V`5MUTj&0+_K`awK*#Q zo7>%U9NuAW+%|jiSB9Q7Orf`odI=Cq_YQU*Ot62pl>fG2z?L*3BRCK!Xn(QgxM=gw zfu;Fij$lGAJlSLg7Qmj!);ULFo@4fZ_ zH@Uc0c`Q}svy8O(8l>l?8!@|G5LCfd$;4~%jROjy&{srmxWsO36yQe8es`$yP$|!> zewgw^oJm6jxCBGsGc=M5W`A|wdMuD3GUAh2Fl(2J;Tep63Kr+%!Y8V*#(BYFAvm1F z%T?`wyMRE~WZD9U3;d~xNDFem$H2fiiqw$xwUDZY7Hh!$jv+oH`9kqq;)b#Q2zdUo zsI9}`acP`;7w#8RL0<~5guMs z3xycssfiUmI}ryH1AoJ7+Ughr?NTb;WrO^`LD*xSvy@oT#v>SjF;xcwU`_Hkt;pjo zxYj_(gb)~$p>48l9hL}+At^2d*Gs^+IMArVJ`)7n#-6+=^t@E#KcD9x%{_P@{(3uB z-TM}->aqmihFSOi`IuD)^lF7&J;0D-brnw-*Orxi#)S~^F@GBj5*e3(U6Oz^raiB+ zqvPfgQzJBorDfX=Lc9>*lEVK-@GV%shSe>n!vaNFs?r55rj+Bc058iXHQ^f!=)a!r zn_ueZSNr^RB)Z)B>Mwo$rOwyV$=KI9U&}GPt@Bl5_B}XXvw3ch8Y`<5J*^C4D9j~a z=SjsB*b?{I1b^x*B>fFNs)m~X^d40rFl!l^2~t}}aixvQetvt_&EgL-d2*~u*qx|e z=?79@AHw3$HS+xxk!`&>{%xBHN}YGvON>--D7WO&PJap$Zv=91g=(UKIRk)u_t*qX z2@13^JpPD&5Eg}M`SrjEFu;(6Nv8o>icFn54eN$p;PYI8Rm;K5uv~~lB;7%NB1Y^n zyOz(duH4lcX+P z(r2zfSyp-OE!*EK0Zye8uBt@Y0GFvsLGD(?*Q@2>yDjqYE0y3rCM;1II`AXV2X={= zzXO76S3hf=d+)A|d&#?^Ofi*~tWM-EiY+nDOn;^I`N1(rESr<-)zHRMg(;g$cGQEf z-xLXQpnJe8RK&)Eqgs#kt%$FmTZp8ApTo!E69+F2R5&rb!wwO3VSz_A7Z;0RRSk^! z((G3M@cHRBJHw3>$%)`;#?{k?0NuA%P?*| z@PBfVZ))0rvaiwvn;1%7iY_CczqG|J3mlf5c?LAR#EO`O*L!pF5^+ey7-FT2>|K({ zTw*pJRtrEU{9LLMFgjD#V1l~~hVNoBCDRCm2S@A=uUXJ=R(5M@{77YZ%o`Dae_xMA zNWZ)L_d7PO>>#Q~xv6saQ44XUN>TJRe1F_C5Sn6#!bB;vsADWXQH?-k5s2*f5dd&( z0lp*zg2ZfI6@iL_-E>+P)Q~7l^UkP`f`VFMjX$yhJ1*6yDgM`}Sfy<1)oFy!kB_&R zE<{{!>eWjt05FW!JqSS(b)i2L4xsL3I^xMl7e!Az7(NpG!QE*0(ZikS-re1Y(SM_T zz8@w0{{2Vy9`5h&-y6E6jjGZ`^ROG4Wgz&M(s?g2;CF2*xRl##@g?mJ)bAp4ps(%S zXyWm&53+Bi#qYJK#gBcKO&29FIwyaTaZJi%Lkw&)CY_G*mu;q;>V>RLkq2&w!15^U zD*6@095w6?PiuO(HV^g-h>)=!e1HFtfr$9TkoDTpX-UCvN8N~Hd@{yr@eI5Eic~ZX zP+iE^=>IoaA<*EU&QWcHCKJpGj&)5eCpHp?@`ELnIqt4U>Yl^hqW%mMM+Yhq^?=o~ z@ckB9xR2@`96*&RQUaWk7$*uS+%%T3eqfuAMVU#B^=-Xs z>mUPqOQoGzZ@lE8K;|6d>RraL$)*BLiU|?0poDI1)zDrq=qHmAIW-vJ1|@i&PC^1^v*f>uogWxOQ|u znC*OY$_%?CthJMvrLB0Hf`3F02`%RpEz*alU?!6(n{eyF0sA09`WhvDjv#$-vx3Dt zqIMbK6TG0Zza}4}C~%#&p0V()+qHmUn-SX5XUh7=N3i7n64WtiZKXjlX|za3NMl9D za$&TEN5n=F>#J#OmvrHsGwgA|-V#hkAjoqGUYB4($2@gzo`@&8gnu~eCIQtL`K}kN zHL6YSPl#O9)PJI2ROfn_ypX+`mk1Q*hoeknL-787#vJ7n8VNJP^WE;wUko4WCkS}8 zigCY9#h8Ovn5s$#g%HP3V4!A%j;drq#DPiThW}dEkNfM@k2daC=Rkl<3QeA1p2IPu zO6N*ED5QczEEK{RUhHcwbT9n`Q?@mxPFL>{U#{Tn4Rm&U~;o&I~hS zv!uuzDXck-1A+uvH}SIUlyvNsG{?9!@vy+j<=!%){3nSm2!GL>ZYCeOd*z_%*C`nm zh@DCAgNmr^oZzS4M7e)ywyarTlM6-}80*NWy8C2zwS51uO}<~QfsV0v?{q>XU?MW^ z6Xrep;5zx1zV<`1hil{iTjbVI1yixnmin)!Ao@5&L`%W>ku^D+K9cJqYG{4tglr&%7g zFXV>{Vd*yyMIWtApaX+Ovizk%Cf0<(G++IMawyB#q7DG0eF2VMCPQ9&Yr9sEp zynTS&8&3o@$sYpTZ0yal~2i7V=z? zq*}!67%WPG;PWxL@j!EI4Wo~fTE#itB6F({K!50RQLfnV?Y7zF^R%o$7lD5P%D6vU zU3ekQFV*myg>t*=>+osXZjfy_a!EOr_AvFh!VPX(JvZyBgLb)4Hbk05BchoP{_smY z_Lq0rk?Ryy<(TL44{NrhKf!u>`kK-NmpE>n`RLL&$J*UMjcvW~A)YhLU6Gl+shet> zHh)4Z+!Pi1!yNYP?Ff4|bcIJ4v7x)9IvfhCZDhr>`;Gj8?@M%8HIuj5&tsX~ZrEH2 zjkAMPRS7#jXrIBqi#DFHel`s0Fkd|5?5(Z*Vs*Tx3Z^0_ay&_~B^$Y_DUZ!{K=>jW zYW1Pzu-cf+jjiiuW8nRKrh2wwE^D*n=6`9GesuXTlGw#`SP)LMpBmU*U*FAqC=oYA zsM*CH_XsN`sCRv~jN`e^Sb*|uZUSI3%S0mKr*z6Bc9kKM7Ae}?#C_?qY0kNK{(9Z~ z93;}L-L8)=ghz47oRh{D`ME5WtsmXMb8aDLR$qqDxbG{LfHu1o`p#wmnTJy}n}4i6 zdCh&E%vL{T6F0Rl2;W8D0&h$xkmKo<X?gnYBmVdxD?MNPQM8|=mSS11`xq@yxtk+|wmD`o82#f=t zTf=+hz&#xJn{sUyBDr$#T^wBHRHR?AGHSE$u|WVu47Kx52Z&H2UHraq;SV-?JKAa6`CYe+&Sm4k(NnpL{w;l}GJh3}K$YQB ze>1dar9I_`zM@MIAQ(^?7(wyb@Lmn+B89+?2d5+`oYECGS4srjWY%oqJV|U~f#c;1 zIklY5Rq*gW5M&hBjca2mscpYlhd!P`2ZJgQj}VSvO)E;hco@1!Tz>#k>VVF;?0!-! z-MJ+HYplMqfTLg7Mij(jh<_eEo|6R9o;*Kb`w#9tVoo~Pz3x3k;`SOXfu*Oa=$-FH z3Rk%o#VHauLX>qxI~w67JBavq*6+DurPXFn$U&HPvWmI6=<0QtQ0SvXwy&<%*ZL8z z&ISio=}23exRNqP)#-j}!cPOSF>pG#@XW{kre0={be47ml^G!J6 zVB-x<`4@Xnm>z7-y$!c#aGQEq0cWqT`QZoU?D?Jfaaek<&8q#) zS^Bl#hZQUBz4aCLe=yd*Zijv#7H_jI{{<|*Dz&}0zQX;F%G*D%-fpuF-w%3;e18%A zm`IHUyShcb{o3f>cTtM>7lqxB3h)E+b5lZfu~^8AgZxm8uz&lR@{=0x*|o=B7l!(2 zZ6+d^7nu3(Y@Md<{M_;a$o-w2`wv(|ch1+TT$C(F2NbmCkOLm{8w$Kl$CGJjuLB5= zz^z&~+Uy=U#6`$qg&S0#`i@H;(=p|mXMCCP8`MqrzKaHeB%niaIUVK`6mvyW*Z+=* zXIDR+Z*{D4e}C2#+gn&(VWTTH$v7!(?zi+)0{bHhvxmg%O9aDXV2)|mB~^EUwEae) zaCcB%M9gg`v#Zwtndg-Ooq3&7LykS&&gghjtV*(9^x4rNT1rozuATBeOnH=_=WvKY1pgheRe4FY5V$OeSH>WGlW|q zh%l%R)E&6gqS6z*r#2zOM};0pMZPMB`3_Dy*>#53RU~Vji4e44@ zY}d;LV#wX~ZF4;VunAR8dtxnQV;bo)-{t31fc8-;Gif46G1m^XVxera*!#Thx1Kv^ z5uUMVUm(|4;$4h|=GN}w_-lPSBvLcb5~|Da;NEnmi+zySpn(mw%EZzp_xYQDj*k5S zZGUG+1U8;3KsV}R1i<%jN>Y)8 z2vc~oW7z=R{8fm8W%hD#%Is`5b2kSS?SFA2UY|7rG*@k&+bonnmnC-KTmFdW8`oxA z)Rs3D*-oxpgLL&CPr(*2d%I#lA8XccNLo|( z(*lv{?|9<1Am^gQj=EpPG;BB2TE)`c{`jxi%l1RIvi+-HT)5X}U&Rajb7?^?(|_mb z@qP@OJ7_*XAL+Ze7P zf{|T3Jg)GtIY{*<5&J)+gq>!f4~2=l*HkISgpez6gzdd`yU$Iwh%^#5x1nyuzu1Wo z=^RL@RIe(EK$iHjT+YtU%QMf^J_>1Nw!+}6Y+A5G;wj#e*~Ux=el?f# zrpqVxrn`eovF#@YZuTcs{v&J)uxsCSyd4DB2BQqS) ze>d+vmOE5%p(kU8_>apD__%({v}6ll>*Ci3My1`6;hJ4W-Na7(jBb^P=z&3c}OulqE(ApSPmMZ}v zC`x9E6;sETbC#{~k`H-%LVvGo-8@I@T9eNvg}D}MVvKg{H=~@+9EkflDCNwa`k@oe z33|6471#OPxM$6^BF1X>=M&F$57yU!w2w5sO4W(uQN? zh+&+jeY<`v4GaHr2QHaDTD=y@!eayR^Wl|Hh$1E@oo+g?}mSuWkD}3e$KC zP5SbFWOzpt-chl8`TaJsr;O=_75)31hF~Ut?5tsQUXAHzK_Vc_W!0Y?A(pgs3FVFX z&ZPAA&ENj&rs<22*qX;{!E<__w1&fLzV0A2TcG*=MI!flY3%Ge)w53TP3c&(G$TFs z@fxmuajYg!Q{~fXntx%-p56#hO+k55uq9?jTg2BuUgqLp{ysR^oVN zl;9?CHGiD=_6{qQS5*VF9-9OZcuJMXos@Eh8buRW2o3Tpi0A^;6d4*%+Eh5Y zxHkA+Ktz=@a~!YhjPq?dlOnqzuD)Mx$!6{vk0!zLGQKrlCOW>B4HJuW0bb>FxoN=< z3GjJG&-@h`qwuod9UQ2ej8MEj`@@tg+MYtQZ$1cOmwyu4rG)-OrgKOT+PjOZsKd5| z9RtxG$DO|GOIYsu5>~sugznLHeF=l<@{rg?=<-Ljg!$?8oFgPppw71f#`p!TU~F?_ zOo?RP@8a_M248p46K2D*7ZNQ8+57V$=3eX&b34S`&OQ3#!EE)G8WJ%FwYGIZo$f$$ z-6*YHP=9Bqwf^t5R!BG`wAT6Q+vs&_KFK6r0G3C_naz@hS4!Q1Alpp$8pKJwgs52i zUgJk@{bbzqpv;dZY#6;2(ao1+D=; zqEi7RmIgeJYULVWG2CwzZFo(D1T=MHgnxI3TG|=m{M(laTu401McgW4(E5k)Lbhel z6Kv$~_tuv%yx)tQ5C{TXTJ$JqoK#B+jn)LMe>f&spD{L5P_x0ppxFgASI%ITq_EUT zEn*eEVyhO^Moe#{mj*UTF_q_YX-A~RDY`C5P1|xF$o9R}8GSTOS#3Se0ayIOA%Dw* zy84tOmKIb(?+FS&U0QgF1X|r=0q?lZ!Jly$(zYDsC)JILJcE++T~ZT6=g+ye z1N9)EXglNvhA3SjtKjohG27k8yAO*~7PVEFPZyu#=X z+;AU`T(Y?dBjxbfK%OTf` zW@r}{Wkyy#uOSB=N7~p8CePBPwoR@b76mTN0J$)e8tHDgHY7}{LZ4D@RTqU<8C{OI zW_vOCOyF=@xz45~KP0X~8-5GTR`jx3*k(np#^Q}-I}I=K9it;^rVP!et$&KW&da!- zmo+S~bbwCdKA28uJ)mT<&Bj50IG^JhAjJ>WLR7wEac&e{(0-ROJ=T=0H3QC#1nL=! zERR6SC%HoPSme?qstGwI*aoF`%G3ksH}(QN;hIf`7nJ-vxP+;inRGNx^YLgF)26%_ zU4rcoPb~+1bMRbZS@gk0vwud%`hw}piwfbWV;&{#)`)-7j&51qWCl;QANjzIb+{zm zGK@C7u0kgEFB^_6$mIk?sbw_I?=3e$g?`vwM&EOIFbSLjf0z>;QlA5|OA@-uk6yW^ z_owGrIeGQrM%Rr;YA0x8oqXZ5aaUj!e?ums$#@T0XQ2AnyStlQ(|`JA(rA*|g!sAZ zYki_V9gjA*T(nXsoEOI1g9WauvRxP~)c^bF+kfZodj06&i1yx3iP#9k7U}I1uGkIB^ijyX{3HD^&%X~Y-bY)J zp*IM1&>P0aFmFwYc-+eer-hdQLf2OQot!s~Shs7r-U{IIc%RYc8c!w*xOZ*^fEvgN z|Ec(CbqfV|C7~+PYNpz@{fI&@v|aB<;KFW>NB8sAE%^et>3;&4`u7VDjMe;I=WPj`n26^0h`pGbEFK)|X!j=GheRpCB+B8eNR%(rS99`4vrxz{T_vX!* zO)JHaxRJ{iS+jL1_=HFk#@xhEa&N?+U**)UL^DFoOBk;NCt zjGZ}M=Co%sd4M`4VyowwT^dYngwv5tZ_aPD4`bb93xD@w((2|R%xzZ;_&3>kVJ|>9 zm2~{Qq1dME^ zs2eC(o_`%zWj;?*D0ZY>kQu2*DL#0Njyx$mJ^7ZV|JIaf!$R)+#4Nm|j#u<6hW4#l zuA0Qj;`U>l&4x)nqBUd6Vzh|wMyDA$$XRkjTiG`U&tKB$Vbjn@x(@w2O@5a@T{!B5 z{*fWk2a6z~k2c>qoKL13UREJdB%dL&gVZU{nSaiH_(j$ol;k1s;MWq_HD`_WJtqfA zPS2V@@c`^Cuy(vmCHK#A#UEvz%_KW5uNKU!MaN*tBC(K24aZ$Rn97oDny2@sHH)=l z7S5e`LMG`v9w({TUppSU4%3uJA<;74+Fvc#VY(*{bE$(Ee&KhAo4IOHRcON9J+tgu zmw)H)`VCxx@=^C2aa-lZ>U*9vJ5H&wm%^H$Yelu&J6&KS-nZVB7>yNeXT1%JQ%Ee# z>)*M~ELCcF^7N8Yqhj3DMuNA_R5_<_7MC|Bwej`v0@fX7=H=44&L1S*D<$++kuD`5 zO*3R9HDQ{Q#~AFsJ(uGIhzm?|-v)G3X@AJ$R`kpYYrh2?%B9|CdS#>`>g=?Pgt<-l zOZzveL<4qoIi80BZH!blHX3Ydwy}WsI$ymxbs)xPPXESPLQ4E*k!NX@O;`aRJU{q$ z^ez4W_fc^j16|IU!gxaO4IK;y-h&O;OdKrChboO1gYm(5z>nmRWupx*osfVLPJf0x zfa2B8Mz4;a3eS7g9a`k^cwXN}FYKI<1>x#P)oz*RaGW`!_UDD_?#Mvhf1h27ArUNF zQc`u)F_>jnQuUW9sX7V?Q~~>h>}DSByame-zgV^ckfQ6P4a3KhX<+cdEdhZTM#tIG z#hhth`M?^VJXqGqWsXotVZ(}`L1eW2u~m3v5#1Ee$0+>&*ShmJLn&Cc-h*&W7VjW?js)3sA! zdBMBN>Dra{74A4j97*R+?4$SGrV-Vh#RV*ucw&^>(V^=(B!9Nx;ihqw zU88g)n$r{UhwFGYk4faA+E3hzOeB;9HwB4A?p{2zbqKsQu!SS^X&TGoR_?BnfWy~v zJ?3oTsbI*l$Lxsn`x>9~zn@nNv@_fABKa;PYQhf-!4EklKg4t3LDlaQY6f2|-*pF> zSjoCnkZpIf$YNNZ6=FS4O@CZ+%AE6j+R@DO&^h;4G~ypKZ|e9w%%`LGWcWZV{{Pp@ zQ2mGdzLqO*CfqBSr}1)(2lr>u!_%z&xv0i(^oYjn?#&nGCs|n#6FUEu;*=%Kz4m4} zEicOEc_(>hyvgv_#@;w3#c`FCskwiI_etb^%gT*xtswpZA$&*xn}5PrC?Gll7KhVu zY+vhuBIJQnoA{HKbRgg5U4NNZ;9XKa)w2aqGul46&lx!DuaWw@kX_$I`gZo9S%pfnK?RD)z-20KYPPzq+ur#_dJaSTB!Lvb8kOY^=W8z|z3?SgWV% zb@&E7?m2F_R@;#P;Hb~KDTPk@sI1^V#pytd!O1|hnCh)}n zor2PHe-_X8C3mzxj*H~F*njrHly8oIwkJL74LN|*kMy`+^us?OV*A{ejzoXI%-i?gG(s4ODF-W9u1{wQ&(Ps(xw(D008lq H14jXY>Qr|3 delta 10345 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 H14jXYdrSic diff --git a/Solutions/Azure Active Directory/Package/createUiDefinition.json b/Solutions/Azure Active Directory/Package/createUiDefinition.json index 32c8a51d799..2bba4e602b8 100644 --- a/Solutions/Azure Active Directory/Package/createUiDefinition.json +++ b/Solutions/Azure Active Directory/Package/createUiDefinition.json @@ -6,7 +6,7 @@ "config": { "isWizard": false, "basics": { - "description": ""\n\n**Note:** Please refer to the following before installing the solution: \r \n • Review the solution [Release Notes](https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Azure%20Active%20Directory/ReleaseNotes.md)\r \n • There may be [known issues](https://aka.ms/sentinelsolutionsknownissues) pertaining to this Solution, please refer to them before installing._\n\nThe [ Azure Active Directory](https://docs.microsoft.com/azure/active-directory/fundamentals/active-directory-whatis) solution for Microsoft Sentinel enables you to ingest Azure Active Directory [Audit](https://docs.microsoft.com/azure/active-directory/reports-monitoring/concept-audit-logs), [Sign-in](https://docs.microsoft.com/azure/active-directory/reports-monitoring/concept-sign-ins), [Provisioning](https://docs.microsoft.com/azure/active-directory/reports-monitoring/concept-provisioning-logs), [Risk Events and Risky User/Service Principal](https://docs.microsoft.com/azure/active-directory/identity-protection/howto-identity-protection-investigate-risk#risky-users) logs using Diagnostic Settings into Microsoft Sentinel.\n\n**Data Connectors:** 1, **Workbooks:** 2, **Analytic Rules:** 60, **Playbooks:** 11\n\n[Learn more about Microsoft Sentinel](https://aka.ms/azuresentinel) | [Learn more about Solutions](https://aka.ms/azuresentinelsolutionsdoc)", + "description": "\n\n**Note:** Please refer to the following before installing the solution: \r \n • Review the solution [Release Notes](https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Azure%20Active%20Directory/ReleaseNotes.md)\r \n • There may be [known issues](https://aka.ms/sentinelsolutionsknownissues) pertaining to this Solution, please refer to them before installing._\n\nThe [ Azure Active Directory](https://docs.microsoft.com/azure/active-directory/fundamentals/active-directory-whatis) solution for Microsoft Sentinel enables you to ingest Azure Active Directory [Audit](https://docs.microsoft.com/azure/active-directory/reports-monitoring/concept-audit-logs), [Sign-in](https://docs.microsoft.com/azure/active-directory/reports-monitoring/concept-sign-ins), [Provisioning](https://docs.microsoft.com/azure/active-directory/reports-monitoring/concept-provisioning-logs), [Risk Events and Risky User/Service Principal](https://docs.microsoft.com/azure/active-directory/identity-protection/howto-identity-protection-investigate-risk#risky-users) logs using Diagnostic Settings into Microsoft Sentinel.\n\n**Data Connectors:** 1, **Workbooks:** 2, **Analytic Rules:** 60, **Playbooks:** 11\n\n[Learn more about Microsoft Sentinel](https://aka.ms/azuresentinel) | [Learn more about Solutions](https://aka.ms/azuresentinelsolutionsdoc)", "subscription": { "resourceProviders": [ "Microsoft.OperationsManagement/solutions", From 055add334b9c380cc53acdd3952aec50487f64f1 Mon Sep 17 00:00:00 2001 From: v-rbajaj Date: Thu, 19 Oct 2023 14:53:44 +0530 Subject: [PATCH 6/6] create ui --- .../Azure Active Directory/Package/3.0.5.zip | Bin 83844 -> 83843 bytes .../Package/createUiDefinition.json | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/Solutions/Azure Active Directory/Package/3.0.5.zip b/Solutions/Azure Active Directory/Package/3.0.5.zip index ac6e25ba53a64a1fa7174c9ebfb6e907da4ea438..7b398a8970369b32eb788ef9517856ebff8f879c 100644 GIT binary patch delta 9896 zcmV;ZCRf>nj|GE|1s70D0|XQR000O8Bz99*KDe*n6(|4z@Ua&p0)I$(K#09#v=(Mp z!s>N2C?zU}h1A@Rl%h@V*|vUmL|k>*RVEk&V9qoYiLz^f9b>47Z7qA(Fhm=SQX-tMq>r*fP} zGH-bfZK2W($E7-#sDCS9K+Dq<0qA-~CsKc8&(4A1nt?`R`1_Q-(a7VXJeRRx#{eak z1y8>OADQ4@nkmk1;2BKco2Uz;q9t#D2;?I%zh~O zI9D(<24*q9EbvC=z#@xG)U}%BkQ>epRGt%J8kNj$huyhTD}OV5vWHLlIZvku`J@8g z!^itO`20BK(|Y9YE`ojcQt&co8A=o%s>&>xe?g*&QeLdL*+1AKlv=%9{c)`mU_Z7u zI)Uof)iBikfmMK)06I?h}BUzDmU7Vzh2HlKZx8pQfy%(JbPr2a9D)}zGdkr%k>c>>+)$+OWTMi<`pl=aKa8_W zrk>-11ZGUoOS+J0%2M2Sm8Stq1RSAn$r9R>;D16Hy|AYwI3oF-r?BO;ff+BhEJJQt z@z~m&6@bm{?l}(cFgI?SJ^3p`#~P;4TSmPEh^2c6I}awOw+c02D8j%qkh!eEf za$L0e=fKi@u<>}XvDslbjK1oy&A~=zutAtCfBSh8K);{kQ{-(h+{vPj2r1U6q;Qa9 zw14+rdw`c*T&p~ms`6PzT6_)C^U{r&-7bi!V5?-}wfM#XMNsG~A~#%OH#Q1zBWAxl zRC%bBXI4Ks5E=2wESR-R#qbP9KLv~Pap4nHSmV54 zu@D^2;pM7!z+F6`Ycg$t!v+4-M5G0|-+yCZU>rqi$og7HRYQw4;C{yto{@Z^_$_h6 zSbqdOe_7DhVeq&#&b>Usn{~%X^tf?LY8kl z!FkX$t}5k5kleV`4fhUW&r}!$@YKfx5o~1{kvB6B{`2gEuOR2{%_(_m9sh+7YJY;b zSnrTga7Q7)!r;r~4gXn2?FD?7${h{8JqyrhSFnKv>tyi7qEKBD+zwH|D0o5nSQ08@ z@YVWXyXwKz?iB70k9@{ zoL1!V7F=r}WI_mx$s_~!C^N;2p zybpi99joqr3s!Ymf^WmDd;fgQssnnp!mb`*$g#SLCyZ;$%0A;li1?Td28oPIz%EI^ z8PlFu+0k+Hh^Y~p!_u;C2O(Yva7p3+Bls4qU&HE_(_w+4ELG`(7E{XcSbu<*WpkSF z4F>dI&-TqP_4BKJ{yGv}?tJx^zW!3@Yw2X{>zuFU7~aoUhq5w?~bYRf?Wg z1~C+-lCSfmVhU`D`)mSr7Lxvk9#uole|nE95ty}%%mk^eqqx#WWk0_?>t^u>nLIgG zCG1XAuk-_{uMc5u=oVd^Es9(b@=GM+1f|NN=|8xQiWoI%IBP?RIX7B2y ztj*q?0_T9uz|sU6jl$=_8RE#c-W>n7%><>+yX+-KDmau|a%m@pi8lf{xI#72z?=cV zy?bl|rUV7r7#@E_KL~3=wfuTu1Q=jQ!lcuHEJdcyorZNoFYtM;z<;XcU}jh@L?V*z zAU_c!_LyDE=T}#9w1`1q%rt5&D<$V6zv`bfvI7YJxk&uOuQqMBV*OSyx7-y!^`uyM+B$my|^=fG2slt@a zB|GZD*KdjhInX`e6)Ixm!BMTp`c}l(&n-mKz|Y}h@ri>M2Y)J@7~Wxrh`O-AqneA0 z#jvUd#(ZgZtAF_Xbeo;wMvCM_@HAs;_%|5e1U#Ig9h9XQW`o57s(=7apClsj-4%8{ zfTm>_w;p)8$Tu}@K-pJmf;|i+FGZJ;&tKYNmjw<>&O8GeUSdVe!t1>`d5JirVhpiT zM)oerWG*oq4}Yr#pc8&BRS6iKDQhsn-37yUF`1HS1j2(O_J`LjXgDjoH8p;uGCbyu z2*AIuM z`v?Fywg6ue0zqOnuZlp$!EQRO3u;Idrg>-7M?pcYuz$uM*?=9F>eCeeYgDXKw)N^X z!so}w+e{ZCt~d4Sr4;}eM(ZAgAc?xr9|{Lh_c9&vWTcCtCmswR3I5=2wEO7cPIT|? z?!)NOKHrZLe*gZXdk^>b_wNne(neM3qIuYj%rX%COX<9q81TC;6!=(MEZx1(;vF+Le%wRnb2 ze?=-92dFOOYxMt{tPp5$Q0J(&L6Zq)1;@H3mVXl)i9`9plFA%+*CTb$;ciiXhKZvC zm56%4YFYSxi!9tn^$rf8$`mO9PDzXt1r%-?OISa!&Bvn5q{jL-dr|UyF*)9ZG`35+@Xi_bIACuHCL<8!xdg9EFrj0fIyXB!7EHvrGr9eb6Si&IY`%sP9d)1ENbpL^$>;CSfjv);ecC zSQ}@CnXy??WR4WpoW=n`0T+ zp%O3=8TSeEo_%ngd`n;ZA=$&V@&7GyYp8;$*l0`r*HaLE93rBn;QYv%oK13zd_IEv zD{%hr9AdT(pd{g~J6(gBBaK~+mKMruOT!e#y# z%Zk%1kJ=aV!-cT)n}?#0)+W$_K_glI(jXIS!ed_+>R%FZg6^n;S+y*p^YP(j@mQ@~ z;ByoWl2jL^PwkC`v=>z$zkf`0d6lKRNK@|9Dj=;8%&pAdp)P# zRz3(Z8yj^9J!>NN_&=iT;T>ct$&`Ib=5(;TqqkN&7u*} z%m;t?B_8|ByX?qyimGzVbNPogThgCkJw1I*X@W}}x6XWY>6>HiZlK1tUic8t8Ro9Y z%-+;ZwM`qL6>f?O{b3G!_I89l8@j?HjM&g!QXLM3)i$!?(fvmL!1pCOteVN&?B}se zZZ~YMgvQxHs(-449UrvM;NL|XPgp-2hIE)Oo^kfpR(`QMUQ-2AkrO$dq}Y;;T-B7v z<~ksJ5e>Ea&~jL9Oyem+w@TQQfl*>UrrV~hM;mde(TZs0k$kTa_`eK3X(>ix}HSacw&p`SU40u z9o7GarPSRu_nO!sfFg$4`KJR!D3LCHU%2oG8@(OvwC((^TSn)yap35w+(rMEzEqhC zMxe^@slOT8v(ldOLtoJ)2oMaY42+=oY?rlK(YUUs=G>FKiA-39x*2!>|XaCB5`|-mcY_e zRrJpHB898mi{ccC8zIU%q8*L!k{v|+JAdovnS*rOgmY{++1|^I!q|^Q6k${ zSLWH|_o_~>> zbF({G*gik6uVLhe-*->Hv2nn&Z9?;_6I73ua!F#Q;&6>Q0=qu`g%UTe-^&Y z28H=1oN%!5hNk?By(df$HfVPHD)8dq#i|*+&EAIFGq_DXtbnuE*ZlBcj zy+pph2!2eY#)4hlBHw;(bnm+;#ruoGZb$|A0r|Npp}JTsWX3^$C`Q=*O!-NT_w3qZ zuM0!{v^EnF%nQtXceYN`c7ASo0p$M9&iw~0qC4m7R4z)EqXPyoOw zK-zvIP`EoNFCyl)liAg4fPc*M%7D(iPN^Zso^EG!JSkQs*)RI+=nyTXCr{T-c^{@c z%Fppezxq{&VTBD(V2Dozoy3^?Xg~M}K;{)5)b(VK8YxJWux01^;&*NE{4!FU$|$aG zbbn`eFNBGYk;y}R>Anx?C(ZE>^4NyaWrJ6(PulFoc=ic(zclRC^M5`&6#2A$eX+hi z3$hu)tq?>Q)CcMgTxwD23Eoqikl~|38#k_}*taj#CwzPdvJ==%-SD3~MikdQ#VhBA zHjCjSkgX54c>00EzeQn7h(Lq0Z(9K0TXO-tanu{#PkpkB6q&gpL5BA)P`TL_VP|UF z)W=Ij?E_oXUUH1Z{eOjruyhT2?%5}Iq8M+U9jZ^jz2}k>X3yT9;`ISk+^vs^BC{*$ zk+Gm)LM_Se;lnrgt#zJ#zcX9l+J{=ON8E6UBWq5FJI@85I$ZOERhFWD}X_Nc> z%|A!S{(!c#BLW*wm2u4%!-aNo=VJy}_?9TLcvm{il~jVEo#e~ifkuWuEMX8K85|OVeM;?^%d5apG0@50Dq(o+H!S~hxeyo3z)rKF`$n% z>o+8=srzYx$n281g*X(8cAzRu0)h{mGYqPK71^&6T zAeZU$^msppO>)n-O{pB1+}&9DEy@<_>!Yx==-0HEuUpI%4bI$QRL~3Hg(DBLbNs6p zpluA-5P!kQE*>6Nc-S1I`jd$LA5y|jGth^^#NBJE6k|fj6*$87-n!lACR;=r37gwc zx8h&yLb|v@%;^@KrV~*dg&0Z^>+9 zCIr8l%X!n~6MNI$K_*%S;}Y-mojUdfnSh7`_12$UA&3}(Rif7@1*2Kx8O7X2`~JL= zoRJxh=)ary9?KmnxX_a^L;S~O2Yg(=Wm>WYuyyh41EW^r!Bs(ae)@)G_eDtH#AQ{? z$$zkbF7aJ|i^wm?zfNQB8GVK#P%Q|*%JcL#32#Hb=nf?D5Sx+ChG<|Lym2O9x*TY2 zj4I2OfDjZVGsTLjygi}UwQioHb)Cs)lfqn!H8DoF^_x*nXAZ>u9F%fq zPyNt|<^;W4kBaMjZd^2G_2zmBOLPZcS%1<1;|fLKrPPYUq2)9>4W$@@h@~&lcln4# zq919)F>=H(PSd_!KbD4tf4KvfOdqXYjrT=;{E*(m#Q$AdVAOx(&>9;qZt5CbE!`9)X%o4oSpKhfBQ1!5fa0M9OH%gDEUJY zXrv;;>xZqtD{*YrFBDZZ0c(3typ|Y`E&cw5O zX#>j4!Kk_ZIb-=i43e|0-eKO){4zX{cc4Im>Z75a z=5s4?yfVsj7da1L$oLvge0zr#%B!jYT8~Wv2t1`q{wUqbh2yS{|Mba_bZB6Rs9TEhHvdVkIlk|$8-TLEMI zf>toLIWne1GVgbBd3}SgyXXnCVc83bmV@m5`4Dq2c8IwhVs7UieeqzndP@z7n1fo| zx}Z*Xpt)|8)-I^C(^~)cS}PF96FUk_5~TmIJUud}4K9o<6anVo^B&u?xM zY5ieHOe70%{kFIRob-{Vzs{->4QBDef{XECckoBwgIy6-Eg`j2fPG6tl{y(De>5MP zku{f5FS~9kdKeOd2BG63_BQgq9b@$*Qy}@_#c(^ZXns5xWq+Nj^j79$3&VOcqDFIe zSy?_J%o4e*zVfdcDMyyb*1^;axMh6Z)^8wddcYR6{J7yI6cUKFVWZ=4D*)`7Wu6 zq4Vcl+kb(2kWaK7asxw@u8>vm`Kp-hbAdLj6+$8#9PMB+U(h>k^^0`{@|Px_rA#n< zc@|z_bO&y@4@WN9+=TI4)^J-p8A9w+Fu~Z8mj!eM$vo3fYHwIK$(Ps5h*kz3N)|vt5 zMt=hJj7645Amx)>p?WNGX%f|hoDytd6dUW_im_J^mIgT6UX)G?2ec5B2xX-BuLZZdo1j8J>@K74IXsvIPJutni4LjH0of%9 zUFAowT+{p0bF7@a`f#J`#v`>8w6RXU@Y%R4u!_GS6VYV6hpaPDeeB)cO|EHuGifx* zY(o6p^|d}xpN>bHTP|8D6wV9d?Lh??3h4s!5NuLngcfz!&%wob7+nB7exk zkV*KLD~yyagZ2DrxI_=T%fz3kaq2(c8fH#*UTXNDDee~^fcfEdea726Wr$lUoVT<(k30LffW%?*&UjC7OnCIUI z7w@C3$j}>vI_M2!W0b&_aks&H^-ypjTCwbuR^2oxOhiyu?rP_9IMSs$5-UDkz z2y3kyLyOPEastx~${t!z8eRRU?-Y$cn#Mb&!w#O$ScTb(a@u0d_m&grm>1C`Ueb>K zE-%gZ(TR}nHs2z78AUSo1%o{9JpE)Cw->i%F=0ypzP>xL1Z|onUMsamJdUpE_0x-% z?R)cP%%+uMNZiO}i>%qY6o34_t?=-7F%4tJ$5Zi;LeD9;oE z?1ISR3uMO5oGx?Pvza_Vof5It^UN*{rZ&Rq$fh^vH`<4>?y-e?F==)45azZk2K<}s zys#G_oJuF3613qZA)JMn|3$o}PS5(|>D9v|%ClePR|~QpYR$ z6+`>hELTn9WO4g3&VOdZBp=b5F=a7Y#CN09j2z@FxuLD>n}g>sY4osZ=p$W+{+%Yj z%bzYBbwdBhkm!R&kkCh)?;Or2(+w}HkSLPR5ZOWMl;=!mKl~!=4odP6c<^h9?3%O2 z`ks@6B&TQ1pLhWF7Fau8rjq+-x#Ewq&SsLGmRAer)uLmtWPg!ZNTi12E+0%~NjA;X zd()c5+A#~~PCOx#bRLhBRP3)E4_$|8%A=5I8E@^cmg_Lx6NkCfK@7j}yTi>~wWumI z;qIPUcCE|vcl`#gK>4WqjkvAyV)Z>wnjNRq*h^te(6yr4?VT>L5${{?N{q&ewzJ-b z#VI5f=JoGfXMdI|H9UEGNvTmWZfYaJTW6}A(>IID80IXzlJ1of zdaFp65|E}DGLo7w&B5OsE1 zM#9`C{H6VyRH6Ypx*X5LfHp=d8ygKaHQQLgd!4V|oPRnH<1?p!<18U1ezVB4w8|!| zfDfJ@d^`G<{{Q=^xQ>A?=S*Qdq4$Ok1_STG25cq{7Un~h#*4xDU_9VQa>%mLhL=uA zzz8Qp9zgMGXQNlgPle|_>JBaPcs#G~qZf8g$bxY7qiVOzb2!c%QTy{kb$4W-?!V72 z#gGV=Eq^JgI_enAvMZ_j%al|dg#@aAeL{9K4|m>z<%eG^TLDPXb<&36W63ly_~4d+ zKn$bfZ0Taow6A>NjECSr?5Utz&`z=>Qkj4CSSfHdcP2N%JTjkk<~kH}Z5H2|FDm_3 zi|koxRrZ`7G*Pou7qr7)tlC8pvj6c=_xOdxW<7E3%a%I)aT^&Apg z@Nm<(%C1p563yv}_``KPo5v*bQ0*t~MJ5tTf}4UwB6lyI**XN?8rZ@S`ZSGYaVvLM zNq@lMYq=hCw(wLiYXf{?~ZD48O zd#u${^*Vfm9`_tKT&wL!0C3c2-G7uqCw){_aG&CIAjaTiAZguVU?2UTKVJ=J*S{u{ z9|R>ia1Z+{yGy^m;vo2srzd7L8QM}&%{Q=4MahR>^wIY6s+?D4W48A0^2Kd2kIB!o zbrX2v|4u>axj&2N`;t4_AIC*Z*?n_6a zzhCBW5YW`$hsmTzlCR&{+#9>P`@JCqrPu45->Nt*>>2p7Z*PBB-q0)HQn^nek2$7nIk zE``+#X>dwZ3@fSG9Z5yI-m}{t)%)HXRe8cu-hfXR-bNP_ZX}@JYziR7YB^$_=1k;# zmv&}8rWRU*xoU|Whpl}1OI0*O~8Ow$8lh(%!{jxZx&W4+yB?@r}7 zk7VBR9NI#q8IDVJE`L#3z<`#gDFV>-icX~d$ex`8!8HSw#_;zkd!v!bMR_h`!Hxk+ zEDN4~2|hBxy);vt-M}-LzBf@9Mny~B01?h%gXI|XXH)_vKjD9-5o#x37sQ!W8oB*Y z@^P+UXbj9^fLY*;%z;G~nW$@3%ON+M9jH7f#58J|-445Rr+?OF_+$^C^mCq05%Ng| zyoZnXckuaf%BS_n-CYFx?xo;m&N37!K2()iGXH`|6Q#UdZ?k`}MJTm?x%%T;DZqYg zZ*&6Pud89G`~$N9F9Cq6%2*JuCD!b`3rDcfsJ#Xy!)caRwH58vGl#QY_90J?a*gU< z_b!0iy5KQbjeo+=-s50M4H5eaXfq&a8?G1(7D>i5as)O*Z-fKiH@|!iNtUXZFC`b4 zW}X1|%)dY{KqkP&XkCAi3G$@}(qR{ZjfG*-uu-WpGC{zR%Tj=S^ubJ>u$fy`h^5>G^I*szfvkalemhFGqh(TnWAUJhSP>(8pz2F6SyW2 zdm`?MqX8o#Fb&2xHX@mU4Vo~K-XD55CO@s*N<}_4ldTydZf$pQh1;E-?e`nAr2act zUbBozCVvV&vyB(e&Sp6i{5vzD8Br5+vlR*_OeB-eW*`kW6`-GaAtUEmKH1yZ+lh7_ zMmxKkfbg>2tx;OGix)TCzyp4a`kRdYSlUXopmx|#TjD89h=i|aBs<6g+ z!D1meoWsji?SQ+0K-Xm20*4FysfkDna(}c1et;67PX`Fi(?iYb0&!fQ>qq^?K?9x7mzs{P`>j@9|EK;#$!qXf}UW6>) zc!KkwXK*)p;7?YuGvTYrf2!DzpDJ}%pOTf1{(5S*b69n7Fp1dgZyj0^qpXVRV zJ$N7fdOKF#`xdO~vIO6TS@-_=m{kY#YK2`rz>s5g6;Bw~mX&?Rg%I&E8w?T|mw;W8 zfHS5&ud<`#<`GjPG>4^S+YUm!5a5!+|3~mGSigqVEvLf*MOmuS1udqOMSJv4Lz!cn*a13RU$BJ8JP)ETSsxFjmmz0d)Ce34>Eaj ztV-COs9xy@QePj!;?Onn{eKnYZ`A{fV^F__Sfk!nL z7mHz44UGBH>{kEq`RO)0!;KWliQs9*)bMXGz6p3ZMLQ@!@+%piGVu!*+DYK|!EIv_aBKm-Bm{!QY+ekzT7O}UKe7QkF4dk!CMNd2!J`()F-DvmG!=32f z-Q9=LqkX;~CH(&VNB17?@9*Cmx}}Y((na&I8<}Mw_?OaoFEQYEZ7R5w+iUS9?GDuM zB66Uw?SI{9;_1PH08EYcwa&I$e}efa*vFYT5=POc*7}&0xSd%js0AVK;XC4G({ zeQ>ja#XF*Q8Q~MWpt8RvAEPL6owlB_@PDn_wSZxp5!%vc%KFDgu;l&{)G=vor9m)h zv`9xtV@1YtVYG!u#6}Y9t7&YPbm5&d>~X-}5==%Q$a4u^mtaE2JaulKh$p#(IO`?> z)foA%7pyg^P3}*KT-4NmqF_|#dYHVBy_%N@6y}GcOk_jw{(iHOTqb(H94E)7WsSx z_gCQj-#Nr=9Y9IKTX(z$Ge;V`8p(srgS1hQVZua3%nLr0X;Zlup9(?!YXdSSO^ECgCfB2O^MuR% zF_smlSst}7aQ{2#^|-l9VxnCJ2jYqq36!Fqc7n$iT9IBuQ!=+ZaG+TB2nZN2azo-@o{ zk(s@zn`)ajLMz-975c**_U!Eldp2~1M;Ni8yQDfC3af2o#k2d3{DJRFbXYZ$x7p8Q zncQyJTnUY{gMU<22|GS$pTWP2HlDD4HVo-7Up(XNt*!iGb-bnurXnYDJV~)78@Z|} zkIi*J_#zr=^`Ygk+L+9Zt?OoE;Qf52dbVONYqR6#X_bC-`7n~$#dKH@PPCsI*j-=W z&3q^kH$6PTbGnewRR8H64(sIyz+NUp14L4Yr zP-&IrjDODj*8N115>^20g3n{(HYNbaEWAMu?v4F$=54rb2oA+i11D>0?%KKxuP0B~ z?snJ=p&t+O+Y3`bvB+Z5!@>~8qhA8<25GF8z&7nj9&kj*fudL?0w%eFZab{kW2cqd zm8%Gh1D{*Nd*#4A9Qd1ZZ5ATAa`0UoT;)`xUw^SOYP0X;pcEvHJas*Zw(-Ok)3I$SzwewF0h)^P3{JwDE4>o!`+G*SQUAK(RW#honQ@M-&Eq$pn z6^uZY;ZuJzv}dI~<%hnaOAsI!P#G9O@!9ZR4e26Wu}Bq*HH6*gB&1l(lSY~egf zY=2^b7KVbV0?mc2oI@rDLJw)R68ZCjP zr>f|k??nn%xfjJL5;sDWbwoQF;UznW_UEe<=%Ylo zuddeD`Vp?q1_xH@NL!k?k}^is>3(3MtjfIr%6v$&fhwdj_UDmnX{!&PdvVn+ny@GQ z@N>{hL0ALA_IfU-nS4E**i=Dl=sBR~%D+gDtZPgKRn}0nc zH|J(|u&{l8USGq=56RE|Sl9Q>qiyzg+?+>`9PJNO3STRCD5f6kI-%NU;q~==eE%$b zn+*!{O*r9T;|)#u7kf{b9&FI;_Eq4;!HZQhc$>Wqw`XvhdRPHxudn&x2j%Sfo%wNC zdauo@{mohWwcm#oEA74Y750BH)_=ZkhkhUyZ?i7{1uVWQwY|5#!u^lR+dr`0ZnF;G z4|<7we-ZqcNR0)%x<$VI+UVYQQHu8$h24+}@B{L5Q$lsISjdcn{7{Ur`V) z$6gnP`e|(@BA6GL`R;6;rtSRP@&d^Hot^s+SVVWu*Qs2TEJp_vwC0cl9)I*33cO9n zlWAzL0|<}6ty(tP>>fD8MaW@=8&seAj!PcXG3AlhEDQ)hz^iu-+BMP&J#Oq50!((8MY1buH zcY(D1MxbzaP+mmLZ6~v<*M9(+=am7Sd7V;2jy>JZ=y+1BO0r+{+0h|dN>84yo$@|R zd6b{yjehm34#Nr?p1=^F3Ob1~_tAdv5rE7qJgDo*9yL;sC}GRa^~LYn;Q3{wIF(Uc z-RS<#?p_EJA0v~8_|knJ(odS>U*xe3qss=bTA#Gpi}CCe>V9e1tAFQxb|~^``}$&i zeHLUhgj*qqFsKjI9k|q@(i6O=HX*}Dg*I+nPqA-bs89I#4rC{=o4VmYcZ?{mdx}@i z4Q&>~M<81tZ1MC1hkuL0mJopkXWzB}zPIKAc;l!yx}W-F7b!AxLxK$NU!ZccEyB*! zwyBSoirNRZsJ-MEi+}qI4`JyV^xU&g?nE)(JUdjMfP2p+C(NF`J;mz-sJL4n6GdiM z(j#L*!Gv0p-NTE$*&rWI9pX*7K4jn!cjsLNi)k*Kn8iQ1?1}!WmMdlDn!4+$%4J|~ zEQSr~T2XA*%LQV{-SusAJpr%@RZe?iEo5UF=`!Et=Tm_8QGY5kX(C54*ABE|p=`6* z`@HVAo;zm|p0Q|OAlFyoU5th1*6!l?YkfK-QZvvJs>|@;-gKsmeUR6nfep3F#L_1B z`I~=^j{N~`XGa7!o+{&-FNO>4q z!1r)UQjvrRQ+Tsu*#O=ARfvLR_HuB_>})o3HwP8%aU))zH3BqOZJygKls}gxcHmq7 zi02#EW?R&jHx=1Vu3Uv*BYg_{SHs%ZBI_%xFF%RyQhxzR9kk`@A`kCR!4@!kyJA2e zYu0Z_T2uGa0+H$Oc;dAn=c2@px?jaKY&X`TG*4Ia2Y0FJazzatnWas!- zFF@NEu74qdkzG7IuJEuqNcATX`#+?Foo1j9g^9b@R4K-UkSlP6?Y(uo&rP<7G!izq zp>D;$*ohG6??pAL?f=`m+TON}B>Y!+28vjKUQ)*{4h4D#C(hw~NMgfw+YgtbpsZEQ zm?Bk?jH`ct^UTaHmz3-{&018iDvCgs__AEi&VSC!GtbmM3Tb7w!r-fHTChXnDc+LV z#!Lu)HJ9_I%P01xyMs)$3dSYg={t4o3o-!_2kNaqxk3;z0;@!?Q3^)0#xsh!jrRR{ zB{?HA9MOL_?>&|~RB)juV}|&T%MSRse#^9E3t;Qw*9S(e#DlAX?ELf%%kGPiz=_MM zn17RD0bSy|{uYs6kbj-V+%)4p{k`<#YgCV%X#VRT-N>1RPAAj@UdpMM-7 zmb7#U<&F8yr1bX9-~Q^R>5Guqn#XIwb9$e&hQn*V?jSTDiL#P2A^;#KSO0>yPSz< z_tFNGnS)Vt{dHUqu_DW?lkjRpOJaPT<{+Rd8&s)JN$P-c)fA}pG5}A|K#~pv#hiGh z=AKi9si2GJ;)h5J5q3nZ+4bY=m&ZZ}B=4wPp3+k0hkdC`mB%VSlIDb-pntbowSsWk zRul7L+bL~$J%+?hy>)yv9R5|px|?J!P0~=o%*mb1+@-d~npPqY!>`-!AXJ_tNz_L} zJx7ZocQ(*E0kAN1GFBS1Q2*imB^ixa)ug36Icih@+*kw0@M^4 z8c*6(IJ&qt_+CInl{0f3uYc=|^KChkBD*23zF%(1X6_n~Cc*MDzBOJZI=+?-6N_{K zUgdPTX~7Q(@Oeki{1q9a@Uq_>9H^U&P`p0-!;~x9os)^wuBu6(H_U0zUxa^?)nl|yS{|((RO_agX!{+*hT2_N3?|b>3{T`BP36t&bI=_ z_yw(CY;$BxiDcgI;_~_iUw6?HX2Y@<5-kVW`|}~@UhEKaJH*`1J^JFoZ1t8J5-|t0 zwsk?B?m%z`RUu}b!tAzBwhfPN5+}Wl7?4G-GLz6O!peZ zNxX!pSo>b%M{fOO+<)|-%#S8)7`+wI&@*v+KG!8o3%2~N*grWW16Y#x27f}1fpaBT!$?*y<*rg2N9q_RjyvrNoycfyNdupJM)RfUC*GyF?g`~W zbW7R=t^q!xQvoEF20V{ymB-D3go!DXg`zU9H6aTwCJ9OWm~jfy;jlJi|s z6GP|Exqr3;^&p>UJLCq2C|x0|;PX{6+vfspSSy4?HaObBV!ohv+UghU3gj29|+BuuJ8pHgmB z7ll_DU5>YAdolP-;BZ>G&ZZ?lB(6dmehbZ3^s-vmW<{>X;*DiH4KMK>qa$jj49%yl zioMRuxSp3aEUKThHk3h;NxkB|=9rmgsGaDbTm%$ z@n{y)ro0$kg6$7aEeCyb@LXb9^ua~5M#uVs>C1}>;izLCCGFOTf6|U_S>0p?PqiQU zz>RgdB;7KMHoUGvCiX8IjxEUL1VpK2G=I+TEjK}he%M_`-*b2{37i6dm=hgRp98W> z61vKdUb&|Cr{`EXdG+B&*NsPNCun1xeBrZkS6~%?Lnflhcn?`;p!(RmyPI6o`exE- zlG%j#x$A3vqCOpuHn&`~QYf4k#@mAmFci`S?0_%uDLC8zqJKq@ zhar>jFIN~TTL$a-({PC%c9)4iQRCEqzBSC8?7Y?z&LZKq?RK$*gk2SZ(;~*yC5sY^ z=-~N)BpA06Q2H>kT^KCX|NH3M=k9v_=-`O<-cO0x2*VcX?Gvup4a@XV$h`a`{V>nJ z4=&zETalqR2zAgK#>OyjO^SHj%YO%_g_i(A*H-?WoHvbFw`;lH3gGg1pV8(TPbLev zcWwoM8psL%srYGi3k7#2p(@g9rrNgsh(a&4UGGQW!fuX7_w&{*`2x7<0+{;u83Hh4 zZ1`neQ8I(P=o;14pQQs*Ve>9DEN{1ahpRo$F7v;3YnC~qo&@nHfNxY;T z{as#~@1qkT-)+7{@-m8K>%NAL)b$==NeOuw-?_#pLraTQL{T^O5c840dCmrreU)&VgFi@T; z1lR?U#TUqoojG0Rv}ZGUfI1~&tLK?r8cc13(~(VY&Tq62W8Gs5_hQoO<{`{&R}AL**6EzU()Dd)6hq{4*fe# zewRO8IO>G{ks;9siy)zoHs3j%Po^7QRv}R&pCPh?)G5!I&VKks)*Y1OA@JbW64^Cp zjrBbz2T4xPnm_RX>@Bc%yi6tc&vL~dWu46=J1wsk%&SGmV1LOXv5-g&$6Y>{%93oF zr}w5ci?w4G&YgHdCh0sLC#l$9J07|Y)09Uc(K6oJUoF>Rx+e~Ese>4P;dh6dxoS~W zXu{n+v+P=z=kNLrT!HdY_Zx9r<;CiIo-{j7sj-*BnxJb%wc9&gU?bkQ-jx`Q6>Vp| z4U1DqEX?cQxqr?qRcd(h^paAeV%*e5g1638Ij3(Hmp3N0@%8Wm)*WW%<pGec62$OhXHMjR5msmY-+Z#fcH9Iy?;4%AjW4-|HfHDO8jP#XK9s9 zSOFhAKlpa^E&c!ZQE?puUCx=pctYe zkbn_RhCG1c)y_t*j-Lw8d(<6TPOXXndfkvIimLGh3f9eK;3_z zU5X(QEPq>4QgzfZm}OT|^_MBBItmF?0sDmPW*+Xm1akMbYVJ&Kf_Y><>&$g1=GrX2GhbBt ztrpp{(yHt^J!qn4sV-=TzsS>xS@eCN1;klms^giA3&RJhOEOyfv_eBlKw+%i>n< zu78q%!`E^>=4|1qV92q@?1=OG8lUsOpH~aCGu!YY`7R`C!Ve3<4>=`2#B<<5)$bE( z245}TbqASP$+}dKZFjTCVpyLQVm(hyTyn~s^L*OT%=6GW_g6IHA2V<2_&m&~qxWR^ zKrH_M*UM1-hx@*kD{m&;E10M8a*PM}XMfSd)2#iusK#&fh{o*h%@^h;Sy>PhI{%g8 zlqJl)_GUOOFUsb5CwXSP$?(_4-Z&-2ag~&*xqpQBN#uRY%8hKTApQX%d`JMB!dECD zIsz7l({XHH>wqHUfm56Kla_QK-{oC@nOERlQa;tQ1yD2EKDo~sIP0&G`n!-_-+x5= zmuJTpy}J5}?1|%P$tFAB-@;?{JI`I1DN>1^wPUb%rP_Qe|jzcPHk zy0En5LoqNG*RGjLDchdZ7$0FJuIG$l>~!5%ITQa!|E|XEMbua?k5jU>G|+6UzS_Xj z!1q|Ir|Nb120iXMZn#$4kpSSR&wsipg--gYtl&Py=|GIZ$w1P&#lSxLKYzX&&aQt= zCO-&Da^N2JS9X_veZ@iWA5TxrYBIE?qMC1Dor;nVzv!dw\n\n**Note:** Please refer to the following before installing the solution: \r \n • Review the solution [Release Notes](https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Azure%20Active%20Directory/ReleaseNotes.md)\r \n • There may be [known issues](https://aka.ms/sentinelsolutionsknownissues) pertaining to this Solution, please refer to them before installing._\n\nThe [ Azure Active Directory](https://docs.microsoft.com/azure/active-directory/fundamentals/active-directory-whatis) solution for Microsoft Sentinel enables you to ingest Azure Active Directory [Audit](https://docs.microsoft.com/azure/active-directory/reports-monitoring/concept-audit-logs), [Sign-in](https://docs.microsoft.com/azure/active-directory/reports-monitoring/concept-sign-ins), [Provisioning](https://docs.microsoft.com/azure/active-directory/reports-monitoring/concept-provisioning-logs), [Risk Events and Risky User/Service Principal](https://docs.microsoft.com/azure/active-directory/identity-protection/howto-identity-protection-investigate-risk#risky-users) logs using Diagnostic Settings into Microsoft Sentinel.\n\n**Data Connectors:** 1, **Workbooks:** 2, **Analytic Rules:** 60, **Playbooks:** 11\n\n[Learn more about Microsoft Sentinel](https://aka.ms/azuresentinel) | [Learn more about Solutions](https://aka.ms/azuresentinelsolutionsdoc)", + "description": "\n\n**Note:** Please refer to the following before installing the solution: \r \n • Review the solution [Release Notes](https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Azure%20Active%20Directory/ReleaseNotes.md)\r \n • There may be [known issues](https://aka.ms/sentinelsolutionsknownissues) pertaining to this Solution, please refer to them before installing.\n\nThe [ Azure Active Directory](https://docs.microsoft.com/azure/active-directory/fundamentals/active-directory-whatis) solution for Microsoft Sentinel enables you to ingest Azure Active Directory [Audit](https://docs.microsoft.com/azure/active-directory/reports-monitoring/concept-audit-logs), [Sign-in](https://docs.microsoft.com/azure/active-directory/reports-monitoring/concept-sign-ins), [Provisioning](https://docs.microsoft.com/azure/active-directory/reports-monitoring/concept-provisioning-logs), [Risk Events and Risky User/Service Principal](https://docs.microsoft.com/azure/active-directory/identity-protection/howto-identity-protection-investigate-risk#risky-users) logs using Diagnostic Settings into Microsoft Sentinel.\n\n**Data Connectors:** 1, **Workbooks:** 2, **Analytic Rules:** 60, **Playbooks:** 11\n\n[Learn more about Microsoft Sentinel](https://aka.ms/azuresentinel) | [Learn more about Solutions](https://aka.ms/azuresentinelsolutionsdoc)", "subscription": { "resourceProviders": [ "Microsoft.OperationsManagement/solutions",