Suspicious number of resource creation or deployment activities
Id | 361dd1e3-1c11-491e-82a3-bb2e44ac36ba |
Rulename | 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. 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. |
Severity | Medium |
Tactics | Impact |
Techniques | T1496 |
Required data connectors | AzureActivity |
Kind | Scheduled |
Query frequency | 1d |
Query period | 7d |
Trigger threshold | 0 |
Trigger operator | gt |
Source Uri | https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/Azure Activity/Analytic Rules/Creating_Anomalous_Number_Of_Resources_detection.yaml |
Version | 2.0.1 |
Arm template | 361dd1e3-1c11-491e-82a3-bb2e44ac36ba.json |
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"
}
}
]
}