Visão geral da linguagem YARA-L 2.0

A 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 sua instância de Operações de segurança do Google. A sintaxe YARA-L é derivada da linguagem YARA desenvolvida pelo VirusTotal. A linguagem funciona em conjunto com o Google Security Operations Detection Engine e permite procurar ameaças e outros eventos em grandes volumes de dados.

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

Regras de exemplo da YARA-L 2.0

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

Regras e ajustes

A regra a seguir verifica padrões específicos em dados de eventos e cria uma detecção se os encontrar. Essa regra inclui uma variável $e1 para rastrear o tipo de evento e um campo de UDM metadata.event_type. A regra verifica ocorrências específicas de correspondências de expressões regulares com e1. Quando o evento $e1 ocorre, uma detecção é criada. Uma condição not está incluída na regra para excluir determinados caminhos não maliciosos. Você pode 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 procura usuários que tenham feito login em sua empresa em duas ou mais cidades em menos de 5 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 de evento:$udm

Variável do marcador de posição: $city e $user

Veja a seguir como essa regra funciona:

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

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

A regra a seguir pesquisa usuários que foram criados e excluídos em até 4 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 do marcador de posição: N/A

Veja a seguir como essa regra funciona:

  • Agrupa eventos com o nome de usuário ($user) e o retorna ($user) quando uma correspondência é encontrada.
  • A janela de tempo é de 4 horas, ou seja, apenas eventos com intervalos de menos de 4 horas são correlacionados.
  • Pesquisa dois grupos de eventos ($create e $delete, em que $create é equivalente a #create >= 1).
  • $create corresponde a eventos USER_CREATION e chama o ID do usuário como $user.
  • $user é usado para unir os dois grupos de eventos.
  • $delete corresponde a eventos 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, retornando uma correspondência quando descoberto.

Regra de evento único

Regras de evento único são regras que se correlacionam com um único evento. Uma única regra de evento 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 do usuário e retorna o primeiro encontrado nos dados corporativos armazenados na sua conta das Operações de segurança do Google:

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

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

  condition:
    $e
}

Este é outro exemplo de regra de evento único com uma seção de correspondência. Esta regra procura um usuário que tenha feito login pelo menos uma vez em menos de 5 minutos. Ele verifica a existência simples de um evento de login de 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

Usar várias regras de eventos para agrupar diversos eventos em um período específico e tentar encontrar correlações entre os eventos. Uma regra típica de vários eventos 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 verifique a 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 pesquisando 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 "todos"

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 conhecido por ser 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 da 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, essas duas 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 da 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 somente as janelas de 10 minutos após cada evento firewall_1 sejam 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 mecanismo de regras filtra implicitamente os valores zero para todos os marcadores usados na seção match. Para mais informações, consulte Processamento de valores zero na seção match. Ela pode ser desativada usando a opção allow_zero_values, conforme descrito em allow_zero_values.

No entanto, para outros campos de eventos referenciados, os valores zero não sã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
}

Exemplo de regra com outcome seção

É 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 "Condição", também é possível especificar condicionais nas variáveis de resultado. É possível usar a seção outcome de uma regra de detecção para definir variáveis para 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 conseguir o valor de $hostname. Se o valor de $hostname corresponder a um período de cinco minutos, uma pontuação de gravidade será aplicada. Ao incluir 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
}

Refatorar uma regra de resultado de vários eventos em uma regra de resultado de evento único.

Você pode usar a seção outcome para regras de evento único (regras sem uma seção match) e de vários eventos (regras com uma seção match). Se você já projetou uma regra para ser de vários eventos apenas para usar a seção de resultados, é possível 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 aplique agrupamento, você pode receber 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 uma 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 o agregado na seção outcome, já que a regra agora será um evento único. Para mais informações 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 de posição ao resultado de uma chamada de função e usá-la em outras seções da regra, como a 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 nas 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
}