Sintaxis del lenguaje YARA-L 2.0

En esta sección, se describen los elementos principales de la sintaxis de YARA-L. Consulta también la Descripción general del lenguaje YARA-L 2.0.

Estructura de la regla

Para YARA-L 2.0, debes especificar declaraciones de variables, definiciones y usos en el siguiente orden:

  1. meta
  2. events
  3. coincidencia (opcional)
  4. resultado (opcional)
  5. condición
  6. opciones (opcional)

A continuación, se ilustra la estructura genérica de una regla:

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.
}

Comentarios

Designa los comentarios con dos caracteres de barra (// comment) o de varias líneas activados con caracteres de asterisco de barra (/* comment */), como lo harías en C.

Constantes

Se admiten constantes de números enteros, strings, booleanos y regex.

Constantes de string y regex

Puedes usar cualquiera de los siguientes caracteres de comillas para encerrar strings en YARA-L 2.0. Sin embargo, el texto citado se interpreta de manera diferente según el que se use.

  1. Comillas dobles (") Se usan para strings normales. Debe incluir caracteres de escape.
    Por ejemplo: "hello\tworld" —\t se interpreta como una pestaña.

  2. Frases inversas (`): úsalas para interpretar literalmente todos los caracteres.
    Por ejemplo: “hello\tworld”: \t no se interpreta como una pestaña

Tienes dos opciones para expresiones regulares.

Si deseas usar expresiones regulares directamente sin la función re.regex(), usa /regex/ para las constantes de expresiones regulares.

También puedes usar constantes de string como constantes de regex cuando uses la función re.regex(). Ten en cuenta que, para las constantes de string de comillas dobles, debes escapar los caracteres de la barra inversa con caracteres de barra invertida, que pueden verse extraños.

Por ejemplo, las siguientes expresiones regulares son equivalentes:

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

Google recomienda usar caracteres de comillas inversas para las strings en expresiones regulares a fin de facilitar la legibilidad.

Operadores

Puedes usar los siguientes operadores en YARA-L:

Operador Descripción
= igual/declaración
!= no igual
< menor que
<= menor o igual que
> mayor que
>= mayor o igual que

Variables

En YARA-L 2.0, todas las variables se representan como $<variable name>.

Puedes definir los siguientes tipos de variables:

  • Variables de eventos: Representan grupos de eventos en forma normalizada (UDM) o eventos de entidades. En la sección events, especifica las condiciones de las variables de eventos. Puede identificar las variables de evento con un nombre, una fuente y eventos de campo. Las fuentes permitidas son udm (para eventos normalizados) y graph (para eventos de entidad). Si se omite la fuente, udm se configura como la fuente predeterminada. Los campos de eventos se representan como una cadena de .<field name> (por ejemplo, $e.field1.field2). Las cadenas de campos de eventos siempre comienzan con la fuente de nivel superior (UDM o Entidad).

  • Variables de coincidencia: Declara en la sección match. Las variables de coincidencia se convierten en grupos de agrupación para la consulta, ya que se muestra una fila para cada conjunto único de variables de coincidencia (y para cada período). Cuando la regla encuentra una coincidencia, se muestran los valores de las variables de coincidencia. En la sección events, especifica qué representa cada variable de coincidencia.

  • Variables de marcadores de posición: Declara y define en la sección events. Las variables de marcadores de posición son similares a las variables de coincidencia. Sin embargo, puedes usar variables de marcador de posición en la sección condition para especificar las condiciones de coincidencia.

Usa variables de coincidencia y variables de marcador de posición para declarar relaciones entre campos de evento a través de condiciones de unión transitivas (consulta Sintaxis de la sección de eventos para obtener más detalles).

Funciones

En esta sección, se describen las funciones de YARA-L 2.0 que admite Chronicle en el motor de detección.

Estas funciones se pueden usar en las siguientes áreas de una regla:

Funciones de string

Chronicle admite las siguientes funciones de manipulación de strings:

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

En las siguientes secciones, se describe cómo usar cada una.

Concatena strings o números enteros

Muestra la concatenación de dos strings, dos números enteros o una combinación de ambos.

strings.concat(a, b)

Esta función toma dos argumentos, que pueden ser strings o números enteros, y muestra los dos valores concatenados como una string. Los números enteros se convierten en una string antes de la concatenación. Los argumentos pueden ser literales o campos de eventos. Si ambos argumentos son campos, los dos atributos deben ser del mismo evento.

En el siguiente ejemplo, se incluyen una variable y un literal de string como argumentos.

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

En el siguiente ejemplo, se incluyen una variable de string y una variable de número entero como argumentos. Tanto principal.hostname como principal.port son del mismo evento, $e, y se concatenan para mostrar una string.

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

En el siguiente ejemplo, se intenta concatenar principal.port del evento $e1 con principal.hostname del evento $e2. Se mostrará un error de compilador porque los argumentos son diferentes variables de evento.

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

Convierte la string en mayúsculas o minúsculas

Estas funciones muestran texto de string después de cambiar todos los caracteres a mayúscula o minúscula.

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

Base64 decodifica una string

Muestra una string que contiene la versión decodificado en Base64 de la string codificada.

strings.base64_decode(encodedString)

Esta función toma una string codificada en base 64 como argumento. Si codificadoString no es una string codificada en base64 válida, la función muestra encodedString como está.

Este ejemplo muestra el valor Verdadero si principal.domain.name es "dGVzdA==", que es la codificación base64 para la string "test"

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

Funciones RegExp

Chronicle admite las siguientes funciones de expresión regular:

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

Coincidencia de la expresión regular

Puedes definir la coincidencia de expresiones regulares en YARA-L 2.0 mediante cualquiera de las siguientes sintaxis:

  • Usa la sintaxis de YARA: relacionada con eventos. La siguiente es una representación genérica de esta sintaxis: $e.field = /regex/
  • Usar la sintaxis de YARA-L como una función que acepta los siguientes parámetros:
    • Campo al que se aplica la expresión regular.
    • Expresión regular especificada como una string. Puedes usar el modificador nocase después de las strings para indicar que la búsqueda debe ignorar el uso de mayúsculas. La siguiente es una representación genérica de esta sintaxis: re.regex($e.field, `regex`)

Cuando definas expresiones regulares en YARA-L 2.0, ten en cuenta lo siguiente:

  • En cualquier caso, el predicado es verdadero si la string contiene una substring que coincide con la expresión regular proporcionada. No es necesario agregar .* al principio ni al final de la expresión regular.
  • Para que la string exacta coincida o solo un prefijo o sufijo, incluye los caracteres de anclaje ^ (comienzo) y $ (final) en la expresión regular. Por ejemplo, /^full$/ coincide exactamente con "full", mientras que /full/ podría coincidir con "fullest", "lawfull" y "joyfully".
  • Si el campo UDM incluye caracteres de salto de línea, regexp solo coincide con la primera línea del campo UDM. Para aplicar la coincidencia completa del campo de UDM, agrega un (?s) a la expresión regular. Por ejemplo, reemplaza /.*allUDM.*/ por /(?s).*allUDM.*/.

Captura de la expresión regular

Captura (extrae) datos de una string con el patrón de expresión regular proporcionado en el argumento.

re.capture(stringText, regex)

Esta función toma dos argumentos:

  • stringText: la string original que se buscará.
  • regex: la expresión regular que indica el patrón que se debe buscar.

La expresión regular puede contener 0 o 1 grupos de captura entre paréntesis. Si la expresión regular contiene 0 grupos de captura, la función muestra la primera substring coincidente completa. Si la expresión regular contiene 1 grupo de captura, se muestra la primera substring coincidente para el grupo de captura. Definir dos o más grupos de captura muestra un error de compilador.

En este ejemplo, si $e.principal.hostname contiene "aaa1bbaa2&quot, lo siguiente sería verdadero, ya que la función muestra la primera instancia. Este ejemplo no tiene grupos de captura.

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

En este ejemplo, se captura todo después del símbolo @ en un correo electrónico. Si el campo $e.network.email.from es test@google.com, el ejemplo muestra google.com. Este ejemplo contiene un grupo de captura.

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

Reemplazo de expresión regular

Realiza un reemplazo de expresiones regulares.

re.replace(stringText, replaceRegex, replacementText)

Esta función utiliza tres argumentos:

  • stringText: es la string original.
  • replaceRegex: la expresión regular que indica el patrón que se debe buscar.
  • replaceText: Es el texto que se debe insertar en cada coincidencia.

Muestra una string nueva derivada de la string de texto original, en la que todas las substrings que coinciden con el patrón en replaceRegex se reemplazan por el valor en reemplazo de texto. Puedes usar dígitos con escape de barras invertidas (\1 a \9) dentro de replacementText para insertar texto que coincida con el grupo entre paréntesis correspondiente en el patrón replaceRegex. Usa \0 para hacer referencia a todo el texto coincidente.

La función reemplaza las coincidencias que no se superponen y priorizará el reemplazo del primer caso que se encuentre. Por ejemplo, re.replace("banana", "ana", 111") muestra la string &b111na"

En este ejemplo, se captura todo lo que sucede después del símbolo @ en un correo electrónico, se reemplaza com por org y, luego, se muestra el resultado. Observa el uso de las funciones anidadas.

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

En este ejemplo, se usan dígitos de escape de barras inversas en el argumento replaceText para hacer referencia a coincidencias con el patrón 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"
                     )

Funciones de fecha

Chronicle admite las siguientes funciones relacionadas con las fechas:

  • 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()

Chronicle admite números enteros negativos como argumento de unix_seconds. Los números enteros negativos representan horas antes de la época Unix. Si proporcionas un valor entero no válido, por ejemplo, un valor que genera un desbordamiento, la función mostrará -1. Esta situación es poco común.

Debido a que YARA-L 2 no admite literales de número entero negativos, asegúrate de verificar esta condición con un operador menor o mayor que. Por ejemplo:

0 > timestamp.get_hour(123)

Extracción de tiempo

Muestra un número entero en el rango [0, 59].

timestamp.get_minute(unix_seconds [, time_zone])

La siguiente función muestra un número entero en el rango [0, 23], que representa la hora del día.

timestamp.get_hour(unix_seconds [, time_zone])

La siguiente función muestra un número entero en el rango [1, 7] que representa el día de la semana a partir del domingo. Por ejemplo: 1 = domingo; 2 = lunes, etcétera.

timestamp.get_day_of_week(unix_seconds [, time_zone])

La siguiente función muestra un número entero en el rango [0, 53] que representa la semana del año. Las semanas comienzan con el domingo. Las fechas anteriores al primer domingo del año están en la semana 0.

timestamp.get_week(unix_seconds [, time_zone])

Estas funciones de extracción de tiempo tienen los mismos argumentos.

  • unix_seconds es un número entero que representa la cantidad de segundos pasados de la época de Unix, como $e.metadata.event_timestamp.seconds, o un marcador de posición que contiene ese valor.
  • time_zone es opcional y es una string que representa una zona horaria. Si se omite, el valor predeterminado es “GMT”. Puedes especificar zonas horarias mediante literales de string. Las opciones son las siguientes:
    • El nombre de la base de datos TZ, por ejemplo, América/Los_Ángeles Para obtener más información, consulta la columna Nombre de la base de datos TZ en esta página.
    • La compensación de zona horaria desde UTC, en el formato (+|-)H[H][:M[M]], por ejemplo: "-08:00"

En este ejemplo, se omite el argumento time_zone, por lo que su valor predeterminado es &GMTt.

$ts = $e.metadata.collected_timestamp.seconds

timestamp.get_hour($ts) = 15

En este ejemplo, se usa un literal de string para definir la zona horaria.

$ts = $e.metadata.collected_timestamp.seconds

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

Estos son algunos ejemplos de otros especificadores de zona horaria válidos, que puedes pasar como segundo argumento a las funciones de extracción de tiempo:

  • "America/Los_Angeles" o "-08:00". (no se admite "PST")
  • "America/New_York" o "-05:00". (no se admite "EST")
  • "Europe/London"
  • "UTC"
  • "GMT"

Marca de tiempo actual

Muestra un número entero que representa la hora actual en segundos Unix. Este valor es similar a la marca de tiempo de detección y se basa en el momento en que se ejecuta la regla.

timestamp.current_seconds()

En el siguiente ejemplo, se muestra el valor True si el certificado está vencido por más de 24 horas. Para calcular la diferencia de tiempo, se restan los segundos Unix actuales y, luego, se comparan con un operador mayor que.

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

Funciones matemáticas

Valor absoluto

Muestra el valor absoluto de una expresión de número entero.

math.abs(intExpression)

En este ejemplo, se muestra el valor True si los eventos tenían más de 5 minutos de diferencia, independientemente del evento que haya ocurrido primero. Observa cómo el ejemplo usa funciones anidadas.

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

Funciones de red

El resultado es verdadero cuando la dirección IP está dentro de la subred especificada.

net.ip_in_range_cidr(ipAddress, subnetworkRange)

Puedes usar YARA-L para buscar eventos de UDM en todas las direcciones IP de una subred mediante la declaración net.ip_in_range_cidr(). Se admiten IPv4 y, también, IPv6.

Para buscar en un rango de direcciones IP, especifica un campo de UDM de IP y un rango de enrutamiento entre dominios sin clases (CIDR). YARA-L puede manejar campos de direcciones IP únicos y repetidos.

Ejemplo de IPv4:

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

Ejemplo de IPv6:

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

Si deseas ver una regla de ejemplo con net.ip_in_range_cidr(), consulta la regla de ejemplo. Un solo evento dentro del rango de direcciones IP

Sintaxis de la sección Meta

La metasección consta de varias líneas en las que cada línea define un par clave-valor. Una parte de clave debe ser una string sin comillas y una parte de valor debe ser una string entrecomillada:

<key> = "<value>"

A continuación, se muestra un ejemplo de una línea de sección de meta válida: meta: author = "Chronicle" severity = "HIGH"

Sintaxis de la sección de eventos

En la sección events, enumera los predicados para especificar lo siguiente:

  • Qué representa cada coincidencia o variable de marcador de posición
  • Expresiones binarias simples como condiciones
  • Expresiones de funciones como condiciones
  • Expresiones de listas de referencia como condiciones
  • Operadores lógicos

Declaraciones variables

Para declaraciones de variables, usa la siguiente sintaxis:

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

Ambos son equivalentes, como se muestra en los siguientes ejemplos:

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

Esta declaración indica que esta variable representa el campo especificado para la variable del evento. Cuando el campo del evento es un campo repetido, la variable de coincidencia puede representar cualquier valor en el array. También es posible asignar varios campos de evento a una sola coincidencia o a una variable de marcador de posición. Esta es una condición de unión transitiva.

Por ejemplo:

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

Son equivalentes a lo siguiente:

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

Cuando se usa una variable, se debe declarar mediante la declaración de la variable. Si se usa una variable sin ninguna declaración, se considera un error de compilación.

Expresiones binarias simples como condiciones

Para que una expresión binaria simple se use como condición, usa la siguiente sintaxis:

  • <EXPR> <OP> <EXPR>

La expresión puede ser un campo de evento, una variable, una constante o una expresión de función.

Por ejemplo:

  • $e.source.hostname = "host1234"
  • $e.source.port < 1024
  • 1024 < $e.source.port
  • $e1.source.hostname != $e2.target.hostname
  • $e1.metadata.timestamp > $e2.metadata.timestamp
  • $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")

Si ambas partes son constantes, se consideran un error de compilación.

Expresiones de funciones como condiciones

Algunas expresiones de función muestran un valor booleano, que se puede usar como un predicado individual en la sección events. Esas funciones son las siguientes:

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

Por ejemplo:

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

Expresiones de listas de referencia como condiciones

Usa el operador in para verificar la existencia de valores UDM dentro de una lista de referencia basada en la igualdad. El operador in se puede combinar con not para excluir los valores de una lista de referencia. El nombre de la lista de referencia debe estar precedido por un carácter %.

Actualmente, solo se admiten valores de string:

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

Operadores lógicos

Puedes usar los operadores lógicos and y or lógicos en la sección events, como se muestra en los siguientes ejemplos:

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

De forma predeterminada, el orden de prioridad de mayor a menor es not, and y or.

Por ejemplo, "a or b and c" se evalúa como "a or (b and c)". Puedes usar paréntesis para alterar la prioridad si es necesario.

En la sección events, todos los predicados se consideran AND juntos de forma predeterminada.

Teclas modificadoras

sin caso

Cuando tienes una expresión de comparación entre valores de string o una expresión regex, puedes agregar el nombre en mayúsculas al final de la expresión para ignorar el uso de mayú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

No se puede usar cuando un tipo de campo es un valor enumerado. Los siguientes ejemplos son no válidos y generarán errores de compilación:

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

Campos repetidos

cualquiera

En UDM y entidad, algunos campos están etiquetados como repetidos, lo que indica que son listas de valores o de otros tipos de mensajes. En YARA-L, cada elemento del campo repetido se trata de forma individual. Esto significa que, si se usa el campo repetido en la regla, se evalúa la regla para cada elemento del campo. Esto puede provocar un comportamiento inesperado. Por ejemplo, si una regla tiene $e.principal.ip = "1.2.3.4" y $e.principal.ip = "5.6.7.8" en la sección events, la regla nunca genera coincidencias, incluso si "1.2.3.4" y "5.6.7.8" están en principal.ip.

Para evaluar todo el campo repetido, puedes usar los operadores any y all. Cuando se usa any, el predicado se evalúa como verdadero si algún valor en el campo repetido cumple con la condición. Cuando se usa all, el predicado se evalúa como verdadero si todos los valores en el campo repetido satisfacen la condición.

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

Los operadores any y all solo se pueden usar con campos repetidos. Además, no se pueden utilizar cuando se asigna un campo repetido a un marcador de posición o si se une a un campo de otro evento.

Por ejemplo, any $e.principal.ip = $ip y any $e1.principal.ip = $e2.principal.ip no son sintaxis válidas. Para hacer coincidir un campo repetido o unirse a él, usa $e.principal.ip = $ip. Habrá un valor de coincidencia de variable o unión para cada elemento del campo repetido.

Cuando escribes una condición con any o all, ten en cuenta que negar la condición con not puede no tener el mismo significado que usar el operador negado.

Por ejemplo:

  • not all $e.principal.ip = "192.168.12.16" verifica si no todas las direcciones IP coinciden con "192.168.12.16", lo que significa que la regla está verificando si alguna dirección IP no coincide con "192.168.12.16".
  • all $e.principal.ip != "192.168.12.16" verifica si todas las direcciones IP no coinciden con "192.168.12.16", lo que significa que la regla está verificando que ninguna dirección IP coincide con "192.168.12.16".

Sintaxis de la sección de coincidencias

En la sección match, enumera las variables de coincidencia para los eventos de grupo antes de verificar las condiciones de coincidencia. Estos campos se muestran con cada coincidencia.

  • En la sección events, especifica qué representa cada variable de coincidencia.
  • Especifica el intervalo de tiempo que se utilizará para correlacionar eventos después de la palabra clave over. Se ignoran los eventos que se encuentran fuera del intervalo de tiempo.
  • Usa la siguiente sintaxis para especificar el intervalo de tiempo: <number><s/m/h/d> Cuando s/m/h/d significa segundos, minutos, horas y días, respectivamente.
  • El tiempo mínimo que puedes especificar es 1 minuto.
  • El tiempo máximo que puedes especificar es de 48 horas.

A continuación, se muestra un ejemplo de un match válido:

$var1, $var2 over 5m

Esta declaración muestra $var1 y $var2 (que se definen en la sección events) cuando la regla encuentra una coincidencia. El tiempo especificado es de 5 minutos. Los eventos que tienen más de 5 minutos de diferencia no se correlacionan y, por lo tanto, la regla los ignora.

Este es otro ejemplo de un match válido:

$user over 1h

Esta declaración muestra $user cuando la regla encuentra una coincidencia. El período especificado es de 1 hora. Los eventos que tienen más de una hora de diferencia no se correlacionan. La regla no los considera una detección.

Este es otro ejemplo de un match válido:

$source_ip, $target_ip, $hostname over 2m

Esta declaración muestra $source_ip, $target_ip y $hostname cuando la regla encuentra una coincidencia. El período especificado es de 2 minutos. Los eventos que tienen más de 2 minutos de diferencia no se correlacionan. La regla no los considera una detección.

En los siguientes ejemplos, se ilustran las secciones no válidas match:

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

Ventana corrediza

De forma predeterminada, las reglas YARA-L 2.0 se evalúan mediante ventanas de salto. Un rango de tiempo de datos empresariales de eventos se divide en un conjunto de ventanas de salto superpuestas, cada una con la duración especificada en la sección match. Luego, los eventos se correlacionan dentro de cada ventana de salto. Con las ventanas de salto, es imposible buscar eventos que ocurren en un orden específico (por ejemplo, e1 ocurre hasta 2 minutos después de e2). Un caso de evento e1 y un evento de e2 se correlacionan siempre que estén dentro de la duración de la ventana de salto entre sí.

Las reglas también se pueden evaluar con ventanas variables. En el caso de las ventanas deslizantes, las ventanas variables con la duración especificada en la sección match se generan cuando se inicia o termina con una variable de evento dinámica específica. Luego, los eventos se correlacionan dentro de cada ventana deslizante. Esto permite buscar eventos que ocurran en un orden específico (por ejemplo, e1 ocurre dentro de los 2 minutos antes de e2). Un caso del evento e1 y un evento e2 se correlacionan si el evento e1 ocurre dentro de la ventana deslizante después del evento e2.

Especifica las ventanas variables en la sección match de una regla de la siguiente manera:

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

La variable de evento dinámica es la variable de evento en la que se basan las ventanas variables. Si usas la palabra clave before, se generan ventanas variables que terminan en cada caso del evento de tabla dinámica. Si se usa la palabra clave after, las ventanas deslizantes se generan a partir de cada caso del evento de tabla dinámica.

Los siguientes son ejemplos de usos válidos de ventanas variables:

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

Sintaxis de la sección de resultados

En la sección outcome, puedes definir hasta 10 variables de resultado con nombres arbitrarios. Estos resultados se almacenarán en las detecciones que generó la regla. Cada detección puede tener valores diferentes para los resultados.

El nombre del resultado, $risk_score, es especial. Opcionalmente, puedes definir un resultado con este nombre y, si lo haces, debe ser un tipo de número entero. Si se propaga, risk_score se mostrará en la vista de estadísticas empresariales para las alertas que provienen de detecciones de reglas.

Tipos de datos variables de los resultados

Cada variable de resultado puede tener un tipo de datos diferente, que se determina por la expresión que se usa para calcularlo. Se admiten los siguientes tipos de datos de resultados:

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

Lógica condicional

Puedes usar la lógica condicional para calcular el valor de un resultado. Los condicionales se especifican con el siguiente patrón de sintaxis:

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

Puedes leer una expresión condicional como "si BOOL_CLAUSE es verdadera, luego muestra THEN_CLAUSE; de lo contrario, muestra ELSE_CLAUSE"

BOOL_CLAUSE debe evaluarse como un valor booleano. Una expresión BOOL_CLAUSE tiene una forma similar a las expresiones en la sección events. Por ejemplo, puede incluir lo siguiente:

  • Nombres de campos de UDM con un operador de comparación, por ejemplo:

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

  • variable del marcador de posición que se definió en la sección events, por ejemplo:

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

  • funciones que muestran un valor booleano, por ejemplo:

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

  • buscar una lista de referencia, por ejemplo:

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

THEN_CLAUSE y ELSE_CLAUSE deben ser del mismo tipo de datos. Se admiten strings y números enteros.

Puedes omitir ELSE_CLAUSE si el tipo de datos es un número entero. Si se omite, ELSE_CLAUSE se evalúa como 0. Por ejemplo:

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

Debes proporcionar ELSE_CLAUSE si el tipo de datos es una string.

Operaciones matemáticas

Puedes usar operaciones matemáticas para calcular los resultados de tipos de datos de números enteros. Admitimos la suma y la resta. Por ejemplo:

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

Variables de marcadores de posición en los resultados

Cuando calculas las variables de un resultado, puedes usar variables de marcador de posición que se definieron en la sección de eventos de tu regla. En este ejemplo, supongamos que $email_sent_bytes se definió en la sección de eventos de la regla:

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

Datos recopilados

La expresión para calcular un resultado debe unirse en una función de agregación. Las funciones de agregación operan sobre todos los eventos que generaron una detección en particular. Puedes usar las siguientes funciones de agregación:

  • max(): Muestra el máximo sobre todos los valores posibles. Solo funciona con números enteros.
  • min(): Muestra el mínimo en todos los valores posibles. Solo funciona con números enteros.
  • sum(): Muestra la suma de todos los valores posibles. Solo funciona con números enteros.
  • count_distinct(): Recopila todos los valores posibles y, luego, da como resultado el recuento de valores posibles.
  • count(): se comporta como count_distinct(), pero muestra un recuento no distinto de valores posibles.
  • array_distinct(): Recopila todos los valores posibles y, luego, muestra una lista de estos valores. truncará la lista de valores en 25 elementos aleatorios.
  • array(): se comporta como array_distinct(), pero muestra una lista de valores no distintos. También trunca la lista de valores a 25 elementos aleatorios.

La función de agregación es importante cuando una regla incluye una sección condition que especifica que deben existir varios eventos, ya que la función de agregación operará en todos los eventos que generaron la detección.

Por ejemplo, si las secciones outcome y condition contienen lo siguiente:

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

Dado que la sección de condición requiere que haya más de un event para cada detección, las funciones de agregación operarán en varios eventos. Supongamos que los siguientes eventos generaron una detección:

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

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

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

Luego, los valores de los resultados serán los siguientes:

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

Debes tener en cuenta lo siguiente cuando uses la sección de resultados:

  • Solo puedes usar la sección outcome en las reglas de varios eventos, que son reglas que tienen una sección match.
  • La sección outcome no puede incluir eventos que no se definieron en la sección events. Solo puedes correlacionar eventos que ya se correlacionaron en la sección events. Del mismo modo, no puedes definir una nueva variable de marcador de posición que no esté definida en la sección events.

Puedes encontrar un ejemplo en la sección de resultados de la página Descripción general de YARA-L 2.0. Además, consulta Cómo crear estadísticas contextuales para obtener detalles sobre la eliminación de duplicados en la sección de resultados.

Sintaxis de la sección de condiciones

Recuento

El carácter # es un carácter especial en la sección condition. Si se usa antes de cualquier nombre de variable de evento o marcador de posición, representa la cantidad de eventos o valores distintos que satisfacen todas las condiciones de la sección events.

.

Sintaxis

En la sección condition, especifica la condición de coincidencia en eventos y variables definidos en la sección events. Haz una lista de predicados de coincidencia aquí, unidos a la palabra clave and o or.

Las siguientes son condiciones de límite. Fuerzan la variable de evento asociada para que exista, lo que significa que debe aparecer al menos un caso del evento en cualquier detección.

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

Las siguientes condiciones no se limitan a los límites. Permiten que la variable de evento asociada no exista, lo que significa que es posible que no se muestre ningún evento en una detección. Esto permite la creación de reglas de inexistencia, que buscan la ausencia de una variable en lugar de la presencia de una variable.

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

En el siguiente ejemplo, el carácter especial # en una variable (ya sea la variable de evento o la variable de marcador de posición) representa el recuento de valores o eventos distintos de esa variable:

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

El siguiente ejemplo de inexistencia también es válido y se evalúa como verdadero si hay más de dos eventos diferentes de $event1 y cero eventos distintos de $event2:

#event1 > 2 and !$event2

Los siguientes son ejemplos de predicados no válidos:

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

Sintaxis de la sección de opciones

En la sección options, puedes especificar las opciones para la regla. La sintaxis de la sección options es similar a la de la sección meta. Sin embargo, una clave debe ser uno de los nombres de opciones predefinidos y el valor no se limita al tipo de string.

Por el momento, la única opción disponible es allow_zero_values.

  • allow_zero_value: Si se establece como verdadera, las coincidencias generadas por la regla pueden tener cero valores como valores de variable coincidentes. Se asignan cero valores a los campos de eventos cuando no se propagan. Esta opción se establece como falsa de forma predeterminada.

A continuación, se muestra la línea de sección options válida:

  • allow_zero_values = true

Comprobación de tipos

Chronicle realiza una verificación de tipo con tu sintaxis YARA-L a medida que creas reglas dentro de la interfaz. Los errores de comprobación de tipos que se muestran le permiten revisar la regla para garantizar que funcione según lo esperado.

Los siguientes son ejemplos de predicados no vá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"