Stay organized with collections Save and categorize content based on your preferences.

Use context-enriched data in rules

To enable security analysts during an investigation, Chronicle ingests contextual data from different sources, performs analysis on the ingested data, and provides additional context about artifacts in a customer environment. This document provides examples of how analysts can use contextually-enriched data in Detection Engine rules.

For more information about how Chronicle enriches incoming data, the types of enrichment performed, and the enriched fields, see Enriching UDM data during log ingestion.

Prevalence enriched fields in rules

The following examples demonstrate how to use the prevalence-related enriched fields in Detection Engine. For reference, see the list of prevalence-related enriched fields.

Identifying low prevalence domain access

This detection rule generates a detection event, not a detection alert, when a match is found. It is primarily meant as a secondary indicator when investigating an asset. For example, there are other higher severity alerts that triggered an incident.

rule network_prevalence_low_prevalence_domain_access {

  meta:
    author = "Chronicle Security"
    description = "Detects access to a low prevalence domain. Requires baseline of prevalence be in place for effective deployment."
    severity = "LOW"

  events:
        $e.metadata.event_type = "NETWORK_HTTP"
        $e.principal.ip = $ip

        // filter out URLs with RFC 1918 IP addresses, i.e., internal assets
        not re.regex($e.target.hostname, `(127(?:\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$)|(10(?:\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$)|(192\.168(?:\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){2}$)|(172\.(?:1[6-9]|2\d|3[0-1])(?:\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){2})`)

        // only match valid FQDN, filter out background non-routable noise
        re.regex($e.target.hostname, `(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]`)
        $domainName = $e.target.hostname

        //join event ($e) to entity graph ($d)
        $e.target.hostname = $d.graph.entity.domain.name

        $d.graph.metadata.entity_type = "DOMAIN_NAME"
        // tune prevalence as fits your results
        $d.graph.entity.domain.prevalence.rolling_max <= 10

    match:
        $ip over 1h

    outcome:
      $risk_score = max(
          // increment risk score based upon rolling_max prevalence
          if ( $d.graph.entity.domain.prevalence.rolling_max >= 10, 10) +
          if ( $d.graph.entity.domain.prevalence.rolling_max >= 2 and $d.graph.entity.domain.prevalence.rolling_max <= 9 , 20) +
          if ( $d.graph.entity.domain.prevalence.rolling_max = 1, 30)
    )
    $domain_list = array_distinct($domainName)
    $domain_count = count_distinct($domainName)

  condition:
    $e and $d
}

Here is an example showing the detections generated by this rule.

Low prevalence domain access View image in new window

Identifying access to domains with a low prevalence score

This rule can be used to detect access to domains with a low prevalence score. To be effective, a baseline of prevalence scores for artifacts must exist. The following example uses reference lists to tune the result and applies a threshold prevalence value.

rule network_prevalence_low_prevalence_domain_access {
  meta:
    author = "Chronicle Security"
    description = "Detects access to a low prevalence domain. Requires baseline of prevalence be in place for effective deployment."
    severity = "LOW"

  events:
        $e.metadata.event_type = "NETWORK_HTTP"
        $e.principal.ip = $ip

        // filter out URLs with RFC 1918 IP addresses, i.e., internal assets
        not re.regex($e.target.hostname, `(127(?:\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$)|(10(?:\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$)|(192\.168(?:\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){2}$)|(172\.(?:1[6-9]|2\d|3[0-1])(?:\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){2})`)

        // used an explicit exclusion reference list
        not $e.target.hostname in %exclusion_network_prevalence_low_prevalence_domain_access

        // only match valid FQDN, filter out background non-routable noise
        re.regex($e.target.hostname, `(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]`)

        $domainName = $e.target.hostname

        //join event ($e) to entity graph ($d)
        $e.target.hostname = $d.graph.entity.domain.name

        $d.graph.metadata.entity_type = "DOMAIN_NAME"

        // tune prevalence as fits your results
        $d.graph.entity.domain.prevalence.rolling_max <= 10

  match:
        $ip over 1h

  outcome:
    $risk_score = max(
        // increment risk score based upon rolling_max prevalence
        if ( $d.graph.entity.domain.prevalence.rolling_max >= 10, 10) +
        if ( $d.graph.entity.domain.prevalence.rolling_max >= 2 and $d.graph.entity.domain.prevalence.rolling_max <= 9 , 20) +
        if ( $d.graph.entity.domain.prevalence.rolling_max = 1, 30)
    )

    $domain_list = array_distinct($domainName)
    $domain_count = count_distinct($domainName)

  condition:
    $e and #d > 10
}

Here is a screen capture showing the example detections generated by this rule.

Low prevalence domain access View image in new window

Identifying low prevalence domains with an IOC match

This detection rule generates a detection alert and provides a high fidelity match comparing a low prevalence domain that is also a known IOC.

rule network_prevalence_uncommon_domain_ioc_match {

  meta:
    author = "Chronicle Security"
    description = "Lookup Network DNS queries against Entity Graph for low prevalence domains with a matching IOC entry."
    severity = "MEDIUM"

  events:
    $e.metadata.event_type = "NETWORK_DNS"
    $e.network.dns.questions.name = $hostname

    //only match FQDNs, e.g., exclude chrome dns access tests and other internal hosts
    $e.network.dns.questions.name = /(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]/

    //prevalence entity graph lookup
    $p.graph.metadata.entity_type = "DOMAIN_NAME"
    $p.graph.entity.domain.prevalence.rolling_max <= 3
    $p.graph.entity.domain.name = $hostname

    //ioc entity graph lookup
    $i.graph.metadata.vendor_name = "ET_PRO_IOC"
    $i.graph.metadata.entity_type = "DOMAIN_NAME"
    $i.graph.entity.hostname = $hostname

  match:
    $hostname over 10m

  outcome:
    $risk_score = max(
        //increment risk score based upon rolling_max prevalence
        if ( $p.graph.entity.domain.prevalence.rolling_max = 3, 50) +
        if ( $p.graph.entity.domain.prevalence.rolling_max = 2, 70) +
        if ( $p.graph.entity.domain.prevalence.rolling_max = 1, 90)
    )

  condition:
    $e and $p and $i
}

Here is an example showing the detections generated by this rule.

Low prevalence domain with an IOC match

Using Safe Browsing enriched fields in rules

Chronicle ingests data from threat lists related to file hashes. This enriched information is stored as Entities in Chronicle.

You can create Detection Engine rules to identify matches against entities ingested from Safe Browsing. The following is an example Detection Engine rule that queries against this enriched information to build context-aware analytics.

rule safe_browsing_file_execution {
    meta:
        author = "Chronicle Security"
        description = "Example usage of Safe Browsing data, to detect execution of a file that's been deemed malicious"
        severity = "LOW"

    events:
        // find a process launch event, match on hostname
        $execution.metadata.event_type = "PROCESS_LAUNCH"
        $execution.principal.hostname = $hostname

        // join execution event with Safe Browsing graph
        $sb.graph.entity.file.sha256 = $execution.target.process.file.sha256

        // look for files deemed malicious
        $sb.graph.metadata.entity_type = "FILE"
        $sb.graph.metadata.threat.severity = "CRITICAL"

    match:
        $hostname over 1h

    condition:
        $execution and $sb
}