Correlaciona datos con uniones externas

Compatible con:

En este documento, se describen las uniones externas (unión izquierda y unión derecha). Las operaciones de unión se usan para correlacionar y combinar datos de varias fuentes según los valores de campo comunes. Si combinas eventos y entidades de seguridad relacionados en una sola vista integral, puedes proporcionar una detección y una investigación de amenazas eficaces.

A diferencia de las uniones (internas) estándar, que requieren entradas coincidentes en ambas fuentes de datos, una unión externa recupera todos los registros de un lado de la unión, incluso si no hay entradas coincidentes en el otro. Los campos no coincidentes del otro lado suelen completarse con null. Esto evita que pierdas datos que no tienen una coincidencia.

Cómo funcionan las uniones externas

El concepto de uniones externas en YARA-L 2.0 es idéntico a las uniones externas de SQL estándar:

  • La unión externa izquierda conserva todos los registros del lado izquierdo de la unión.

  • La unión externa derecha conserva todos los registros del lado derecho de la unión.

La sintaxis de unión externa (unión izquierda y unión derecha) es compatible con todas las consultas, con y sin una condición match. El comportamiento fundamental de una unión externa es el mismo en la búsqueda, los paneles y las reglas de detección, aunque la sintaxis difiere según el contexto:

  • Búsqueda y paneles: Usa las palabras clave explícitas left join o right join en la sección events.

  • Reglas de detección: Define la relación de unión con un signo igual (=) en la sección events y especifica una condición sin límites en la sección condition (por ejemplo, #data_table >= 0 para una unión externa izquierda o #data_table = 0 para una exclusión antiunión).

Comprende la unión externa izquierda

Una unión externa izquierda (o unión izquierda) conserva todos los registros de la fuente de datos en el lado izquierdo (conservado) de la unión, ya sea que uses la palabra clave left join en la búsqueda o una condición sin límites (#data_table >= 0) en una regla de detección.

  • Si un registro del lado izquierdo no tiene coincidencia en la tabla de eventos o datos de la derecha, los campos del lado derecho se devuelven como null.

  • Implicación del marcador de posición: Cualquier variable de marcador de posición que se use en la sección match debe hacer referencia a un campo del evento de la izquierda para garantizar una agregación de datos precisa en todo el conjunto de resultados.

Ejemplo de unión izquierda de evento a evento

En el siguiente ejemplo, se muestra una unión externa izquierda para correlacionar los eventos de acceso de los usuarios con los eventos de conexión de red posteriores que ocurren en el mismo host. La unión izquierda garantiza que todos los eventos USER_LOGIN se conserven en el conjunto de resultados. Si se encuentra un evento NETWORK_CONNECTION ($e2) coincidente, se unen sus datos. Si no se encuentra ninguna coincidencia, los campos de $e2 serán null.


$e1.metadata.event_type = "USER_LOGIN"
$e2.metadata.event_type = "NETWORK_CONNECTION"
left join $e1.principal.hostname = $e2.principal.hostname

Define el evento de salida

En el siguiente ejemplo de consulta, se define el lado izquierdo de la unión ($e1), que es el conjunto de eventos que se conserva en el resultado final:

$e1.metadata.event_type = "USER_LOGIN"

En la siguiente tabla, se representa el resultado de la consulta, que identifica el conjunto inicial de eventos de acceso de los usuarios:

Tipo de evento Nombre de host principal Dirección IP
USER_LOGIN workstation-01 192.168.1.101
USER_LOGIN laptop-hr-02 192.168.1.102
USER_LOGIN server-db-03 10.0.0.50
USER_LOGIN kiosk-4 192.168.1.104

Define el evento correcto

En el siguiente ejemplo de consulta, se define el lado derecho de la unión ($e2), que es el conjunto de eventos que se compara con los eventos de la izquierda:

$e2.metadata.event_type = "NETWORK_CONNECTION"

En la siguiente tabla, se representa el conjunto de eventos de conexión de red disponibles para la coincidencia:

Tipo de evento Nombre de host principal Dirección IP
NETWORK_CONNECTION workstation-01 192.168.1.101
NETWORK_CONNECTION laptop-hr-02 192.168.1.101
NETWORK_CONNECTION kiosk-4 203.0.113.3

Únete a los eventos

con una sección de coincidencias

En el siguiente ejemplo, se muestra una consulta de coincidencia con una unión externa izquierda en el campo principal.hostname:


  $e1.metadata.event_type = "USER_LOGIN"

  $e2.metadata.event_type = "NETWORK_CONNECTION"

  left join $e1.principal.hostname = $e2.principal.hostname

  $host = $e1.principal.hostname

  match:
    $host over 5m

  • La unión externa izquierda garantiza que cada evento USER_LOGIN ($e1) se incluya en el conjunto de resultados final.

  • Al marcador de posición $host se le asigna el valor de $e1.principal.hostname. La unión externa izquierda garantiza la presencia del evento $e1, lo que asegura que la variable $host siempre se complete para la agregación.

  • La regla agrega los resultados por host para un período de 5 minutos.

Resultado de la unión

Los datos resultantes muestran la combinación de los dos eventos. Se conservan todos los registros de la tabla izquierda ($e1) y los campos de la tabla derecha ($e2) se establecen en null cuando no se encuentra un nombre de host coincidente (por ejemplo, para server-db-03).

Tipo de evento ($e1) Nombre de host principal ($host) Dirección IP ($e1) Tipo de evento ($e2) Dirección IP ($e2) Estado de coincidencia
USER_LOGIN workstation-01 192.168.1.101 NETWORK_CONNECTION 192.168.1.101 Se encontró una coincidencia
USER_LOGIN laptop-hr-02 192.168.1.102 NETWORK_CONNECTION 192.168.1.101 Se encontró una coincidencia
USER_LOGIN server-db-03 10.0.0.50 null null No hay coincidencias
USER_LOGIN kiosk-4 192.168.1.104 NETWORK_CONNECTION 203.0.113.3 Se encontró una coincidencia

Ejemplos de consultas de unión izquierda

En esta sección, se proporcionan ejemplos de consultas de unión izquierda.

Uniones con una condición de coincidencia

  • Entidad de evento

    
    $e1.metadata.event_type = "NETWORK_CONNECTION"
    $g1.graph.metadata.entity_type = "ASSET"
    left join $e1.principal.asset.hostname = $g1.graph.entity.asset.hostname
    $host = $e1.principal.asset.hostname
    
    match:
      $host over 5m
    
    
  • Event-datatable

    
    $host = $e1.principal.hostname
    left join $e1.principal.hostname = %all_dt_column_types.hostname
    
    match:
      $host by 5m
    

Uniones sin una condición de coincidencia

  • Event-event

    
    $e1.metadata.event_type = "USER_LOGIN"
    $e1.principal.ip = "114.241.96.87"
    $e2.metadata.event_type = "NETWORK_CONNECTION"
    left join $e1.principal.hostname = $e2.principal.hostname
    
    
  • Entidad de evento

    
    $e1.metadata.event_type = "NETWORK_CONNECTION"
    $g1.graph.metadata.entity_type = "ASSET"
    left join $e1.principal.asset.hostname = $g1.graph.entity.asset.hostname
    $host = $e1.principal.asset.hostname
    
    
  • Event-datatable

    
    $host = $e1.principal.hostname
    left join $e1.principal.hostname = %all_dt_column_types.hostname
    
    

Uniones izquierdas en las reglas de detección

En las reglas de detección, no usas la palabra clave left join en la sección events. En su lugar, vinculas un evento de UDM a una tabla de datos o a un evento secundario en la sección events con igualdad (=) y controlas el comportamiento de unión en la sección condition:

Tipo de unión Sección events Sección condition Comportamiento en eventos no coincidentes
Unión interna $key = %data_table.key $e and #data_table > 0 Los eventos que no coinciden se descartan del flujo de detección.
Unión externa izquierda (enriquecimiento) $key = %data_table.key $e and #data_table >= 0 Se conservan todos los eventos de $e; los campos de la tabla de datos que no coinciden son null.
Anti-join (exclusión) $key = %data_table.key $e and #data_table = 0 Activa una alerta solo cuando la clave del evento no existe en la tabla de datos.

Ejemplo de unión izquierda de evento a tabla de datos en una regla

En el siguiente ejemplo, se usa una tabla de datos llamada corporate_asset_directory para enriquecer los eventos con metadatos geográficos y de importancia de los recursos sin descartar eventos de hosts no administrados.

Define la tabla de datos

La tabla de datos corporate_asset_directory contiene las siguientes filas, con hostname como columna clave:

hostname (clave) country_code country_name asset_tier owner_dept risk_score
ES01-W10 ES Spain TIER_3_WORKSTATION Finance 20
CH02-SRV CH Switzerland TIER_1_CRITICAL Engineering 80
US03-LAP US United States TIER_2_PRODUCTION Executive 50

Compara las condiciones de INNER JOIN y LEFT OUTER JOIN

  • Unión interna (#corporate_asset_directory > 0): Si se requiere que el recuento de tablas de datos sea mayor que 0, se realiza una unión interna. Si un evento se origina en un host no administrado que no aparece en corporate_asset_directory (por ejemplo, unmanaged-byod-09), el evento se filtra y no se genera ninguna detección:

    rule inner_join_drops_unmatched_events {
      meta:
        author = "Google SecOps"
        description = "Inner join example: drops events whose hostname is not in the data table."
    
      events:
        $e.principal.hostname != ""
        $hostname = $e.principal.hostname
    
        // Direct inner join against data table
        $hostname = %corporate_asset_directory.hostname
    
      match:
        $hostname over 1h
    
      outcome:
        $country = array_distinct(%corporate_asset_directory.country_code)
        $asset_tier = array_distinct(%corporate_asset_directory.asset_tier)
        $risk_score = max(%corporate_asset_directory.risk_score)
    
      condition:
        $e and #corporate_asset_directory > 0
    }
    
  • Unión externa izquierda (#corporate_asset_directory >= 0): El uso de la condición sin límites #corporate_asset_directory >= 0 realiza una unión externa izquierda. Todos los eventos de $e se conservan, incluso cuando el nombre de host no coincide con una fila de corporate_asset_directory.

    Cuando un evento no coincide con una fila de la tabla de datos, las referencias a %corporate_asset_directory.column se evalúan como null. En la sección outcome, usa strings.coalesce para las columnas de cadena y las expresiones condicionales if para las columnas numéricas con el objetivo de asignar valores de resguardo predeterminados:

    rule left_outer_join_enrichment {
      meta:
        author = "Google SecOps"
        description = "Left outer join using #dt >= 0: preserves all events and populates enrichment fields."
    
      events:
        $e.principal.hostname != ""
        $hostname = $e.principal.hostname
    
        // Outer join equality binding
        $hostname = %corporate_asset_directory.hostname
    
      match:
        $hostname over 1h
    
      outcome:
        $country = array_distinct(strings.coalesce(%corporate_asset_directory.country_code, "UNKNOWN"))
        $asset_tier = array_distinct(strings.coalesce(%corporate_asset_directory.asset_tier, "UNMANAGED"))
        $risk_score = max(if(%corporate_asset_directory.risk_score > 0, %corporate_asset_directory.risk_score, 0))
    
      condition:
        $e and #corporate_asset_directory >= 0
    }
    

Resultado de la unión de reglas

En la siguiente tabla, se comparan los valores de resultado para los hosts coincidentes y no coincidentes cuando se usa #corporate_asset_directory >= 0:

Nombre de host principal ($hostname) Estado de coincidencia de la tabla de datos $country $asset_tier $risk_score
CH02-SRV Se encontró una coincidencia ["CH"] ["TIER_1_CRITICAL"] 80
ES01-W10 Se encontró una coincidencia ["ES"] ["TIER_3_WORKSTATION"] 20
unmanaged-byod-09 No hay coincidencias (null se reemplazó por los valores predeterminados) ["UNKNOWN"] ["UNMANAGED"] 0

Ejemplos de Left anti-join (exclusión) en reglas

Puedes usar una unión externa izquierda con una condición de recuento cero (#data_table = 0) para realizar una antiunión izquierda. Este patrón suprime las detecciones cuando un evento coincide con una tabla de datos de exclusión y activa una alerta solo cuando no hay coincidencia.

  • Exclusión de una sola columna (#authorized_scanners_exclusion = 0): La siguiente regla une $e.principal.hostname con una tabla de datos authorized_scanners_exclusion y se activa solo cuando el host no está presente en la tabla:

    rule anti_join_scanner_exclusion {
      meta:
        author = "Google SecOps"
        description = "Anti-join exclusion using #dt = 0: triggers only if the host is not in the authorized scanners table."
    
      events:
        $e.principal.hostname != ""
        $hostname = $e.principal.hostname
    
        // Bind join key to data table
        $hostname = %authorized_scanners_exclusion.hostname
    
      match:
        $hostname over 1h
    
      outcome:
        $total_sent_bytes = sum($e.network.sent_bytes)
    
      condition:
        $e and #authorized_scanners_exclusion = 0
    }
    

    Como alternativa, puedes contar las filas de la tabla de datos coincidentes en la sección outcome ($scanner_match_count = count(%authorized_scanners_exclusion.hostname)) y evaluar $e and $scanner_match_count = 0 en la sección condition:

    rule anti_join_outcome_count {
      meta:
        author = "Google SecOps"
        description = "Anti-join via outcome variable count check: triggers when scanner match count is zero."
    
      events:
        $e.principal.hostname != ""
        $hostname = $e.principal.hostname
    
        $hostname = %authorized_scanners_exclusion.hostname
    
      match:
        $hostname over 1h
    
      outcome:
        $total_sent_bytes = sum($e.network.sent_bytes)
        $scanner_match_count = count(%authorized_scanners_exclusion.hostname)
    
      condition:
        $e and $scanner_match_count = 0
    }
    
  • Exclusión de tuplas de filas de varias columnas (#multi_column_admin_exceptions = 0): Para excluir eventos solo cuando una combinación específica de varios campos coincida con la misma fila en una tabla de datos de excepción, vincula cada campo de evento a su columna correspondiente en la sección events y especifica #data_table = 0 en la sección condition:

    rule multi_column_tuple_exclusion {
      meta:
        author = "Google SecOps"
        description = "Multi-column row-tuple anti-join: excludes activity matching composite (origin_ip, target_ip, username, action) rows."
    
      events:
        // Bind event fields to match variables
        $e.principal.ip = $src_ip
        $e.target.ip = $dst_ip
        $e.principal.user.userid = $user
        $e.metadata.product_event_type = $action
    
        // Multi-column equality against the same data table row
        $src_ip = %multi_column_admin_exceptions.origin_ip
        $dst_ip = %multi_column_admin_exceptions.target_ip
        $user = %multi_column_admin_exceptions.username
        $action = %multi_column_admin_exceptions.action
    
      match:
        $src_ip, $dst_ip, $user, $action over 5m
    
      outcome:
        $event_count = count($e.metadata.id)
    
      condition:
        $e and #multi_column_admin_exceptions = 0
    }
    

Unión externa derecha

Una unión externa derecha (o unión derecha) conserva todos los registros de la fuente de datos en el lado derecho de la palabra clave right join.

  • Si un registro del evento de la derecha no tiene coincidencia en el evento de la izquierda, los campos del evento de la izquierda se devuelven como null.

  • Implicación del marcador de posición: Cualquier variable de marcador de posición que se use en la sección match debe hacer referencia a un campo del evento correcto para garantizar la agregación precisa de datos en todo el conjunto de resultados.

Ejemplo de unión derecha de evento a evento

En el siguiente ejemplo, se muestra una right outer join para correlacionar los eventos de acceso de los usuarios con los eventos de conexión de red posteriores que ocurren en el mismo host. El right join garantiza que todos los eventos NETWORK_CONNECTION se conserven en el conjunto de resultados. Si se encuentra un evento de USER_LOGIN coincidente, se unen sus datos. Si no se encuentra ninguna coincidencia, los campos de $e1 serán null.


$e1.metadata.event_type = "USER_LOGIN"

$e2.metadata.event_type = "NETWORK_CONNECTION"

right join $e1.principal.hostname = $e2.principal.hostname

Define el evento de salida

En la siguiente consulta, se define el lado izquierdo de la unión ($e1), que es el conjunto de eventos opcional en el resultado final:


$e1.metadata.event_type = "USER_LOGIN"

En la siguiente tabla, se representa el resultado de la consulta, que identifica el conjunto inicial de eventos de acceso de los usuarios:

Tipo de evento Nombre de host principal Dirección IP
USER_LOGIN workstation-01 192.168.1.101
USER_LOGIN laptop-hr-02 192.168.1.102
USER_LOGIN server-db-03 10.0.0.50

Define el evento correcto

La siguiente consulta define el lado derecho de la unión ($e2), que es el conjunto de eventos que se conserva en el resultado final.


$e2.metadata.event_type = "NETWORK_CONNECTION"

En la siguiente tabla, se muestra el conjunto de eventos de conexión de red disponibles para la coincidencia.

Tipo de evento Nombre de host principal Dirección IP
NETWORK_CONNECTION workstation-01 192.168.1.101
NETWORK_CONNECTION laptop-hr-02 192.168.1.101
NETWORK_CONNECTION vm-unauth-05 203.0.113.3

Únete a los eventos

En el siguiente ejemplo, se muestra una consulta de coincidencia con una unión externa derecha en el campo principal.hostname:


$e1.metadata.event_type = "USER_LOGIN"

$e2.metadata.event_type = "NETWORK_CONNECTION"

right join $e1.principal.hostname = $e2.principal.hostname

$host = $e1.principal.hostname

match:
  $host over 5m

  • La unión externa derecha garantiza que cada evento de NETWORK_CONNECTION ($e2) se incluya en el conjunto de resultados final.

  • Al marcador de posición $host se le asigna el valor de $e2.principal.hostname. La unión externa derecha garantiza la presencia del evento $e2, lo que asegura que la variable $host siempre se complete para la agregación.

  • La regla agrega los resultados por host para un período de 5 minutos.

Resultado de la unión

El conjunto de datos resultante muestra la combinación de los dos eventos. Se conservan todos los registros de la tabla derecha ($e2) y los campos de la tabla izquierda ($e1) se establecen como nulos cuando no se encuentra un nombre de host coincidente (por ejemplo, vm-unauth-05).

Tipo de evento ($e1) Nombre de host principal ($e1) Dirección IP ($e1) Tipo de evento ($e2) Nombre de host principal ($host) Dirección IP ($e2) Estado de coincidencia
USER_LOGIN workstation-01 192.168.1.101 NETWORK_CONNECTION workstation-01 192.168.1.101 Se encontró una coincidencia
USER_LOGIN laptop-hr-02 192.168.1.102 NETWORK_CONNECTION laptop-hr-02 192.168.1.101 Se encontró una coincidencia
null null null NETWORK_CONNECTION vm-unauth-05 203.0.113.4 No hay coincidencias

Ejemplos de consultas de unión derecha

En esta sección, se proporcionan ejemplos de consultas de unión derecha.

Uniones con una condición de coincidencia

  • Event-event

    
    $e1.metadata.event_type = "USER_LOGIN"
    
    $e2.metadata.event_type = "NETWORK_CONNECTION"
    
    right join $e1.principal.hostname = $e2.principal.hostname
    
    $host = $e2.principal.hostname
    
    match:
      $host over 5m
    
    
  • Evento de entidad

    
    $e1.metadata.event_type = "NETWORK_CONNECTION"
    
    $g1.graph.metadata.entity_type = "ASSET"
    
    right join $g1.graph.entity.asset.hostname = $e1.principal.asset.hostname
    
    $host = $e1.principal.asset.hostname
    
    match:
      $host over 5m
    
    
  • Datatable-event

    
    $host = $e1.principal.hostname
    
    right join %all_dt_column_types.hostname = $e1.principal.hostname
    
    match:
      $host by 5m
    
    

Uniones sin una condición de coincidencia

  • Event-event

    
    $e1.metadata.event_type = "USER_LOGIN"
    
    $e1.principal.ip = "114.241.96.87"
    
    $e2.metadata.event_type = "NETWORK_CONNECTION"
    
    right join $e1.principal.hostname = $e2.principal.hostname
    
    
  • Evento de entidad

    
    $e1.metadata.event_type = "NETWORK_CONNECTION"
    
    $g1.graph.metadata.entity_type = "ASSET"
    
    right join $g1.graph.entity.asset.hostname = $e1.principal.asset.hostname
    
    $host = $e1.principal.asset.hostname
    
    
  • Datatable-event

    
    $host = $e1.principal.hostname
    
    right join %all_dt_column_types.hostname = $e1.principal.hostname
    
    

Limitaciones

Ten en cuenta las siguientes limitaciones cuando crees uniones externas:

  • No se admite una unión externa completa (unión izquierda y unión derecha juntas).

  • El período de la consulta para las uniones sin coincidencias se limita a un máximo de 14 días.

  • No puedes unir directamente dos fuentes contextuales (por ejemplo, una entidad directamente a una tabla de datos).

  • El evento principal del modelo de datos unificado (UDM) debe ser el lado conservado de la unión externa. La consulta no es válida si el evento principal está en el lado "anulable".

    • Una unión de evento-entidad debe ser una unión izquierda. Esto conserva correctamente el evento ($e1).

    • Una unión de entidad-evento debe ser una unión derecha. Esto conserva correctamente el evento ($e1).

    El siguiente ejemplo no es válido porque el evento de UDM ($e1) está a la izquierda, pero la unión derecha conserva el lado derecho ($g1), lo que infringe la regla de que se debe conservar el evento de UDM:

    
    // Invalid query
    $e1.metadata.event_type = "NETWORK_CONNECTION"
    $g1.graph.metadata.entity_type = "ASSET"
    right join $e1.principal.asset.hostname = $g1.graph.entity.asset.hostname
    
    
  • Las palabras clave explícitas left join y right join de la sección events no se admiten en las reglas de detección y solo se admiten en las búsquedas de YARA-L y los paneles. Para realizar una unión externa izquierda o una antiunión en una regla de detección, usa una condición sin límites, como #data_table >= 0 o #data_table = 0 en la sección condition. Para obtener más detalles, consulta Uniones izquierdas en las reglas de detección.

Prácticas recomendadas

Para evitar el rendimiento lento y los tiempos de espera de las consultas en las consultas de unión externa, usa filtros específicos y limitados.

Por ejemplo, una consulta amplia como la siguiente:


$e1.metadata.event_type = "USER_LOGIN"
$e2.metadata.event_type = "NETWORK_CONNECTION"
right join $e1.principal.hostname = $e2.principal.hostname

Se puede optimizar agregando criterios específicos de la siguiente manera:


$e1.metadata.event_type = "USER_LOGIN"
$e1.principal.ip = "121.121.121.121"
$e1.principal.user.userid = "alex"
$e2.metadata.event_type = "NETWORK_CONNECTION"
$e2.src.hostname = "altostrat.com"
$e1.principal.hostname = $e2.principal.hostname

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