Avancerade metodtips för sökningsfrågor
Viktigt
Den förbättrade Microsoft 365 Defender-portalen är nu tillgänglig. Med den här nya upplevelsen kommer Defender för Endpoint, Defender för Office 365, 365 Microsoft 365 Defender och annat till Microsoft Defender for Cloud Apps. Läs om de senaste.
Gäller för:
- Microsoft 365 Defender
Använd de här rekommendationerna för att få resultat snabbare och undvika tidsgränser när du kör komplexa frågor. Mer vägledning om hur du förbättrar frågeprestanda finns i Metodtips för Kusto-frågor.
Förstå kvoter för CPU-resurser
Beroende på klientorganisationens storlek har varje klientorganisation tillgång till en viss mängd CPU-resurser som tilldelats för avancerade sökfrågor. Detaljerad information om olika användningsparametrar finns i avancerade kvoter för sökning och användningsparametrar.
När du har kört frågan kan du se körningstiden och dess resursanvändning (Låg, Medel, Hög). Hög anger att frågan tog fler resurser att köra och skulle kunna förbättras för att returnera resultat mer effektivt.
Kunder som kör flera frågor regelbundet bör spåra förbrukning och använda optimeringsvägledningen i den här artikeln för att minimera avbrottet som ett resultat av att kvoter eller användningsparametrar överskrids.
Allmänna optimeringstips
Storlek på nya frågor – Om du misstänker att en fråga kommer att returnera en stor resultatuppsättning bör du utvärdera den först med hjälp av antal-operatorn. Använd begränsningen eller dess synonym
takeför att undvika stora resultatuppsättningar.Använda filter tidigt – Använd tidsfilter och andra filter för att minska datauppsättningen, särskilt innan du använder omvandlings- och parsningsfunktioner, t.ex. understräng(), ersätt(), rensa(), toupper() eller parse_json(). I exemplet nedan används tolkningsfunktionen extractjson() när filtreringsoperatorer har minskat antalet poster.
DeviceEvents | where Timestamp > ago(1d) | where ActionType == "UsbDriveMount" | where DeviceName == "user-desktop.domain.com" | extend DriveLetter = extractjson("$.DriveLetter", AdditionalFields)Har beats innehåller . Du kan undvika att söka efter understrängar i ord i onödan genom att använda
hasoperatorn i stället förcontains. Lär dig mer om strängoperatorerTitta i specifika kolumner– Leta i en specifik kolumn i stället för att köra en fullständig textsökning i alla kolumner. Använd inte för
*att kontrollera alla kolumner.Case-sensitive for speed– Case-sensitive searches are more specific and generally more performant. Namnen på de case-känsliga strängoperatorersom exempelvis
has_csoch , vanligtvis slutar medcontains_cs_cs. Du kan också använda operatorn case-sensitive equals==i stället för=~.Tolka, extrahera inte– När det är möjligt använder du parsoperatorn eller en tolkningsfunktion som parse_json(). Undvik
matches regexsträngoperatorn eller extrahera()-funktionen,som båda använder reguljära uttryck. Reservera användningen av reguljära uttryck för mer komplexa scenarier. Läs mer om tolkningsfunktionerFiltrera tabeller och inte uttryck – Filtrera inte efter en beräknad kolumn om du kan filtrera på en tabellkolumn.
Inga termer med tre tecken– Undvik att jämföra eller filtrera med hjälp av termer med tre tecken eller färre. Termerna indexeras inte och för att de ska matchas krävs fler resurser.
Project selektivt– Gör resultatet enklare att förstå genom att projicera bara de kolumner du behöver. Att projicera specifika kolumner innan du kör koppling eller liknande åtgärder ger också bättre prestanda.
Optimera join operatorn
Kopplingsoperatorn slår samman rader från två tabeller genom att matcha värden i angivna kolumner. Använd de här tipsen om du vill optimera frågor som använder den här operatorn.
Mindre tabell till vänster – Operatorn matchar poster i tabellen på vänster sida av kopplingssatsen till poster till
joinhöger. Genom att ha den mindre tabellen till vänster behöver färre poster matchas, vilket gör frågan snabbare.I tabellen nedan ser vi till att den vänstra tabellen endast omfattar tre specifika enheter innan du ansluter
DeviceLogonEventstill den med viaIdentityLogonEventskonto-SID.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 AccountSidAnvänd den inre join-smak– Standardkopplings förvald smak eller innerunique-koppling deduplicerar rader i den vänstra tabellen med kopplingstangenten innan du returnerar en rad för varje matchning till höger tabell. Om den vänstra tabellen har flera rader med samma värde för nyckeln de här raderna dedupliceras till att lämna en enda
joinslumpmässig rad för varje unikt värde.Den här standardbeteendet kan lämna viktig information från den vänstra tabellen som kan ge användbar insyn. Frågan nedan visar till exempel bara ett e-postmeddelande som innehåller en viss bifogad fil, även om samma bifogade fil skickades med flera e-postmeddelanden:
EmailAttachmentInfo | where Timestamp > ago(1h) | where Subject == "Document Attachment" and FileName == "Document.pdf" | join (DeviceFileEvents | where Timestamp > ago(1h)) on SHA256För att åtgärda den här begränsningen tillämpar vi den inre join-smak genom att ange att alla rader i den vänstra tabellen ska visas
kind=innermed matchande värden till höger:EmailAttachmentInfo | where Timestamp > ago(1h) | where Subject == "Document Attachment" and FileName == "Document.pdf" | join kind=inner (DeviceFileEvents | where Timestamp > ago(1h)) on SHA256Koppla poster från ett tidsfönster– När analytiker undersöker säkerhetshändelser letar de efter relaterade händelser som inträffar under samma tidsperiod. Tillämpa samma metod när du också
joinanvänder fördelar prestanda genom att minska antalet poster att kontrollera.Med frågan nedan söker du efter inloggningshändelser inom 30 minuter efter att en skadlig fil mottagits:
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)Använda tidsfilter på båda sidor – Även om du inte undersöker ett visst tidsfönster kan du minska antalet poster för att kontrollera och förbättra prestanda genom att använda tidsfilter på både den vänstra och den högra
jointabellen. Frågan nedan gäller förTimestamp > ago(1h)båda tabellerna så att den bara sammanför poster från den senaste timmen:EmailAttachmentInfo | where Timestamp > ago(1h) | where Subject == "Document Attachment" and FileName == "Document.pdf" | join kind=inner (DeviceFileEvents | where Timestamp > ago(1h)) on SHA256Använd tips för prestanda – Använd tips med operatorn för att instruera backend att fördela belastningen när du kör
joinresursintensiva åtgärder. Läs mer om kopplingstipsMed slumpningen kan du till exempel förbättra frågeprestandan när du sammanfogar tabeller med en tangent med hög kardinalitet – en nyckel med många unika värden – som i
AccountObjectIdfrågan nedan:IdentityInfo | where JobTitle == "CONSULTANT" | join hint.shufflekey = AccountObjectId (IdentityDirectoryEvents | where Application == "Active Directory" | where ActionType == "Private data retrieval") on AccountObjectIdSändningstipset hjälper när den vänstra tabellen är liten (upp till 100 000 poster) och den högra tabellen är extremt stor. Frågan nedan försöker till exempel ansluta till några e-postmeddelanden som har specifika ämnen med alla meddelanden som innehåller länkar i
EmailUrlInfotabellen:EmailEvents | where Subject in ("Warning: Update your credentials now", "Action required: Update your credentials now") | join hint.strategy = broadcast EmailUrlInfo on NetworkMessageId
Optimera summarize operatorn
Summeringsoperatorn aggregerar innehållet i en tabell. Använd de här tipsen om du vill optimera frågor som använder den här operatorn.
Hitta distinkta värden– Använd i allmänhet för
summarizeatt hitta distinkta värden som kan upprepas. Det kan vara onödigt att använda den för att sammanställa kolumner som inte har repetitiva värden.Även om ett enskilt e-postmeddelande kan ingå i flera händelser är exemplet nedan inte effektivt, eftersom ett nätverksmeddelande-ID för ett enskilt e-postmeddelande alltid levereras med en
summarizeunik avsändaradress.EmailEvents | where Timestamp > ago(1h) | summarize by NetworkMessageId, SenderFromAddressOperatorn
summarizekan enkelt ersättas med , vilketprojecteventuellt ger samma resultat samtidigt som färre resurser används:EmailEvents | where Timestamp > ago(1h) | project NetworkMessageId, SenderFromAddressFöljande exempel är ett mer effektivt sätt att använda eftersom det kan finnas flera distinkta instanser av en avsändaradress som skickar
summarizee-post till samma mottagaradress. Sådana kombinationer är mindre distinkta och kan ha dubbletter.EmailEvents | where Timestamp > ago(1h) | summarize by SenderFromAddress, RecipientEmailAddressBlanda frågan – Även om den bäst används i kolumner med repetitiva värden, kan samma kolumner också ha hög
summarizekardinalitet eller ett stort antal unika värden. Precis som operatorn kan du även använda slumpa aningen med för att fördela belastningen och potentiellt förbättra prestandan när dujoinarbetar med kolumner med högsummarizekardinalitet.Frågan nedan använder för
summarizeatt räkna distinkta mottagares e-postadress, som kan köras i hundratals tusentals i stora organisationer. För att förbättra prestanda omfattarhint.shufflekeydet:EmailEvents | where Timestamp > ago(1h) | summarize hint.shufflekey = RecipientEmailAddress count() by Subject, RecipientEmailAddress
Frågescenarier
Identifiera unika processer med process-ID
Process-ID:n (PID) återanvänds i Windows återanvänds för nya processer. De kan på egen hand inte fungera som unika identifierare för specifika processer.
Om du vill få en unik identifierare för en process på en viss dator kan du använda process-ID:t tillsammans med den tid då processen skapades. När du sammanfogar eller sammanfattar data runt processer tar du med kolumner för maskinidentifieraren (antingen eller DeviceId DeviceName ), process-ID ( eller ) och tiden då processen skapades ProcessId ( eller InitiatingProcessId ProcessCreationTime InitiatingProcessCreationTime )
Följande exempelfråga hittar processer som har åtkomst till fler än 10 IP-adresser via port 445 (SMB), eventuellt genomsökning efter filresurser.
Exempelfråga:
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
Frågan sammanfattas av båda och så att den tittar på en enda InitiatingProcessId InitiatingProcessCreationTime process, utan att blanda flera processer med samma process-ID.
Frågekommandon
Det finns flera sätt att konstruera en kommandorad för att utföra en aktivitet. En attackerare kan till exempel referera till en bildfil utan en sökväg, utan filnamnstillägg, med hjälp av miljövariabler eller med citattecken. Attacken kan också ändra ordningen på parametrar eller lägga till flera citattecken och blanksteg.
Använd följande metoder för att skapa mer beständiga frågor runt kommandorader:
- Identifiera de kända processerna (till exempelnet.exe eller psexec.exe) genom att matcha på filnamnsfälten, i stället för att filtrera på själva kommandoraden.
- Tolka kommandoradsavsnitt med funktionen parse_command_line()
- Vid sökning efter kommandoradsargument bör du inte söka efter en exakt matchning för flera orelaterade argument i en viss ordning. I stället kan du använda reguljära uttryck eller använda flera separata operatorer.
- Använd fallkänsliga matchningar. Använd till exempel
=~, och i stället för , ochin~contains==incontains_cs. - Överväg att ta bort citattecken, ersätta kommatecken med blanksteg och ersätta flera efterföljande blanksteg med ett enda blanksteg för att minimera teknik för att begränsa anropsteknik för kommandorader. Det finns mer komplexa lösningar på problem som kräver andra metoder, men de här justeringarna kan vara till hjälp för vanliga åtgärder.
Följande exempel visar olika sätt att skapa en fråga som söker efter filennet.exeför att stoppa brandväggstjänsten "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"
Mata in data från externa källor
Om du vill infoga långa listor eller stora tabeller i frågan använder du operatorn externaldata för att mata in data från en viss URI. Du kan hämta data från filer i TXT, CSV, JSON eller andra format. Exemplet nedan visar hur du kan använda den omfattande listan med SHA-256-hashprogram för skadlig programvara som tillhandahålls av MalwareBazaar (abuse.ch) för att kontrollera bifogade filer i e-postmeddelanden:
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
Tolka strängar
Det finns olika funktioner som du kan använda för att effektivt hantera strängar som behöver analyseras eller konverteras.
| Sträng | Funktion | Användningsexempel |
|---|---|---|
| Kommandorader | parse_command_line() | Extrahera kommandot och alla argument. |
| Sökvägar | parse_path() | Extrahera avsnitten i en fil- eller mappsökväg. |
| Versionsnummer | parse_version() | Avmarkera ett versionsnummer med upp till fyra avsnitt och upp till åtta tecken per avsnitt. Använd tolkade data för att jämföra versions ålder. |
| IPv4-adresser | parse_ipv4() | Konvertera en IPv4-adress till ett långt heltal. Om du vill jämföra IPv4-adresser utan att konvertera dem använder du ipv4_compare(). |
| IPv6-adresser | parse_ipv6() | Konvertera en IPv4- eller IPv6-adress till den kanoniska IPv6-notationen. Jämför IPv6-adresser med hjälp av ipv6_compare(). |
Mer information om alla parsingsfunktioner som stöds finns i Kusto-strängfunktioner.
Anteckning
Vissa tabeller i den här artikeln kanske inte är tillgängliga i Microsoft Defender för Endpoint. Aktivera Microsoft 365 Defender för att leta efter hot med hjälp av fler datakällor. Du kan flytta dina avancerade arbetsflöden för sökning från Microsoft Defender för Endpoint till Microsoft 365 Defender genom att följa stegen i Migrera avancerade sökfrågor från Microsoft Defender för Slutpunkt.