Detection rules › Kusto

Ngrok Reverse Proxy on Network (ASIM DNS Solution)

Status
available
Severity
medium
Time window
1h
Group by
DnsQuery, Domain, Dvc, SrcIpAddr
Source
github.com/Azure/Azure-Sentinel

This detection identifies the top four Ngrok domains from DNS resolution. Ngrok reverse proxy can bypass network defense. While not inherently harmful, it has been used for malicious activities recently.

MITRE ATT&CK coverage

TacticTechniques
Command & ControlT1090 Proxy, T1102 Web Service, T1572 Protocol Tunneling

Event coverage

ProviderEventTitle
SysmonEvent ID 22DNSEvent (DNS query)

Rule body kusto

id: 50b0dfb7-2c94-4eaf-a332-a5936d78c263
name: Ngrok Reverse Proxy on Network (ASIM DNS Solution)
description: |
  'This detection identifies the top four Ngrok domains from DNS resolution. Ngrok reverse proxy can bypass network defense. While not inherently harmful, it has been used for malicious activities recently.'
severity: Medium
status: Available 
tags:
  - Schema: ASimDns
    SchemaVersion: 0.1.6
requiredDataConnectors: []
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
  - CommandAndControl
relevantTechniques:
  - T1572
  - T1090
  - T1102
query: |
  // Define a list of Ngrok domains
  let NgrokDomains = dynamic(["ngrok.com", "ngrok.io", "ngrok", "tunnel.com", "korgn", "lennut.com"]);
  // Query the _Im_Dns function for the past 1 hour
  _Im_Dns(starttime=ago(1h))
  | where isnotempty(DnsQuery) // Filter out empty DNS queries
  | where DnsQuery has_any (NgrokDomains) // Filter DNS queries that match any of the Ngrok domains
  | summarize Starttime = min(EventStartTime),Endtime=max(EventEndTime),EventsCount=sum(EventCount),EventResults=make_set(EventResult,4) by DnsQuery, Domain, SrcIpAddr, Dvc
  // Summarize the data by Domain, DNS query, source IP address, and device Dvc
entityMappings:
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: SrcIpAddr
  - entityType: DNS
    fieldMappings:
      - identifier: DomainName
        columnName: Domain
eventGroupingSettings:
  aggregationKind: AlertPerResult
version: 1.0.0
kind: Scheduled

Stages and Predicates

Parameters

let NgrokDomains = dynamic(["ngrok.com", "ngrok.io", "ngrok", "tunnel.com", "korgn", "lennut.com"]);

Stage 1: source

_Im_Dns(starttime=ago(1h))

Stage 2: where

| where isnotempty(DnsQuery)

Stage 3: where

| where DnsQuery has_any (NgrokDomains)

Stage 4: summarize

| summarize Starttime = min(EventStartTime),Endtime=max(EventEndTime),EventsCount=sum(EventCount),EventResults=make_set(EventResult,4) by DnsQuery, Domain, SrcIpAddr, Dvc

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.

FieldKindValues
DnsQueryis_not_null
  • (no value, null check)
DnsQuerymatch
  • korgn
  • lennut.com
  • ngrok
  • ngrok.com
  • ngrok.io
  • tunnel.com

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.

FieldSource
DnsQuerysummarize
Domainsummarize
Dvcsummarize
Endtimesummarize
EventResultssummarize
EventsCountsummarize
SrcIpAddrsummarize
Starttimesummarize