From b0ca02605f60c4d7ede41e8b58b84206f0102efb Mon Sep 17 00:00:00 2001 From: Terrance DeJesus <99630311+terrancedejesus@users.noreply.github.com> Date: Thu, 26 Jun 2025 12:38:48 -0400 Subject: [PATCH] [New Hunt] Potential Spoofed `microsoftonline.com` via Fuzzy Match (#4770) * new hunt for spoofed MSFT domains * added lookback time to ESQL query --- ...spoofed_microsoft_authentication_domain.md | 69 +++++++++++++++++++ ...oofed_microsoft_authentication_domain.toml | 56 +++++++++++++++ hunting/index.md | 4 ++ hunting/index.yml | 7 ++ 4 files changed, 136 insertions(+) create mode 100644 hunting/cross-platform/docs/potentially_spoofed_microsoft_authentication_domain.md create mode 100644 hunting/cross-platform/queries/potentially_spoofed_microsoft_authentication_domain.toml diff --git a/hunting/cross-platform/docs/potentially_spoofed_microsoft_authentication_domain.md b/hunting/cross-platform/docs/potentially_spoofed_microsoft_authentication_domain.md new file mode 100644 index 000000000..6bba4859d --- /dev/null +++ b/hunting/cross-platform/docs/potentially_spoofed_microsoft_authentication_domain.md @@ -0,0 +1,69 @@ +# Potential Spoofed `microsoftonline.com` via Fuzzy Match + +--- + +## Metadata + +- **Author:** Elastic +- **Description:** This hunting query identifies potential spoofed domain activity targeting Microsoft online services by detecting fuzzy matches to the domain `microsoftonline.com`. The approach uses approximate string matching (fuzziness) on domain and URL fields, then scores each result by similarity. A static confidence threshold is applied to filter out high-confidence legitimate matches while surfacing potential typosquats and lookalikes. + +This technique is useful for identifying phishing campaigns, misconfigured infrastructure, or domain squatting activity targeting Microsoft users and applications. It relies on string similarity scoring and known-good domain exclusions to reduce false positives and focus the hunt on medium- to high-risk spoofed domains. + +- **UUID:** `e912f5c6-eed3-11ef-a5d7-6f9f7a1e2e00` +- **Integration:** [endpoint](https://docs.elastic.co/integrations/endpoint), [network_traffic](https://docs.elastic.co/integrations/network_traffic), [system](https://docs.elastic.co/integrations/system), [azure](https://docs.elastic.co/integrations/azure), [o365](https://docs.elastic.co/integrations/o365), [windows](https://docs.elastic.co/integrations/windows) +- **Language:** `[ES|QL]` +- **Source File:** [Potential Spoofed `microsoftonline.com` via Fuzzy Match](../queries/potentially_spoofed_microsoft_authentication_domain.toml) + +## Query + +```sql +FROM logs-* METADATA _score +| WHERE ( + url.domain IS NOT NULL OR + url.original IS NOT NULL OR + destination.domain IS NOT NULL OR + dns.question.name IS NOT NULL +) +| EVAL domain = COALESCE(url.domain, url.original, destination.domain, dns.question.name)::STRING +| WHERE NOT( + domain RLIKE "^(login|portal|api)\\.microsoftonline\\.com$" OR + domain RLIKE ".*\\.onmicrosoft\\.com$" OR + domain == "microsoftonline.com") +| WHERE ( + match(url.domain, "microsoftonline.com", { "fuzziness": "AUTO", "max_expansions": 10 }) OR + match(url.original, "microsoftonline.com", { "fuzziness": "AUTO", "max_expansions": 10 }) OR + match(destination.domain, "microsoftonline.com", { "fuzziness": "AUTO", "max_expansions": 10 }) OR + match(dns.question.name, "microsoftonline.com", { "fuzziness": "AUTO", "max_expansions": 10 }) +) +| EVAL confidence = CASE( + _score >= 5.999, "low", + _score > 4, "medium", + "high" +) +| WHERE confidence != "low" + OR domain IN ("micsrosoftonline.com", "outlook-office.micsrosoftonline.com") +| SORT _score DESC +| KEEP @timestamp, source.ip, user.id, domain, _score, confidence +``` + +## Notes + +- Investigate domains that resemble `microsoftonline.com` but have slight character substitutions (e.g., `micros0ftonline.com`, `m1crosoftonline.com`). +- Fuzzy matching assigns a `_score` based on edit distance. Higher scores mean a closer match to the legitimate domain. +- Only medium- and high-confidence results are surfaced by excluding `_score >= 6`, which usually represents exact or near-exact matches. +- Legitimate Microsoft domains like `login.microsoftonline.com`, `portal.microsoftonline.com`, and tenant domains ending in `.onmicrosoft.com` are excluded from results to reduce noise. +- Results are ranked by `_score DESC` and tagged with a confidence level: `low`, `medium`, or `high`. +- This query is best used interactively during hunts and may require tuning for specific environments with high Microsoft traffic. + +## MITRE ATT&CK Techniques + +- [T1566.002](https://attack.mitre.org/techniques/T1566/002) +- [T1583.001](https://attack.mitre.org/techniques/T1583/001) + +## References + +- https://www.microsoft.com/en-us/security/blog/2025/05/27/new-russia-affiliated-actor-void-blizzard-targets-critical-sectors-for-espionage/ + +## License + +- `Elastic License v2` diff --git a/hunting/cross-platform/queries/potentially_spoofed_microsoft_authentication_domain.toml b/hunting/cross-platform/queries/potentially_spoofed_microsoft_authentication_domain.toml new file mode 100644 index 000000000..dab4e5f42 --- /dev/null +++ b/hunting/cross-platform/queries/potentially_spoofed_microsoft_authentication_domain.toml @@ -0,0 +1,56 @@ +[hunt] +author = "Elastic" +description = """ +This hunting query identifies potential spoofed domain activity targeting Microsoft online services by detecting fuzzy matches to the domain `microsoftonline.com`. The approach uses approximate string matching (fuzziness) on domain and URL fields, then scores each result by similarity. A static confidence threshold is applied to filter out high-confidence legitimate matches while surfacing potential typosquats and lookalikes. + +This technique is useful for identifying phishing campaigns, misconfigured infrastructure, or domain squatting activity targeting Microsoft users and applications. It relies on string similarity scoring and known-good domain exclusions to reduce false positives and focus the hunt on medium- to high-risk spoofed domains. +""" +integration = ["endpoint", "network_traffic", "system", "azure", "o365", "windows"] +uuid = "e912f5c6-eed3-11ef-a5d7-6f9f7a1e2e00" +name = "Potential Spoofed `microsoftonline.com` via Fuzzy Match" +language = ["ES|QL"] +license = "Elastic License v2" +notes = [ + "Investigate domains that resemble `microsoftonline.com` but have slight character substitutions (e.g., `micros0ftonline.com`, `m1crosoftonline.com`).", + "Fuzzy matching assigns a `_score` based on edit distance. Higher scores mean a closer match to the legitimate domain.", + "Only medium- and high-confidence results are surfaced by excluding `_score >= 6`, which usually represents exact or near-exact matches.", + "Legitimate Microsoft domains like `login.microsoftonline.com`, `portal.microsoftonline.com`, and tenant domains ending in `.onmicrosoft.com` are excluded from results to reduce noise.", + "Results are ranked by `_score DESC` and tagged with a confidence level: `low`, `medium`, or `high`.", + "This query is best used interactively during hunts and may require tuning for specific environments with high Microsoft traffic." +] +mitre = ["T1566.002", "T1583.001"] +query = [ +''' +FROM logs-* METADATA _score +| WHERE @timestamp > now() - 30 day +| WHERE ( + url.domain IS NOT NULL OR + url.original IS NOT NULL OR + destination.domain IS NOT NULL OR + dns.question.name IS NOT NULL +) +| EVAL domain = COALESCE(url.domain, url.original, destination.domain, dns.question.name)::STRING +| WHERE NOT( + domain RLIKE "^(login|portal|api)\\.microsoftonline\\.com$" OR + domain RLIKE ".*\\.onmicrosoft\\.com$" OR + domain == "microsoftonline.com") +| WHERE ( + match(url.domain, "microsoftonline.com", { "fuzziness": "AUTO", "max_expansions": 10 }) OR + match(url.original, "microsoftonline.com", { "fuzziness": "AUTO", "max_expansions": 10 }) OR + match(destination.domain, "microsoftonline.com", { "fuzziness": "AUTO", "max_expansions": 10 }) OR + match(dns.question.name, "microsoftonline.com", { "fuzziness": "AUTO", "max_expansions": 10 }) +) +| EVAL confidence = CASE( + _score >= 5.999, "low", + _score > 4, "medium", + "high" +) +| WHERE confidence != "low" + OR domain IN ("micsrosoftonline.com", "outlook-office.micsrosoftonline.com") +| SORT _score DESC +| KEEP @timestamp, source.ip, user.id, domain, _score, confidence +''' +] +references = [ + "https://www.microsoft.com/en-us/security/blog/2025/05/27/new-russia-affiliated-actor-void-blizzard-targets-critical-sectors-for-espionage/" +] diff --git a/hunting/index.md b/hunting/index.md index 66fa88c1d..0d6b79359 100644 --- a/hunting/index.md +++ b/hunting/index.md @@ -41,6 +41,10 @@ Here are the queries currently available: - [Microsoft Entra Infrequent Suspicious OData Client Requests](./azure/docs/entra_suspicious_odata_client_requests.md) (ES|QL) +## cross-platform +- [Potential Spoofed `microsoftonline.com` via Fuzzy Match](./cross-platform/docs/potentially_spoofed_microsoft_authentication_domain.md) (ES|QL) + + ## linux - [Defense Evasion via Capitalized Process Execution](./linux/docs/defense_evasion_via_capitalized_process_execution.md) (ES|QL) - [Drivers Load with Low Occurrence Frequency](./linux/docs/persistence_via_driver_load_with_low_occurrence_frequency.md) (ES|QL) diff --git a/hunting/index.yml b/hunting/index.yml index 2ddcf2d70..bcfdc1168 100644 --- a/hunting/index.yml +++ b/hunting/index.yml @@ -771,3 +771,10 @@ azure: path: ./azure/queries/entra_rare_actions_by_service_principal.toml mitre: - T1098.001 +cross-platform: + e912f5c6-eed3-11ef-a5d7-6f9f7a1e2e00: + name: Potential Spoofed `microsoftonline.com` via Fuzzy Match + path: ./cross-platform/queries/potentially_spoofed_microsoft_authentication_domain.toml + mitre: + - T1566.002 + - T1583.001