Sintaxe da linguagem YARA-L 2.0

Esta seção descreve os principais elementos da sintaxe YARA-L. Consulte também Visão geral do idioma YARA-L 2.0.

Estrutura da regra

Para YARA-L 2.0, você precisa especificar declarações, definições e usos de variáveis na seguinte ordem:

  1. meta
  2. events
  3. match (opcional)
  4. resultado (opcional)
  5. condição
  6. opções (opcional)

Veja a seguir a estrutura genérica de uma regra:

rule <rule Name>
{
  meta:
    // Stores arbitrary key-value pairs of rule details, such as who wrote
    // it, what it detects on, version control, etc.

  events:
    // Conditions to filter events and the relationship between events.

  match:
    // Values to return when matches are found.

  outcome:
    // Additional information extracted from each detection.

  condition:
    // Condition to check events and the variables used to find matches.

  options:
    // Options to turn on or off while executing this rule.
}

Comentários

Use comentários com duas barras (// comment) ou com várias linhas para definir comentários com caracteres de asteriscos (/* comment */), como você faria em C.

Constantes

Constantes de números inteiros, strings, booleanos e regex são compatíveis.

Constantes de string e regex

É possível usar as aspas abaixo para inserir strings em YARA-L 2.0. No entanto, o texto citado é interpretado de maneiras diferentes dependendo do que você usa.

  1. Aspas duplas ("): use para strings normais. Precisa incluir caracteres de escape.
    Por exemplo: "hello\tworld" —\t é interpretado como uma guia

  2. Aspas (`) para interpretar todos os caracteres de maneira literal.
    Por exemplo: "hello\tworld" —\t não é interpretado como uma guia

Você tem duas opções para expressões regulares.

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

Também é possível usar constantes de string como constantes de regex ao usar a função re.regex(). Observe que, para constantes de string de aspas duplas, é necessário evitar caracteres de barra invertida com caracteres de barra invertida, o que pode parecer estranho.

Por exemplo, as expressões regulares a seguir são 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 o uso de caracteres de aspas duplas para strings em expressões regulares para facilitar a leitura.

Operadores

É possível usar os seguintes operadores em YARA-L:

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

Variáveis

No YARA-L 2.0, todas as variáveis são representadas como $<variable name>.

Você pode definir os seguintes tipos de variáveis:

  • Variáveis de evento — Representam grupos de eventos de forma normalizada (UDM) ou eventos de entidade. Especifique as condições das variáveis de evento na seção events. Identifique variáveis de evento usando um nome, uma fonte e campos de evento. As origens permitidas são udm (para eventos normalizados) e graph (para eventos de entidade). Se a fonte for omitida, udm será definido como padrão. Os campos de evento são representados como uma cadeia de .<field name> (por exemplo, $e.field1.field2). As cadeias de campos de evento sempre começam na origem de nível superior (UDM ou Entity).

  • Variáveis de correspondência: declare na seção match. As variáveis de correspondência 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 janela de tempo). Quando a regra encontra uma correspondência, os valores da variável são retornados. Especifique o que cada variável de correspondência representa na seção events.

  • Variáveis de marcador: declare e defina na seção events. As variáveis de marcador são semelhantes às variáveis de correspondência. No entanto, é possível usar variáveis de marcador na seção condition para especificar condições de correspondência.

Use variáveis de correspondência e variáveis de marcador para declarar relações entre campos de eventos com condições de junção transitivas. Veja mais detalhes na seção Sintaxe da seção de eventos.

Funções

Esta seção descreve as funções YARA-L 2.0 compatíveis com o Chronicle no Detection Engine.

Essas funções podem ser usadas nas seguintes áreas em uma regra:

Funções de string

O Chronicle é compatível com as seguintes funções de manipulação de strings:

  • strings.concat(a, b)
  • strings.to_lower(stringText)
  • strings.to_upper(stringText)
  • strings.base64_decode(encodedString)

As seções a seguir descrevem como usar cada um.

Concatenar strings ou números inteiros

Retorna a concatenação de duas strings, dois números inteiros ou uma combinação das duas.

strings.concat(a, b)

Essa função usa dois argumentos, que podem ser strings ou números inteiros, e retorna os dois valores concatenados como uma string. Os inteiros são enviados a uma string antes da concatenação. Os argumentos podem ser literais ou campos de evento. Se os dois argumentos forem campos, os dois atributos precisarão ser do mesmo evento.

O exemplo a seguir inclui uma variável e um literal de string como argumentos.

"google-test" = strings.concat($e.principal.hostname, "-test")

O exemplo a seguir inclui uma variável de string e uma variável inteira como argumentos. Ambos main.hostname e principal.port são do mesmo evento, $e, e são concatenados para retornar uma string.

"google80" = strings.concat($e.principal.hostname, $e.principal.port)

O exemplo a seguir tenta concatenar o main.port do evento $e1, com o main.hostname do evento $e2. Ele retornará um erro de compilador porque os argumentos são variáveis diferentes de eventos.

// returns a compiler error
"test" = strings.concat($e1.principal.port, $e2.principal.hostname)

Converter string em maiúsculas ou minúsculas

Essas funções retornam texto da string após alterar todos os caracteres para maiúsculas ou minúsculas.

  • strings.to_lower(stringText)
  • strings.to_upper(stringText)
"test@google.com" = strings.to_lower($e.network.email.from)
"TEST@GOOGLE.COM" = strings.to_upper($e.network.email.to)

Decodificar uma string Base64

Retorna uma string que contém a versão decodificada em base64 da string codificada.

strings.base64_decode(encodedString)

Essa função usa uma string codificada em base64 como argumento. Se ela não for válida e codificada em Base64, a função retornará codificada como está.

Este exemplo retorna "True" se participante.domain.name for "dGVzdA==", que é uma codificação base64 para a string "test"

"test" = strings.base64_decode($e.principal.domain.name)

Funções RegExp

O Chronicle é compatível com as seguintes funções de expressão regular:

  • re.regex(stringText, regex)
  • re.capture(stringText, regex)
  • re.replace(stringText, replaceRegex, replaceText)

Correspondência RegExp

Você pode definir a correspondência de expressão regular no YARA-L 2.0 usando uma das seguintes sintaxes:

  • Usando a sintaxe YARA: relacionada a eventos. Veja a seguir uma representação genérica dessa sintaxe: $e.field = /regex/
  • Uso da sintaxe YARA-L: uma função que usa os seguintes parâmetros:
    • Campo a que a expressão regular é aplicada.
    • Expressão regular especificada como uma string. É possível usar o modificador nocase após strings para indicar que a pesquisa precisa ignorar o uso de letras maiúsculas. Veja a seguir uma representação genérica dessa sintaxe: re.regex($e.field, `regex`)

Esteja ciente do seguinte ao definir expressões regulares em YARA-L 2.0:

  • Em ambos os casos, o predicado é verdadeiro se a string contém uma substring que corresponde à expressão regular fornecida. Não é necessário adicionar .* no início ou no fim da expressão regular.
  • Para corresponder à string exata ou apenas a um prefixo ou um sufixo, inclua os caracteres de âncora ^ (início) e $ (final) na expressão regular. Por exemplo, /^full$/ corresponde exatamente a "full", enquanto /full/ pode corresponder a "fullest", "lawfull" e "joyfully".
  • Se o campo de UDM incluir caracteres de nova linha, o regexp corresponderá apenas à primeira linha do campo de UDM. Para aplicar a correspondência total do campo de UDM, adicione um (?s) à expressão regular. Por exemplo, substitua /.*allUDM.*/ por /(?s).*allUDM.*/.

Captura RegExp

Captura (extrai) dados de uma string usando o padrão de expressão regular fornecido no argumento.

re.capture(stringText, regex)

Essa função usa dois argumentos:

  • stringText: a string original a ser pesquisada.
  • regex: a expressão regular que indica o padrão a ser pesquisado.

A expressão regular pode conter 0 ou 1 grupo de captura entre parênteses. Se a expressão regular contiver 0 grupos de captura, a função retornará a primeira substring correspondente inteira. Se a expressão regular contiver um grupo de captura, ele retornará a primeira substring correspondente para o grupo de captura. Definir dois ou mais grupos de captura retorna um erro de compilador.

Neste exemplo, se $e.principal.hostname contém "aaa1bbaa2" o seguinte seria True, porque a função retorna a primeira instância. Este exemplo não tem grupos de captura.

"aaa1" = re.capture($e.principal.hostname, "a+[1-9]")

Este exemplo captura tudo depois do símbolo @ em um e-mail. Se o campo $e.network.email.from for test@google.com, o exemplo retornará google.com. Este exemplo contém um grupo de captura.

"google.com" = re.capture($e.network.email.from , "@(.*)")

Substituição de RegExp

Realiza uma substituição de expressão regular.

re.replace(stringText, replaceRegex, replacementText)

Essa função usa três argumentos:

  • stringText: a string original.
  • replaceRegex: a expressão regular que indica o padrão a ser pesquisado.
  • replaceText: o texto a ser inserido em cada correspondência.

Retorna uma nova string derivada da stringText original, em que todas as substrings que correspondem ao padrão em replaceRegex são substituídas pelo valor em replacementText. É possível usar dígitos com escape de barra invertida (\1 a \9) em replacementText para inserir texto correspondente ao grupo entre parênteses no padrão replaceRegex. Use \0 para indicar o texto correspondente inteiro.

A função substitui as correspondências não sobrepostas e priorizará a primeira ocorrência encontrada. Por exemplo, re.replace("banana", "ana", quot;111") retorna a string "b111na".

Este exemplo captura tudo após o símbolo @ em um e-mail, substitui com por org e, em seguida, retorna o resultado. Observe o uso de funções aninhadas.

"email@google.org" = re.replace($e.network.email.from, "com", "org")

Este exemplo usa dígitos com escape de barra invertida no argumento replaceText para referenciar correspondências ao padrão replaceRegex.

"test1.com.google" = re.replace(
                       $e.principal.hostname, // holds "test1.test2.google.com"
                       "test2.([a-z]*).([a-z]*).*",
                       "\\2.\\1"  // \\1 holds "google", \\2 holds "com"
                     )

Funções de data

O Chronicle é compatível com as seguintes funções relacionadas a datas:

  • timestamp.get_minute(unix_seconds [, time_zone])
  • timestamp.get_hour(unix_seconds [, time_zone])
  • timestamp.get_day_of_week(unix_seconds [, time_zone])
  • timestamp.get_week(unix_seconds [, time_zone])
  • timestamp.current_seconds()

O Chronicle é compatível com números inteiros negativos como o argumento unix_seconds. Números inteiros negativos representam períodos antes da época Unix. Se você fornecer um número inteiro inválido, por exemplo, um valor que resulta em um estouro, a função retornará -1. Este é um cenário incomum.

Como o YARA-L 2 não é compatível com literais inteiros negativos, verifique essa condição usando o operador "menor que" ou "maior que". Exemplo:

0 > timestamp.get_hour(123)

Extração de data/hora

Retorna um número inteiro no intervalo [0, 59].

timestamp.get_minute(unix_seconds [, time_zone])

A função a seguir retorna um número inteiro no intervalo [0, 23], representando a hora do dia.

timestamp.get_hour(unix_seconds [, time_zone])

A função a seguir retorna um número inteiro no intervalo [1, 7] que representa o dia da semana a partir de domingo. Por exemplo, 1 = domingo; 2 = segunda-feira etc.

timestamp.get_day_of_week(unix_seconds [, time_zone])

A função a seguir retorna um número inteiro no intervalo [0, 53] que representa a semana do ano. As semanas começam no domingo. As datas anteriores ao primeiro domingo do ano estão na semana 0.

timestamp.get_week(unix_seconds [, time_zone])

Essas funções de extração de tempo têm os mesmos argumentos.

  • unix_seconds é um número inteiro que representa o número de segundos após a época Unix, como $e.metadata.event_timestamp.seconds ou um marcador que contém esse valor.
  • time_zone é opcional e é uma string que representa um time_zone. Se for omitido, o padrão será "GMT". É possível especificar fusos horários usando literais de string. Estas são as opções:
    • O nome do banco de dados TZ, por exemplo, "América/Los_Angeles". Para mais informações, consulte a coluna "TZ Database Name" nesta página.
    • O deslocamento do fuso horário em relação ao UTC, no formato (+|-)H[H][:M[M]], por exemplo: "-08:00".

Neste exemplo, o argumento time_zone é omitido e o padrão é "GMT".

$ts = $e.metadata.collected_timestamp.seconds

timestamp.get_hour($ts) = 15

Este exemplo usa um literal de string para definir time_zone.

$ts = $e.metadata.collected_timestamp.seconds

2 = timestamp.get_day_of_week($ts, "America/Los_Angeles")

Veja alguns exemplos de outros especificadores válidos de time_zone, que você pode transmitir como o segundo argumento para funções de extração de tempo:

  • "America/Los_Angeles" ou "-08:00". ("PST" não é compatível)
  • "America/New_York" ou "-05:00". ("EST" não é compatível)
  • "Europe/London"
  • "UTC"
  • "GMT"

Carimbo de data/hora atual

Retorna um número inteiro que representa o horário atual em segundos do Unix. Isso é aproximadamente igual ao carimbo de data/hora de detecção e se baseia na execução da regra.

timestamp.current_seconds()

O exemplo a seguir retornará True se o certificado tiver expirado por mais de 24 horas. Ela calcula a diferença de tempo subtraindo os segundos Unix atuais e fazendo a comparação usando um operador "maior que".

86400 < timestamp.current_seconds() - $e.network.tls.certificate.not_after

Funções matemáticas

Valor absoluto

Retorna o valor absoluto de uma expressão inteira.

math.abs(intExpression)

O exemplo a seguir retorna "Verdadeiro" quando os eventos têm mais de cinco minutos de diferença, independentemente de qual evento veio primeiro. Observe como o exemplo usa funções aninhadas.

5 < timestamp.get_minute(
      math.abs($e1.metadata.event_timestamp.seconds
               - $e2.metadata.event_timestamp.seconds
      )
    )

Funções de rede

Retorna verdadeiro quando o endereço IP especificado está dentro da sub-rede especificada.

net.ip_in_range_cidr(ipAddress, subnetworkRange)

É possível usar YARA-L para pesquisar eventos UDM em todos os endereços IP em uma sub-rede usando a instrução net.ip_in_range_cidr(). O IPv4 e o IPv6 são compatíveis.

Para pesquisar em um intervalo de endereços IP, especifique um campo de IP UDM e um intervalo de roteamento entre domínios sem classe (CIDR). A YARA-L processa os campos de endereço IP único e repetido.

Exemplo de IPv4:

net.ip_in_range_cidr($e.principal.ip, "192.0.2.0/24")

Exemplo de IPv6:

net.ip_in_range_cidr($e.network.dhcp.yiaddr, "2001:db8::/32")

Veja um exemplo de regra usando a instrução net.ip_in_range_cidr(). Evento único dentro do intervalo de endereços IP

Função para atribuição de marcador

É possível atribuir o resultado de uma chamada de função a um marcador na seção events. Exemplo:

$placeholder = strings.concat($e.principal.hostname, "my-string").

É possível usar as variáveis de marcador nas seções match, condition e outcome. No entanto, existem duas limitações de atribuição de função para marcador:

  1. Cada marcador de função na atribuição de marcador deve ser atribuído a uma expressão que contenha um campo de evento. Por exemplo, os seguintes exemplos são válidos:

    $ph1 = $e.principal.hostname
    $ph2 = $e.src.hostname
    
    // Both $ph1 and $ph2 have been assigned to an expression containing an event field.
    $ph1 = strings.concat($ph2, ".com")
    
    $ph1 = $e.network.email.from
    $ph2 = strings.concat($e.principal.hostname, "@gmail.com")
    
    // Both $ph1 and $ph2 have been assigned to an expression containing an event field.
    $ph1 = strings.to_lower($ph2)
    

    No entanto, o exemplo abaixo é inválido:

    $ph1 = strings.concat($e.principal.hostname, "foo")
    $ph2 = strings.concat($ph1, "bar") // $ph2 has NOT been assigned to an expression containing an event field.
    
  2. A chamada de função precisa depender de um e exatamente um evento. No entanto, mais de um campo do mesmo evento pode ser usado em argumentos de chamada de função. Por exemplo, o seguinte é válido:

    $ph = strings.concat($event.principal.hostname, "string2")

    $ph = strings.concat($event.principal.hostname, $event.src.hostname)

    No entanto, os seguintes itens são inválidos:

    $ph = strings.concat("string1", "string2")

    $ph = strings.concat($event.principal.hostname, $anotherEvent.src.hostname)

Sintaxe da seção meta

A seção meta é composta por várias linhas, em que cada linha define um par de chave-valor. Uma parte da chave precisa ser uma string sem aspas, e uma parte do valor precisa ser uma string entre aspas:

<key> = "<value>"

Veja a seguir um exemplo de uma linha de seção meta válida: meta: author = "Chronicle" severity = "HIGH"

Sintaxe da seção "Eventos"

Na seção events, liste os predicados para especificar o seguinte:

  • O que cada variável de correspondência ou marcador representa
  • Expressões binárias simples como condições
  • Expressões de função como condições
  • Expressões da lista de referência como condições
  • Operadores lógicos

Declarações de variáveis

Para declarações de variáveis, use a seguinte sintaxe:

  • <EVENT_FIELD> = <VAR>
  • <VAR> = <EVENT_FIELD>

Ambos são equivalentes, conforme mostrado nos exemplos a seguir:

  • $e.source.hostname = $hostname
  • $userid = $e.principal.user.userid

Esta declaração indica que esta variável representa o campo especificado para a variável do evento. Quando o campo de evento é repetido, a variável de correspondência pode representar qualquer valor da matriz. Também é possível atribuir vários campos de eventos a uma única correspondência ou variável de marcador. Esta é uma condição de junção transitiva.

Por exemplo, os seguintes URLs:

  • $e1.source.ip = $ip
  • $e2.target.ip = $ip

São equivalentes a:

  • $e1.source.ip = $ip
  • $e1.source.ip = $e2.target.ip

Quando uma variável é usada, ela precisa ser declarada na declaração de variáveis. Se uma variável for usada sem uma declaração, ela será considerada um erro de compilação.

Expressões binárias simples como condições

Para usar uma expressão binária simples como condição, use a seguinte sintaxe:

  • <EXPR> <OP> <EXPR>

A expressão pode ser um campo de evento, uma variável, uma constante ou uma expressão de função.

Exemplo:

  • $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")

Se ambos os lados forem constantes, ele será considerado um erro de compilação.

Expressões de função como condições

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

  • re.regex()
  • net.ip_in_range_cidr()

Exemplo:

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

Expressões da lista de referência como condições

Use o operador in para verificar a existência de valores de UDM em uma lista de referência com base na igualdade. O operador in pode ser combinado com not para excluir os valores de uma lista de referência. O nome da lista de referência precisa ter antes do caractere %.

Atualmente, apenas valores de string são compatíveis:

  • $e.principal.hostname in %hostname_list
  • $e.about.ip in %phishing_site_list
  • $hostname in %whitelisted_hosts

Operadores lógicos

É possível usar os operadores lógicos and e or na seção events, conforme mostrado nos exemplos a seguir:

  • $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 da maior para a menor é not, and, or.

Por exemplo, "a or b and c" é avaliado como "a or (b and c)". Se necessário, use parênteses para alterar a precedência.

Na seção events, todos os predicados são considerados AND juntos por padrão.

Modificadores

bico

Quando houver uma expressão de comparação entre valores de string ou uma expressão regex, será possível acrescentar um maiúsculo no final da expressão para ignorar letras maiúsculas.

  • $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

Não pode ser usado quando um tipo de campo é um valor enumerado. Os exemplos abaixo são inválidos e gerarão erros de compilação:

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

Campos repetidos

todos, todos

Em UDM e Entity, alguns campos são marcados como repetidos, o que indica que são listas de valores ou outros tipos de mensagens. Em YARA-L, cada elemento no campo repetido é tratado individualmente. Isso significa que, se o campo repetido for usado na regra, avaliaremos a regra para cada elemento no campo. Isso pode levar a um comportamento inesperado. Por exemplo, se uma regra tiver $e.principal.ip = "1.2.3.4" e $e.principal.ip = "5.6.7.8" na seção events, ela nunca gerará correspondências, mesmo que "1.2.3.4" e "5.6.7.8" estejam em principal.ip.

Para avaliar o campo repetido como um todo, use os operadores any e all. Quando any é usado, o predicado é avaliado como verdadeiro se qualquer valor no campo repetido atender à condição. Quando all é usado, o predicado é avaliado como verdadeiro se todos os valores no campo repetido atenderem à condição.

  • any $e.target.ip = "127.0.0.1"
  • all $e.target.ip != "127.0.0.1"
  • re.regex(any $e.about.hostname, `server-[0-9]+`)
  • net.ip_in_range_cidr(all $e.principal.ip, "10.0.0.0/8")

Os operadores any e all só podem ser usados com campos repetidos. Além disso, eles não podem ser usados ao atribuir um campo repetido a uma variável de marcador ou ao mesclar com um campo de outro evento.

Por exemplo, any $e.principal.ip = $ip e any $e1.principal.ip = $e2.principal.ip não são sintaxes válidas. Para corresponder ou mesclar um campo repetido, use $e.principal.ip = $ip. Haverá um valor de variável de correspondência ou mesclagem para cada elemento do campo repetido.

Ao gravar uma condição com any ou all, lembre-se de que negá-la com not pode não ter o mesmo significado que usar o operador de negação.

Exemplo:

  • O not all $e.principal.ip = "192.168.12.16" verifica se nem todos os endereços IP correspondem a "192.168.12.16". Isso significa que a regra verifica se algum endereço IP não corresponde a "192.168.12.16".
  • O all $e.principal.ip != "192.168.12.16" verifica se todos os endereços IP não correspondem a "192.168.12.16". Isso significa que a regra está verificando se nenhum endereço IP corresponde a "192.168.12.16".

Requisitos de participação das variáveis de evento

Todas as variáveis de eventos usadas na regra precisam ser unidas a cada uma das seguintes maneiras:

  • diretamente por uma comparação de igualdade entre os campos de eventos das duas variáveis de evento associadas, por exemplo: $e1.field = $e2.field A expressão não pode incluir chamadas aritméticas ou de função.

  • indiretamente por meio de uma junção transitiva que envolve apenas um campo de evento. Consulte a declaração de variáveis para ver uma definição de "joinive join". A expressão não pode incluir chamadas aritméticas ou de função.

Por exemplo, supondo que $e1, $e2 e $e3 sejam usados na regra, as seções events a seguir são válidas.

events:
  $e1.principal.hostname = $e2.src.hostname // $e1 joins with $e2
  $e2.principal.ip = $e3.src.ip // $e2 joins with $e3
events:
  // all of $e1, $e2 and $e3 are transitively joined via the placeholder variable $ip
  $e1.src.ip = $ip
  $e2.target.ip = $ip
  $e3.about.ip = $ip
events:
  $e1.principal.hostname = $e2.src.hostname // $e1 joins with $e2

  // Function to event comparison is not a valid join condition for $e1 and $e2,
  // but the whole events section is valid because we have a valid join condition in the first line.
  re.capture($e1.src.hostname, ".*") = $e2.target.hostname

No entanto, veja alguns exemplos de seções events inválidas.

events:
  // Event to function comparison is an invalid join condition for $e1 and $e2.
  $e1.principal.hostname = re.capture($e2.principal.application, ".*")
events:
  // Event to arithmetic comparison is an invalid join condition for $e1 and $e2.
  $e1.principal.port = $e2.src.port + 1
events:
  $e1.src.ip = $ip
  $e2.target.ip = $ip
  $e3.about.ip = "192.1.2.0" //$e3 is not joined with $e1 or $e2.
events:
  $e1.src.ip = $ip

  // Function to placeholder comparison is an invalid transitive join condition.
  re.capture($e2.target.ip, ".*") = $ip
events:
  $e1.src.port = $port

  // Arithmetic to placeholder comparison is an invalid transitive join condition.
  $e2.principal.port + 800 = $port

Sintaxe da seção de correspondência

Na seção match, liste as variáveis de correspondência para eventos de grupo antes de verificar as condições de correspondência. Esses campos são retornados a cada correspondência.

  • Especifique o que cada variável de correspondência representa na seção events.
  • Especifique o período a ser usado para correlacionar eventos após a palavra-chave over. Os eventos fora do período serão ignorados.
  • Use a seguinte sintaxe para especificar o período: <number><s/m/h/d>, em que s/m/h/d significa segundos, minutos, horas e dias, respectivamente.
  • O tempo mínimo que você pode especificar é de 1 minuto.
  • O tempo máximo que você pode especificar é de 48 horas.

Veja a seguir um exemplo de match válido:

$var1, $var2 over 5m

Essa instrução retorna $var1 e $var2 (definidas na seção events) quando a regra encontra uma correspondência. A duração especificada é de 5 minutos. Os eventos com mais de cinco minutos de intervalo não são correlacionados e, portanto, são ignorados pela regra.

Veja outro exemplo de um match válido:

$user over 1h

Esta instrução retorna $user quando a regra encontra uma correspondência. A janela de tempo especificada é de 1 hora. Os eventos com mais de uma hora de intervalo não têm correlação. A regra não os considera uma detecção.

Veja outro exemplo de um match válido:

$source_ip, $target_ip, $hostname over 2m

Essa instrução retorna $source_ip, $target_ip e $hostname quando a regra encontra uma correspondência. A janela de tempo especificada é de dois minutos. Os eventos com mais de dois minutos de intervalo não estão correlacionados. A regra não os considera uma detecção.

Os exemplos a seguir ilustram seções inválidas de match:

  • var1, var2 over 5m // invalid variable name
  • $user 1h // missing keyword

Janela deslizante

Por padrão, as regras YARA-L 2.0 são avaliadas usando janelas de salto. Um período de dados de eventos corporativos é dividido em um conjunto de janelas de salto sobrepostas, cada uma com a duração especificada na seção match. Os eventos são correlacionados em cada janela de salto. Com as janelas de salto, é impossível pesquisar eventos que acontecem em uma ordem específica, por exemplo, e1 ocorre até dois minutos após e2. Uma ocorrência do evento e1 e uma ocorrência do evento e2 estão correlacionadas, desde que estejam dentro da duração da janela de salto uma da outra.

As regras também podem ser avaliadas usando janelas deslizantes. Com as janelas deslizantes, as janelas deslizantes com a duração especificada na seção match são geradas ao começar ou terminar com uma variável de evento dinâmica especificada. Os eventos são correlacionados em cada janela deslizante. Isso possibilita a pesquisa de eventos que ocorrem em uma ordem específica (por exemplo, e1 acontece em dois minutos de e2). Uma ocorrência do evento e1 e uma do evento e2 serão correlacionadas se o evento e1 ocorrer dentro do período da janela deslizante após o evento e2.

Especifique janelas deslizantes na seção match de uma regra da seguinte maneira:

<match-var-1>, <match-var-2>, ... over <duration> before|after <pivot-event-var>

A variável de evento dinâmica é a variável de evento em que as janelas deslizantes são baseadas. Se você usar a palavra-chave before, serão geradas janelas deslizantes, terminando com cada ocorrência do evento dinâmico. Se a palavra-chave after for usada, janelas deslizantes serão geradas começando com cada ocorrência do evento dinâmico.

Veja a seguir exemplos de usos válidos de janelas deslizantes:

  • $var1, $var2 over 5m after $e1
  • $user over 1h before $e2

Sintaxe da seção de resultados

Na seção outcome, é possível definir até 10 variáveis de resultado com nomes arbitrários. Esses resultados serão armazenados nas detecções geradas pela regra. Cada detecção pode ter valores diferentes para os resultados.

O nome do resultado, $risk_score, é especial. Você tem a opção de definir um resultado com esse nome e, se fizer isso, ele precisa ser um tipo de número inteiro. Se preenchido, o risk_score será exibido na visualização do Enterprise Insights para alertas provenientes de detecções de regras.

Tipos de dados da variável "Resultado"

Cada variável de resultado pode ter um tipo de dados diferente, que é determinado pela expressão usada para calculá-la. Os seguintes tipos de dados de resultado são compatíveis:

  • integer
  • string
  • listas de números inteiros
  • listas de strings

Lógica condicional

Você pode usar a lógica condicional para calcular o valor de um resultado. As condicionais são especificadas usando o seguinte padrão de sintaxe:

if(BOOL_CLAUSE, THEN_CLAUSE)
if(BOOL_CLAUSE, THEN_CLAUSE, ELSE_CLAUSE)

Leia uma expressão condicional como "se BOOL_CLAUSE for verdadeiro, retorne THEN_CLAUSE; caso contrário, retorne ELSE_CLAUSE".

BOOL_CLAUSE deve ser avaliado como um valor booleano. Uma expressão BOOL_CLAUSE assume uma forma semelhante às expressões na seção events. Por exemplo, ele pode conter:

  • Nomes dos campos de UDM com operador de comparação, por exemplo:

    if($context.graph.entity.user.title = "Vendor", 100, 0)

  • Variável de marcador definida na seção events, por exemplo:

    if($severity = "HIGH", 100, 0)

  • funções que retornam um booleano, por exemplo:

    if(re.regex($e.network.email.from, .*altostrat\.com), 100, 0)

  • procure em uma lista de referência, por exemplo:

    if($u.principal.hostname in %my_reference_list_name, 100, 0)

THEN_CLAUSE e ELSE_CLAUSE precisam ser do mesmo tipo de dados. Temos compatibilidade com números inteiros e strings.

Você poderá omitir ELSE_CLAUSE se o tipo de dados for um número inteiro. Se omitido, a ELSE_CLAUSE será avaliada como 0. Exemplo:

`if($e.field = "a", 5)` is equivalent to `if($e.field = "a", 5, 0)`

Forneça o ELSE_CLAUSE se o tipo de dados for string.

Operações matemáticas

Você pode usar operações matemáticas para calcular resultados de tipos de dados inteiros. Temos compatibilidade com adição e subtração. Exemplo:

outcome:
  $risk_score = max(100 + if($severity = "HIGH", 10, 5) - if($severity = "LOW", 20, 0))

Variáveis de marcador nos resultados

Ao calcular variáveis de resultado, é possível usar variáveis de marcador definidas na seção de eventos da regra. Neste exemplo, suponha que $email_sent_bytes foi definido na seção de eventos da regra:

Exemplo de evento único:

// No match section, so this is a single-event rule.

outcome:
  // Use placeholder directly as an outcome value.
  $my_outcome = $email_sent_bytes

  // Use placeholder in a conditional.
  $other_outcome = if($file_size > 1024, "SEVERE", "MODERATE")

condition:
  $e

Exemplo de vários eventos:

match:
  // This is a multi event rule with a match section.
  $hostname over 5m

outcome:
  // Use placeholder directly in an aggregation function.
  $max_email_size = max($email_sent_bytes)

  // Use placeholder in a mathematical computation.
  $total_bytes_exfiltrated = sum(
    1024
    + $email_sent_bytes
    + $file_event.principal.file.size
  )

condition:
  $email_event and $file_event

Agregações

A seção de resultado pode ser usada em regras de vários eventos (regras que contêm uma seção de correspondência) e em regras de evento único (regras que não contêm uma seção de correspondência). Os requisitos para agregações são os seguintes:

  • Regras de vários eventos (com a seção de correspondência)

    • A expressão para calcular os resultados é avaliada em todos os eventos que geraram uma detecção específica.
    • A expressão precisa ser unida a uma função agregada.
      • Exemplo: $max_email_size = max($e.network.sent_bytes)
      • Se a expressão contiver um campo repetido, o agregado opera em todos os elementos no campo repetido, em todos os eventos que geraram a detecção.
  • Regras de evento único (sem a seção de correspondência)

    • A expressão para calcular os resultados é avaliada sobre o único evento que gerou uma detecção específica.
    • É preciso usar a função agregada para expressões que envolvem pelo menos um campo repetido.
      • Exemplo: $suspicious_ips = array($e.principal.ip)
      • O valor agregado opera em todos os elementos no campo repetido
    • Não é possível usar uma função agregada para expressões que não envolvem um campo repetido
      • Exemplo: $threat_status = if($e.principal.file.size > 1024, "SEVERE", "MODERATE")

É possível usar as seguintes funções de agregação:

  • max(): gera o máximo sobre todos os valores possíveis. Funciona apenas com números inteiros.
  • min(): gera o mínimo sobre todos os valores possíveis. Funciona apenas com números inteiros.
  • sum(): gera a soma de todos os valores possíveis. Funciona apenas com números inteiros.
  • count_distinct(): coleta todos os valores possíveis e gera a contagem distinta de valores possíveis.
  • count(): se comporta como count_distinct(), mas retorna uma contagem não distinta de valores possíveis.
  • array_distinct(): coleta todos os valores possíveis e gera uma lista com esses valores. A lista de valores será truncada em 25 elementos aleatórios.
  • array(): se comporta como array_distinct(), mas retorna uma lista não distinta de valores. Ele também reduz a lista de valores para 25 elementos aleatórios.

A função agregada é importante quando uma regra inclui uma seção condition que especifica que vários eventos precisam existir, porque a função de operação operará em todos os eventos que geraram a detecção.

Por exemplo, se as seções outcome e condition contiverem:

outcome:
  $asset_id_count = count($event.principal.asset_id)
  $asset_id_distinct_count = count_distinct($event.principal.asset_id)

  $asset_id_list = array($event.principal.asset_id)
  $asset_id_distinct_list = array_distinct($event.principal.asset_id)

condition:
  #event > 1

Como a seção de condição exige que haja mais de um event para cada detecção, as funções de agregação operarão em vários eventos. Suponha que os seguintes eventos geraram uma detecção:

event:
  // UDM event 1
  asset_id="asset-a"

event:
  // UDM event 2
  asset_id="asset-b"

event:
  // UDM event 3
  asset_id="asset-b"

Então, os valores dos resultados serão:

  • $asset_id_count = 3
  • $asset_id_distinct_count = 2
  • $asset_id_list = ["asset-a", "asset-b", "asset-b"]`
  • $asset_id_distinct_list = ["asset-a", "asset-b"]

Veja a seguir o que você precisa saber ao usar a seção de resultados:

Outras observações e restrições:

  • A seção outcome não pode fazer referência a uma nova variável de marcador que ainda não foi definida na seção events.
  • Da mesma forma, a seção outcome não pode usar eventos não definidos na seção events.
  • A seção outcome só pode correlacionar eventos que já tenham sido correlacionados na seção events.

Veja um exemplo usando a seção de resultados em Visão geral da YARA-L 2.0. Consulte Criar análise baseada no contexto para ver detalhes sobre a detecção de detecção com a seção de resultados.

Sintaxe da seção "Condição"

Contar

O caractere # é especial na seção condition. Se ele for usado antes de qualquer nome de variável de evento ou marcador, ele representará o número de eventos ou valores distintos que atendem a todas as condições da seção events.

.

Sintaxe

Na seção condition, especifique a condição de correspondência para eventos e variáveis definidos na seção events. Liste predicados de correspondência aqui, mesclados com a palavra-chave and ou or.

As condições a seguir são delimitadoras. Eles forçam a variável do evento associada a existir, o que significa que pelo menos uma ocorrência do evento precisa aparecer em qualquer detecção.

  • $var // equivalent to #var > 0
  • #var > n // where n >= 0
  • #var >= m // where m > 0

As condições a seguir são ilimitadas. Eles permitem que a variável de evento associada não exista, o que significa que é possível que nenhuma ocorrência do evento apareça em uma detecção. Isso permite a criação de regras não existentes, que buscam a ausência de uma variável em vez da presença de uma variável.

  • !$var // equivalent to #var = 0
  • #var >= 0
  • #var < n // where n > 0
  • #var <= m // where m >= 0

No exemplo a seguir, o caractere especial # em uma variável (a variável de evento ou a de marcador) representa a contagem de eventos ou valores distintos dessa variável:

$e and #port > 50 or #event1 > 2 or #event2 > 1 or #event3 > 0

O seguinte exemplo não existente também será válido e será avaliado como verdadeiro se houver mais de dois eventos distintos de $event1 e eventos diferentes de $event2:

#event1 > 2 and !$event2

Veja a seguir exemplos de predicados inválidos:

  • $e, #port > 50 // incorrect keyword usage
  • $e or #port < 50 // or keyword not supported with non-bounding conditions

Sintaxe da seção "Opções"

Na seção options, é possível especificar as opções da regra. A sintaxe da seção options é semelhante à da seção meta. Mas uma chave precisa ser uma das opções predefinidas e o valor não está restrito ao tipo de string.

Atualmente, a única opção disponível é allow_zero_values.

  • allow_zero_value: se definida como verdadeira, as correspondências geradas pela regra poderão ter valores zero como valores de variável de correspondência. Os valores zero são fornecidos aos campos de evento quando não são preenchidos. Por padrão, essa opção é definida como falsa.

Veja a seguir a linha de seção options válida:

  • allow_zero_values = true

Verificação de tipo

O Chronicle realiza a verificação de tipo na sintaxe YARA-L à medida que você cria regras na interface. Os erros de verificação de tipo exibidos ajudam você a revisar a regra de forma a garantir que ela funcione conforme o esperado.

Veja a seguir exemplos de predicados inválidos:

// $e.target.port is of type integer which cannot be compared to a string.
$e.target.port = "80"

// "LOGIN" is not a valid event_type enum value.
$e.metadata.event_type = "LOGIN"