Detection rules › Kusto
TI Map IP Entity to Azure SQL Security Audit Events
This query maps any IP indicators of compromise (IOCs) from threat intelligence (TI), by searching for matches in SQL Security Audit Events.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Command & Control | T1071 Application Layer Protocol |
Rules detecting the same action
Other rules on this platform that filter on the same API call or operation.
- Affected rows stateful anomaly on database (Kusto)
- Credential errors stateful anomaly on database (Kusto)
- Drop attempts stateful anomaly on database (Kusto)
- Execution attempts stateful anomaly on database (Kusto)
- Firewall errors stateful anomaly on database (Kusto)
- Firewall rule manipulation attempts stateful anomaly on database (Kusto)
- OLE object manipulation attempts stateful anomaly on database (Kusto)
- Outgoing connection attempts stateful anomaly on database (Kusto)
Rule body kusto
id: d0aa8969-1bbe-4da3-9e76-09e5f67c9d85
name: TI Map IP Entity to Azure SQL Security Audit Events
description: |
This query maps any IP indicators of compromise (IOCs) from threat intelligence (TI), by searching for matches in SQL Security Audit Events.
severity: Medium
requiredDataConnectors:
- connectorId: ThreatIntelligence
dataTypes:
- ThreatIntelligenceIndicator
- connectorId: ThreatIntelligenceTaxii
dataTypes:
- ThreatIntelligenceIndicator
- connectorId: AzureSql
dataTypes:
- AzureDiagnostics
- connectorId: MicrosoftDefenderThreatIntelligence
dataTypes:
- ThreatIntelligenceIndicator
queryFrequency: 1h
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
tactics:
- CommandAndControl
relevantTechniques:
- T1071
query: |
let dt_lookBack = 1h; // Look back 1 hour for AzureDiagnostics logs
let ioc_lookBack = 14d; // Look back 14 days for threat intelligence indicators
// Fetch threat intelligence indicators related to IP addresses
let IP_Indicators = ThreatIntelligenceIndicator
| where isnotempty(NetworkIP) or isnotempty(EmailSourceIpAddress) or isnotempty(NetworkDestinationIP) or isnotempty(NetworkSourceIP)
| where TimeGenerated >= ago(ioc_lookBack)
| extend TI_ipEntity = iff(isnotempty(NetworkIP), NetworkIP, NetworkDestinationIP)
| extend TI_ipEntity = iff(isempty(TI_ipEntity) and isnotempty(NetworkSourceIP), NetworkSourceIP, TI_ipEntity)
| extend TI_ipEntity = iff(isempty(TI_ipEntity) and isnotempty(EmailSourceIpAddress), EmailSourceIpAddress, TI_ipEntity)
| where ipv4_is_private(TI_ipEntity) == false and TI_ipEntity !startswith "fe80" and TI_ipEntity !startswith "::" and TI_ipEntity !startswith "127."
| summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by IndicatorId
| where Active == true and ExpirationDateTime > now();
// Perform a join between IP indicators and AzureDiagnostics logs for SQL Security Audit events
IP_Indicators
// Use innerunique to keep performance fast and result set low, as we only need one match to indicate potential malicious activity that needs investigation
| join kind=innerunique (
AzureDiagnostics
| where TimeGenerated >= ago(dt_lookBack)
| where ResourceProvider == 'MICROSOFT.SQL'
| where Category == 'SQLSecurityAuditEvents'
| extend SQLSecurityAuditEvents_TimeGenerated = TimeGenerated
| extend ClientIP = column_ifexists("client_ip_s", "Not Available")
| extend Action = column_ifexists("action_name_s", "Not Available")
| extend Application = column_ifexists("application_name_s", "Not Available")
| extend HostName = column_ifexists("host_name_s", "Not Available")
)
on $left.TI_ipEntity == $right.ClientIP
// Filter out logs that occurred after the expiration of the corresponding indicator
| where SQLSecurityAuditEvents_TimeGenerated < ExpirationDateTime
// Group the results by IndicatorId and ClientIP, and keep the log entry with the latest timestamp
| summarize SQLSecurityAuditEvents_TimeGenerated = arg_max(SQLSecurityAuditEvents_TimeGenerated, *) by IndicatorId, ClientIP
// Select the desired output fields
| project SQLSecurityAuditEvents_TimeGenerated, Description, ActivityGroupNames, IndicatorId, ThreatType, Url, ExpirationDateTime, ConfidenceScore,
TI_ipEntity, ResourceId, ClientIP, Action, Application, HostName, NetworkIP, NetworkDestinationIP, NetworkSourceIP, EmailSourceIpAddress, Type
// Rename the timestamp field
| extend timestamp = SQLSecurityAuditEvents_TimeGenerated
entityMappings:
- entityType: IP
fieldMappings:
- identifier: Address
columnName: ClientIP
version: 1.3.2
kind: Scheduled
Stages and Predicates
Parameters
let dt_lookBack = 1h;
let ioc_lookBack = 14d;
The stages below define let IP_Indicators (the rule's main pipeline source).
Stage 1: source
ThreatIntelligenceIndicator
Stage 2: where
| where isnotempty(NetworkIP) or isnotempty(EmailSourceIpAddress) or isnotempty(NetworkDestinationIP) or isnotempty(NetworkSourceIP)
Stage 3: where
| where TimeGenerated >= ago(ioc_lookBack)
Stage 4: extend (3 consecutive steps)
| extend TI_ipEntity = iff(isnotempty(NetworkIP), NetworkIP, NetworkDestinationIP)
| extend TI_ipEntity = iff(isempty(TI_ipEntity) and isnotempty(NetworkSourceIP), NetworkSourceIP, TI_ipEntity)
| extend TI_ipEntity = iff(isempty(TI_ipEntity) and isnotempty(EmailSourceIpAddress), EmailSourceIpAddress, TI_ipEntity)
TI_ipEntity =isnotempty(NetworkIP)NetworkIPNetworkDestinationIPStage 5: where
| where ipv4_is_private(TI_ipEntity) == false and TI_ipEntity !startswith "fe80" and TI_ipEntity !startswith "::" and TI_ipEntity !startswith "127."
Stage 6: summarize
| summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by IndicatorId
Stage 7: where
| where Active == true and ExpirationDateTime > now()
The stages below run on IP_Indicators (the outer pipeline).
Stage 8: join
IP_Indicators
| join kind=innerunique (
AzureDiagnostics
| where TimeGenerated >= ago(dt_lookBack)
| where ResourceProvider == 'MICROSOFT.SQL'
| where Category == 'SQLSecurityAuditEvents'
| extend SQLSecurityAuditEvents_TimeGenerated = TimeGenerated
| extend ClientIP = column_ifexists("client_ip_s", "Not Available")
| extend Action = column_ifexists("action_name_s", "Not Available")
| extend Application = column_ifexists("application_name_s", "Not Available")
| extend HostName = column_ifexists("host_name_s", "Not Available")
)
on $left.TI_ipEntity == $right.ClientIP
Stage 9: where
| where SQLSecurityAuditEvents_TimeGenerated < ExpirationDateTime
Stage 10: summarize
| summarize SQLSecurityAuditEvents_TimeGenerated = arg_max(SQLSecurityAuditEvents_TimeGenerated, *) by IndicatorId, ClientIP
Stage 11: project
| project SQLSecurityAuditEvents_TimeGenerated, Description, ActivityGroupNames, IndicatorId, ThreatType, Url, ExpirationDateTime, ConfidenceScore,
TI_ipEntity, ResourceId, ClientIP, Action, Application, HostName, NetworkIP, NetworkDestinationIP, NetworkSourceIP, EmailSourceIpAddress, Type
Stage 12: extend
| extend timestamp = SQLSecurityAuditEvents_TimeGenerated
Exclusions
Top-level NOT(...) conjuncts: predicates this rule actively suppresses.
| Field | Kind | Excluded values |
|---|---|---|
TI_ipEntity | cidr_match | 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16, 127.0.0.0/8 |
TI_ipEntity | starts_with | 127. |
TI_ipEntity | starts_with | :: |
TI_ipEntity | starts_with | fe80 |
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 |
|---|---|---|
Active | eq |
|
Category | eq |
|
EmailSourceIpAddress | is_not_null | |
NetworkDestinationIP | is_not_null | |
NetworkIP | is_not_null | |
NetworkSourceIP | is_not_null | |
ResourceProvider | eq |
|
SQLSecurityAuditEvents_TimeGenerated | lt |
|
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 |
|---|---|
Action | project |
ActivityGroupNames | project |
Application | project |
ClientIP | project |
ConfidenceScore | project |
Description | project |
EmailSourceIpAddress | project |
ExpirationDateTime | project |
HostName | project |
IndicatorId | project |
NetworkDestinationIP | project |
NetworkIP | project |
NetworkSourceIP | project |
ResourceId | project |
SQLSecurityAuditEvents_TimeGenerated | project |
TI_ipEntity | project |
ThreatType | project |
Type | project |
Url | project |
timestamp | extend |