Melhores práticas de consulta de investigação avançada
Aplica-se a:
- Microsoft Defender XDR
Aplique estas recomendações para obter resultados mais rapidamente e evitar tempos limite durante a execução de consultas complexas. Para obter mais orientações sobre como melhorar o desempenho das consultas, leia As melhores práticas de consulta do Kusto.
Compreender as quotas de recursos da CPU
Consoante o tamanho, cada inquilino tem acesso a uma quantidade definida de recursos da CPU alocados para executar consultas de investigação avançadas. Para obter informações detalhadas sobre vários parâmetros de utilização, leia sobre quotas de investigação avançadas e parâmetros de utilização.
Depois de executar a consulta, pode ver o tempo de execução e a respetiva utilização de recursos (Baixa, Média, Alta). Alto indica que a consulta precisou de mais recursos para ser executada e poderia ser melhorada para devolver resultados de forma mais eficiente.
Os clientes que executam várias consultas regularmente devem controlar o consumo e aplicar as orientações de otimização neste artigo para minimizar a interrupção resultante da exceção de quotas ou parâmetros de utilização.
Veja Otimizar consultas KQL para ver algumas das formas mais comuns de melhorar as consultas.
Sugestões de otimização geral
Dimensionar novas consultas — se suspeitar que uma consulta irá devolver um conjunto de resultados grande, avalie-o primeiro com o operador de contagem. Utilize o limite ou o 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 utilizar funções de transformação e análise, como subcadeia(), substituir(), cortar(), toupper()ou parse_json(). No exemplo abaixo, a função de análise extractjson() é utilizada depois de os operadores de filtragem terem reduzido o número de registos.
DeviceEvents | where Timestamp > ago(1d) | where ActionType == "UsbDriveMount" | where DeviceName == "user-desktop.domain.com" | extend DriveLetter = extractjson("$.DriveLetter", AdditionalFields)
Tem batidas: para evitar procurar subcadeias dentro de palavras desnecessariamente, utilize o
has
operador em vez decontains
. Saiba mais sobre os operadores de cadeias de carateresProcurar em colunas específicas — Procure numa coluna específica em vez de executar pesquisas de texto completo em todas as colunas. Não utilize
*
para verificar todas as colunas.Sensível às maiúsculas e minúsculas para a velocidade — as pesquisas sensíveis a maiúsculas e minúsculas são mais específicas e, geralmente, mais eficazes. Os nomes dos operadores de cadeias sensíveis a maiúsculas e minúsculas, tais como
has_cs
econtains_cs
, geralmente terminam com_cs
. Também pode utilizar o operador==
de igual sensível às maiúsculas e minúsculas em vez de=~
.Analisar, não extrair — Sempre que possível, utilize o operador de análise ou uma função de análise como parse_json(). Evite o
matches regex
operador de cadeia ou a função extract(), ambas com expressão regular. Reserve a utilização da expressão regular para cenários mais complexos. Leia mais sobre as funções de análiseFiltrar tabelas e não expressões — não filtre numa coluna calculada se conseguir filtrar numa coluna de tabela.
Sem termos de três carateres — evite comparar ou filtrar com termos com três ou menos carateres. Estes termos não estão indexados e a respetiva correspondência exigirá mais recursos.
Projetar seletivamente – facilite a compreensão dos resultados ao projetar apenas as colunas de que precisa. Projetar colunas específicas antes de executar a associação ou operações semelhantes também ajuda a melhorar o desempenho.
Otimizar o join
operador
O operador de associação intercala linhas de duas tabelas ao corresponder valores em colunas especificadas. Aplique estas sugestões para otimizar as consultas que utilizam este operador.
Tabela mais pequena à esquerda — o
join
operador corresponde aos registos na tabela no lado esquerdo da instrução de associação aos registos à direita. Ao ter a tabela mais pequena à esquerda, terá de corresponder menos registos, acelerando assim a consulta.Na tabela abaixo, reduzimos a tabela
DeviceLogonEvents
esquerda para abranger apenas três dispositivos específicos antes de os associarIdentityLogonEvents
por 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
Utilize o sabor de associação interna — o sabor de associação predefinido ou a associação innerunique-join elimina duplicados linhas na tabela esquerda pela tecla de associação antes de devolver uma linha para cada correspondência à tabela direita. Se a tabela à esquerda tiver múltiplas linhas com o mesmo valor para a
join
chave, essas linhas serão duplicadas para deixar uma única linha aleatória para cada valor exclusivo.Este comportamento predefinido pode deixar de fora informações importantes da tabela esquerda que podem fornecer informações úteis. Por exemplo, a consulta abaixo mostrará apenas um e-mail com um anexo específico, mesmo que esse mesmo anexo tenha sido enviado através de várias mensagens de e-mail:
EmailAttachmentInfo | where Timestamp > ago(1h) | where Subject == "Document Attachment" and FileName == "Document.pdf" | join (DeviceFileEvents | where Timestamp > ago(1h)) on SHA256
Para resolver esta limitação, aplicamos o sabor de associação
kind=inner
interna ao especificar 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
Associar registos a partir de um período de tempo – ao investigar eventos de segurança, os analistas procuram eventos relacionados que ocorram por volta do mesmo período de tempo. Aplicar a mesma abordagem ao utilizar
join
também beneficia o desempenho ao reduzir o número de registos a verificar.A consulta abaixo verifica a existência de eventos de início de sessão no prazo de 30 minutos após a receção de um ficheiro malicioso:
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 não esteja a investigar um período de tempo específico, aplicar filtros de tempo nas tabelas esquerda e direita pode reduzir o número de registos para verificar e melhorar
join
o desempenho. A consulta abaixo aplica-se a ambas as tabelasTimestamp > ago(1h)
para que associe apenas registos 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
Utilizar sugestões para o desempenho — utilize sugestões com o
join
operador para instruir o back-end a distribuir a carga ao executar operações com muitos recursos. Saiba mais sobre sugestões de associaçãoPor exemplo, a sugestão de aleatorização ajuda a melhorar o desempenho das consultas ao associar tabelas com uma chave com cardinalidade elevada ( uma chave com muitos valores exclusivos), tal como na
AccountObjectId
consulta abaixo:IdentityInfo | where JobTitle == "CONSULTANT" | join hint.shufflekey = AccountObjectId (IdentityDirectoryEvents | where Application == "Active Directory" | where ActionType == "Private data retrieval") on AccountObjectId
A sugestão de difusão ajuda quando a tabela esquerda é pequena (até 100 000 registos) e a tabela direita é extremamente grande. Por exemplo, a consulta abaixo está a tentar associar alguns e-mails que têm assuntos específicos com todas as mensagens que contêm ligações 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 summarize agrega os conteúdos de uma tabela. Aplique estas sugestões para otimizar as consultas que utilizam este operador.
Localizar valores distintos — Em geral, utilize
summarize
para localizar valores distintos que possam ser repetitivos. Pode ser desnecessário utilizá-lo para agregar colunas que não têm valores repetitivos.Embora um único e-mail possa fazer parte de vários eventos, o exemplo abaixo não é uma utilização eficiente de porque um ID de
summarize
mensagem de rede para um e-mail individual vem sempre 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 , o que produz potencialmente os mesmos resultados enquanto consome menos recursos:EmailEvents | where Timestamp > ago(1h) | project NetworkMessageId, SenderFromAddress
O exemplo seguinte é uma utilização mais eficiente porque
summarize
pode haver várias instâncias distintas de um endereço de remetente a enviar e-mails para o mesmo endereço de destinatário. Estas combinações são menos distintas e são susceptíveis de ter duplicados.EmailEvents | where Timestamp > ago(1h) | summarize by SenderFromAddress, RecipientEmailAddress
Misturar a consulta – embora
summarize
seja mais utilizada em colunas com valores repetitivos, as mesmas colunas também podem ter uma cardinalidade elevada ou um grande número de valores exclusivos. Tal como ojoin
operador, também pode aplicar a sugestão aleatória comsummarize
para distribuir a carga de processamento e melhorar potencialmente o desempenho ao operar em colunas com cardinalidade elevada.A consulta abaixo utiliza
summarize
para contar o endereço de e-mail de destinatário distinto, que pode ser executado em centenas de milhares em grandes organizações. Para melhorar o desempenho, 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
Os IDs de Processo (PIDs) são reciclados no Windows e reutilizados para novos processos. Por si só, não podem servir como identificadores exclusivos para processos específicos.
Para obter um identificador exclusivo para um processo num computador específico, utilize o ID do processo juntamente com a hora de criação do processo. Quando associa ou resume dados em torno de processos, inclua colunas para o identificador do computador (ou DeviceName
DeviceId
), o ID do processo (ProcessId
ou InitiatingProcessId
), e a hora de criação do processo (ProcessCreationTime
ou InitiatingProcessCreationTime
)
A consulta de exemplo seguinte localiza processos que acedem a mais de 10 endereços IP através da porta 445 (SMB), possivelmente à procura de partilhas de ficheiros.
Consulta de exemplo:
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 resume por ambos InitiatingProcessId
e InitiatingProcessCreationTime
para que analise um único processo, sem misturar vários processos com o mesmo ID de processo.
Linhas de comandos de consulta
Existem várias formas de construir uma linha de comandos para realizar uma tarefa. Por exemplo, um atacante pode referenciar um ficheiro de imagem sem um caminho, sem uma extensão de ficheiro, com variáveis de ambiente ou com aspas. O atacante também pode alterar a ordem dos parâmetros ou adicionar múltiplas aspas e espaços.
Para criar consultas mais duráveis em torno das linhas de comandos, aplique as seguintes práticas:
- Identifique os processos conhecidos (como net.exe ou psexec.exe) ao corresponder nos campos de nome de ficheiro, em vez de filtrar na própria linha de comandos.
- Analisar secções da linha de comandos com a função parse_command_line()
- Ao consultar argumentos da linha de comandos, não procure uma correspondência exata em vários argumentos não relacionados numa determinada ordem. Em vez disso, utilize expressões regulares ou utilize vários operadores separados.
- Utilizar correspondências não sensíveis a maiúsculas e minúsculas. Por exemplo, utilize
=~
,in~
econtains
em vez de==
,in
econtains_cs
. - Para mitigar técnicas de obfuscation da linha de comandos, considere remover aspas, substituir vírgulas por espaços e substituir múltiplos espaços consecutivos por um único espaço. Existem técnicas de obfuscation mais complexas que requerem outras abordagens, mas estes ajustes podem ajudar a lidar com as mais comuns.
Os exemplos seguintes mostram várias formas de construir uma consulta que procura o ficheiro net.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 origens externas
Para incorporar listas longas ou tabelas grandes na consulta, utilize o operador externaldata para ingerir dados de um URI especificado. Pode obter dados de ficheiros em formatos TXT, CSV, JSON ou outros. O exemplo abaixo mostra como pode utilizar a extensa lista de hashes SHA-256 de software maligno fornecidos pelo MalwareBazaar (abuse.ch) para verificar anexos em e-mails:
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
Existem várias funções que pode utilizar para processar eficientemente cadeias de carateres que precisam de análise ou conversão.
Cadeia | Função | Exemplo de utilização |
---|---|---|
Linhas de comandos | parse_command_line() | Extraia o comando e todos os argumentos. |
Caminhos | parse_path() | Extraia as secções de um caminho de ficheiro ou pasta. |
Números de versão | parse_version() | Desconstrua um número de versão com até quatro secções e até oito carateres por secção. Utilize os dados analisados para comparar a idade da versão. |
Endereços IPv4 | parse_ipv4() | Converta um endereço IPv4 num número inteiro longo. Para comparar endereços IPv4 sem os converter, utilize ipv4_compare(). |
Endereços IPv6 | parse_ipv6() | Converta um endereço IPv4 ou IPv6 para a notação IPv6 canónica. Para comparar endereços IPv6, utilize ipv6_compare(). |
Para saber mais sobre todas as funções de análise suportadas, leia sobre as funções de cadeia kusto.
Nota
Algumas tabelas neste artigo poderão não estar disponíveis no Microsoft Defender para Endpoint. Ative Microsoft Defender XDR para procurar ameaças através de mais origens de dados. Pode mover os fluxos de trabalho de investigação avançados de Microsoft Defender para Endpoint para Microsoft Defender XDR ao seguir os passos em Migrar consultas de investigação avançadas de Microsoft Defender para Endpoint.
Tópicos relacionados
- Documentação da linguagem de consulta Kusto
- Parâmetros de quota e utilização
- Lidar com erros de investigação avançada
- Descrição geral da investigação avançada
- Aprender a linguagem de consulta
Sugestão
Quer saber mais? Interaja com a comunidade do Microsoft Security na nossa Tech Community: Microsoft Defender XDR Tech Community.