Crea consultas de varias etapas en YARA-L

Compatible con:

En este documento, se describe cómo las consultas de varias etapas en YARA-L te permiten ingresar el resultado de una etapa de la consulta directamente en la entrada de una etapa posterior. Este proceso te brinda un mayor control sobre la transformación de datos que una sola consulta monolítica.

Integrar búsquedas de varias etapas con funciones existentes

Las consultas de varias etapas funcionan en conjunto con las siguientes funciones existentes en Google Security Operations:

  • Reglas de detección compuestas: Las consultas de varias etapas complementan las reglas de detección compuestas. A diferencia de las reglas compuestas, las búsquedas de varias etapas que usan Search pueden devolver resultados en tiempo real.

  • Períodos y reglas de varios eventos: Puedes usar consultas de varias etapas para detectar anomalías comparando diferentes períodos en tus datos. Por ejemplo, puedes usar las etapas iniciales de tu búsqueda para establecer un valor de referencia durante un período prolongado y, luego, usar una etapa posterior para evaluar la actividad reciente en comparación con ese valor de referencia. También puedes usar reglas de varios eventos para crear un tipo de comparación similar.

Las consultas de varias etapas en YARA-L son compatibles con los paneles y la búsqueda.

Las uniones ayudan a correlacionar datos de múltiples fuentes para proporcionar más contexto para una investigación. Al vincular eventos, entidades y otros datos relacionados, puedes investigar situaciones de ataque complejas. Para obtener más información, consulta Cómo usar uniones en la Búsqueda.

Cómo definir la sintaxis de YARA-L de varias etapas

A medida que configures una consulta de varias etapas, ten en cuenta lo siguiente:

  • Etapa de límite: Las consultas de varias etapas deben contener entre 1 y 4 etapas con nombre, además de la etapa raíz.
  • Sintaxis de orden: Siempre define la sintaxis de la etapa con nombre antes de definir la sintaxis de la etapa raíz.

Crea una consulta de YARA-L de varias etapas

Para crear una búsqueda de YARA-L de varias etapas, completa los siguientes pasos.

Estructura y sintaxis de la etapa

Ve a Investigación > Búsqueda. Sigue estos requisitos estructurales cuando definas las etapas de tu consulta:

Sintaxis: Usa la siguiente sintaxis para nombrar cada etapa y separarla de otras etapas:

stage <stage name> { }

  • Llaves: Coloca toda la sintaxis de la etapa dentro de llaves {}.

  • Orden: Define la sintaxis para todas las etapas con nombre antes de definir la etapa raíz.

  • Referencias: Cada etapa puede hacer referencia a etapas definidas anteriormente en la consulta.

  • Etapa raíz: Una consulta debe tener una etapa raíz, que se procesa después de todas las etapas con nombre.

La siguiente etapa de ejemplo, daily_stats, recopila estadísticas diarias de la red:

stage daily_stats {
  metadata.event_type = "NETWORK_CONNECTION"
  $source = principal.hostname
  $target = target.ip
  $source != ""
  $target != ""
  $total_bytes = cast.as_int(network.sent_bytes + network.received_bytes)
  match:
    $source, $target by day
  outcome:
    $exchanged_bytes = sum($total_bytes)
}

Salida de la etapa de acceso

Se puede acceder al resultado de una etapa con nombre en etapas posteriores a través de los campos de etapa. Los campos de etapa corresponden a las variables match y outcome de la etapa, y se pueden usar de manera similar a los campos del modelo de datos unificado (UDM).

Usa la siguiente sintaxis para acceder a un campo de etapa:

$<stage name>.<variable name>

Marcas de tiempo de la ventana de acceso (opcional)

Si una etapa con nombre usa una ventana de salto, deslizante o rotativa, accede al inicio y al final de la ventana para cada fila de salida con estos campos reservados:

  • $<stage name>.window_start

  • $<stage name>.window_end

window_start y window_end son campos de números enteros expresados en segundos desde la época de Unix. Las ventanas en diferentes etapas pueden variar en tamaño.

Limitaciones

Las consultas de varias etapas tienen las siguientes restricciones funcionales y estructurales:

Límites estructurales y de etapas

  • Etapa raíz: Solo se permite una etapa raíz por búsqueda.

  • Etapas con nombre: Se admite un máximo de cuatro etapas con nombre.

  • Referencia de etapas: Una etapa solo puede hacer referencia a etapas definidas lógicamente antes de ella en la misma consulta.

  • Uniones: Se permite un máximo de cuatro uniones que no sean de tablas de datos en todas las etapas.

  • Requisito de resultado: Cada etapa con nombre (excepto la etapa raíz) debe incluir una sección match o una sección outcome. La sección outcome no requiere agregación.

Límites de ventanas y compatibilidad

  • Compatibilidad con funciones: Las consultas de varias etapas son compatibles con Search y Dashboards, pero no con Rules.

  • Tipos de ventanas: Evita mezclar diferentes tipos de ventanas en una sola búsqueda.

  • Dependencia de ventana: Una etapa que usa una ventana deslizante o de salto no puede depender de otra etapa que también use una ventana deslizante o de salto.

  • Tamaño de la ventana deslizante: Si bien las ventanas deslizantes en diferentes etapas pueden variar en tamaño, la diferencia de tamaño debe ser inferior a 720x.

Ejemplo: Diferencia de agregación por etapa

No se permite la siguiente configuración de ventana de ejemplo:

stage monthly_stats {
  metadata.event_type = "NETWORK_CONNECTION"
    $source = principal.hostname
    $target = target.ip
    $source != ""
    $target != ""
    $total_bytes = cast.as_int(network.sent_bytes + network.received_bytes)

  match:
    $source, $target by month

  outcome:
    $exchanged_bytes = sum($total_bytes)
}

$source = $monthly_stats.source
$target = $monthly_stats.target

match:
    $source, $target by minute

Si la etapa monthly_stats agrega datos por mes y la etapa raíz agrega el resultado de monthly_stats por minuto, cada fila de monthly_stats se asigna a 43,200 filas en la etapa raíz (porque hay 43,200 minutos en un mes).

Limitaciones de las etapas y las consultas

Cada etapa individual dentro de una consulta de varias etapas tiene las siguientes restricciones:

  • La mayoría de las limitaciones que se aplican a una consulta de una sola etapa también se aplican a cada etapa individual:

  • Las consultas de varias etapas están sujetas a las mismas limitaciones que las consultas de estadísticas:

    • Consultas de estadísticas: 120 QPH (API y IU)

    • Vistas de búsqueda de Google SecOps: 100 vistas por minuto

    • Las uniones de varias etapas son compatibles con la interfaz de usuario y la API de EventService.UDMSearch, pero no con la API de SearchService.UDMSearch. Las consultas de varias etapas sin uniones también se admiten en la interfaz de usuario.

Limitaciones globales y de eventos

Cantidad máxima de eventos:

Las consultas de varias etapas están estrictamente limitadas en la cantidad de eventos que pueden procesar de forma simultánea:

  • Eventos del UDM: Se permite un máximo de 2 eventos del UDM.

  • Eventos del gráfico de contexto de entidades (ECG): Se permite un máximo de un evento del ECG.

Limitaciones de las búsquedas globales:

Estos límites son restricciones en toda la plataforma que controlan la antigüedad y la cantidad de datos que puede devolver una consulta de varias etapas.

  • En el caso de un intervalo de tiempo de la consulta, el intervalo máximo para una consulta estándar es de 30 días.

  • El tamaño máximo total del conjunto de resultados es de 10,000 resultados.

Ejemplos de consultas de varias etapas

Los ejemplos de esta sección ayudan a ilustrar cómo puedes crear una consulta de YARA-L completa de varias etapas.

Ejemplo: Buscar conexiones de red inusualmente activas (horas)

Este ejemplo de YARA-L de varias etapas identifica pares de direcciones IP con actividad de red superior a la normal, y se enfoca en los pares que mantienen una actividad alta durante más de tres horas. La consulta incluye dos componentes obligatorios: la etapa con nombre, hourly_stats, y la etapa root.

La etapa hourly_stats busca pares de principal.ip y target.ip con altos niveles de actividad de red.

Esta etapa devuelve un solo valor por hora para los siguientes campos:

  • Estadísticas de la IP de origen (cadena): $hourly_stats.src_ip

  • Estadísticas de la IP de destino (cadena): $hourly_stats.dst_ip

  • Estadísticas para el recuento de eventos (número entero): $hourly_stats.count

  • Desviación estándar de los bytes recibidos (número de punto flotante): $hourly_stats.std_recd_bytes

  • Promedio de bytes recibidos (número de punto flotante): $hourly_stats.avg_recd_bytes

  • Hora de inicio del intervalo horario en segundos desde la época de Unix (número entero): $hourly_stats.window_start

  • Hora de finalización del intervalo horario en segundos desde la época de Unix (número entero): $hourly_stats.window_end

La etapa raíz procesa el resultado de la etapa hourly_stats. Calcula estadísticas para los pares principal.ip y target.ip con actividad que supera el umbral especificado por $hourly_stats. Luego, filtra los pares con más de tres horas de actividad alta.


stage hourly_stats {
  metadata.event_type = "NETWORK_CONNECTION"
  $src_ip = principal.ip
  $dst_ip = target.ip
  $src_ip != ""
  $dst_ip != ""

  match:
    $src_ip, $dst_ip by hour

  outcome:
    $count = count(metadata.id)
    $avg_recd_bytes = avg(network.received_bytes)
    $std_recd_bytes = stddev(network.received_bytes)

  condition:
    $avg_recd_bytes > 100 and $std_recd_bytes > 50
}

$src_ip = $hourly_stats.src_ip
$dst_ip = $hourly_stats.dst_ip
$time_bucket_count = strings.concat(timestamp.get_timestamp($hourly_stats.window_start), "|", $hourly_stats.count)

match:
 $src_ip, $dst_ip

outcome:
 $list = array_distinct($time_bucket_count)
 $count = count_distinct($hourly_stats.window_start)

condition:
 $count > 3

Si modificas la condición de coincidencia en la etapa raíz de la siguiente manera, puedes introducir una agregación con ventanas por día para la consulta de varias etapas.

match:
 $src_ip, $dst_ip by day

Ejemplo: Busca conexiones de red inusualmente activas (con la puntuación Z)

Esta consulta de varias etapas compara la actividad de red promedio diaria con la actividad de hoy usando un cálculo de la puntuación Z (que mide la cantidad de desviaciones estándar con respecto a la media). Esta consulta busca de manera eficaz actividad de red inusualmente alta entre los activos internos y los sistemas externos.

Requisito previo: El período de la consulta debe ser mayor o igual a 2 días y debe incluir el día actual para que la puntuación Z calculada sea efectiva.

Esta consulta de varias etapas incluye la etapa daily_stats y la etapa root, que trabajan en conjunto para calcular la puntuación Z de la actividad de la red:

  • La etapa daily_stats realiza la agregación diaria inicial. Calcula los bytes totales intercambiados cada día para cada par de IP (source y target) y devuelve los siguientes campos de etapa (que corresponden a las columnas de las filas de salida):

    • $daily_stats.source: singular, cadena
    • $daily_stats.target: singular, cadena
    • $daily_stats.exchanged_bytes: Singular, número entero
    • $daily_stats.window_start: Singular, número entero
    • $daily_stats.window_end: Singular, número entero
  • La etapa raíz agrega el resultado de la etapa daily_stats para cada par de IP. Calcula el promedio y la desviación estándar de los bytes diarios intercambiados en todo el rango de búsqueda, junto con los bytes intercambiados hoy. Utiliza esos tres valores calculados para determinar la puntuación Z.

  • En el resultado, se enumeran las puntuaciones Z de todos los pares de IP del día, ordenadas de forma descendente.

// Calculate the total bytes exchanged per day by source and target

stage daily_stats {
  metadata.event_type = "NETWORK_CONNECTION"
  $source = principal.hostname
  $target = target.ip
  $source != ""
  $target != ""
  $total_bytes = cast.as_int(network.sent_bytes + network.received_bytes)
  match:
    $source, $target by day
  outcome:
    $exchanged_bytes = sum($total_bytes)
}

// Calculate the average per day over the time window and compare with the bytes
   exchanged today

$source = $daily_stats.source
$target = $daily_stats.target
$date = timestamp.get_date($daily_stats.window_start)

match:
  $source, $target

outcome:
  $today_bytes = sum(if($date = timestamp.get_date(timestamp.current_seconds()), $daily_stats.exchanged_bytes, 0))
  $average_bytes = window.avg($daily_stats.exchanged_bytes)
  $stddev_bytes = window.stddev($daily_stats.exchanged_bytes)
  $zscore = ($today_bytes - $average_bytes) / $stddev_bytes

order:
  $zscore desc

Cómo exportar variables sin agregar de etapas

Las etapas con nombre pueden incluir una sección outcome sin agregar. Esto significa que las variables definidas dentro de esa sección outcome se generan directamente desde la etapa, lo que permite que las etapas posteriores accedan a ellas como campos de etapa sin necesidad de una agregación agrupada.

Ejemplo: Exporta una variable sin agregar

En este ejemplo, se muestra cómo exportar variables sin agregar. Ten en cuenta la siguiente lógica:

  • La etapa top_5_bytes_sent busca los cinco eventos con la mayor actividad de red.

  • La etapa top_5_bytes_sent genera los siguientes campos de etapa que corresponden a las columnas de las filas de salida:

    • $top_5_bytes_sent.bytes_sent: Singular, número entero
    • $top_5_bytes_sent.timestamp_seconds: Singular, número entero
  • La etapa root calcula las marcas de tiempo más recientes y más tempranas para los cinco eventos con la mayor actividad de red.

stage top_5_bytes_sent {
  metadata.event_type = "NETWORK_CONNECTION"
  network.sent_bytes > 0

  outcome:
    $bytes_sent = cast.as_int(network.sent_bytes)
    $timestamp_seconds = metadata.event_timestamp.seconds

  order:
    $bytes_sent desc 
  
  limit:
    5
}

outcome:
  $latest_timestamp = timestamp.get_timestamp(max($top_5_bytes_sent.timestamp_seconds))
  $earliest_timestamp = timestamp.get_timestamp(min($top_5_bytes_sent.timestamp_seconds))

Implementa el sistema de ventanas en consultas de varias etapas

Las consultas de varias etapas admiten todos los tipos de ventanas (de salto, deslizantes y continuas) en etapas con nombre. Si una etapa con nombre incluye una ventana, se puede acceder al inicio y al final de la ventana para cada fila de salida con los siguientes campos reservados:

  • $<stage name>.window_start
  • $<stage name>.window_end

Ejemplo: Ventana de salto

En el siguiente ejemplo, se ilustra cómo podrías usar ventanas de salto en una consulta de varias etapas:

  • La etapa hourly_stats busca pares de IP que tengan una alta actividad de red en la misma hora.

  • hourly_stats genera los siguientes campos de etapa que corresponden a las columnas de las filas de salida:

    • $hourly_stats.src_ip: singular, cadena
    • $hourly_stats.dst_ip: singular, cadena
    • $hourly_stats.count: Singular, número entero
    • $hourly_stats.std_recd_bytes: Singular, número de punto flotante
    • $hourly_stats.avg_recd_bytes: Singular, número de punto flotante
    • $hourly_stats.window_start: Singular, número entero
    • $hourly_stats.window_end: Singular, número entero
  • La etapa raíz filtra los pares de IP con más de 3 horas de actividad alta. Las horas podrían superponerse debido al uso de una ventana de salto en la etapa hourly_stats.

stage hourly_stats {
  metadata.event_type = "NETWORK_CONNECTION"
  $src_ip = principal.ip
  $dst_ip = target.ip
  $src_ip != ""
  $dst_ip != ""

  match:
    $src_ip, $dst_ip over 1h

  outcome:
    $count = count(metadata.id)
    $avg_recd_bytes = avg(network.received_bytes)
    $std_recd_bytes = stddev(network.received_bytes)

  condition:
    $avg_recd_bytes > 100 and $std_recd_bytes > 50
}

$src_ip = $hourly_stats.src_ip
$dst_ip = $hourly_stats.dst_ip
$time_bucket_count = strings.concat(timestamp.get_timestamp($hourly_stats.window_start), "|", $hourly_stats.count)

match:
 $src_ip, $dst_ip

outcome:
 $list = array_distinct($time_bucket_count)
 $count = count_distinct($hourly_stats.window_start)

condition:
 $count > 3

Problemas conocidos

Te recomendamos que revises las siguientes limitaciones y soluciones alternativas recomendadas cuando implementes consultas de varias etapas:

  • Todas las consultas de varias etapas se comportan como consultas de búsqueda de estadísticas (el resultado consta de estadísticas agregadas en lugar de eventos sin agregar o filas de tablas de datos).

  • El rendimiento de las combinaciones con eventos de UDM y de entidades en un lado puede ser bajo debido al tamaño de ese conjunto de datos. Te recomendamos que filtres los eventos de UDM y de entidades del lado de la unión tanto como sea posible (por ejemplo, filtra por tipo de evento).

Para obtener orientación general sobre las prácticas recomendadas, consulta Prácticas recomendadas de Yara-L y, para obtener información específica sobre las uniones, consulta Prácticas recomendadas.

¿Necesitas más ayuda? Obtén respuestas de miembros de la comunidad y profesionales de Google SecOps.