Crear consultas de varias fases en YARA-L
En este documento se describe cómo las consultas de varias fases de YARA-L te permiten introducir la salida de una fase de una consulta directamente en la entrada de una fase posterior. Este proceso te ofrece un mayor control sobre la transformación de datos que una sola consulta monolítica.
Integrar consultas de varias fases con funciones actuales
Las consultas de varias fases funcionan junto con las siguientes funciones de Google Security Operations:
Reglas de detección compuestas: las consultas de varias fases complementan las reglas de detección compuestas. A diferencia de las reglas compuestas, las consultas de varias fases que usan la búsqueda pueden devolver resultados en tiempo real.
Intervalos de tiempo y reglas de varios eventos: puede usar consultas de varias fases para detectar anomalías comparando diferentes ventanas de tiempo en sus datos. Por ejemplo, puedes usar las fases de consulta iniciales para establecer una base de referencia durante un periodo prolongado y, después, usar una fase posterior para evaluar la actividad reciente en comparación con esa base de referencia. También puedes usar reglas de varios eventos para crear un tipo de comparación similar.
Las consultas de varias fases en YARA-L se admiten tanto en los paneles de control como en la búsqueda.
Las combinaciones ayudan a correlacionar datos de varias fuentes para proporcionar más contexto a una investigación. Al vincular eventos, entidades y otros datos relacionados, puede investigar escenarios de ataque complejos. Para obtener más información, consulta Usar combinaciones en la Búsqueda.
Definir la sintaxis de YARA-L de varias fases
Cuando configure una consulta multietapa, tenga en cuenta lo siguiente:
- Fase de límite: las consultas de varias fases deben contener entre 1 y 4 fases con nombre, además de la fase raíz.
- Sintaxis de orden: define siempre la sintaxis de la fase con nombre antes de definir la sintaxis de la fase raíz.
Crear una consulta YARA-L de varias fases
Para crear una consulta YARA-L de varias fases, sigue estos pasos.
Estructura y sintaxis de las fases
Ve a Investigación > Búsqueda. Sigue estos requisitos estructurales cuando definas las fases de tu consulta:
Sintaxis: usa la siguiente sintaxis para asignar un nombre a cada fase y separarla de las demás:
stage <stage name> { }
Llaves: coloca toda la sintaxis de la fase entre llaves {}.
Orden: define la sintaxis de todas las fases con nombre antes de definir la fase raíz.
Referencias: cada fase puede hacer referencia a fases definidas anteriormente en la consulta.
Fase raíz: una consulta debe tener una fase raíz, que se procesa después de todas las fases con nombre.
La siguiente fase de ejemplo, daily_stats, recoge estadísticas de red diarias:
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 fase de acceso
Las fases posteriores pueden acceder a la salida de una fase con nombre mediante campos de fase. Los campos de fase se corresponden con las variables match y outcome
de la fase y se pueden usar de forma similar a los campos del modelo de datos unificado (UDM).
Usa la siguiente sintaxis para acceder a un campo de fase:
$<stage name>.<variable name>
Marcas de tiempo de la ventana de acceso (opcional)
Si una fase con nombre usa una ventana de salto, deslizamiento o volcado, accede al inicio y al final de la ventana de cada fila de salida mediante 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 fases pueden variar de tamaño.
Limitaciones
Las consultas de varias fases tienen las siguientes restricciones funcionales y estructurales:
Límites de estructura y de fases
Fase raíz: solo se permite una fase raíz por consulta.
Etapas con nombre: se admiten un máximo de cuatro etapas con nombre.
Referencia de fases: una fase solo puede hacer referencia a fases definidas lógicamente antes que ella en la misma consulta.
Combinaciones: se permiten un máximo de cuatro combinaciones que no sean de tablas de datos en todas las fases.
Requisito de resultado: cada fase con nombre (excepto la fase raíz) debe incluir una sección
matcho una secciónoutcome. La secciónoutcomeno requiere agregación.
Límites de ventanas y compatibilidad
Compatibilidad con funciones: las consultas de varias fases se admiten en Búsqueda y Paneles de control, pero no en Reglas.
Tipos de ventana: no mezcles diferentes tipos de ventana en una misma consulta.
Dependencia de ventanas: una fase que use una ventana de salto o una ventana deslizante no puede depender de otra fase que también use una ventana de salto o una ventana deslizante.
Tamaño de la ventana de tiempo: aunque las ventanas de tiempo de las diferentes fases pueden variar de tamaño, la diferencia entre ellas debe ser inferior a 720x.
Ejemplo: Diferencia de agregación de fases
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 fase monthly_stats agrega datos por mes y la fase raíz agrega el resultado de monthly_stats por minuto, cada fila de monthly_stats se asigna a 43.200 filas en la fase raíz (porque hay 43.200 minutos en un mes).
Limitaciones de las fases y las consultas
Cada fase de una consulta de varias fases tiene las siguientes restricciones:
La mayoría de las limitaciones que se aplican a una consulta de una sola fase también se aplican a cada fase individual:
Requisito de salida: cada fase debe generar al menos una variable de coincidencia o de resultado (campo de fase).
Ventana en la combinación: el tamaño máximo de la ventana (de salto, acumulativa o deslizante) que se puede usar en una combinación es de 2 días.
Número máximo de variables de resultados:
20 para los clientes que no han habilitado el límite de variables de resultado más alto
50 para los clientes que han habilitado un límite más alto para las variables de resultado
Número máximo de elementos de una variable de resultado con valores de matriz.
Las consultas multietapa están sujetas a las mismas limitaciones que las consultas de estadísticas:
Consultas de estadísticas: 120 consultas por hora (API e interfaz de usuario)
Vistas de búsqueda de Google SecOps: 100 vistas por minuto
Las combinaciones de varias fases se admiten en la interfaz de usuario y en la API de
EventService.UDMSearch, pero no en la API deSearchService.UDMSearch. Las consultas de varias fases sin combinaciones también se admiten en la interfaz de usuario.
Limitaciones de eventos y globales
Número máximo de eventos:
El número de eventos que pueden procesar simultáneamente las consultas multietapa está estrictamente limitado:
Eventos de UDM: se permiten un máximo de dos eventos de UDM.
Eventos de gráfico de contexto de entidad (ECG): se permite un máximo de un evento de ECG.
Limitaciones de las consultas globales:
Estos límites son restricciones de toda la plataforma que controlan la antigüedad y la cantidad de datos que puede devolver una consulta multietapa.
En el caso de un intervalo de tiempo de una consulta, el intervalo máximo de una consulta estándar es de 30 días.
El tamaño máximo del conjunto de resultados es de 10.000 resultados.
Ejemplos de consultas de varias fases
Los ejemplos de esta sección te ayudarán a entender cómo puedes crear una consulta completa de YARA-L de varias fases.
Ejemplo: Buscar conexiones de red inusualmente activas (horas)
En este ejemplo de YARA-L de varias fases se identifican pares de direcciones IP con una actividad de red superior a la normal. El objetivo son los pares que mantienen una actividad alta durante más de tres horas. La consulta incluye dos componentes obligatorios: la fase con nombre, hourly_stats, y la fase root.
En la fase hourly_stats, se buscan pares de principal.ip y target.ip con niveles altos de actividad de red.
Esta fase devuelve un único valor por hora para los siguientes campos:
Estadísticas de la IP de origen (cadena):
$hourly_stats.src_ipEstadísticas de la IP de destino (cadena):
$hourly_stats.dst_ipEstadísticas del recuento de eventos (número entero):
$hourly_stats.countDesviación estándar de los bytes recibidos (float):
$hourly_stats.std_recd_bytesMedia de bytes recibidos (float):
$hourly_stats.avg_recd_bytesHora de inicio del intervalo en segundos desde el inicio del registro de tiempo de Unix (entero):
$hourly_stats.window_startHora de finalización del intervalo en segundos desde el inicio del registro de tiempo de Unix (entero):
$hourly_stats.window_end
La fase raíz procesa el resultado de la fase hourly_stats. Calcula estadísticas de los pares principal.ip y target.ip cuya actividad supera el umbral especificado por $hourly_stats. A continuación, filtra las parejas 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 modifica la condición de coincidencia en la fase raíz de la siguiente manera, puede introducir una agregación por día en la consulta de varias fases.
match:
$src_ip, $dst_ip by day
Ejemplo: Buscar conexiones de red inusualmente activas (con la puntuación Z)
Esta consulta de varias fases compara la actividad de red media diaria con la actividad de hoy mediante un cálculo de puntuación Z (que mide el número de desviaciones estándar con respecto a la media). Esta consulta busca de forma eficaz una actividad de red inusualmente alta entre recursos internos y sistemas externos.
Requisito previo: la ventana temporal de la consulta debe ser igual o superior a 2 días e incluir el día actual para que la puntuación Z calculada sea efectiva.
Esta consulta de varias fases incluye las fases daily_stats y root, que funcionan conjuntamente para calcular la puntuación Z de la actividad de la red:
La fase
daily_statsrealiza la agregación diaria inicial. Calcula el total de bytes intercambiados cada día por cada par de IPs (sourceytarget) y devuelve los siguientes campos de la fase (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, entero$daily_stats.window_start: singular, entero$daily_stats.window_end: singular, entero
La fase raíz agrega la salida de la fase
daily_statsde cada par de IPs. Calcula la media y la desviación estándar de los bytes diarios intercambiados en todo el intervalo de búsqueda, así como los bytes intercambiados hoy. Usa esos tres valores calculados para determinar la puntuación Z.En la salida se muestran las puntuaciones Z de todos los pares de IPs de hoy, 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
Exportar variables sin agregar de fases
Las fases con nombre pueden incluir una sección outcome sin agregar. Esto significa que las variables definidas en esa sección outcome se generan directamente desde la fase, lo que permite que las fases posteriores accedan a ellas como campos de fase sin necesidad de una agregación agrupada.
Ejemplo: Exportar una variable sin agregar
En este ejemplo se muestra cómo exportar variables sin agregar. Ten en cuenta la siguiente lógica:
top_5_bytes_sentbusca los cinco eventos con la mayor actividad de red.La fase
top_5_bytes_sentgenera los siguientes campos de fase correspondientes a las columnas de las filas de salida:$top_5_bytes_sent.bytes_sent: singular, entero$top_5_bytes_sent.timestamp_seconds: singular, entero
La fase
rootcalcula las marcas de tiempo más recientes y más antiguas de 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))
Implementar ventanas en consultas de varias fases
Las consultas de varias fases admiten todos los tipos de ventanas (saltos, deslizantes y de acoplamiento) en fases con nombre. Si una fase con nombre incluye una ventana, se puede acceder al inicio y al final de la ventana de cada fila de salida mediante los siguientes campos reservados:
$<stage name>.window_start$<stage name>.window_end
Ejemplo: ventana de salto
En el siguiente ejemplo se muestra cómo puedes usar ventanas de salto en una consulta de varias fases:
La fase
hourly_statsbusca pares de IPs que tengan una actividad de red alta en la misma hora.hourly_statsgenera los siguientes campos de fase correspondientes a las columnas de las filas de salida:$hourly_stats.src_ip: singular, cadena$hourly_stats.dst_ip: singular, cadena$hourly_stats.count: singular, entero$hourly_stats.std_recd_bytes: singular, float$hourly_stats.avg_recd_bytes: singular, float$hourly_stats.window_start: singular, entero$hourly_stats.window_end: singular, entero
La fase raíz filtra los pares de IPs con más de 3 horas de actividad alta. Las horas podrían solaparse debido al uso de una ventana de salto en la fase
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 cuando implementes consultas multietapa:
Todas las consultas de varias fases se comportan como las consultas de búsqueda de estadísticas (la salida consta de estadísticas agregadas en lugar de eventos sin agregar o filas de tablas de datos).
El rendimiento de las uniones con eventos de UDM y de entidad en un lado puede ser bajo debido al tamaño de ese conjunto de datos. Recomendamos encarecidamente filtrar los eventos de UDM y de entidad del lado de la unión tanto como sea posible (por ejemplo, filtrar por tipo de evento).
Para obtener directrices generales sobre las prácticas recomendadas, consulta las prácticas recomendadas de Yara-L. Para obtener información específica sobre las combinaciones, consulta las prácticas recomendadas.
¿Necesitas más ayuda? Recibe respuestas de los miembros de la comunidad y de los profesionales de Google SecOps.