Expressões, operadores e outras construções

Compatível com:

Este documento inclui informações para ajudar você a criar regras e consultas YARA-L usando expressões.

Expressões booleanas

As expressões booleanas são expressões com um tipo booleano, que inclui expressões de comparação, expressões de função e expressões de lista de referência ou tabela de dados. É possível usar expressões booleanas na seção events e outcome em uma regra ou consulta da YARA-L.

Expressões de comparação

As expressões de comparação são aquelas que aplicam um operador de comparação a duas expressões. As expressões podem ser campos de eventos, variáveis, literais ou expressões de função.

Exemplo: expressões de comparação

$e.source.hostname = "host1234"
$e.source.port < 1024
1024 < $e.source.port
$e1.source.hostname != $e2.target.hostname
$e1.metadata.collected_timestamp.seconds > $e2.metadata.collected_timestamp.seconds
$port >= 25
$host = $e2.target.hostname
"google-test" = strings.concat($e.principal.hostname, "-test")
"email@google.org" = re.replace($e.network.email.from, "com", "org")

Expressões de função

Algumas expressões de função retornam um valor booleano, que pode ser usado como um predicado individual na seção events, como:

re.regex()

net.ip_in_range_cidr()

Exemplo: expressões de função

re.regex($e.principal.hostname, `.*\.google\.com`)
net.ip_in_range_cidr($e.principal.ip, "192.0.2.0/24")

Lista de referência ou tabela de dados

Você pode usar listas de referência ou tabelas de dados nas seções events ou outcome. Consulte Listas de referência e Usar tabelas de dados para mais informações sobre o comportamento e a sintaxe das listas de referência e das tabelas de dados.

Exemplo: sintaxe para listas de referência

Os exemplos a seguir mostram a sintaxe de vários tipos de listas de referência em uma consulta:

// STRING reference list
$e.principal.hostname in %string_reference_list

// REGEX reference list
$e.principal.hostname in regex %regex_reference_list

// CIDR reference list
$e.principal.ip in cidr %cidr_reference_list

Exemplo: sintaxe para tabelas de dados

// STRING data table
$e.target.hostname in %data_table_name.column_name

// REGEX data table
$e.target.hostname in regex %regex_table_name.column_name

// CIDR data table
$e.principal.ip in cidr %cidr_table_name.column_name

Exemplo: use not e nocase na sintaxe de listas de referência

// Exclude events whose hostnames match substrings in my_regex_list.
not $e.principal.hostname in regex %my_regex_list

// Event hostnames must match at least 1 string in my_string_list (case insensitive).
$e.principal.hostname in %my_string_list nocase

O operador nocase é compatível com listas STRING e REGEX.

Por motivos de desempenho, o uso de listas de referência e tabelas de dados tem as seguintes limitações:

  • Número máximo de instruções in em uma consulta, com ou sem operadores especiais: 7
  • Número máximo de instruções in com o operador regex: 4
  • Número máximo de instruções in com o operador cidr: 2

Expressões lógicas

É possível usar os operadores lógicos and e or na seção events.

Exemplo: expressões lógicas

$e.metadata.event_type = "NETWORK_DNS" or $e.metadata.event_type = "NETWORK_DHCP"
($e.metadata.event_type = "NETWORK_DNS" and $e.principal.ip = "192.0.2.12") or ($e.metadata.event_type = "NETWORK_DHCP" and $e.principal.mac = "AB:CD:01:10:EF:22")
not $e.metadata.event_type = "NETWORK_DNS"

Por padrão, a ordem de precedência do mais alto para o mais baixo é not, and, or. Por exemplo, "a or b and c" é avaliado como "a or (b and c)" quando os operadores or e and são definidos explicitamente na expressão.

Na seção events, os predicados são unidos usando o operador and se um operador não for definido explicitamente. A ordem de avaliação pode ser diferente se o operador and estiver implícito na expressão. Considere as seguintes expressões de comparação em que or é definido explicitamente e o operador and está implícito.

$e1.field = "bat"
or $e1.field = "baz" 
$e2.field = "bar"

Ela é interpretada da seguinte forma:

($e1.field = "bat" or $e1.field = "baz")
and ($e2.field = "bar")

Como or é definido explicitamente, os predicados ao redor são agrupados e avaliados primeiro. O último predicado, $e2.field = "bar". é unido implicitamente usando and. O resultado é que a ordem de avaliação muda.

Tipos enumerados

É possível usar os operadores com tipos enumerados. Ele pode ser aplicado a regras para simplificar e otimizar a performance (use o operador em vez de listas de referência).

No exemplo a seguir, "USER_UNCATEGORIZED" e "USER_RESOURCE_DELETION" correspondem a 15000 e 15014. Portanto, a regra vai procurar todos os eventos listados:

$e.metadata.event_type >= "USER_CATEGORIZED" and $e.metadata.event_type <= "USER_RESOURCE_DELETION"

Modificador nocase

Para ignorar o uso de maiúsculas em uma expressão de comparação entre valores de string ou uma expressão regular, adicione nocase ao final da expressão, conforme mostrado nos exemplos a seguir.

Exemplo: modificador nocase

$e.principal.hostname != "http-server" nocase
$e1.principal.hostname = $e2.target.hostname nocase
$e.principal.hostname = /dns-server-[0-9]+/ nocase
re.regex($e.target.hostname, `client-[0-9]+`) nocase

O modificador nocase não pode ser usado quando o tipo de campo é um valor enumerado. Os exemplos a seguir são inválidos e vão gerar erros de compilação:

$e.metadata.event_type = "NETWORK_DNS" nocase
$e.network.ip_protocol = "TCP" nocase

Comentários

Os comentários podem ser usados em consultas para fornecer mais informações. Use a barra para indicar um comentário:

  • Para um comentário de uma só linha, use duas barras (// comment).
  • Para um comentário de várias linhas, use o caractere de barra e o caractere de asterisco (/* comment */).

Literais

A YARA-L é compatível com números inteiros e de ponto flutuante não negativos, strings, booleanos e literais de expressões regulares. Os literais são valores fixos usados em condições de consulta. A YARA-L também usa outras construções semelhantes a literais, como expressões regulares (entre barras) para correspondência de padrões e booleanos (verdadeiro/falso) para lógica.

Literais de strings

Os literais de string são sequências de caracteres entre aspas duplas (") ou crases (`). A string é interpretada de maneira diferente, dependendo do tipo de aspas usado:

  • Aspas duplas ("hello\tworld"): use para strings normais. Os caracteres de escape precisam ser incluídos, em que \t é interpretado como uma tabulação.
  • Aspas graves (`hello\tworld`): use quando todos os caracteres precisarem ser interpretados literalmente, em que \t não é interpretado como uma tabulação.

Literais de expressão regular

Para literais de expressão regular, você tem duas opções:

  • Se você quiser usar expressões regulares diretamente sem a função re.regex(), use /regex/ para os literais de expressão regular.

  • Se você quiser usar literais de string como literais de expressão regular, use a função re.regex(). Para literais de string com aspas duplas, é necessário usar caracteres de escape com barra invertida, o que pode parecer estranho.

Os exemplos a seguir mostram expressões regulares equivalentes:

re.regex($e.network.email.from, `.*altostrat\.com`)

re.regex($e.network.email.from, ".*altostrat\\.com")

$e.network.email.from = /.*altostrat\.com/

O Google recomenda usar caracteres de crase para strings em expressões regulares para facilitar a leitura.

Operadores

Operador Descrição
= equal/declaration
!= diferente
< menor que
<= menor ou igual a
> maior que
>= maior ou igual a

Variáveis

Em YARA-L, todas as variáveis usam a sintaxe $<variable name>. Os seguintes tipos de variáveis podem ser usados em YARA-L.

Variáveis de evento

As variáveis de evento representam grupos de eventos ou eventos de entidade. Você especifica condições para variáveis de evento na seção events usando um nome, uma origem e campos de evento.

  • As origens de eventos são udm (para eventos normalizados) e graph (para eventos de entidade). Se a origem for omitida, udm será definida como a origem padrão.

  • Os campos de evento são representados como uma cadeia de .<nome do campo> (por exemplo, $e.field1.field2), e as cadeias de campos sempre começam na origem de nível superior (UDM ou entidade).

Variáveis de correspondência

As variáveis de correspondência são usadas na seção match para agrupar eventos com base em valores comuns em uma janela de tempo especificada.

Eles se tornam campos de agrupamento para a consulta, já que uma linha é retornada para cada conjunto exclusivo de variáveis de correspondência (e para cada período). Quando a consulta encontra uma correspondência, os valores das variáveis de correspondência são retornados.

Você especifica o que cada variável de correspondência representa na seção events.

Variáveis de marcador

As variáveis de substituição são usadas para capturar e armazenar valores específicos de campos de eventos da UDM para serem referenciados e usados em uma consulta. Eles são usados para vincular eventos diferentes, principalmente em consultas com vários eventos. Ao atribuir um valor comum (por exemplo, um userid ou hostname) a um marcador de posição, você pode usar esse marcador na seção match para agrupar eventos que compartilham esse valor em um período especificado.

Você define variáveis de marcador de posição na seção events atribuindo o valor de um campo da UDM a um nome de variável com o prefixo $ (por exemplo: $targetUser = $e.target.user.userid).

Você também pode definir variáveis de marcador de posição nas seguintes seções:

  • Seção condition para especificar condições de correspondência.
  • outcome para fazer cálculos, definir métricas ou extrair pontos de dados específicos dos eventos correspondentes.
  • match para agrupar eventos por valores comuns.

Palavras-chave

Em YARA-L, as palavras-chave são palavras reservadas que definem a estrutura e a lógica de uma consulta de detecção. Elas são usadas para especificar diferentes seções de uma consulta, realizar operações lógicas e matemáticas e definir condições para eventos correspondentes. Essas palavras-chave não podem ser usadas como identificadores para consultas, strings ou variáveis.

As palavras-chave não diferenciam maiúsculas de minúsculas. Por exemplo, and e AND são equivalentes.

Principais categorias de palavras-chave da YARA-L 2.0

Essa lista não é exaustiva, mas inclui as principais palavras-chave usadas na YARA-L 2.0 para criar consultas de detecção robustas.

  • Definição da consulta:
    • rule: inicia a definição de uma nova consulta YARA-L.
    • private: designa uma consulta como particular, impedindo que ela seja exposta diretamente ou acionada externamente.
    • global: marca uma consulta como global, indicando que ela deve ser aplicada de maneira geral.
  • Seções de consulta:
    • meta: apresenta a seção de metadados com informações descritivas sobre a consulta.
    • strings: indica a seção em que os padrões de string são definidos.
    • condition: especifica a seção que contém a lógica booleana para acionamento de consultas.
    • events: define a seção para especificar variáveis de evento e as condições delas.
    • match: apresenta a seção para agregar valores em um intervalo de tempo.
    • outcome: define a seção para adicionar contexto e pontuação às consultas acionadas.
  • Modificadores de string:
    • ascii: especifica que uma string deve ser correspondida como texto ASCII.
    • wide: indica que uma string deve ser correspondida como caracteres largos (UTF-16).
    • nocase: realiza uma correspondência de string que não diferencia maiúsculas de minúsculas.
    • fullword: exige que a string corresponda a uma palavra completa.
    • xor: aplica a transformação XOR à string antes da correspondência.
    • base64, base64wide: aplica a codificação Base64 antes da correspondência.
  • Operadores lógicos:
    • and, or, not: operadores lógicos booleanos padrão para combinar condições.
    • all of, any of: usado para avaliar várias expressões em uma condição.
  • Operadores de comparação e relacionais:
    • at: especifica um deslocamento exato para a correspondência de strings.
    • contains: verifica se uma string contém uma substring.
    • startswith, endswith: verifica se uma string começa ou termina com uma substring.
    • icontains, istartswith, iendswith, iequals: versões sem diferenciação de maiúsculas e minúsculas.
    • matches: usado para correspondência de expressões regulares.
  • Tipos de dados e especificadores de tamanho:
    • int8, uint8, int16, uint16, int32, uint32: tipos de números inteiros com tamanhos especificados.
    • int8be, uint8be, int16be, uint16be, int32be, uint32be: versões big-endian de tipos de números inteiros.
    • filesize: representa o tamanho do arquivo que está sendo analisado.
    • entrypoint: refere-se ao ponto de entrada de um executável.

Maps

O YARA-L é compatível com mapas para os tipos de dados Struct e Label, que são usados em alguns campos do UDM.

Para pesquisar um par de chave-valor específico nos tipos de dados Struct e Label, use a sintaxe de mapa padrão:

  • Sintaxe de campo de struct: $e.udm.additional.fields["pod_name"] = "kube-scheduler"
  • Sintaxe do campo de marcador: $e.metadata.ingestion_labels["MetadataKeyDeletion"] = "startup-script"

Exemplo: uso válido e inválido de mapas

Os exemplos a seguir mostram usos válidos e inválidos de mapas.

Uso válido de mapas

Usando um campo de estrutura na seção de eventos:

events:
  $e.udm.additional.fields["pod_name"] = "kube-scheduler"
  

Usar um campo de marcador na seção de resultados:

outcome:
  $value = array_distinct($e.metadata.ingestion_labels["MetadataKeyDeletion"])
 

Atribuir um valor de mapa a um marcador de posição:

$placeholder = $u1.metadata.ingestion_labels["MetadataKeyDeletion"]

Usar um campo de mapa em uma condição de junção:

// using a Struct field in a join condition between two udm events $u1 and $u2
$u1.metadata.event_type = $u2.udm.additional.fields["pod_name"]

Uso não compatível de mapas

Como combinar palavras-chave any ou all com um mapa

all $e.udm.additional.fields["pod_name"] = "kube-scheduler"

Outros tipos de valores

A sintaxe de mapa só pode retornar um valor de string. No caso de tipos de dados [Struct](https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#struct), a sintaxe de mapa só pode acessar chaves cujos valores são strings. Não é possível acessar chaves cujos valores são outros tipos primitivos, como números inteiros.

Como lidar com valores duplicados em mapas

O acesso ao mapa tem como objetivo recuperar um único valor associado a uma chave específica. Esse é o comportamento padrão e esperado. No entanto, em situações raras e incomuns, o contexto do map access pode apontar inadvertidamente para vários valores. No caso incomum em que o acesso ao mapa se refere a vários valores, map access retorna deterministicamente o primeiro valor. Isso pode acontecer se um rótulo tiver uma chave duplicada ou um campo repetido ancestral.

O identificador tem uma chave duplicada

A estrutura do rótulo representa um mapa, mas não exige exclusividade de chave. Por convenção, um mapa precisa ter chaves exclusivas. Por isso, o Google SecOps não recomenda preencher um rótulo com chaves duplicadas.

Exemplo: rótulo com chave duplicada

O texto da consulta $e.metadata.ingestion_labels["dupe-key"] retornaria o primeiro valor possível, val1, se executado no exemplo de dados a seguir:

    // Disrecommended usage of label with a duplicate key:
    event {
      metadata{
        ingestion_labels{
          key: "dupe-key"
          value: "val1" // This is the first possible value for "dupe-key"
        }
        ingestion_labels{
          key: "dupe-key"
          value: "val2"
        }
      }
    }
  

O rótulo tem um campo repetido ancestral

Um campo repetido pode conter um rótulo como um campo filho. Duas entradas diferentes no campo repetido de nível superior podem conter rótulos com a mesma chave.

Exemplo: rótulo com campo repetido de ancestral

O texto da consulta $e.security_result.rule_labels["key"] retornaria o primeiro valor possível, "val3", se executado no exemplo de dados a seguir:

    event {
      // security_result is a repeated field.
      security_result {
        threat_name: "threat1"
        rule_labels {
          key: "key"
          value: "val3" // This is the first possible value for "key"
        }
      }
      security_result {
        threat_name: "threat2"
        rule_labels {
          key: "key"
          value: "val4"
        }
      }
    }
  

Acessar variáveis de resultado em mapas

Esta seção explica como acessar variáveis de resultado em mapas como os tipos de dados originais (por exemplo, números inteiros, booleanos ou listas desses tipos) em vez de apenas strings. Você pode usar essa funcionalidade para ter mais flexibilidade e precisão na lógica de consulta.

Os dados de resultado estão disponíveis nos seguintes campos:

  • Os valores de resultado mantêm os tipos originais no campo variables.
  • O campo outcomes armazena versões string para compatibilidade com versões anteriores.

É possível acessar esses valores de resultado usando o mapa variables para recuperar o tipo específico ou acessar elementos em uma sequência usando a indexação de matriz. É possível acessar um item específico na sequência pelo índice ou selecionar a sequência inteira para avaliar cada valor individualmente.

Sintaxe:

$d.detection.detection.variables[OUTCOME_NAME].TYPE_SUFFIX

Sintaxe para sequências:

$d.detection.detection.variables[OUTCOME_NAME].SEQUENCE_TYPE_SUFFIX.TYPE_VALS_SUFFIX

Exemplos: acessar variáveis de resultado em mapas

Acessar um resultado de string:

    $my_string_outcome = $d.detection.detection.variables["outcome_ip"].string_val
   

Este exemplo recupera o valor da string diretamente (por exemplo, "1.1.1.1" se outcome_ip fosse uma única string).

Acessar um resultado inteiro

    $my_int_outcome = $d.detection.detection.variables["outcome_port"].int64_value
    

Este exemplo recupera o valor inteiro (por exemplo, 30).

Acessar uma lista de números inteiros usando Int64Sequence

   $my_int_list = $d.detection.detection.variables["outcome_ports"].int64_seq.int64_vals
   

Este exemplo recupera a lista completa de números inteiros e os desaninha como campos repetidos (por exemplo, [2, 3, 4]).

Acessar um elemento específico de uma lista de números inteiros

    $first_int = $d.detection.detection.variables["outcome_ports"].int64_seq.int64_vals[0]
    

Este exemplo recupera o primeiro número inteiro da lista (por exemplo, 2).

Acessar uma lista de strings (StringSequence)

    $my_string_list = $d.detection.detection.variables["outcome_ips"].string_seq.string_vals
    

Este exemplo recupera a lista completa de strings e as descompacta como campos repetidos (por exemplo, ["1.1.1.1", "2.2.2.2"]).

Acessar um elemento específico de uma lista de strings

    $first_ip = $d.detection.detection.variables["outcome_ips"].string_seq.string_vals[0]
    

Este exemplo recupera o primeiro endereço IP da lista (por exemplo, "1.1.1.1").

Sufixos de tipo disponíveis para variables

Para uma lista completa de sufixos compatíveis, consulte FindingVariable.

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