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

Suspicious number of resource creation or deployment activities

Back
Id361dd1e3-1c11-491e-82a3-bb2e44ac36ba
RulenameSuspicious number of resource creation or deployment activities
DescriptionIndicates when an anomalous number of VM creations or deployment activities occur in Azure via the AzureActivity log.

The anomaly detection identifies activities that have occurred both since the start of the day 1 day ago and the start of the day 7 days ago.

The start of the day is considered 12am UTC time.
SeverityMedium
TacticsImpact
TechniquesT1496
Required data connectorsAzureActivity
KindScheduled
Query frequency1d
Query period7d
Trigger threshold0
Trigger operatorgt
Source Urihttps://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Azure Activity/Analytic Rules/Creating_Anomalous_Number_Of_Resources_detection.yaml
Version2.0.1
Arm template361dd1e3-1c11-491e-82a3-bb2e44ac36ba.json
Deploy To Azure
let szOperationNames = dynamic(["microsoft.compute/virtualMachines/write", "microsoft.resources/deployments/write"]);
let starttime = 7d;
let endtime = 1d;
AzureActivity
| where TimeGenerated between (startofday(ago(starttime)) .. startofday(ago(endtime)))
| where OperationNameValue  in~ (szOperationNames)
| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), ActivityTimeStamp = makelist(TimeGenerated), ActivityStatusValue = makelist(ActivityStatusValue),
OperationIds = makelist(OperationId), CallerIpAddress = makelist(CallerIpAddress), CorrelationId = makelist(CorrelationId)
by ResourceId, Caller, OperationNameValue, Resource, ResourceGroup
| mvexpand CallerIpAddress
| where isnotempty(CallerIpAddress)
| make-series dResourceCount=dcount(ResourceId)  default=0 on StartTimeUtc in range(startofday(ago(7d)), now(), 1d)
by Caller, tostring(ActivityTimeStamp), tostring(ActivityStatusValue), tostring(OperationIds), tostring(CallerIpAddress), tostring(CorrelationId), ResourceId, OperationNameValue , Resource, ResourceGroup
| extend (RSquare,Slope,Variance,RVariance,Interception,LineFit)=series_fit_line(dResourceCount)
| where Slope > 0.2
| join kind=leftsemi (
// Last day's activity is anomalous
AzureActivity
| where TimeGenerated >= startofday(ago(endtime))
| where OperationNameValue in~ (szOperationNames)
| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), ActivityTimeStamp = makelist(TimeGenerated), ActivityStatusValue = makelist(ActivityStatusValue),
OperationIds = makelist(OperationId), CallerIpAddress = makelist(CallerIpAddress), CorrelationId = makelist(CorrelationId)
by ResourceId, Caller, OperationNameValue, Resource, ResourceGroup
| mvexpand CallerIpAddress
| where isnotempty(CallerIpAddress)
| make-series dResourceCount=dcount(ResourceId)  default=0 on StartTimeUtc in range(startofday(ago(1d)), now(), 1d)
by Caller, tostring(ActivityTimeStamp), tostring(ActivityStatusValue), tostring(OperationIds), tostring(CallerIpAddress), tostring(CorrelationId), ResourceId, OperationNameValue , Resource, ResourceGroup
| extend (RSquare,Slope,Variance,RVariance,Interception,LineFit)=series_fit_line(dResourceCount)
| where Slope > 0.2
) on Caller, CallerIpAddress
| mvexpand todynamic(ActivityTimeStamp), todynamic(ActivityStatusValue), todynamic(OperationIds), todynamic(CorrelationId)
| extend timestamp = ActivityTimeStamp, AccountCustomEntity = Caller, IPCustomEntity = CallerIpAddress
version: 2.0.1
status: Available
queryFrequency: 1d
requiredDataConnectors:
- connectorId: AzureActivity
  dataTypes:
  - AzureActivity
entityMappings:
- fieldMappings:
  - columnName: AccountCustomEntity
    identifier: FullName
  entityType: Account
- fieldMappings:
  - columnName: IPCustomEntity
    identifier: Address
  entityType: IP
kind: Scheduled
queryPeriod: 7d
severity: Medium
query: |
  let szOperationNames = dynamic(["microsoft.compute/virtualMachines/write", "microsoft.resources/deployments/write"]);
  let starttime = 7d;
  let endtime = 1d;
  AzureActivity
  | where TimeGenerated between (startofday(ago(starttime)) .. startofday(ago(endtime)))
  | where OperationNameValue  in~ (szOperationNames)
  | summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), ActivityTimeStamp = makelist(TimeGenerated), ActivityStatusValue = makelist(ActivityStatusValue),
  OperationIds = makelist(OperationId), CallerIpAddress = makelist(CallerIpAddress), CorrelationId = makelist(CorrelationId)
  by ResourceId, Caller, OperationNameValue, Resource, ResourceGroup
  | mvexpand CallerIpAddress
  | where isnotempty(CallerIpAddress)
  | make-series dResourceCount=dcount(ResourceId)  default=0 on StartTimeUtc in range(startofday(ago(7d)), now(), 1d)
  by Caller, tostring(ActivityTimeStamp), tostring(ActivityStatusValue), tostring(OperationIds), tostring(CallerIpAddress), tostring(CorrelationId), ResourceId, OperationNameValue , Resource, ResourceGroup
  | extend (RSquare,Slope,Variance,RVariance,Interception,LineFit)=series_fit_line(dResourceCount)
  | where Slope > 0.2
  | join kind=leftsemi (
  // Last day's activity is anomalous
  AzureActivity
  | where TimeGenerated >= startofday(ago(endtime))
  | where OperationNameValue in~ (szOperationNames)
  | summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), ActivityTimeStamp = makelist(TimeGenerated), ActivityStatusValue = makelist(ActivityStatusValue),
  OperationIds = makelist(OperationId), CallerIpAddress = makelist(CallerIpAddress), CorrelationId = makelist(CorrelationId)
  by ResourceId, Caller, OperationNameValue, Resource, ResourceGroup
  | mvexpand CallerIpAddress
  | where isnotempty(CallerIpAddress)
  | make-series dResourceCount=dcount(ResourceId)  default=0 on StartTimeUtc in range(startofday(ago(1d)), now(), 1d)
  by Caller, tostring(ActivityTimeStamp), tostring(ActivityStatusValue), tostring(OperationIds), tostring(CallerIpAddress), tostring(CorrelationId), ResourceId, OperationNameValue , Resource, ResourceGroup
  | extend (RSquare,Slope,Variance,RVariance,Interception,LineFit)=series_fit_line(dResourceCount)
  | where Slope > 0.2
  ) on Caller, CallerIpAddress
  | mvexpand todynamic(ActivityTimeStamp), todynamic(ActivityStatusValue), todynamic(OperationIds), todynamic(CorrelationId)
  | extend timestamp = ActivityTimeStamp, AccountCustomEntity = Caller, IPCustomEntity = CallerIpAddress  
triggerOperator: gt
id: 361dd1e3-1c11-491e-82a3-bb2e44ac36ba
description: |
  'Indicates when an anomalous number of VM creations or deployment activities occur in Azure via the AzureActivity log.
  The anomaly detection identifies activities that have occurred both since the start of the day 1 day ago and the start of the day 7 days ago.
  The start of the day is considered 12am UTC time.'  
triggerThreshold: 0
name: Suspicious number of resource creation or deployment activities
relevantTechniques:
- T1496
tactics:
- Impact
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Azure Activity/Analytic Rules/Creating_Anomalous_Number_Of_Resources_detection.yaml
{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "workspace": {
      "type": "String"
    }
  },
  "resources": [
    {
      "id": "[concat(resourceId('Microsoft.OperationalInsights/workspaces/providers', parameters('workspace'), 'Microsoft.SecurityInsights'),'/alertRules/361dd1e3-1c11-491e-82a3-bb2e44ac36ba')]",
      "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/361dd1e3-1c11-491e-82a3-bb2e44ac36ba')]",
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules",
      "kind": "Scheduled",
      "apiVersion": "2022-11-01",
      "properties": {
        "displayName": "Suspicious number of resource creation or deployment activities",
        "description": "'Indicates when an anomalous number of VM creations or deployment activities occur in Azure via the AzureActivity log.\nThe anomaly detection identifies activities that have occurred both since the start of the day 1 day ago and the start of the day 7 days ago.\nThe start of the day is considered 12am UTC time.'\n",
        "severity": "Medium",
        "enabled": true,
        "query": "let szOperationNames = dynamic([\"microsoft.compute/virtualMachines/write\", \"microsoft.resources/deployments/write\"]);\nlet starttime = 7d;\nlet endtime = 1d;\nAzureActivity\n| where TimeGenerated between (startofday(ago(starttime)) .. startofday(ago(endtime)))\n| where OperationNameValue  in~ (szOperationNames)\n| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), ActivityTimeStamp = makelist(TimeGenerated), ActivityStatusValue = makelist(ActivityStatusValue),\nOperationIds = makelist(OperationId), CallerIpAddress = makelist(CallerIpAddress), CorrelationId = makelist(CorrelationId)\nby ResourceId, Caller, OperationNameValue, Resource, ResourceGroup\n| mvexpand CallerIpAddress\n| where isnotempty(CallerIpAddress)\n| make-series dResourceCount=dcount(ResourceId)  default=0 on StartTimeUtc in range(startofday(ago(7d)), now(), 1d)\nby Caller, tostring(ActivityTimeStamp), tostring(ActivityStatusValue), tostring(OperationIds), tostring(CallerIpAddress), tostring(CorrelationId), ResourceId, OperationNameValue , Resource, ResourceGroup\n| extend (RSquare,Slope,Variance,RVariance,Interception,LineFit)=series_fit_line(dResourceCount)\n| where Slope > 0.2\n| join kind=leftsemi (\n// Last day's activity is anomalous\nAzureActivity\n| where TimeGenerated >= startofday(ago(endtime))\n| where OperationNameValue in~ (szOperationNames)\n| summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), ActivityTimeStamp = makelist(TimeGenerated), ActivityStatusValue = makelist(ActivityStatusValue),\nOperationIds = makelist(OperationId), CallerIpAddress = makelist(CallerIpAddress), CorrelationId = makelist(CorrelationId)\nby ResourceId, Caller, OperationNameValue, Resource, ResourceGroup\n| mvexpand CallerIpAddress\n| where isnotempty(CallerIpAddress)\n| make-series dResourceCount=dcount(ResourceId)  default=0 on StartTimeUtc in range(startofday(ago(1d)), now(), 1d)\nby Caller, tostring(ActivityTimeStamp), tostring(ActivityStatusValue), tostring(OperationIds), tostring(CallerIpAddress), tostring(CorrelationId), ResourceId, OperationNameValue , Resource, ResourceGroup\n| extend (RSquare,Slope,Variance,RVariance,Interception,LineFit)=series_fit_line(dResourceCount)\n| where Slope > 0.2\n) on Caller, CallerIpAddress\n| mvexpand todynamic(ActivityTimeStamp), todynamic(ActivityStatusValue), todynamic(OperationIds), todynamic(CorrelationId)\n| extend timestamp = ActivityTimeStamp, AccountCustomEntity = Caller, IPCustomEntity = CallerIpAddress\n",
        "queryFrequency": "P1D",
        "queryPeriod": "P7D",
        "triggerOperator": "GreaterThan",
        "triggerThreshold": 0,
        "suppressionDuration": "PT1H",
        "suppressionEnabled": false,
        "tactics": [
          "Impact"
        ],
        "techniques": [
          "T1496"
        ],
        "alertRuleTemplateName": "361dd1e3-1c11-491e-82a3-bb2e44ac36ba",
        "customDetails": null,
        "entityMappings": [
          {
            "entityType": "Account",
            "fieldMappings": [
              {
                "identifier": "FullName",
                "columnName": "AccountCustomEntity"
              }
            ]
          },
          {
            "entityType": "IP",
            "fieldMappings": [
              {
                "identifier": "Address",
                "columnName": "IPCustomEntity"
              }
            ]
          }
        ],
        "status": "Available",
        "OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Azure Activity/Analytic Rules/Creating_Anomalous_Number_Of_Resources_detection.yaml",
        "templateVersion": "2.0.1"
      }
    }
  ]
}