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 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 decontains
. Saiba mais sobre operadores de cadeia de caracteresProcure 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
econtains_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çõesFiltrar 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 porIdentityLogonEvents
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 tabelasTimestamp > 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çãoPor 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ídoproject
por , 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 ojoin
operador, você também pode aplicar a dica de embaralhar parasummarize
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 incorporahint.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~
econtains
em vez de==
,in
econtains_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.
Tópicos relacionados
- Documentação da linguagem de consulta kusto
- Cotas e parâmetros de uso
- Manipular erros avançados de caça
- Visão geral da busca avançada
- Aprender a linguagem de consulta
Dica
Você deseja aprender mais? Engage com a comunidade de Segurança da Microsoft em nossa Comunidade Tecnológica: Microsoft Defender XDR Tech Community.
Comentários
https://aka.ms/ContentUserFeedback.
Brevemente: Ao longo de 2024, vamos descontinuar progressivamente o GitHub Issues como mecanismo de feedback para conteúdos e substituí-lo por um novo sistema de feedback. Para obter mais informações, veja:Submeter e ver comentários