Detection rules › Kusto
Azure Machine Learning Write Operations
Shows the most prevalent users who perform write operations on Azure Machine Learning resources. List the common source IP address for each of those accounts. If an operation is not from those IP addresses, it may be worthy of investigation.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Initial Access | T1078 Valid Accounts |
| Execution | T1059 Command and Scripting Interpreter |
| Impact | T1496 Resource Hijacking |
Event coverage
| Provider | Event | Title |
|---|---|---|
| Azure-Microsoft.MachineLearningServices | _catch_all | Azure Machine Learning (catch-all) |
Rule body kusto
id: 68c89998-8052-4c80-a1f6-9d81060b6d57
name: Azure Machine Learning Write Operations
description: |
'Shows the most prevalent users who perform write operations on Azure Machine Learning resources. List the common source IP address for each of those accounts. If an operation is not from those IP addresses, it may be worthy of investigation.'
severity: Low
status: Available
requiredDataConnectors:
- connectorId: AzureActivity
dataTypes:
- AzureActivity
tactics:
- InitialAccess
- Execution
- Impact
relevantTechniques:
- T1078
- T1059
- T1496
queryFrequency: 1d # Added queryFrequency property
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
query: |
AzureActivity
| where ResourceProviderValue == "MICROSOFT.MACHINELEARNINGSERVICES" // Filter activities related to Microsoft Machine Learning Services
| extend SCOPE = tostring(parse_json(Authorization).scope) // Parse Authorization scope as string
| extend subname = split(Hierarchy, "/") // Split Hierarchy to extract Subscription Name and ID
| extend ['Subscription Name'] = subname[-2], ['Subscription ID'] = subname[-1] // Extract Subscription Name and ID
| extend Properties = parse_json(Properties) // Parse Properties as JSON
| extend Properties_entity = tostring(Properties.entity) // Cast Properties.entity to string
| where isnotempty(Properties_entity) // Filter activities where Properties.entity is not empty
// | where Properties_entity contains "deepseek" // Filter activities where Properties.entity contains "deepseek"
| where OperationNameValue contains "write" // Filter activities where OperationNameValue contains "write"
| where OperationNameValue !contains "MICROSOFT.AUTHORIZATION/ROLEASSIGNMENTS/WRITE" // Exclude role assignments
| extend LLM = tostring(split(Properties_entity, "/")[-1]) // Extract the last segment of Properties_entity and cast it to string
| distinct TimeGenerated, tostring(['Subscription Name']), ResourceGroup, tostring(['Subscription ID']), Caller, CallerIpAddress, OperationNameValue, LLM, _ResourceId // Select distinct relevant fields for output
eventGroupingSettings:
aggregationKind: SingleAlert
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: Caller
- entityType: IP
fieldMappings:
- identifier: Address
columnName: CallerIpAddress
- entityType: AzureResource
fieldMappings:
- identifier: ResourceId
columnName: _ResourceId
version: 1.0.0
kind: Scheduled
Stages and Predicates
Stage 1: source
AzureActivity
Stage 2: where
| where ResourceProviderValue == "MICROSOFT.MACHINELEARNINGSERVICES"
Stage 3: extend (5 consecutive steps)
| extend SCOPE = tostring(parse_json(Authorization).scope)
| extend subname = split(Hierarchy, "/")
| extend ['Subscription Name'] = subname[-2], ['Subscription ID'] = subname[-1]
| extend Properties = parse_json(Properties)
| extend Properties_entity = tostring(Properties.entity)
Stage 4: where
| where isnotempty(Properties_entity)
Stage 5: where
| where OperationNameValue contains "write"
Stage 6: where
| where OperationNameValue !contains "MICROSOFT.AUTHORIZATION/ROLEASSIGNMENTS/WRITE"
Stage 7: extend
| extend LLM = tostring(split(Properties_entity, "/")[-1])
Stage 8: distinct
| distinct TimeGenerated, tostring(['Subscription Name']), ResourceGroup, tostring(['Subscription ID']), Caller, CallerIpAddress, OperationNameValue, LLM, _ResourceId
Exclusions
Top-level NOT(...) conjuncts: predicates this rule actively suppresses.
| Field | Kind | Excluded values |
|---|---|---|
OperationNameValue | contains | MICROSOFT.AUTHORIZATION/ROLEASSIGNMENTS/WRITE |
Indicators
Each row is a field, operator, and value that the rule matches. The corpus column counts how many other rules in the catalog look for the same combination: high numbers point to widely-used, community-vetted indicators. Blank or 1 shows that the indicator is specific to this rule.
| Field | Kind | Values |
|---|---|---|
OperationNameValue | contains |
|
Properties_entity | is_not_null | |
ResourceProviderValue | eq |
|
Output fields
Fields the rule emits when it matches. Chronicle authors list these in the outcome block; they appear on the detection and $risk_score drives alerting. Sentinel / Defender XDR rules build them up through project / summarize / extend stages. Sentinel maps these into alert fields via entityMappings and customDetails; Defender XDR custom detections surface them as alert fields directly.
| Field | Source |
|---|---|
SCOPE | extend |
subname | extend |
Subscription ID | extend |
Subscription Name | extend |
Properties | extend |
Properties_entity | extend |
LLM | extend |