Adversaries may exfiltrate data by leveraging Azure Storage services while simultaneously establishing persistence through compromised credentials in CommonSecurityLogs. SOC teams should proactively hunt for this behavior to detect potential data exfiltration and credential misuse in their Azure Sentinel environment.
KQL Query
SecurityAlert
| where DisplayName has_any ("Potential malware uploaded to a storage blob container","Storage account identified as source for distribution of malware")
| extend Entities = parse_json(Entities)
| mv-expand Entities
| where Entities['Type'] =~ "ip"
| extend AttackerIP = tostring(Entities['Address']), AttackerCountry = tostring(Entities['Location']['CountryName'])
| join kind=inner (
union
StorageFileLogs,
StorageBlobLogs
//File upload operations
| where StatusText =~ "Success"
| where OperationName =~ "PutBlob" or OperationName =~ "PutRange"
| extend ClientIP = tostring(CallerIpAddress)
) on $left.AttackerIP == $right.ClientIP
| project AlertTimeGenerated = TimeGenerated, AttackerIP, AttackerCountry
| join kind=inner (
CommonSecurityLog
| where DeviceVendor =~ "Fortinet"
| where ApplicationProtocol has_any ("SSL","RDP")
| where LogSeverity has_any ("2","3")
| where isnotempty(SourceIP) and isnotempty(DestinationIP) and SourceIP != "0.0.0.0"
| where DeviceAction !in ("close", "client-rst", "server-rst", "deny") and DestinationPort != 161
| project DeviceProduct,LogSeverity,DestinationPort,DestinationIP,Message,SourceIP,SourcePort,Activity,SentBytes,ReceivedBytes)
on $left.AttackerIP==$right.DestinationIP
| summarize count() by AlertTimeGenerated,IpAddress=DestinationIP,SentBytes,ReceivedBytes,AttackerCountry
id: 7098cae1-c632-4b40-b715-86d6b07720d7
name: Storage Alert Correlation with CommonSecurityLogs and StorageLogs
description: |
'This query combines different Storage alerts with CommonSecurityLogs and StorageLogs helping analysts triage and investigate any
possible Storage related attacks faster thus reducing Mean Time To Respond'
requiredDataConnectors:
- connectorId: AzureSecurityCenter
dataTypes:
- SecurityAlert (ASC)
- connectorId: Fortinet
dataTypes:
- CommonSecurityLog
tactics:
- InitialAccess
- LateralMovement
relevantTechniques:
- T1586
- T1570
query: |
SecurityAlert
| where DisplayName has_any ("Potential malware uploaded to a storage blob container","Storage account identified as source for distribution of malware")
| extend Entities = parse_json(Entities)
| mv-expand Entities
| where Entities['Type'] =~ "ip"
| extend AttackerIP = tostring(Entities['Address']), AttackerCountry = tostring(Entities['Location']['CountryName'])
| join kind=inner (
union
StorageFileLogs,
StorageBlobLogs
//File upload operations
| where StatusText =~ "Success"
| where OperationName =~ "PutBlob" or OperationName =~ "PutRange"
| extend ClientIP = tostring(CallerIpAddress)
) on $left.AttackerIP == $right.ClientIP
| project AlertTimeGenerated = TimeGenerated, AttackerIP, AttackerCountry
| join kind=inner (
CommonSecurityLog
| where DeviceVendor =~ "Fortinet"
| where ApplicationProtocol has_any ("SSL","RDP")
| where LogSeverity has_any ("2","3")
| where isnotempty(SourceIP) and isnotempty(DestinationIP) and SourceIP != "0.0.0.0"
| where DeviceAction !in ("close", "client-rst", "server-rst", "deny") and DestinationPort != 161
| project DeviceProduct,LogSeverity,DestinationPort,DestinationIP,Message,SourceIP,SourcePort,Activity,SentBytes,ReceivedBytes)
on $left.AttackerIP==$right.DestinationIP
| summarize count() by AlertTimeGenerated,IpAddress=DestinationIP,SentBytes,ReceivedBytes,AttackerCountry
entityMappings:
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IpAddress
| Sentinel Table | Notes |
|---|---|
CommonSecurityLog | Ensure this data connector is enabled |
SecurityAlert | Ensure this data connector is enabled |
Scenario: A system administrator is performing a scheduled backup using Azure Backup or Veeam Backup & Replication.
Filter/Exclusion: Exclude events related to known backup tools by checking the Process Name or Command Line for strings like backup.exe, veeam.exe, or azurebackup.exe.
Scenario: An IT admin is manually reviewing storage logs using PowerShell or Log Analytics for routine compliance checks.
Filter/Exclusion: Exclude events where the User field matches known admin accounts (e.g., admin, root, svc_account) or where the Event Source is PowerShell or Log Analytics.
Scenario: A user is accessing cloud storage via AWS CLI or Azure CLI to transfer files for a legitimate business purpose.
Filter/Exclusion: Exclude events where the Command Line contains aws s3 cp or az storage blob upload and the User is a known cloud admin or developer account.
Scenario: A scheduled Azure DevOps pipeline is running and interacting with storage accounts to deploy code or artifacts.
Filter/Exclusion: Exclude events where the User is a service account associated with Azure DevOps or where the Command Line includes az pipelines run or azure-pipelines.yml.
Scenario: A Windows Task Scheduler job is configured to clean up temporary files or archive logs, which involves accessing storage.
Filter/Exclusion: Exclude events where the Process Name is schtasks.exe or where the User is a system account like SYSTEM or LocalService.