Avancerede bedste praksisser for jagtforespørgslen

Gælder for:

  • Microsoft Defender XDR

Anvend disse anbefalinger for at opnå resultater hurtigere og undgå timeout under kørsel af komplekse forespørgsler. Hvis du vil have mere hjælp til at forbedre ydeevnen af forespørgsler, skal du læse Bedste praksis for Kusto-forespørgsler.

Forstå kvoter for CPU-ressourcer

Afhængigt af størrelsen har hver lejer adgang til en bestemt mængde CPU-ressourcer, der er allokeret til kørsel af avancerede jagtforespørgsler. Du kan finde detaljerede oplysninger om forskellige forbrugsparametre ved at læse om avancerede jagtkvoter og forbrugsparametre.

Når du har kørt din forespørgsel, kan du se udførelsestiden og dens ressourceforbrug (Lav, Mellem, Høj). High angiver, at forespørgslen tog flere ressourcer at køre og kunne forbedres for at returnere resultater mere effektivt.

Forespørgselsdetaljerne under fanen **Resultater** på Microsoft Defender-portalen

Kunder, der kører flere forespørgsler regelmæssigt, bør spore forbruget og anvende optimeringsvejledningen i denne artikel for at minimere afbrydelse som følge af overskridelse af kvoter eller forbrugsparametre.

Se Optimering af KQL-forespørgsler for at se nogle af de mest almindelige måder at forbedre dine forespørgsler på.

Generelle optimeringstip

  • Tilpas størrelsen på nye forespørgsler – Hvis du har mistanke om, at en forespørgsel returnerer et stort resultatsæt, skal du først vurdere det ved hjælp af optællingsoperatoren. Brug grænse eller synonymet take for at undgå store resultatsæt.

  • Anvend filtre tidligt – Anvend tidsfiltre og andre filtre for at reducere datasættet, især før du bruger transformations- og fortolkningsfunktioner, f.eks . understreng(), erstat(), trim(), toupper()eller parse_json(). I eksemplet nedenfor bruges fortolkningsfunktionen extractjson(), når filtreringsoperatorer har reduceret antallet af poster.

    DeviceEvents
    | where Timestamp > ago(1d)
    | where ActionType == "UsbDriveMount"
    | where DeviceName == "user-desktop.domain.com"
    | extend DriveLetter = extractjson("$.DriveLetter", AdditionalFields)
    
  • Har beats indeholder– Hvis du vil undgå unødvendigt at søge efter understrenge i ord, skal du bruge operatoren has i stedet for contains. Få mere at vide om strengoperatorer

  • Søg i bestemte kolonner – Søg i en bestemt kolonne i stedet for at køre fuldtekstsøgninger på tværs af alle kolonner. Brug ikke * til at kontrollere alle kolonner.

  • Forskel på store og små bogstaver i forbindelse med hastighed – Søgninger med forskel på store og små bogstaver er mere specifikke og generelt mere udførligt. Navne på strengoperatorer med forskel på store og små bogstaver, f.eks has_cs . og contains_cs, slutter normalt med _cs. Du kan også bruge operatoren == equals i stedet for =~.

  • Opspar, udtræk ikke – Når det er muligt, skal du bruge fortolkningsoperatoren eller en fortolkningsfunktion, f.eks. parse_json(). matches regex Undgå strengoperatoren eller funktionen extract(), som begge bruger regulært udtryk. Forbeholder dig brugen af regulære udtryk til mere komplekse scenarier. Læs mere om fortolkningsfunktioner

  • Filtrer ikke tabeller – Filtrer ikke efter en beregnet kolonne, hvis du kan filtrere på en tabelkolonne.

  • Ingen ord med tre tegn – undgå at sammenligne eller filtrere ved hjælp af ord med tre tegn eller færre. Disse ord er ikke indekseret, og matchning af dem kræver flere ressourcer.

  • Projekt selektivt – Gør dine resultater nemmere at forstå ved kun at projektere de kolonner, du har brug for. Projektering af bestemte kolonner, før der køres joinforbindelser eller lignende handlinger, hjælper også med at forbedre ydeevnen.

Optimer operatoren join

Joinoperatoren fletter rækker fra to tabeller ved at matche værdier i angivne kolonner. Anvend disse tip til at optimere forespørgsler, der bruger denne operator.

  • Mindre tabel til venstre – operatoren join matcher poster i tabellen i venstre side af joinsætningen med poster til højre. Når den mindre tabel er til venstre, skal der matches færre poster, så forespørgslen bliver hurtigere.

    I nedenstående tabel reducerer vi den venstre tabel DeviceLogonEvents , så den kun dækker tre specifikke enheder, før den forbindes med IdentityLogonEvents konto-SID'er.

    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
    
  • Brug den indre joinforbindelsessmagjoinforbindelsens standardsmag eller den innerunique-joinforbindelse deduplikerer rækker i den venstre tabel med joinnøglen, før der returneres en række for hver forekomst af den højre tabel. Hvis den venstre tabel indeholder flere rækker med den samme værdi for join nøglen, deduplikeres disse rækker for at efterlade en enkelt tilfældig række for hver entydige værdi.

    Denne standardfunktionsmåde kan udelade vigtige oplysninger fra den venstre tabel, som kan give nyttig indsigt. Forespørgslen nedenfor viser f.eks. kun én mail, der indeholder en bestemt vedhæftet fil, selvom den samme vedhæftede fil blev sendt ved hjælp af flere mails:

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

    For at løse denne begrænsning anvender vi den indre joinforbindelsessmag ved at angive kind=inner , at alle rækker i tabellen til venstre skal vises med tilsvarende værdier til højre:

    EmailAttachmentInfo
    | where Timestamp > ago(1h)
    | where Subject == "Document Attachment" and FileName == "Document.pdf"
    | join kind=inner (DeviceFileEvents | where Timestamp > ago(1h)) on SHA256
    
  • Joinforbind poster fra et tidsvindue – Når analytikere undersøger sikkerhedshændelser, søger de efter relaterede hændelser, der forekommer omkring samme tidsperiode. Anvendelse af den samme tilgang, når du bruger join , gavner også ydeevnen ved at reducere antallet af poster, der skal kontrolleres.

    Forespørgslen nedenfor kontrollerer, om der er logonhændelser inden for 30 minutter efter modtagelse af en skadelig fil:

    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)
    
  • Anvend tidsfiltre på begge sider – Selvom du ikke undersøger et bestemt tidsvindue, kan anvendelse af tidsfiltre på både venstre og højre tabeller reducere antallet af poster for at kontrollere og forbedre join ydeevnen. Forespørgslen nedenfor gælder for Timestamp > ago(1h) begge tabeller, så den kun joinforbinder poster fra den seneste time:

    EmailAttachmentInfo
    | where Timestamp > ago(1h)
    | where Subject == "Document Attachment" and FileName == "Document.pdf"
    | join kind=inner (DeviceFileEvents | where Timestamp > ago(1h)) on SHA256
    
  • Brug tip til ydeevne – Brug tip med operatoren join til at instruere backend til at distribuere belastningen, når der køres ressourcetunge handlinger. Få mere at vide om jointip

    Shuffle-tip hjælper f.eks. med at forbedre forespørgslens ydeevne, når tabeller forbindes ved hjælp af en nøgle med høj kardinalitet – en nøgle med mange entydige værdier – f.eksAccountObjectId. i forespørgslen nedenfor:

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

    Udsendelsestip hjælper, når den venstre tabel er lille (op til 100.000 poster), og den højre tabel er meget stor. Forespørgslen nedenfor forsøger f.eks. at joinforbinde et par mails, der har specifikke emner med alle meddelelser, der indeholder links i tabellen EmailUrlInfo :

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

Optimer operatoren summarize

Opsummeringsoperatoren samler indholdet af en tabel. Anvend disse tip til at optimere forespørgsler, der bruger denne operator.

  • Find entydige værdier – Generelt kan du bruge summarize til at finde entydige værdier, der kan gentages. Det kan være unødvendigt at bruge det til at aggregere kolonner, der ikke har gentagne værdier.

    Selvom en enkelt mail kan være en del af flere hændelser, er eksemplet nedenfor ikke en effektiv brug af summarize , fordi et netværksmeddelelses-id for en individuel mail altid leveres med en entydig afsenderadresse.

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

    Operatoren summarize kan nemt erstattes med , der potentielt giver de samme resultater, samtidig med projectat der bruges færre ressourcer:

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

    Følgende eksempel er en mere effektiv brug af summarize , fordi der kan være flere forskellige forekomster af en afsenderadresse, der sender mail til den samme modtageradresse. Disse kombinationer er mindre entydige og vil sandsynligvis have dubletter.

    EmailEvents
    | where Timestamp > ago(1h)
    | summarize by SenderFromAddress, RecipientEmailAddress
    
  • Bland forespørgslen – Selvom summarize den bedst bruges i kolonner med gentagne værdier, kan de samme kolonner også have høj kardinalitet eller et stort antal entydige værdier. Ligesom operatoren join kan du også anvende shuffle-tip til summarize at distribuere behandlingsbelastningen og muligvis forbedre ydeevnen, når du arbejder på kolonner med høj kardinalitet.

    Forespørgslen nedenfor bruger summarize til at tælle særskilt modtagermailadresse, som kan køre i hundredtusindvis i store organisationer. For at forbedre ydeevnen omfatter hint.shufflekeyden :

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

Forespørgselsscenarier

Identificer entydige processer med proces-id'er

Proces-id'er (PID'er) genbruges i Windows og genbruges til nye processer. De kan ikke alene fungere som entydige identifikatorer for bestemte processer.

Hvis du vil hente et entydigt id for en proces på en bestemt computer, skal du bruge proces-id'et sammen med processens oprettelsestid. Når du joinforbinder eller opsummerer data om processer, skal du inkludere kolonner for computer-id'et (enten DeviceId eller DeviceName), proces-id'et (ProcessId eller InitiatingProcessId) og tidspunktet for oprettelse af processen (ProcessCreationTime eller InitiatingProcessCreationTime)

Følgende eksempelforespørgsel finder processer, der har adgang til mere end 10 IP-adresser via port 445 (SMB), og som muligvis søger efter filshares.

Eksempelforespørgsel:

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

Forespørgslen opsummeres af begge InitiatingProcessId , så InitiatingProcessCreationTime den ser på en enkelt proces uden at blande flere processer med det samme proces-id.

Forespørgselskommandolinjer

Der er mange måder at oprette en kommandolinje på for at udføre en opgave. En hacker kan f.eks. referere til en billedfil uden en sti, uden et filtypenavn, ved hjælp af miljøvariabler eller med anførselstegn. Hackeren kan også ændre rækkefølgen af parametre eller tilføje flere anførselstegn og mellemrum.

Hvis du vil oprette mere holdbare forespørgsler omkring kommandolinjer, skal du anvende følgende fremgangsmåder:

  • Identificer de kendte processer (f.eks .net.exe eller psexec.exe) ved at matche felterne med filnavne i stedet for at filtrere på selve kommandolinjen.
  • Fortolk kommandolinjesektioner ved hjælp af funktionen parse_command_line()
  • Når du forespørger efter kommandolinjeargumenter, skal du ikke søge efter et nøjagtigt match på flere ikke-relaterede argumenter i en bestemt rækkefølge. Brug i stedet regulære udtryk, eller brug flere separate indeholder operatorer.
  • Brug match, hvor der ikke skelnes mellem store og små bogstaver. Brug f.eks. =~, in~og contains i stedet for ==, inog contains_cs.
  • Hvis du vil afhjælpe teknikker til tilsløring af kommandolinjer, bør du overveje at fjerne anførselstegn, erstatte kommaer med mellemrum og erstatte flere efter hinanden følgende mellemrum med et enkelt mellemrum. Der er mere komplekse tilsløringsteknikker, der kræver andre metoder, men disse justeringer kan hjælpe med at løse almindelige.

Følgende eksempler viser forskellige måder at konstruere en forespørgsel, der søger efter filen net.exe til at stoppe firewalltjenesten "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"

Indfødning af data fra eksterne kilder

Hvis du vil inkorporere lange lister eller store tabeller i din forespørgsel, skal du bruge operatoren externaldata til at indtage data fra en angivet URI. Du kan hente data fra filer i TXT-, CSV-, JSON- eller andre formater. Nedenstående eksempel viser, hvordan du kan bruge den omfattende liste over malware SHA-256-hashen leveret af MalwareBazaar (abuse.ch) til at kontrollere vedhæftede filer på 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

Fortolkningsstrenge

Der er forskellige funktioner, som du kan bruge til effektivt at håndtere strenge, der skal analyseres eller konverteres.

String Funktion Eksempel på anvendelse
Kommandolinjer parse_command_line() Udpak kommandoen og alle argumenter.
Stier parse_path() Udpak sektionerne i en fil- eller mappesti.
Versionsnumre parse_version() Dekonstruer et versionsnummer med op til fire sektioner og op til otte tegn pr. sektion. Brug de analyserede data til at sammenligne versionens alder.
IPv4-adresser parse_ipv4() Konvertér en IPv4-adresse til et langt heltal. Hvis du vil sammenligne IPv4-adresser uden at konvertere dem, skal du bruge ipv4_compare().
IPv6-adresser parse_ipv6() Konvertér en IPv4- eller IPv6-adresse til den kanoniske IPv6-notation. Hvis du vil sammenligne IPv6-adresser, skal du bruge ipv6_compare().

Hvis du vil vide mere om alle understøttede fortolkningsfunktioner, kan du læse om Kusto-strengfunktioner.

Bemærk!

Nogle tabeller i denne artikel er muligvis ikke tilgængelige i Microsoft Defender for Endpoint. Slå Microsoft Defender XDR til for at jage efter trusler ved hjælp af flere datakilder. Du kan flytte dine avancerede arbejdsprocesser for jagt fra Microsoft Defender for Endpoint til Microsoft Defender XDR ved at følge trinnene i Overfør avancerede jagtforespørgsler fra Microsoft Defender for Endpoint.

Tip

Vil du vide mere? Kontakt Microsoft Security-community'et i vores Tech Community: Microsoft Defender XDR Tech Community.