Correlacionar dados usando junções externas

Compatível com:

Neste documento, descrevemos as mesclagens externas (mesclagem à esquerda e à direita). As operações de mesclagem são usadas para correlacionar e combinar dados de várias fontes com base em valores de campo comuns. Ao combinar ocorrências de segurança e entidades relacionadas em uma visualização única e abrangente, é possível fornecer detecção e investigação de ameaças eficazes.

Ao contrário das mesclagens padrão (internas), que exigem entradas correspondentes em ambas as fontes de dados, uma mesclagem externa recupera todos os registros de um lado da mesclagem, mesmo que não haja entradas correspondentes no outro. Os campos não correspondentes do outro lado geralmente são preenchidos com null. Isso evita que você perca dados que não têm uma correspondência.

Como as mesclagens externas funcionam

O conceito de junções externas no YARA-L 2.0 é idêntico às junções externas do SQL padrão:

  • A mesclagem externa à esquerda preserva todos os registros do lado esquerdo da mesclagem.

  • A mesclagem externa à direita preserva todos os registros do lado direito da mesclagem.

A sintaxe de mesclagem externa (mesclagem à esquerda e à direita) é compatível com todas as consultas, com e sem uma condição match. O comportamento fundamental de uma mesclagem externa é o mesmo em pesquisas, painéis e regras de detecção, embora a sintaxe seja diferente de acordo com o contexto:

  • Pesquisa e painéis: use as palavras-chave explícitas left join ou right join na seção events.

  • Regras de detecção: defina a relação de mesclagem usando um sinal de igual (=) na seção events e especifique uma condição ilimitada na seção condition (por exemplo, #data_table >= 0 para uma mesclagem externa à esquerda ou #data_table = 0 para uma exclusão de antimesclagem).

Entender a mesclagem externa à esquerda

Uma junção externa esquerda (ou junção esquerda) preserva todos os registros da fonte de dados no lado esquerdo (preservado) da junção, seja usando a palavra-chave left join na Pesquisa ou uma condição ilimitada (#data_table >= 0) em uma regra de detecção.

  • Se um registro do lado esquerdo não tiver correspondência no evento ou na tabela de dados à direita, os campos do lado direito serão retornados como null.

  • Implicação do marcador de posição: qualquer variável de marcador de posição usada na seção match precisa referenciar um campo do evento à esquerda para garantir a agregação precisa de dados em todo o conjunto de resultados.

Exemplo de mesclagem à esquerda de evento para evento

O exemplo a seguir demonstra uma mesclagem externa esquerda para correlacionar eventos de login do usuário com eventos de conexão de rede subsequentes que ocorrem no mesmo host. A mesclagem à esquerda garante que todos os eventos USER_LOGIN sejam preservados no conjunto de resultados. Se um evento NETWORK_CONNECTION ($e2) correspondente for encontrado, os dados dele serão combinados. Se nenhuma correspondência for encontrada, os campos de $e2 serão null.


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

Definir o evento de saída

O exemplo de consulta a seguir define o lado esquerdo da mesclagem ($e1), que é o conjunto de eventos preservado no resultado final:

$e1.metadata.event_type = "USER_LOGIN"

A tabela a seguir representa o resultado da consulta, identificando o conjunto inicial de eventos de login do usuário:

Tipo de evento Nome do host principal Endereço 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

Defina o evento certo

O exemplo de consulta a seguir define o lado direito da mesclagem ($e2), que é o conjunto de eventos que corresponde aos eventos à esquerda:

$e2.metadata.event_type = "NETWORK_CONNECTION"

A tabela a seguir representa o conjunto de eventos de conexão de rede disponíveis para correspondência:

Tipo de evento Nome do host principal Endereço 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

Participe dos eventos

com uma seção de correspondência

O exemplo a seguir demonstra uma consulta de correspondência usando uma mesclagem externa esquerda no 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

  • A mesclagem externa à esquerda garante que todos os eventos USER_LOGIN ($e1) sejam incluídos no conjunto de resultados final.

  • O marcador de posição $host recebe o valor de $e1.principal.hostname. A mesclagem externa esquerda garante a presença do evento $e1, garantindo que a variável $host seja sempre preenchida para agregação.

  • A regra agrega os resultados por host em uma janela de tempo de 5 minutos.

Resultado da mesclagem

Os dados resultantes mostram a combinação dos dois eventos. Todos os registros da tabela à esquerda ($e1) são mantidos, e os campos da tabela à direita ($e2) são definidos como null quando nenhum nome de host correspondente é encontrado (por exemplo, para server-db-03).

Tipo de evento ($e1) Nome do host principal ($host) Endereço IP ($e1) Tipo de evento ($e2) Endereço IP ($e2) Status da correspondência
USER_LOGIN workstation-01 192.168.1.101 NETWORK_CONNECTION 192.168.1.101 Correspondência encontrada
USER_LOGIN laptop-hr-02 192.168.1.102 NETWORK_CONNECTION 192.168.1.101 Correspondência encontrada
USER_LOGIN server-db-03 10.0.0.50 null null Nenhuma correspondência
USER_LOGIN kiosk-4 192.168.1.104 NETWORK_CONNECTION 203.0.113.3 Correspondência encontrada

Exemplos de consultas de mesclagem à esquerda

Nesta seção, mostramos exemplos de consultas de mesclagem à esquerda.

Mesclagens com uma condição de correspondência

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

Mesclagens sem uma condição de correspondência

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

Mesclagens à esquerda em regras de detecção

Nas regras de detecção, não use a palavra-chave left join na seção events. Em vez disso, vincule um evento de UDM a uma tabela de dados ou a um evento secundário na seção events usando igualdade (=) e controle o comportamento de mesclagem na seção condition:

Tipo de mesclagem Seção events Seção condition Comportamento em eventos sem correspondência
Inner join $key = %data_table.key $e and #data_table > 0 Os eventos sem correspondência são descartados do stream de detecção.
Left outer join (enriquecimento) $key = %data_table.key $e and #data_table >= 0 Todos os eventos em $e são preservados. Os campos da tabela de dados sem correspondência são null.
Anti-join (exclusão) $key = %data_table.key $e and #data_table = 0 Aciona um alerta somente quando a chave de evento não existe na tabela de dados.

Exemplo de mesclagem à esquerda de evento para tabela de dados em uma regra

O exemplo a seguir usa uma tabela de dados chamada corporate_asset_directory para enriquecer eventos com metadados geográficos e de importância de recursos sem descartar eventos de hosts não gerenciados.

Definir a tabela de dados

A tabela de dados corporate_asset_directory contém as seguintes linhas, usando hostname como a coluna de chave:

hostname (chave) 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

Comparar as condições de mesclagem interna e externa à esquerda

  • Inner join (#corporate_asset_directory > 0): exigir que a contagem da tabela de dados seja maior que 0 realiza um inner join. Se um evento se originar de um host não gerenciado que não esteja listado em corporate_asset_directory (por exemplo, unmanaged-byod-09), o evento será filtrado e nenhuma detecção será gerada:

    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
    }
    
  • Mesclagem externa à esquerda (#corporate_asset_directory >= 0): o uso da condição ilimitada #corporate_asset_directory >= 0 realiza uma mesclagem externa à esquerda. Todos os eventos em $e são preservados mesmo quando o nome do host não corresponde a uma linha em corporate_asset_directory.

    Quando um evento não corresponde a uma linha da tabela de dados, as referências a %corporate_asset_directory.column são avaliadas como null. Na seção outcome, use strings.coalesce para colunas de string e expressões condicionais if para colunas numéricas para atribuir valores de fallback padrão:

    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 da mesclagem de regras

A tabela a seguir compara os valores de resultado para hosts correspondentes e não correspondentes ao usar #corporate_asset_directory >= 0:

Nome do host principal ($hostname) Status de correspondência da tabela de dados $country $asset_tier $risk_score
CH02-SRV Correspondência encontrada ["CH"] ["TIER_1_CRITICAL"] 80
ES01-W10 Correspondência encontrada ["ES"] ["TIER_3_WORKSTATION"] 20
unmanaged-byod-09 Nenhuma correspondência (null substituído pelos padrões) ["UNKNOWN"] ["UNMANAGED"] 0

Exemplos de antijunção à esquerda (exclusão) em regras

É possível usar uma mesclagem externa à esquerda com uma condição de contagem zero (#data_table = 0) para realizar uma antimesclagem à esquerda. Esse padrão suprime as detecções quando um evento corresponde a uma tabela de dados de exclusão e aciona um alerta somente quando não há correspondência.

  • Exclusão de coluna única (#authorized_scanners_exclusion = 0): a regra a seguir mescla $e.principal.hostname com uma tabela de dados authorized_scanners_exclusion e é acionada apenas quando o host não está presente na tabela:

    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, é possível contar as linhas da tabela de dados correspondentes na seção outcome ($scanner_match_count = count(%authorized_scanners_exclusion.hostname)) e avaliar $e and $scanner_match_count = 0 na seção 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
    }
    
  • Exclusão de tupla de linha de várias colunas (#multi_column_admin_exceptions = 0): para excluir eventos somente quando uma combinação específica de vários campos corresponder à mesma linha em uma tabela de dados de exceção, vincule cada campo de evento à coluna correspondente na seção events e especifique #data_table = 0 na seção 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
    }
    

Right outer join

Uma mesclagem externa à direita (ou mesclagem à direita) preserva todos os registros da fonte de dados no lado direito da palavra-chave right join.

  • Se um registro do evento à direita não tiver correspondência no evento à esquerda, os campos do evento à esquerda serão retornados como null.

  • Implicação do marcador de posição:qualquer variável de marcador de posição usada na seção match precisa referenciar um campo do evento correto para garantir a agregação precisa de dados em todo o conjunto de resultados.

Exemplo de junção à direita de evento para evento

O exemplo a seguir demonstra um right outer join para correlacionar eventos de login do usuário com eventos de conexão de rede subsequentes que ocorrem no mesmo host. O right join garante que todos os eventos NETWORK_CONNECTION sejam preservados no conjunto de resultados. Se um evento USER_LOGIN correspondente for encontrado, os dados dele serão mesclados. Se nenhuma correspondência for encontrada, os campos de $e1 serão null.


$e1.metadata.event_type = "USER_LOGIN"

$e2.metadata.event_type = "NETWORK_CONNECTION"

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

Definir evento de saída

A consulta a seguir define o lado esquerdo da mesclagem ($e1), que é o conjunto de eventos opcional no resultado final:


$e1.metadata.event_type = "USER_LOGIN"

A tabela a seguir representa o resultado da consulta, identificando o conjunto inicial de eventos de login do usuário:

Tipo de evento Nome do host principal Endereço 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

Definir o evento certo

A consulta a seguir define o lado direito da mesclagem ($e2), que é o conjunto de eventos preservado no resultado final.


$e2.metadata.event_type = "NETWORK_CONNECTION"

A tabela a seguir representa o conjunto de eventos de conexão de rede disponíveis para correspondência.

Tipo de evento Nome do host principal Endereço 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

Participe dos eventos

O exemplo a seguir mostra uma consulta de correspondência com uma junção externa direita no 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

  • A mesclagem externa direita garante que todos os eventos NETWORK_CONNECTION ($e2) sejam incluídos no conjunto de resultados final.

  • O marcador de posição $host recebe o valor de $e2.principal.hostname. A junção externa direita garante a presença do evento $e2, garantindo que a variável $host seja sempre preenchida para agregação.

  • A regra agrega os resultados por host em uma janela de tempo de 5 minutos.

Resultado da mesclagem

O conjunto de dados resultante mostra a combinação dos dois eventos. Todos os registros da tabela à direita ($e2) são mantidos, e os campos da tabela à esquerda ($e1) são definidos como nulos quando nenhum nome de host correspondente é encontrado (por exemplo, vm-unauth-05).

Tipo de evento ($e1) Nome do host principal ($e1) Endereço IP ($e1) Tipo de evento ($e2) Nome do host principal ($host) Endereço IP ($e2) Status da correspondência
USER_LOGIN workstation-01 192.168.1.101 NETWORK_CONNECTION workstation-01 192.168.1.101 Correspondência encontrada
USER_LOGIN laptop-hr-02 192.168.1.102 NETWORK_CONNECTION laptop-hr-02 192.168.1.101 Correspondência encontrada
null null null NETWORK_CONNECTION vm-unauth-05 203.0.113.4 Nenhuma correspondência

Exemplos de consultas de mesclagem à direita

Nesta seção, mostramos exemplos de consultas de junção à direita.

Mesclagens com uma condição de correspondência

  • 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
    
    
  • Entidade-evento

    
    $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
    
    

Mesclagens sem uma condição de correspondência

  • 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
    
    
  • Entidade-evento

    
    $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
    
    

Limitações

Considere as seguintes limitações ao criar mesclagens externas:

  • Não é possível usar uma mesclagem externa completa (mesclagem à esquerda e à direita juntas).

  • O período da consulta para junções sem correspondência é limitado a no máximo 14 dias.

  • Não é possível mesclar diretamente duas fontes contextuais (por exemplo, uma entidade diretamente a uma tabela de dados).

  • O evento principal do Modelo de dados unificado (UDM) precisa ser o lado preservado da mesclagem externa. A consulta será inválida se o evento principal estiver no lado "anulável".

    • Uma mesclagem de entidade de evento precisa ser uma mesclagem à esquerda. Isso preserva corretamente o evento ($e1).

    • Uma mesclagem de entidade-evento precisa ser uma mesclagem à direita. Isso preserva corretamente o evento ($e1).

    O exemplo a seguir é inválido porque o evento de UDM ($e1) está à esquerda, mas a mesclagem à direita preserva o lado direito ($g1), o que viola a regra de que o evento de UDM precisa ser preservado:

    
    // 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
    
    
  • As palavras-chave explícitas left join e right join na seção events não são compatíveis com as regras de detecção e só são compatíveis com as pesquisas do YARA-L e os painéis. Para realizar uma mesclagem externa à esquerda ou uma antimesclagem em uma regra de detecção, use uma condição ilimitada, como #data_table >= 0 ou #data_table = 0, na seção condition. Para mais detalhes, consulte Left joins em regras de detecção.

Práticas recomendadas

Para evitar lentidão e tempos limite em consultas de mesclagem externa, use filtros específicos e restritos.

Por exemplo, uma consulta ampla como esta:


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

Pode ser otimizado adicionando critérios específicos da seguinte forma:


$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

Precisa de mais ajuda? Receba respostas de membros da comunidade e profissionais do Google SecOps.