Visão geral da linguagem YARA-L 2.0

O YARA-L 2.0 é uma linguagem de computador usada para criar regras de pesquisa nos dados de registro da empresa conforme eles são ingeridos na instância do Chronicle. A sintaxe YARA-L é derivada da linguagem YARA desenvolvida pelo VirusTotal. A linguagem funciona em conjunto com o mecanismo de detecção do Chronicle e permite que você procure ameaças e outros eventos em grandes volumes de dados.

Para ver mais informações, consulte os seguintes tópicos:

Regras de exemplo do YARA-L 2.0

Os exemplos a seguir mostram regras escritas em YARA-L 2.0. Cada um demonstra como correlacionar eventos na linguagem das regras.

Regras e ajustes

A regra a seguir verifica se há padrões específicos nos dados de eventos e cria uma detecção caso os padrões sejam encontrados. Essa regra inclui uma variável $e1 para o tipo de evento de rastreamento e o campo UDM metadata.event_type. A regra verifica ocorrências específicas de correspondências de expressão regular com e1. Quando o evento $e1 ocorre, uma detecção é criada. Uma condição not é incluída na regra para excluir determinados caminhos não maliciosos. É possível adicionar condições not para evitar falsos positivos.

rule suspicious_unusual_location_svchost_execution
{

 meta:
   author = "Google Cloud Security"
   description = "Windows 'svchost' executed from an unusual location"
   yara_version = "YL2.0"
   rule_version = "1.0"

 events:

   $e1.metadata.event_type = "PROCESS_LAUNCH"
   re.regex($e1.principal.process.command_line, `\bsvchost(\.exe)?\b`) nocase
   not re.regex($e1.principal.process.command_line, `\\Windows\\System32\\`) nocase

condition:

   $e1
}

Logins de diferentes cidades

A regra a seguir pesquisa usuários que fizeram login na sua empresa em duas ou mais cidades em menos de cinco minutos:

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
}

Variável de correspondência: $user

Variável do evento:$udm

Variável de marcador: $city e $user

Confira a seguir como essa regra funciona:

  • Agrupa eventos com o nome de usuário ($user) e o retorna ($user) quando é encontrada uma correspondência.
  • O período é de cinco minutos, o que significa que apenas os eventos com menos de cinco minutos de diferença são correlacionados.
  • Pesquisar um grupo de eventos ($udm) com um tipo de evento USER_LOGIN.
  • Nesse grupo de eventos, a regra chama o ID do usuário como $user e a cidade de login como $city..
  • Retornará uma correspondência se o número distinto de valores city (indicados por #city) for maior que 1 no grupo de eventos ($udm) dentro do intervalo de tempo de 5 minutos.

Criação e exclusão rápidas de usuários

A regra a seguir pesquisa usuários que foram criados e excluídos no prazo de quatro horas:

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
}

Variáveis de evento:$create e $delete

Variável de correspondência: $user

Variável de marcador: N/A

Confira a seguir como essa regra funciona:

  • Agrupa eventos com o nome de usuário ($user) e o retorna ($user) quando é encontrada uma correspondência.
  • A janela de tempo é de quatro horas, o que significa que apenas os eventos separados por menos de quatro horas são correlacionados.
  • Pesquisa dois grupos de eventos ($create e $delete, em que $create é equivalente a #create >= 1).
  • $create corresponde a eventos de USER_CREATION e chama o ID do usuário como $user.
  • $user é usado para unir os dois grupos de eventos.
  • $delete corresponde a eventos de USER_DELETION e chama o ID do usuário como $user. Essa regra procura uma correspondência em que o identificador do usuário nos dois grupos de eventos seja o mesmo.
  • Esta regra procura casos em que o evento de $delete acontece depois do evento de $create e retorna uma correspondência quando descoberto.

Regra de evento único

As regras de evento único são regras relacionadas a um único evento. Uma regra de evento único pode ser:

  • Qualquer regra sem uma seção de correspondência.
  • Regra com uma seção match e uma seção condition que verifica apenas a existência de um evento (por exemplo, "$e", "#e > 0", "#e >= 1", "1 <= #e", "0 < #e").

Por exemplo, a regra a seguir pesquisa um evento de login de usuário e retornaria o primeiro que encontrar nos dados da empresa armazenados na sua conta do Chronicle:

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

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

  condition:
    $e
}

Veja outro exemplo de uma regra de evento único com uma seção de correspondência. Esta regra pesquisa um usuário que fez login pelo menos uma vez em menos de 5 minutos. Ele verifica a existência simples de um evento de login do usuário.

rule SingleEventRule {
  meta:
    author = "alice@example.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
}
rule MultiEventRule{
  meta:
    author = "alice@example.com"
    description = "Rule with outcome condition and simple existence condition on one event variable"

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

  match:
    $user over 10m

  outcome:
    $num_events_in_match_window = count($e.metadata.id)

  condition:
    #e > 0 and $num_events_in_match_window >= 10 // Could be rewritten as #e >= 10
}

Regra de vários eventos

Use várias regras de evento para agrupar muitos eventos em uma janela de tempo específica e tente encontrar correlações entre eventos. Uma regra de vários eventos típica terá o seguinte:

  • Uma seção match que especifica o período em que os eventos precisam ser agrupados.
  • Uma seção condition especificando qual condição acionará a detecção e a verificação da existência de vários eventos.

Por exemplo, a regra a seguir pesquisa um usuário que fez login pelo menos 10 vezes em menos de 10 minutos:

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
}

Evento único dentro do intervalo de endereços IP

O exemplo a seguir mostra uma única regra de evento que pesquisa uma correspondência entre dois usuários específicos e um intervalo específico de endereços IP:

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
}

exemplo de regra "qualquer"

A regra a seguir pesquisa eventos de login em que todos os endereços IP de origem não correspondem a um endereço IP considerado seguro em um período de cinco minutos.

rule SuspiciousIPLogins {
  meta:
    author = "alice@example.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
}

Expressões regulares em uma regra

O exemplo de expressão regular YARA-L 2.0 a seguir pesquisa eventos com e-mails recebidos do domínio altostrat.com. Como nocase foi adicionado à comparação regex da variável $host e à função regex, ambas as comparações não diferenciam maiúsculas de minúsculas.

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
}

Exemplo de regra de janela deslizante

O exemplo de janela deslizante YARA-L 2.0 a seguir pesquisa a ausência de eventos firewall_2 após eventos firewall_1. A palavra-chave after é usada com a variável de evento dinâmico $e1 para especificar que apenas janelas de 10 minutos após cada evento firewall_1 precisam ser verificadas ao correlacionar eventos.

rule SlidingWindowRuleExample {
  meta:
    author = "alice@example.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
}

Exemplo de exclusão de valor zero

O Rules Engine filtra implicitamente os valores zero para todos os marcadores usados na seção match. Para mais informações, consulte Processamento de valor zero na seção match. Isso pode ser desativado com a opção allow_zero_values, conforme descrito em allow_zero_values.

No entanto, para outros campos de evento referenciados, valores zero não serão excluídos, a menos que você especifique explicitamente essas condições.

rule ExcludeZeroValues {
  meta:
    author = "alice@example.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. The rule behaves as if the
    // predicate, `$hostname != ""` was added to the events section, because
    // `$hostname` is used in the match section.
    $hostname over 1h

  condition:
    $e1 and $e2
}

Regra com exemplo de seção outcome

É possível adicionar a seção outcome opcional na regra YARA-L 2.0 para extrair mais informações de cada detecção. Na seção de condição, também é possível especificar condicionais em variáveis de resultado. É possível usar a seção outcome de uma regra de detecção para definir variáveis para o consumo downstream. Por exemplo, é possível definir uma pontuação de gravidade com base nos dados dos eventos que estão sendo analisados.

Para ver mais informações, consulte os seguintes tópicos:

Regra de vários eventos com seção de resultados:

A regra a seguir analisa dois eventos para receber o valor de $hostname. Se o valor de $hostname corresponder a um período de cinco minutos, uma pontuação de gravidade será aplicada. Quando inclui um período na seção match, a regra verifica dentro do período especificado.

rule OutcomeRuleMultiEvent {
    meta:
      author = "Google Cloud Security"
    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")
}

rule OutcomeRuleMultiEvent {
    meta:
      author = "alice@example.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:
      $total_network_bytes = sum($u.network.sent_bytes) + sum($u.network.received_bytes)

      $risk_score = if(total_network_bytes > 1024, 100, 50) +
        max(
          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")
}

Regra de evento único com seção de resultados:

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

    outcome:
        $suspicious_host = $hostname
        $admin_severity = if($u.principal.userid in %admin_users, "SEVERE", "MODERATE")
        $severity_tag = if($file_size > 1024, $admin_severity, "LOW")

    condition:
        $u
}

Refatoração de uma regra de resultado de vários eventos em uma regra de resultado de evento único.

É possível usar a seção outcome para regras de evento único (regras sem uma seção match) e regras de vários eventos (regras com uma seção match). Se você já tiver projetado uma regra para ser de múltiplos eventos apenas para poder usar a seção de resultados, poderá refatorar essas regras excluindo a seção match para melhorar o desempenho. Esteja ciente de que, como sua regra não tem mais uma seção match que aplica o agrupamento, talvez você receba mais detecções. Essa refatoração só é possível para regras que usam uma variável de evento, conforme mostrado no exemplo a seguir.

Regra de resultado de vários eventos que usa apenas uma variável de evento (um bom candidato para refatoração):

rule OutcomeMultiEventPreRefactor {
    meta:
      author = "alice@example.com"
      description = "Outcome refactor rule, before the refactor"

    events:
      $u.udm.principal.hostname = $hostname

    match:
      $hostname over 5m

    outcome:
      $risk_score = max(if($hostname = "my-hostname", 100, 50))

    condition:
      $u
}

É possível refatorar a regra excluindo a seção match. Você também precisa remover a agregação na seção outcome, já que a regra agora será de um único evento. Para saber mais sobre agregações, consulte agregações de resultados.

rule OutcomeSingleEventPostRefactor {
    meta:
      author = "alice@example.com"
      description = "Outcome refactor rule, after the refactor"

    events:
      $u.udm.principal.hostname = $hostname

    // We deleted the match section.

    outcome:
      // We removed the max() aggregate.
      $risk_score = if($hostname = "my-hostname", 100, 50)

    condition:
      $u
}

Exemplo de regra de função para marcador de posição

É possível atribuir uma variável de marcador ao resultado de uma chamada de função e usar essa variável em outras seções da regra, como na seção match, outcome ou condition. Veja o exemplo a seguir:

rule FunctionToPlaceholderRule {
    meta:
      author = "alice@example.com"
      description = "Rule that uses function to placeholder assignments"

    events:
        $u.metadata.event_type = "EMAIL_TRANSACTION"

        // Use function-placeholder assignment to extract the
        // address from an email.
        // address@website.com -> address
        $email_to_address_only = re.capture($u.network.email.from , "(.*)@")

        // Use function-placeholder assignment to normalize an email:
        // uid@??? -> uid@company.com
        $email_from_normalized = strings.concat(
            re.capture($u.network.email.from , "(.*)@"),
            "@company.com"
        )

        // Use function-placeholder assignment to get the day of the week of the event.
        // 1 = Sunday, 7 = Saturday.
        $dayofweek = timestamp.get_day_of_week($u.metadata.event_timestamp.seconds)

    match:
        // Use placeholder (from function-placeholder assignment) in match section.
        // Group by the normalized from email, and expose it in the detection.
        $email_from_normalized over 5m

    outcome:
        // Use placeholder (from function-placeholder assignment) in outcome section.
        // Assign more risk if the event happened on weekend.
        $risk_score = max(
            if($dayofweek = 1, 10, 0) +
            if($dayofweek = 7, 10, 0)
        )

    condition:
        // Use placeholder (from function-placeholder assignment) in condition section.
        // Match if an email was sent to multiple addresses.
        #email_to_address_only > 1
}

Regra de exemplo de condicionais de resultado

Na seção condition, é possível usar variáveis de resultado que foram definidas na seção outcome. O exemplo a seguir demonstra como filtrar pontuações de risco para reduzir o ruído em detecções usando condicionais de resultado.

rule OutcomeConditionalRule {
    meta:
        author = "alice@example.com"
        description = "Rule that uses outcome conditionals"

    events:
        $u.metadata.event_type = "FILE_COPY"
        $u.principal.file.size = $file_size
        $u.principal.hostname = $hostname

        // 1 = Sunday, 7 = Saturday.
        $dayofweek = timestamp.get_day_of_week($u.metadata.collected_timestamp.seconds)

    outcome:
        $risk_score =
            if($file_size > 500*1024*1024, 2) + // Files 500MB are moderately risky
            if($file_size > 1024*1024*1024, 3) + // Files over 1G get assigned extra risk
            if($dayofweek=1 or $dayofweek=7, 4) + // Events from the weekend are suspicious
            if($hostname = /highly-privileged/, 5) // Check for files from highly privileged devices

    condition:
        $u and $risk_score >= 10
}