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:
- meta
- events
- match (opcional)
- resultado (opcional)
- condição
- 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.
Aspas duplas ("): use para strings normais. Precisa incluir caracteres de escape.
Por exemplo: "hello\tworld" —\t é interpretado como uma guiaAspas (`) 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ãoudm
(para eventos normalizados) egraph
(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çãoevents
.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çãocondition
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:
- Seção
events
. BOOL_CLAUSE
de um condicional na seção de resultados.
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
Pesquisa de sub-rede IP
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:
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.
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 ques/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.
- Exemplo:
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
- Exemplo:
- 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")
- Exemplo:
É 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 comocount_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 comoarray_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çãoevents
. - Da mesma forma, a seção
outcome
não pode usar eventos não definidos na seçãoevents
. - A seção
outcome
só pode correlacionar eventos que já tenham sido correlacionados na seçãoevents
.
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"