cloudflare/Azure-Sentinel
Publicmirrored fromhttps://github.com/cloudflare/Azure-Sentinel
Detections/SigninLogs/AzurePortalSigninfromanotherAzureTenant.yaml
52lines · modecode
unknown
| 1 | id: 87210ca1-49a4-4a7d-bb4a-4988752f978c |
| 2 | name: Azure Portal Signin from another Azure Tenant |
| 3 | description: | |
| 4 | 'This query looks for sign in attempts to the Azure Portal where the user who is signing in from another Azure tenant, |
| 5 | and the IP address the login attempt is from is an Azure IP. A threat actor who compromises an Azure tenant may look |
| 6 | to pivot to other tenants leveraging cross-tenant delegated access in this manner.' |
| 7 | severity: Medium |
| 8 | requiredDataConnectors: |
| 9 | - connectorId: AzureActiveDirectory |
| 10 | dataTypes: |
| 11 | - SigninLogs |
| 12 | queryFrequency: 1h |
| 13 | queryPeriod: 1h |
| 14 | triggerOperator: gt |
| 15 | triggerThreshold: 0 |
| 16 | tactics: |
| 17 | - InitialAccess |
| 18 | relevantTechniques: |
| 19 | - T1199 |
| 20 | query: | |
| 21 | // Get details of current Azure Ranges (note this URL updates regularly so will need to be manually updated over time) |
| 22 | // You may find the name of the new JSON here: https://www.microsoft.com/download/details.aspx?id=56519 |
| 23 | // On the downloads page, click the 'details' button, and then replace just the filename in the URL below |
| 24 | let azure_ranges = externaldata(changeNumber: string, cloud: string, values: dynamic) |
| 25 | ["https://download.microsoft.com/download/7/1/D/71D86715-5596-4529-9B13-DA13A5DE5B63/ServiceTags_Public_20220321.json"] |
| 26 | with(format='multijson') |
| 27 | | mv-expand values |
| 28 | | mv-expand values.properties.addressPrefixes |
| 29 | | mv-expand values_properties_addressPrefixes |
| 30 | | summarize by tostring(values_properties_addressPrefixes); |
| 31 | SigninLogs |
| 32 | // Limiting to Azure Portal really reduces false positives and helps focus on potential admin activity |
| 33 | | where AppDisplayName =~ "Azure Portal" |
| 34 | // Only get logons where the IP address is in an Azure range |
| 35 | | evaluate ipv4_lookup(azure_ranges, IPAddress, values_properties_addressPrefixes) |
| 36 | // Limit to where the user is external to the tenant |
| 37 | | where HomeTenantId != ResourceTenantId |
| 38 | // 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) |
| 39 | | where ResourceTenantId == AADTenantId |
| 40 | | summarize FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated), make_set(ResourceDisplayName) by UserPrincipalName, IPAddress, UserAgent, Location, HomeTenantId, ResourceTenantId |
| 41 | | extend AccountCustomEntity = UserPrincipalName, IPCustomEntity = IPAddress |
| 42 | entityMappings: |
| 43 | - entityType: Account |
| 44 | fieldMappings: |
| 45 | - identifier: FullName |
| 46 | columnName: AccountCustomEntity |
| 47 | - entityType: IP |
| 48 | fieldMappings: |
| 49 | - identifier: Address |
| 50 | columnName: IPCustomEntity |
| 51 | version: 1.1.0 |
| 52 | kind: Scheduled |