The hypothesis is that adversaries are using domain generation algorithms (DGA) associated with the Nobelium campaign to establish command and control channels, leveraging predictable domain patterns to evade detection. SOC teams should proactively hunt for this behavior in Azure Sentinel to identify potential C2 infrastructure and disrupt ongoing malicious activities.
KQL Query
let cloudApiTerms = dynamic(["api", "east", "west"]);
let timeFrame = ago(1d);
let relevantDeviceNetworkEvents =
DeviceNetworkEvents
| where Timestamp >= timeFrame
| where RemoteUrl !has "\\" and RemoteUrl !has "/"
// performance filter
| where RemoteUrl has_any(cloudApiTerms)
| project-rename DomainName = RemoteUrl
| project Timestamp, DomainName, DeviceId, DeviceName;
let relevantDeviceEvents =
DeviceEvents
| where Timestamp >= timeFrame
| where ActionType == "DnsQueryResponse"
// performance filter
| where AdditionalFields has_any(cloudApiTerms)
| extend query = extractjson("$.DnsQueryString", AdditionalFields)
| where isnotempty(query)
| project-rename DomainName = query
| project Timestamp, DomainName, DeviceId, DeviceName;
let relevantIdentityQueryEvents =
IdentityQueryEvents
| where Timestamp >= timeFrame
| where ActionType == "DNS query"
| where Protocol == "Dns"
// performance filter
| where QueryTarget has_any(cloudApiTerms)
| project-rename DomainName = QueryTarget
| project Timestamp, DomainName, DeviceId = "", DeviceName;
let relevantData =
relevantIdentityQueryEvents
| union
relevantDeviceNetworkEvents
| union
relevantDeviceEvents;
let tokenCreation =
relevantData
| extend domain_split = split(DomainName, ".")
| where tostring(domain_split[-5]) != "" and tostring(domain_split[-6]) == ""
| extend sub_domain = tostring(domain_split[0])
| where sub_domain !contains "-"
| extend sub_directories = strcat(domain_split[-3], " ", domain_split[-4])
| where sub_directories has_any(cloudApiTerms);
tokenCreation
//Based on sample communications the subdomain is always between 20 and 30 bytes
| where strlen(domain_split) < 32 or strlen(domain_split) > 20
| extend domain = strcat(tostring(domain_split[-2]), ".", tostring(domain_split[-1]))
| extend subdomain_no = countof(sub_domain, @"(\d)", "regex")
| extend subdomain_ch = countof(sub_domain, @"([a-z])", "regex")
| where subdomain_no > 1
| extend percentage_numerical = toreal(subdomain_no) / toreal(strlen(sub_domain)) * 100
| where percentage_numerical < 50 and percentage_numerical > 5
| summarize rowcount = count(), make_set(DomainName), make_set(DeviceId), make_set(DeviceName), FirstSeen=min(Timestamp), LastSeen=max(Timestamp) by DomainName
| order by rowcount asc
id: 6c87bdb8-a44e-452a-b782-542640d985e3
name: DNSPattern [Nobelium]
description: |
This query looks for the DGA pattern of the domain associated with the Nobelium campaign, in order to find other domains with the same activity pattern.
This query is inspired by an Azure Sentinel detection.
Reference - https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Hunting%20Queries/DnsEvents/Solorigate-DNS-Pattern.yaml
requiredDataConnectors:
- connectorId: MicrosoftThreatProtection
dataTypes:
- DeviceNetworkEvents
- DeviceEvents
- IdentityQueryEvents
tactics:
- Command and control
tags:
- Nobelium
query: |
let cloudApiTerms = dynamic(["api", "east", "west"]);
let timeFrame = ago(1d);
let relevantDeviceNetworkEvents =
DeviceNetworkEvents
| where Timestamp >= timeFrame
| where RemoteUrl !has "\\" and RemoteUrl !has "/"
// performance filter
| where RemoteUrl has_any(cloudApiTerms)
| project-rename DomainName = RemoteUrl
| project Timestamp, DomainName, DeviceId, DeviceName;
let relevantDeviceEvents =
DeviceEvents
| where Timestamp >= timeFrame
| where ActionType == "DnsQueryResponse"
// performance filter
| where AdditionalFields has_any(cloudApiTerms)
| extend query = extractjson("$.DnsQueryString", AdditionalFields)
| where isnotempty(query)
| project-rename DomainName = query
| project Timestamp, DomainName, DeviceId, DeviceName;
let relevantIdentityQueryEvents =
IdentityQueryEvents
| where Timestamp >= timeFrame
| where ActionType == "DNS query"
| where Protocol == "Dns"
// performance filter
| where QueryTarget has_any(cloudApiTerms)
| project-rename DomainName = QueryTarget
| project Timestamp, DomainName, DeviceId = "", DeviceName;
let relevantData =
relevantIdentityQueryEvents
| union
relevantDeviceNetworkEvents
| union
relevantDeviceEvents;
let tokenCreation =
relevantData
| extend domain_split = split(DomainName, ".")
| where tostring(domain_split[-5]) != "" and tostring(domain_split[-6]) == ""
| extend sub_domain = tostring(domain_split[0])
| where sub_domain !contains "-"
| extend sub_directories = strcat(domain_split[-3], " ", domain_split[-4])
| where sub_directories has_any(cloudApiTerms);
tokenCreation
//Based on sample communications the subdomain is always between 20 and 30 bytes
| where strlen(domain_split) < 32 or strlen(domain_split) > 20
| extend domain = strcat(tostring(domain_split[-2]), ".", tostring(domain_split[-1]))
| extend subdomain_no = countof(sub_domain, @"(\d)", "regex")
| extend subdomain_ch = countof(sub_domain, @"([a-z])", "regex")
| where subdomain_no > 1
| extend percentage_numerical = toreal(subdomain_no) / toreal(strlen(sub_domain)) * 100
| where percentage_numerical < 50 and percentage_numerical > 5
| summarize rowcount = count(), make_set(DomainName), make_set(DeviceId), make_s
| Sentinel Table | Notes |
|---|---|
DeviceEvents | Ensure this data connector is enabled |
DeviceNetworkEvents | Ensure this data connector is enabled |
IdentityQueryEvents | Ensure this data connector is enabled |
Scenario: Legitimate DNS queries for internal domain monitoring tools
Description: A security tool like Microsoft Defender for Endpoint or CrowdStrike Falcon may perform DNS queries to monitor internal domains for potential threats.
Filter/Exclusion: Exclude DNS queries originating from known security tools using the source_process_name field, e.g., source_process_name = "Microsoft Defender for Endpoint".
Scenario: Scheduled job for domain reputation checks
Description: A Microsoft Azure Security Center or Cisco Talos Intelligence scheduled job may query domains against known threat intelligence feeds.
Filter/Exclusion: Exclude DNS queries associated with scheduled jobs using the destination_domain field, e.g., destination_domain = "talosintelligence.com" or destination_domain = "azure.com".
Scenario: DNS-based backup or sync operations
Description: A Veeam Backup & Replication or Dell EMC Data Domain job may use DNS for discovery or sync purposes, leading to suspicious-looking domain queries.
Filter/Exclusion: Exclude DNS queries from backup services using the source_process_name field, e.g., source_process_name = "Veeam Backup & Replication" or source_process_name = "Data Domain".
Scenario: DNS resolution for internal development or testing environments
Description: Developers may use DNSPod or Cloudflare DNS to resolve internal development domains, which may match the DGA pattern.
Filter/Exclusion: Exclude DNS queries to internal development domains using the destination_domain field, e.g., destination_domain contains "dev." or destination_domain contains "test.".
Scenario: DNS queries from legitimate threat intelligence platforms
Description: Tools like IBM X-Force or AlienVault OTX may query