Microsoft Sentinel Analytic Rules
cloudbrothers.infoAzure Sentinel RepoToggle Dark/Light/Auto modeToggle Dark/Light/Auto modeToggle Dark/Light/Auto modeBack to homepage

Subscription moved to another tenant

Back
Id48c026d8-7f36-4a95-9568-6f1420d66e37
RulenameSubscription moved to another tenant
DescriptionThis 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
SeverityLow
TacticsImpact
TechniquesT1496
Required data connectorsAzureActivity
KindScheduled
Query frequency5m
Query period20m
Trigger threshold0
Trigger operatorgt
Source Urihttps://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Azure Activity/Analytic Rules/SubscriptionMigration.yaml
Version1.0.1
Arm template48c026d8-7f36-4a95-9568-6f1420d66e37.json
Deploy To Azure
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]
severity: Low
id: 48c026d8-7f36-4a95-9568-6f1420d66e37
customDetails:
  SourceTenantId: SourceTenantId
  DestinationTenantId: DestinationTenantId
queryFrequency: 5m
queryPeriod: 20m
relevantTechniques:
- T1496
triggerOperator: gt
tactics:
- Impact
kind: Scheduled
alertDetailsOverride:
  alertDescriptionFormat: |
    The user {{Caller}} moved a subscription:

    {{Summary}}

    If this was not expected, it may indicate a subscription hijacking event.    
  alertDisplayNameFormat: |
        Subscription {{SubscriptionId}} changed tenants
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'  
eventGroupingSettings:
  aggregationKind: SingleAlert
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Azure Activity/Analytic Rules/SubscriptionMigration.yaml
requiredDataConnectors:
- dataTypes:
  - AzureActivity
  connectorId: AzureActivity
entityMappings:
- entityType: AzureResource
  fieldMappings:
  - columnName: _ResourceId
    identifier: ResourceId
- entityType: Account
  fieldMappings:
  - columnName: Caller
    identifier: FullName
  - columnName: Name
    identifier: Name
  - columnName: UPNSuffix
    identifier: UPNSuffix
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]  
version: 1.0.1
name: Subscription moved to another tenant
triggerThreshold: 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"
    }
  ]
}