Overview of the YARA-L 2.0 language

YARA-L 2.0 is a computer language used to create rules for searching through your enterprise log data as it is ingested into your Chronicle account. The YARA-L syntax is derived from the YARA language developed by VirusTotal. The language works in conjunction with the Chronicle Detection Engine and enables you to hunt for threats and other events across large volumes of data. See also YARA-L 2.0 language syntax

YARA-L 2.0 example rules

The following examples show rules written in YARA-L 2.0. Each demonstrates how to correlate events within the rule language.

Logins from different cities

The following rule searches for users that have logged in to your enterprise from two or more cities in less than 5 minutes:

rule DifferentCityLogin {
  meta:

  events:
    $udm.metadata.event_type = "USER_LOGIN"
    $udm.principal.user.userid = $user
    $udm.principal.location.city = $city

  match:
    $user over 5m

  condition:
    $udm and #city > 1
}

Match variable: $user

Event variable:$udm

Placeholder variable: $city and $user

The following describes how this rule works:

  • Groups events with username ($user) and returns it ($user) when a match is found.
  • Timespan is 5 minutes, meaning only events that are less than 5 minutes apart are correlated.
  • Searching for an event group ($udm) whose event type is USER_LOGIN.
  • For that event group, the rule calls the user id as $user and the login city as $city.
  • Returns a match if the distinct number of $city values is greater than 1 in the event group ($udm) within the 5 minute time range.

Rapid user creation and deletion

The following rule searches for users that have been created and then deleted within 4 hours:

rule UserCreationThenDeletion {
  meta:

  events:
    $create.target.user.userid = $user
    $create.metadata.event_type = "USER_CREATION"

    $delete.target.user.userid = $user
    $delete.metadata.event_type = "USER_DELETION"

    $create.metadata.event_timestamp.seconds <=
       $delete.metadata.event_timestamp.seconds

  match:
    $user over 4h

  condition:
    $create and $delete
}

Event variables:$create and $delete

Match variable: $user

Placeholder variable: N/A

The following describes how this rule works:

  • Groups events with username ($user) and returns it ($user) when a match is found.
  • Time window is 4 hours, meaning only events separated by less than 4 hours are correlated.
  • Searches for two event groups ($create and $delete, where $create is equivalent to #create >= 1).
  • $create corresponds to USER_CREATION events and calls the user id as $user.
  • $user is used to join the two groups of events together.
  • $delete corresponds to USER_DELETION events and calls the user id as $user. This rule looks for a match where the user identifier in the two event groups is the same.
  • This rule looks for cases where the event from $delete happens later than the event from $create, returning a match when discovered.

Single event rule

Single event rules are rules that correlate over a single event. A single event rule can be:

  • Any rule without a match section.
  • Rule with a match section and a condition section only checking for the existence of 1 event (for example, "$e", "#e > 0", "#e >= 1", "1 <= #e", "0 < #e").

For example, the following rule simply searches for a user login event and would return the first one it encounters within the enterprise data stored within your Chronicle account:

rule SingleEventRule {
  meta:
    author = "noone@altostrat.com"

  events:
    $e.metadata.event_type = "USER_LOGIN"

  condition:
    $e
}

Here is another example of a single event rule with a match section. This rule searches for a user who has logged in at least once in less than 5 minutes. It checks for the simple existence of a user login event.

rule SingleEventRule {
  meta:
    author = "noone@google.com"
    description = "windowed single event example rule"

  events:
    $e.metadata.event_type = "USER_LOGIN"
    $e.principal.user.userid = $user

  match:
    $user over 5m

  condition:
    #e > 0
}

Multiple event rule

Use multiple event rules to group many events over a specified time window and try to find correlations between events. A typical multiple event rule will have the following:

  • Match section which specifies the time range over which events need to be grouped.
  • Condition section specifying what condition should trigger the detection and checking for the existence of multiple events.

For example, the following rule searches for a user who has logged in at least 10 times in less than 10 minutes:

rule MultiEventRule {
  meta:
    author = "noone@altostrat.com"

  events:
    $e.metadata.event_type = "USER_LOGIN"
    $e.principal.user.userid = $user

  match:
    $user over 10m

  condition:
    #e >= 10
}

Single event within range of IP addresses

The following example shows a single event rule searching for a match between two specific users and a specific range of IP addresses:

rule OrsAndNetworkRange {
  meta:
    author = "noone@altostrat.com"

  events:
    // Checks CIDR ranges.
    net.ip_in_range_cidr($e.principal.ip, "203.0.113.0/24")

    // Detection when the hostname field matches either value using or.
    $e.principal.hostname = /pbateman/ or $e.principal.hostname = /sspade/

  condition:
    $e
}

any and all rule example

The following rule searches for login events where all source IP addresses do not match an IP address known to be secure within a timespan of 5 minutes.

rule SuspiciousIPLogins {
  meta:
    author = "noone@google.com"

  events:
    $e.metadata.event_type = "USER_LOGIN"

    // Detects if all source IP addresses in an event do not match "100.97.16.0"
    // For example, if an event has source IP addresses
    // ["100.97.16.1", "100.97.16.2", "100.97.16.3"],
    // it will be detected since "100.97.16.1", "100.97.16.2",
    // and "100.97.16.3" all do not match "100.97.16.0".

    all $e.principal.ip != "100.97.16.0"

    // Assigns placeholder variable $ip to the $e.principal.ip repeated field.
    // There will be one detection per source IP address.
    // For example, if an event has source IP addresses
    // ["100.97.16.1", "100.97.16.2", "100.97.16.3"],
    // there will be one detection per address.

    $e.principal.ip = $ip

  match:
    $ip over 5m

  condition:
    $e
}

Regular expressions in a rule

The following YARA-L 2.0 regular expression example searches for events with emails received from the altostrat.com domain. Since nocase has been added to the $host variable regex comparison and the regex function, both these comparisons are case insensitive.

rule RegexRuleExample {
  meta:
    author = "noone@altostrat.com"

  events:
    $e.principal.hostname = $host
    $host = /.*HoSt.*/ nocase
    re.regex($e.network.email.from, `.*altostrat\.com`) nocase

  match:
    $host over 10m

  condition:
    #e > 10
}

Sliding window rule example

The following YARA-L 2.0 sliding window example searches for the absence of firewall_2 events after firewall_1 events. The after keyword is used with the pivot event variable $e1 to specify that only 10 minute windows after each firewall_1 event should be checked when correlating events.

rule SlidingWindowRuleExample {
  meta:
    author = "noone@google.com"

  events:
    $e1.metadata.product_name = "firewall_1"
    $e1.principal.hostname = $host

    $e2.metadata.product_name = "firewall_2"
    $e2.principal.hostname = $host

  match:
    $host over 10m after $e1

  condition:
    $e1 and !$e2
}

Zero value exclusion example

If the rule does not specify allow_zero_values options, zero values are not returned from match variable values. However, for other referenced event fields, zero values are not excluded unless you explicitly specify such conditions. See here for more details.

rule ExcludeZeroValues {
  meta:
    author = "noone@google.com"

  events:
    $e1.metadata.event_type = "NETWORK_DNS"
    $e1.principal.hostname = $hostname

    // $e1.principal.user.userid may be empty string.
    $e1.principal.user.userid != "Guest"

    $e2.metadata.event_type = "NETWORK_HTTP"
    $e2.principal.hostname = $hostname

    // $e2.target.asset_id cannot be empty string as explicitly specified.
    $e2.target.asset_id != ""

  match:
    // $hostname cannot be empty string.
    $hostname over 1h

  condition:
    $e1 and $e2
}

Rule with outcome section example

You can add the optional outcome section in YARA-L 2.0 rule to extract additional information of each detection. In the condition section, you can also specify conditionals on outcome variables.

For more information, see the following:

Multi-event rule with outcome section:

rule OutcomeRuleMultiEvent {
    meta:
      author = "noone@google.com"
    events:
      $u.udm.principal.hostname = $hostname
      $asset_context.graph.entity.hostname = $hostname

      $severity = $asset_context.graph.entity.asset.vulnerabilities.severity

    match:
      $hostname over 5m

    outcome:
      $risk_score =
        max(
            100
          + if($hostname = "my-hostname", 100, 50)
          + if($severity = "HIGH", 10)
          + if($severity = "MEDIUM", 5)
          + if($severity = "LOW", 1)
        )

      $asset_id_list =
        array(
          if($u.principal.asset_id = "",
             "Empty asset id",
             $u.principal.asset_id
          )
        )

      $asset_id_distinct_list = array_distinct($u.principal.asset_id)

      $asset_id_count = count($u.principal.asset_id)

      $asset_id_distinct_count = count_distinct($u.principal.asset_id)

    condition:
      $u and $asset_context and $risk_score > 50 and not arrays.contains($asset_id_list, "id_1234")
}

Single-event rule with outcome section:

rule OutcomeRuleSingleEvent {
    meta:
        author = "noone@google.com"
    events:
        $u.metadata.event_type = "FILE_COPY"
        $u.principal.file.size = $file_size
        $u.principal.hostname = $hostname

    outcome:
        $suspicious_host = $hostname
        $severity_tag = if($file_size > 1024, "SEVERE", "MODERATE")

    condition:
        $u
}