Práticas recomendadas de consulta de busca avançada

Aplica-se a:

  • Microsoft Defender XDR

Aplique essas recomendações para obter resultados mais rapidamente e evitar tempo limite durante a execução de consultas complexas. Para obter mais informações sobre como melhorar o desempenho da consulta, leia práticas recomendadas de consulta no Kusto.

Entender cotas de recursos da CPU

Dependendo do tamanho, cada locatário tem acesso a uma quantidade definida de recursos de CPU alocados para executar consultas de caça avançadas. Para obter informações detalhadas sobre vários parâmetros de uso, leia sobre cotas de caça avançadas e parâmetros de uso.

Depois de executar sua consulta, você pode ver o tempo de execução e o uso do recurso (Baixo, Médio, Alto). High indica que a consulta precisou de mais recursos para ser executada e poderia ser aprimorada para retornar resultados com mais eficiência.

Os detalhes da consulta na guia **Resultados** no portal Microsoft Defender

Os clientes que executam várias consultas regularmente devem acompanhar o consumo e aplicar as diretrizes de otimização neste artigo para minimizar a interrupção resultante do excesso de cotas ou parâmetros de uso.

Assista Otimizando consultas KQL para ver algumas das maneiras mais comuns de melhorar suas consultas.

Dicas gerais de otimização

  • Tamanho de novas consultas— Se você suspeitar que uma consulta retornará um grande conjunto de resultados, avalie-a primeiro usando o operador de contagem. Use o limite ou seu sinônimo take para evitar grandes conjuntos de resultados.

  • Aplicar filtros antecipadamente— Aplique filtros de tempo e outros filtros para reduzir o conjunto de dados, especialmente antes de usar funções de transformação e análise, como substring(), replace(), trim(), toupper()ou parse_json(). No exemplo abaixo, a função de análise extractjson() é usada depois que os operadores de filtragem reduziram o número de registros.

    DeviceEvents
    | where Timestamp > ago(1d)
    | where ActionType == "UsbDriveMount"
    | where DeviceName == "user-desktop.domain.com"
    | extend DriveLetter = extractjson("$.DriveLetter", AdditionalFields)
    
  • Tem batidas que contêm: para evitar pesquisar substrings em palavras desnecessariamente, use o has operador em vez de contains. Saiba mais sobre operadores de cadeia de caracteres

  • Procure em colunas específicas: procure em uma coluna específica em vez de executar pesquisas de texto completas em todas as colunas. Não use * para marcar todas as colunas.

  • Sensível a casos para velocidade — as pesquisas sensíveis a casos são mais específicas e geralmente mais performantes. Nomes de operadores de cadeia de caracteres sensíveis a casos, como has_cs e contains_cs, geralmente terminam com _cs. Você também pode usar o operador == de igualdade de maiúsculas de maiúsculas e minúsculas em vez de =~.

  • Analisar, não extrair — Sempre que possível, use o operador de análise ou uma função de análise como parse_json(). Evite o operador de matches regex cadeia de caracteres ou a função extração(), que usam expressão regular. Reserve o uso da expressão regular para cenários mais complexos. Leia mais sobre a análise de funções

  • Filtrar tabelas e não expressões — não filtre em uma coluna calculada se você puder filtrar em uma coluna de tabela.

  • Sem termos de três caracteres: evite comparar ou filtrar usando termos com três caracteres ou menos. Esses termos não são indexados e a correspondência deles exigirá mais recursos.

  • Projetar seletivamente– facilite a compreensão dos resultados projetando apenas as colunas necessárias. Projetar colunas específicas antes de executar operações de junção ou semelhantes também ajuda a melhorar o desempenho.

Otimizar o join operador

O operador de junção mescla linhas de duas tabelas combinando valores em colunas especificadas. Aplique estas dicas para otimizar consultas que usam esse operador.

  • Tabela menor à esquerda — o join operador corresponde a registros na tabela no lado esquerdo da instrução de junção aos registros à direita. Ao ter a tabela menor à esquerda, menos registros precisarão ser correspondidos, acelerando assim a consulta.

    Na tabela abaixo, reduzimos a tabela DeviceLogonEvents esquerda para cobrir apenas três dispositivos específicos antes de juní-la por IdentityLogonEvents SIDs de conta.

    DeviceLogonEvents
    | where DeviceName in ("device-1.domain.com", "device-2.domain.com", "device-3.domain.com")
    | where ActionType == "LogonFailed"
    | join
        (IdentityLogonEvents
        | where ActionType == "LogonFailed"
        | where Protocol == "Kerberos")
    on AccountSid
    
  • Use o sabor de junção interna — o sabor de junção padrão ou as linhas deduplicações de junção interna na tabela à esquerda pela chave de junção antes de retornar uma linha para cada correspondência para a tabela direita. Se a tabela esquerda tiver várias linhas com o mesmo valor para a join chave, essas linhas serão deduplicadas para deixar uma única linha aleatória para cada valor exclusivo.

    Esse comportamento padrão pode deixar de fora informações importantes da tabela esquerda que podem fornecer insights úteis. Por exemplo, a consulta abaixo mostrará apenas um email contendo um anexo específico, mesmo que esse mesmo anexo tenha sido enviado usando várias mensagens de email:

    EmailAttachmentInfo
    | where Timestamp > ago(1h)
    | where Subject == "Document Attachment" and FileName == "Document.pdf"
    | join (DeviceFileEvents | where Timestamp > ago(1h)) on SHA256
    

    Para resolver essa limitação, aplicamos o sabor de junção interna especificando kind=inner para mostrar todas as linhas na tabela esquerda com valores correspondentes à direita:

    EmailAttachmentInfo
    | where Timestamp > ago(1h)
    | where Subject == "Document Attachment" and FileName == "Document.pdf"
    | join kind=inner (DeviceFileEvents | where Timestamp > ago(1h)) on SHA256
    
  • Juntar registros de uma janela de tempo— Ao investigar eventos de segurança, os analistas procuram eventos relacionados que ocorrem no mesmo período de tempo. Aplicar a mesma abordagem ao usar join também beneficia o desempenho reduzindo o número de registros para marcar.

    A consulta abaixo verifica se há eventos de logon dentro de 30 minutos após o recebimento de um arquivo mal-intencionado:

    EmailEvents
    | where Timestamp > ago(7d)
    | where ThreatTypes has "Malware"
    | project EmailReceivedTime = Timestamp, Subject, SenderFromAddress, AccountName = tostring(split(RecipientEmailAddress, "@")[0])
    | join (
    DeviceLogonEvents
    | where Timestamp > ago(7d)
    | project LogonTime = Timestamp, AccountName, DeviceName
    ) on AccountName
    | where (LogonTime - EmailReceivedTime) between (0min .. 30min)
    
  • Aplicar filtros de tempo em ambos os lados— Mesmo que você não esteja investigando uma janela de tempo específica, a aplicação de filtros de tempo nas tabelas esquerda e direita pode reduzir o número de registros para marcar e melhorar join o desempenho. A consulta abaixo se aplica a ambas as tabelas Timestamp > ago(1h) para que ela una apenas registros da última hora:

    EmailAttachmentInfo
    | where Timestamp > ago(1h)
    | where Subject == "Document Attachment" and FileName == "Document.pdf"
    | join kind=inner (DeviceFileEvents | where Timestamp > ago(1h)) on SHA256
    
  • Use dicas para desempenho: use dicas com o join operador para instruir o back-end a distribuir carga ao executar operações com uso intensivo de recursos. Saiba mais sobre dicas de junção

    Por exemplo, a dica de embaralhar ajuda a melhorar o desempenho da consulta ao unir tabelas usando uma chave com alta cardinalidade, uma chave com muitos valores exclusivos, como o AccountObjectId na consulta abaixo:

    IdentityInfo
    | where JobTitle == "CONSULTANT"
    | join hint.shufflekey = AccountObjectId
    (IdentityDirectoryEvents
        | where Application == "Active Directory"
        | where ActionType == "Private data retrieval")
    on AccountObjectId
    

    A dica de transmissão ajuda quando a tabela esquerda é pequena (até 100.000 registros) e a tabela direita é extremamente grande. Por exemplo, a consulta abaixo está tentando ingressar em alguns emails que têm assuntos específicos com todas as mensagens que contêm links na EmailUrlInfo tabela:

    EmailEvents
    | where Subject in ("Warning: Update your credentials now", "Action required: Update your credentials now")
    | join hint.strategy = broadcast EmailUrlInfo on NetworkMessageId
    

Otimizar o summarize operador

O operador de resumo agrega o conteúdo de uma tabela. Aplique estas dicas para otimizar consultas que usam esse operador.

  • Localizar valores distintos — em geral, use summarize para encontrar valores distintos que podem ser repetitivos. Pode ser desnecessário usá-lo para agregar colunas que não têm valores repetitivos.

    Embora um único email possa fazer parte de vários eventos, o exemplo abaixo não é um uso eficiente porque uma ID de mensagem de summarize rede para um email individual sempre vem com um endereço de remetente exclusivo.

    EmailEvents
    | where Timestamp > ago(1h)
    | summarize by NetworkMessageId, SenderFromAddress
    

    O summarize operador pode ser facilmente substituído projectpor , gerando potencialmente os mesmos resultados ao consumir menos recursos:

    EmailEvents
    | where Timestamp > ago(1h)
    | project NetworkMessageId, SenderFromAddress
    

    O exemplo a seguir é um uso mais eficiente, summarize pois pode haver várias instâncias distintas de um endereço remetente enviando email para o mesmo endereço do destinatário. Essas combinações são menos distintas e provavelmente terão duplicatas.

    EmailEvents
    | where Timestamp > ago(1h)
    | summarize by SenderFromAddress, RecipientEmailAddress
    
  • Embaralhar a consulta — Embora summarize seja melhor usada em colunas com valores repetitivos, as mesmas colunas também podem ter alta cardinalidade ou um grande número de valores exclusivos. Assim como o join operador, você também pode aplicar a dica de embaralhar para summarize distribuir a carga de processamento e potencialmente melhorar o desempenho ao operar em colunas com alta cardinalidade.

    A consulta abaixo usa para contar endereços de email de destinatário distintos summarize , que podem ser executados em centenas de milhares em grandes organizações. Para melhorar o desempenho, ele incorpora hint.shufflekey:

    EmailEvents
    | where Timestamp > ago(1h)
    | summarize hint.shufflekey = RecipientEmailAddress count() by Subject, RecipientEmailAddress
    

Cenários de consulta

Identificar processos exclusivos com IDs de processo

As IDs de processo (PIDs) são recicladas no Windows e reutilizadas para novos processos. Por si só, eles não servem como identificadores exclusivos para processos específicos.

Para obter um identificador exclusivo para um processo em um computador específico, use a ID do processo juntamente com o tempo de criação do processo. Ao juntar ou resumir dados em um processo, inclua colunas para o identificador da máquina (DeviceId ou DeviceName), a ID do processo (ProcessId ou InitiatingProcessId) e o tempo de criação do processo (ProcessCreationTime ou InitiatingProcessCreationTime)

O exemplo de consulta a seguir localiza processos que acessam mais de 10 endereços IP na porta 445 (SMB), possivelmente procurando por compartilhamentos de arquivos.

Exemplo de consulta:

DeviceNetworkEvents
| where RemotePort == 445 and Timestamp > ago(12h) and InitiatingProcessId !in (0, 4)
| summarize RemoteIPCount=dcount(RemoteIP) by DeviceName, InitiatingProcessId, InitiatingProcessCreationTime, InitiatingProcessFileName
| where RemoteIPCount > 10

A consulta é resumida por tanto InitiatingProcessId quantoInitiatingProcessCreationTime para que ela examine um único processo, sem misturar vários processos com a mesma ID de processo.

Linhas de comando de consulta

Há várias maneiras de criar uma linha de comando para executar uma tarefa. Por exemplo, um invasor pode fazer referência a um arquivo de imagem sem um caminho, sem uma extensão de arquivo, usando variáveis de ambiente ou com aspas. O invasor também pode alterar a ordem dos parâmetros ou adicionar várias cotações e espaços.

Para criar consultas mais duráveis em torno de linhas de comando, aplique as seguintes práticas:

  • Identifique os processos conhecidos (como net.exe ou psexec.exe) combinando nos campos nome do arquivo, em vez de filtrar na própria linha de comando.
  • Analisar seções de linha de comando usando a função parse_command_line()
  • Ao consultar argumentos de linha de comando, não procure uma correspondência exata com vários argumentos não relacionados em uma determinada ordem. Em vez disso, use expressões regulares ou use vários operadores Contém separados.
  • Correspondências que não diferenciam letras maiúsculas de minúsculas. Por exemplo, use =~, in~e contains em vez de ==, ine contains_cs.
  • Para atenuar técnicas de ofuscação de linha de comando, considere remover aspas, substituir vírgulas por espaços e substituir vários espaços consecutivos por um único espaço. Há técnicas de ofuscação mais complexas que exigem outras abordagens, mas esses ajustes podem ajudar a resolver as comuns.

Os exemplos a seguir mostram várias maneiras de construir uma consulta que procura o arquivonet.exe para parar o serviço de firewall "MpsSvc":

// Non-durable query - do not use
DeviceProcessEvents
| where ProcessCommandLine == "net stop MpsSvc"
| limit 10

// Better query - filters on file name, does case-insensitive matches
DeviceProcessEvents
| where Timestamp > ago(7d) and FileName in~ ("net.exe", "net1.exe") and ProcessCommandLine contains "stop" and ProcessCommandLine contains "MpsSvc"

// Best query also ignores quotes
DeviceProcessEvents
| where Timestamp > ago(7d) and FileName in~ ("net.exe", "net1.exe")
| extend CanonicalCommandLine=replace("\"", "", ProcessCommandLine)
| where CanonicalCommandLine contains "stop" and CanonicalCommandLine contains "MpsSvc"

Ingerir dados de fontes externas

Para incorporar listas longas ou tabelas grandes em sua consulta, use o operador externaldata para ingerir dados de um URI especificado. Você pode obter dados de arquivos em TXT, CSV, JSON ou outros formatos. O exemplo a seguir mostra como você pode utilizar a extensa lista de hashes sha-256 de malware fornecidos pelo MalwareBazaar (abuse.ch) para marcar anexos em emails:

let abuse_sha256 = (externaldata(sha256_hash: string)
[@"https://bazaar.abuse.ch/export/txt/sha256/recent/"]
with (format="txt"))
| where sha256_hash !startswith "#"
| project sha256_hash;
abuse_sha256
| join (EmailAttachmentInfo
| where Timestamp > ago(1d)
) on $left.sha256_hash == $right.SHA256
| project Timestamp,SenderFromAddress,RecipientEmailAddress,FileName,FileType,
SHA256,ThreatTypes,DetectionMethods

Analisar cadeias de caracteres

Há várias funções que você pode usar para lidar com cadeias de caracteres com eficiência que precisam de análise ou conversão.

Cadeia de caracteres Função Exemplo de uso
Linhas de comando parse_command_line() Extraia o comando e todos os argumentos.
Caminhos parse_path() Extraia as seções de um caminho de arquivo ou pasta.
Números de versão parse_version() Desconstrua um número de versão com até quatro seções e até oito caracteres por seção. Use os dados analisados para comparar a idade da versão.
Endereços IPv4 parse_ipv4() Converta um endereço IPv4 em um inteiro longo. Para comparar endereços IPv4 sem convertê-los, use ipv4_compare().
Endereços IPv6 parse_ipv6() Converta um endereço IPv4 ou IPv6 na notação IPv6 canônica. Para comparar endereços IPv6, use ipv6_compare().

Para saber mais sobre todas as funções de análise com suporte, leia sobre funções de cadeia de caracteres Kusto.

Observação

Algumas tabelas neste artigo podem não estar disponíveis no Microsoft Defender para Ponto de Extremidade. Ative Microsoft Defender XDR para procurar ameaças usando mais fontes de dados. Você pode mover seus fluxos de trabalho avançados de caça de Microsoft Defender para Ponto de Extremidade para Microsoft Defender XDR seguindo as etapas em Migrar consultas avançadas de caça Microsoft Defender para Ponto de Extremidade.

Dica

Você deseja aprender mais? Engage com a comunidade de Segurança da Microsoft em nossa Comunidade Tecnológica: Microsoft Defender XDR Tech Community.