Subscription moved to another tenant
Id | 48c026d8-7f36-4a95-9568-6f1420d66e37 |
Rulename | Subscription moved to another tenant |
Description | This detection uses AzureActivity logs (Security category) to identify when a subscription is moved to another tenant. A threat actor may move a subscription into their own tenant to circumvent local resource deployment and logging policies. Once moved, threat actors may deploy resources and perform malicious activities such as crypto mining. This is a technique known as “subscription hijacking”. More information can be found here: https://techcommunity.microsoft.com/t5/microsoft-365-defender-blog/hunt-for-compromised-azure-subscriptions-using-microsoft/ba-p/3607121 |
Severity | Low |
Tactics | Impact |
Techniques | T1496 |
Required data connectors | AzureActivity |
Kind | Scheduled |
Query frequency | 5m |
Query period | 20m |
Trigger threshold | 0 |
Trigger operator | gt |
Source Uri | https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Azure Activity/Analytic Rules/SubscriptionMigration.yaml |
Version | 1.0.1 |
Arm template | 48c026d8-7f36-4a95-9568-6f1420d66e37.json |
let queryFrequency = 5m;
let eventCapture = "moved from tenant ([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}) to tenant ([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})";
AzureActivity
| where ingestion_time() > ago(queryFrequency)
| where CategoryValue =~ "Security"
| where OperationNameValue =~ "Microsoft.Subscription/updateTenant/action"
| extend Properties_d = coalesce(parse_json(Properties), Properties_d)
| where isnotempty(Properties_d)
| extend Summary = tostring(Properties_d.message)
| extend EventCapture = extract_all(eventCapture, Summary)
| extend SourceTenantId = iff(isnotempty(EventCapture), EventCapture[0][0], "")
| extend DestinationTenantId = iff(isnotempty(EventCapture), EventCapture[0][1], "")
| extend
Name = split(Caller, "@", 0)[0],
UPNSuffix = split(Caller, "@", 1)[0]
relevantTechniques:
- T1496
name: Subscription moved to another tenant
requiredDataConnectors:
- dataTypes:
- AzureActivity
connectorId: AzureActivity
entityMappings:
- fieldMappings:
- identifier: ResourceId
columnName: _ResourceId
entityType: AzureResource
- fieldMappings:
- identifier: FullName
columnName: Caller
- identifier: Name
columnName: Name
- identifier: UPNSuffix
columnName: UPNSuffix
entityType: Account
triggerThreshold: 0
id: 48c026d8-7f36-4a95-9568-6f1420d66e37
tactics:
- Impact
version: 1.0.1
customDetails:
SourceTenantId: SourceTenantId
DestinationTenantId: DestinationTenantId
queryPeriod: 20m
alertDetailsOverride:
alertDisplayNameFormat: |
Subscription {{SubscriptionId}} changed tenants
alertDescriptionFormat: |
The user {{Caller}} moved a subscription:
{{Summary}}
If this was not expected, it may indicate a subscription hijacking event.
triggerOperator: gt
kind: Scheduled
eventGroupingSettings:
aggregationKind: SingleAlert
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Azure Activity/Analytic Rules/SubscriptionMigration.yaml
queryFrequency: 5m
severity: Low
description: |
'This detection uses AzureActivity logs (Security category) to identify when a subscription is moved to another tenant.
A threat actor may move a subscription into their own tenant to circumvent local resource deployment and logging policies.
Once moved, threat actors may deploy resources and perform malicious activities such as crypto mining.
This is a technique known as "subscription hijacking". More information can be found here: https://techcommunity.microsoft.com/t5/microsoft-365-defender-blog/hunt-for-compromised-azure-subscriptions-using-microsoft/ba-p/3607121'
query: |
let queryFrequency = 5m;
let eventCapture = "moved from tenant ([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}) to tenant ([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})";
AzureActivity
| where ingestion_time() > ago(queryFrequency)
| where CategoryValue =~ "Security"
| where OperationNameValue =~ "Microsoft.Subscription/updateTenant/action"
| extend Properties_d = coalesce(parse_json(Properties), Properties_d)
| where isnotempty(Properties_d)
| extend Summary = tostring(Properties_d.message)
| extend EventCapture = extract_all(eventCapture, Summary)
| extend SourceTenantId = iff(isnotempty(EventCapture), EventCapture[0][0], "")
| extend DestinationTenantId = iff(isnotempty(EventCapture), EventCapture[0][1], "")
| extend
Name = split(Caller, "@", 0)[0],
UPNSuffix = split(Caller, "@", 1)[0]
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"workspace": {
"type": "String"
}
},
"resources": [
{
"apiVersion": "2024-01-01-preview",
"id": "[concat(resourceId('Microsoft.OperationalInsights/workspaces/providers', parameters('workspace'), 'Microsoft.SecurityInsights'),'/alertRules/48c026d8-7f36-4a95-9568-6f1420d66e37')]",
"kind": "Scheduled",
"name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/48c026d8-7f36-4a95-9568-6f1420d66e37')]",
"properties": {
"alertDetailsOverride": {
"alertDescriptionFormat": "The user {{Caller}} moved a subscription:\n\n{{Summary}}\n\nIf this was not expected, it may indicate a subscription hijacking event.\n",
"alertDisplayNameFormat": "Subscription {{SubscriptionId}} changed tenants\n"
},
"alertRuleTemplateName": "48c026d8-7f36-4a95-9568-6f1420d66e37",
"customDetails": {
"DestinationTenantId": "DestinationTenantId",
"SourceTenantId": "SourceTenantId"
},
"description": "'This detection uses AzureActivity logs (Security category) to identify when a subscription is moved to another tenant.\nA threat actor may move a subscription into their own tenant to circumvent local resource deployment and logging policies.\nOnce moved, threat actors may deploy resources and perform malicious activities such as crypto mining.\nThis is a technique known as \"subscription hijacking\". More information can be found here: https://techcommunity.microsoft.com/t5/microsoft-365-defender-blog/hunt-for-compromised-azure-subscriptions-using-microsoft/ba-p/3607121'\n",
"displayName": "Subscription moved to another tenant",
"enabled": true,
"entityMappings": [
{
"entityType": "AzureResource",
"fieldMappings": [
{
"columnName": "_ResourceId",
"identifier": "ResourceId"
}
]
},
{
"entityType": "Account",
"fieldMappings": [
{
"columnName": "Caller",
"identifier": "FullName"
},
{
"columnName": "Name",
"identifier": "Name"
},
{
"columnName": "UPNSuffix",
"identifier": "UPNSuffix"
}
]
}
],
"eventGroupingSettings": {
"aggregationKind": "SingleAlert"
},
"OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Azure Activity/Analytic Rules/SubscriptionMigration.yaml",
"query": "let queryFrequency = 5m;\nlet eventCapture = \"moved from tenant ([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}) to tenant ([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\";\nAzureActivity\n| where ingestion_time() > ago(queryFrequency)\n| where CategoryValue =~ \"Security\"\n| where OperationNameValue =~ \"Microsoft.Subscription/updateTenant/action\"\n| extend Properties_d = coalesce(parse_json(Properties), Properties_d)\n| where isnotempty(Properties_d)\n| extend Summary = tostring(Properties_d.message)\n| extend EventCapture = extract_all(eventCapture, Summary)\n| extend SourceTenantId = iff(isnotempty(EventCapture), EventCapture[0][0], \"\")\n| extend DestinationTenantId = iff(isnotempty(EventCapture), EventCapture[0][1], \"\")\n| extend \n Name = split(Caller, \"@\", 0)[0],\n UPNSuffix = split(Caller, \"@\", 1)[0]\n",
"queryFrequency": "PT5M",
"queryPeriod": "PT20M",
"severity": "Low",
"subTechniques": [],
"suppressionDuration": "PT1H",
"suppressionEnabled": false,
"tactics": [
"Impact"
],
"techniques": [
"T1496"
],
"templateVersion": "1.0.1",
"triggerOperator": "GreaterThan",
"triggerThreshold": 0
},
"type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
}
]
}