Exemplos: consultas da YARA-L 2.0

Compatível com:

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

Regras e ajuste

A regra a seguir verifica padrões específicos nos dados de eventos e cria uma detecção se os encontra. Essa regra inclui uma variável $e1 para rastrear o tipo de evento e o campo metadata.event_type da UDM. 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 é 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 cidades diferentes

A regra a seguir procura 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 de evento:$udm

Variável de marcador: $city e $user

A seguir, descrevemos como essa regra funciona:

  • Agrupa eventos com nome de usuário ($user) e o retorna ($user) quando uma correspondência é encontrada.
  • O período é de 5 minutos, ou seja, 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) dentro do período de cinco minutos.

Criação e exclusão rápidas 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 de substituição: N/A

A seguir, descrevemos como essa regra funciona:

  • Agrupa eventos com nome de usuário ($user) e o retorna ($user) quando uma correspondência é encontrada.
  • O período é de 4 horas, ou seja, apenas eventos separados por 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 de usuário nos dois grupos de eventos seja o mesmo.
  • Essa regra procura casos em que o evento de $delete acontece depois do evento de $create, retornando uma correspondência quando descoberta.

Regra de evento único

As regras de evento único são aquelas que fazem correlação em 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 procura um evento de login do usuário e retorna o primeiro que encontra nos dados corporativos armazenados na sua conta do Google SecOps:

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

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

  condition:
    $e
}

Este exemplo mostra uma regra de evento único que usa a seção match para encontrar qualquer usuário com pelo menos um evento de login em um período de cinco minutos.Ela verifica a existência 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
}

Várias regras de evento

Use várias regras de evento para agrupar muitos eventos em um período especificado e tente encontrar correlações entre eles. Uma regra de vários eventos típica tem o seguinte:

  • Uma seção match que especifica o período em que os eventos precisam ser agrupados.
  • Uma seção condition que especifica qual condição deve acionar a detecção e verifica 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 em um intervalo de endereços IP

O exemplo a seguir mostra uma única regra de evento que procura correspondências entre dois nomes de host 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 "any" e "all"

A regra a seguir procura eventos de login em que todos os endereços IP de origem não correspondem a um endereço IP conhecido como seguro em um período de 5 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 da variável $host regex e à função regex, as 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
}

Exemplos de regras compostas

As detecções compostas melhoram a detecção de ameaças usando regras compostas. Essas regras compostas usam detecções de outras regras como entrada. Isso permite a detecção de ameaças complexas que regras individuais talvez não detectem. Para mais informações, consulte Visão geral das detecções compostas.

Detecções de tripwire

As detecções compostas de tripwire são a forma mais simples de detecção composta que opera em campos dentro de descobertas de detecção, como variáveis de resultado ou metadados de regra. Elas ajudam a filtrar detecções de condições que podem indicar maior risco, como um usuário administrador ou um ambiente de produção.

rule composite_admin_detection {
  meta:
    rule_name = "Detection with Admin User"
    author = "Google Cloud Security"
    description = "Composite rule that looks for any detections where the actor is an admin user"
    severity = "Medium"

  events:
    $rule_name = $d.detection.detection.rule_name
    $principal_user = $d.detection.detection.outcomes["principal_users"]
    $principal_user = /admin|root/ nocase

  match:
    $principal_user over 1h

  outcome:
    $risk_score = 75
    $upstream_rules = array_distinct($rule_name)

  condition:
    $d
}

Detecções de limite e agregação

Com as regras de detecção agregada, é possível agrupar descobertas de detecção com base em atributos compartilhados, como um nome de host ou de usuário, e analisar os dados agregados. Confira alguns casos de uso comuns:

  • Identificar usuários que geram um grande volume de alertas de segurança ou risco agregado.
  • Detectar hosts com padrões de atividade incomuns agregando detecções relacionadas.

Exemplo de agregação de risco

rule composite_risk_aggregation {
  meta:
    rule_name = "Risk Aggregation Composite"
    author = "Google Cloud Security"
    description = "Composite detection that aggregates risk of a user over 48 hours"
    severity = "High"

  events:
    $rule_name = $d.detection.detection.rule_name
    $principal_user = $d.detection.detection.outcomes["principal_users"]
    $risk = $d.detection.detection.risk_score

  match:
    $principal_user over 48h

  outcome:
    $risk_score = 90
    $cumulative_risk = sum($risk)
    $principal_users = array_distinct($principal_users)
    $upstream_rules = array_distinct($rule_name)

  condition:
    $d and $cumulative_risk > 500
}

Exemplo de agregação de táticas

rule composite_tactic_aggregation {
  meta:
    rule_name = "MITRE Tactic Aggregation Composite"
    author = "Google Cloud Security"
    description = "Composite detection that detects if a user has triggered detections over multiple mitre tactics."
    severity = "Medium"

  events:
    $principal_user = $d.detection.detection.outcomes["principal_users"]
    $tactic = $d.detection.detection.rule_labels["tactic"]
    $rule_name = $d.detection.detection.rule_name

  match:
    $principal_user over 48h

  outcome:
    $mitre_tactics_count = count_distinct($tactic)
    $mitre_tactics = array_distinct($d.detection.rule_labels["tactic"])
    $risk_score = min(100, (50+15*$mitre_tactics_count))
    $upstream_rules = array_distinct($rule_name)

  condition:
    $d and $mitre_tactics_count > 1
}

Detecções compostas sequenciais

As detecções compostas sequenciais identificam padrões de eventos relacionados em que a sequência de detecções é importante, como uma tentativa de login por força bruta seguida de um login bem-sucedido. Esses padrões podem envolver várias detecções básicas ou uma combinação de detecções básicas e eventos.

rule composite_bruteforce_login {
  meta:
    rule_name = "Bruteforce Login Composite"
    author = "Google Cloud Security"
    description = "Detects when an IP address associated with a Workspace brute force attempt successfully logs in"
    severity = "High"

  events:
    $bruteforce_detection.detection.detection.rule_name = /Workspace Anomalous Failed Logins/
    $bruteforce_ip = $d.detection.detection.outcomes["principal_ips"]

    $login_event.metadata.product_name = "login"
    $login_event.metadata.product_event_type = "login_success"
    $login_event.metadata.vendor_name = "Google Workspace"
    $login_ip = $login_event.principal.ip

    // Ensure the brute force detection and successful login occurred from the same IP
    $login_ip = $bruteforce_ip

    $target_account = $login_event.target.user.email_addresses

    // Ensure the brute force detection occurred before the successful login
    $bruteforce_detection.detection.detection_time.seconds < $login_event.metadata.event_timestamp.seconds

  match:
    $bruteforce_ip over 24h

  outcome:
    $risk_score = 90
    $principal_users = array_distinct($target_account)

  condition:
    $bruteforce_detection and $login_event
}

Detecções com base no contexto

As detecções compostas com reconhecimento de contexto enriquecem as detecções com mais contexto, como endereços IP encontrados em feeds de ameaças.

rule composite_tor_enrichment {
  meta:
    rule_name = "Detection with IP from TOR Feed"
    author = "Google Cloud Security"
    description = "Adds additional context from the TOR intel feed to detections"
    severity = "High"

  events:
    $detection_ip = $d.detection.detection.outcomes["principal_ips"]
    $gcti.graph.metadata.entity_type = "IP_ADDRESS"
    $gcti.graph.metadata.vendor_name = "Google Cloud Threat Intelligence"
    $gcti_feed.graph.metadata.source_type = "GLOBAL_CONTEXT"
    $gcti.graph.metadata.product_name = "GCTI Feed"
    $gcti.graph.metadata.threat.threat_feed_name = "Tor Exit Nodes"

    $detection_ip = $gcti.graph.entity.ip

    $rule_name = $d.detection.detection.rule_name
    $risk = $d.detection.detection.outcomes["risk_score"]

  match:
    $detection_ip, $rule_name over 1h

  outcome:
    $risk_score = 80
    $upstream_rule = array_distinct($rule_name)

  condition:
    $d and $gcti
}

Detecções de coocorrência

As detecções compostas de coocorrência são uma forma de agregação que pode detectar uma combinação de eventos relacionados, como uma combinação de escalonamento de privilégios e detecções de exfiltração de dados acionadas por um usuário.

rule composite_privesc_exfil_sequential {
  meta:
    rule_name = "Privilege Escalation and Exfiltration Composite"
    author = "Google Cloud Security"
    description = "Looks for a detection sequence of privilege escalation followed by exfiltration."
    severity = "High"

  events:
    $privilege_escalation.detection.detection.rule_labels["tactic"] = "TA0004"
    $exfiltration.detection.detection.rule_labels["tactic"] = "TA0010"

    $pe_user = $privilege_escalation.detection.detection.outcomes["principal_users"]
    $ex_user = $exfiltration.detection.detection.outcomes["principal_users"]

    $pe_user = $ex_user

  match:
    $pe_user over 48h

  outcome:
    $risk_score = 75
    $privesc_rules = array_distinct($privilege_escalation.detection.detection.rule_name)
    $exfil_rules = array_distinct($exfiltration.detection.detection.rule_name)

  condition:
    $privilege_escalation and $exfiltration
}

Exemplo de regra de janela deslizante

O exemplo de janela deslizante do YARA-L 2.0 a seguir procura a ausência de eventos firewall_2 após eventos firewall_1. A palavra-chave after é usada com a variável de evento de pivô $e1 para especificar que apenas janelas de 10 minutos após cada evento firewall_1 devem 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 mecanismo de regras filtra implicitamente os valores zero de todos os marcadores de posição usados na seção match. Use a opção allow_zero_values para desativar. Para mais informações, consulte Valores zero na seção de correspondência.

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

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 seção outcome

É possível adicionar a seção opcional outcome em uma 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. Use 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 analisados.

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

Regra de vários eventos com seção outcome

A regra a seguir analisa dois eventos para extrair o valor de $hostname. Se o valor de $hostname corresponder por um período de 5 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 outcome

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 (sem uma seção match) e de vários eventos (com uma seção match). Se você criou uma regra para ser multievento apenas para usar a seção de resultado, é possível refatorar essas regras excluindo a seção match para melhorar a performance. Como sua regra não tem mais uma seção match que aplica o agrupamento, você pode receber mais detecções. Essa refatoração só é possível para regras que usam uma variável de evento, como mostrado no exemplo a seguir.

Regra de resultado de vários eventos que usa apenas uma variável de evento (uma boa candidata a 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
}

Para refatorar a regra, exclua a seção match. Também é necessário remover o agregado da seção outcome, já que a regra agora será de 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 função para regra de marcador

Você pode atribuir uma variável de marcador de posição ao resultado de uma chamada de função e usar essa variável em outras seções da regra, como 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
}

Exemplo de regra condicional de resultado

Na seção condition, você pode usar variáveis de resultado 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
}

Precisa de mais ajuda? Receba respostas de membros da comunidade e profissionais do Google SecOps.