Anbefalte fremgangsmåter for avansert jaktspørring

Gjelder for:

  • Microsoft Defender XDR

Bruk disse anbefalingene for å få resultater raskere og unngå tidsavbrudd når du kjører komplekse spørringer. Hvis du vil ha mer veiledning om hvordan du forbedrer spørringsytelsen, kan du lese Anbefalte fremgangsmåter for Kusto-spørringer.

Forstå CPU-ressurskvoter

Avhengig av størrelsen har hver leier tilgang til en angitt mengde CPU-ressurser som er tildelt for å kjøre avanserte jaktspørringer. Hvis du vil ha detaljert informasjon om ulike bruksparametere, kan du lese om avanserte jaktkvoter og bruksparametere.

Når du har kjørt spørringen, kan du se utførelsestiden og ressursbruken (lav, middels, høy). Høy indikerer at spørringen tok flere ressurser å kjøre og kunne forbedres for å returnere resultater mer effektivt.

Spørringsdetaljene under **Resultater**-fanen i Microsoft Defender-portalen

Kunder som kjører flere spørringer regelmessig, bør spore forbruk og bruke optimaliseringsveiledningen i denne artikkelen for å minimere forstyrrelser som følge av overskridelse av kvoter eller bruksparametere.

Se optimalisere KQL-spørringer for å se noen av de vanligste måtene å forbedre spørringene på.

Generelle optimaliseringstips

  • Endre størrelse på nye spørringer – hvis du mistenker at en spørring vil returnere et stort resultatsett, bør du vurdere den først ved hjelp av count-operatoren. Bruk grensen eller synonymet take for å unngå store resultatsett.

  • Bruk filtre tidlig – Bruk tidsfiltre og andre filtre for å redusere datasettet, spesielt før du bruker transformasjons- og analysefunksjoner, for eksempel substring(), replace(), trim(), toupper(), eller parse_json(). I eksemplet nedenfor brukes analysefunksjonen extractjson() etter at filtreringsoperatorer har redusert antall poster.

    DeviceEvents
    | where Timestamp > ago(1d)
    | where ActionType == "UsbDriveMount"
    | where DeviceName == "user-desktop.domain.com"
    | extend DriveLetter = extractjson("$.DriveLetter", AdditionalFields)
    
  • Har beats inneholder – Hvis du vil unngå å søke i delstrenger i ord unødvendig, bruker du operatoren has i stedet containsfor . Finn ut mer om strengoperatorer

  • Se i bestemte kolonner – se i en bestemt kolonne i stedet for å kjøre fulltekstsøk i alle kolonner. Ikke bruk * denne til å kontrollere alle kolonnene.

  • Skiller mellom store og små bokstaver for hastighet – Søk som skiller mellom store og små bokstaver, er mer spesifikke og generelt mer effektive. Navn på strengoperatorer som skiller mellom store og små bokstaver, for eksempel has_cs , contains_csslutter vanligvis med _cs. Du kan også bruke operatoren == som skiller mellom store og små bokstaver, i stedet =~for .

  • Analyser, ikke trekk ut – Når det er mulig, kan du bruke analyseoperatoren eller en analysefunksjon som parse_json(). Unngå strengoperatoren matches regex eller extract()-funksjonen, som begge bruker vanlig uttrykk. Reserver bruken av vanlig uttrykk for mer komplekse scenarioer. Les mer om analysering av funksjoner

  • Filtrer tabeller ikke uttrykk – ikke filtrer på en beregnet kolonne hvis du kan filtrere på en tabellkolonne.

  • Ingen termer med tre tegn – Unngå å sammenligne eller filtrere med termer med tre tegn eller færre. Disse termene er ikke indeksert, og samsvarende dem krever flere ressurser.

  • Prosjekt selektivt – Gjør resultatene enklere å forstå ved bare å projisere kolonnene du trenger. Å projisere bestemte kolonner før du kjører sammenføyning eller lignende operasjoner bidrar også til å forbedre ytelsen.

Optimaliser operatoren join

Sammenføyningsoperatoren slår sammen rader fra to tabeller ved å sammenligne verdier i angitte kolonner. Bruk disse tipsene for å optimalisere spørringer som bruker denne operatoren.

  • Mindre tabell til venstre – operatoren join sammenligner poster i tabellen på venstre side av sammenføyningssetningen med poster til høyre. Ved å ha den mindre tabellen til venstre, må færre poster samsvare, og dermed øke hastigheten på spørringen.

    I tabellen nedenfor reduserer vi venstre tabell DeviceLogonEvents for å dekke bare tre bestemte enheter før du slår den sammen med IdentityLogonEvents etter konto-SIDer.

    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
    
  • Bruk den indre sammenføyningssmaken – standard sammenføyningssmak eller innerunique-sammenføyning deduplicates rader i venstre tabell ved hjelp av sammenføyningsnøkkelen før du returnerer en rad for hver kamp til høyre tabell. Hvis den venstre tabellen har flere rader med samme verdi for join nøkkelen, vil disse radene bli deduplicated for å la en enkelt tilfeldig rad for hver unike verdi.

    Denne standard virkemåten kan utelate viktig informasjon fra den venstre tabellen som kan gi nyttig innsikt. Spørringen nedenfor viser for eksempel bare én e-postmelding som inneholder et bestemt vedlegg, selv om det samme vedlegget ble sendt ved hjelp av flere e-postmeldinger:

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

    For å løse denne begrensningen bruker vi den indre sammenføyningssmakenkind=inner ved å angi for å vise alle radene i den venstre tabellen med samsvarende verdier til høyre:

    EmailAttachmentInfo
    | where Timestamp > ago(1h)
    | where Subject == "Document Attachment" and FileName == "Document.pdf"
    | join kind=inner (DeviceFileEvents | where Timestamp > ago(1h)) on SHA256
    
  • Bli med i poster fra et tidsvindu – Når du undersøker sikkerhetshendelser, ser analytikere etter relaterte hendelser som forekommer rundt samme tidsperiode. Bruk av samme fremgangsmåte når du bruker join fordeler også ytelsen ved å redusere antall poster som skal kontrolleres.

    Spørringen nedenfor ser etter påloggingshendelser innen 30 minutter etter mottak av en ondsinnet 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)
    
  • Bruk tidsfiltre på begge sider – Selv om du ikke undersøker et bestemt tidsvindu, kan bruk av tidsfiltre på både venstre og høyre tabell redusere antall poster for å kontrollere og forbedre join ytelsen. Spørringen nedenfor gjelder for begge tabellene, slik at den bare føyer Timestamp > ago(1h) sammen poster fra den siste timen:

    EmailAttachmentInfo
    | where Timestamp > ago(1h)
    | where Subject == "Document Attachment" and FileName == "Document.pdf"
    | join kind=inner (DeviceFileEvents | where Timestamp > ago(1h)) on SHA256
    
  • Bruk tips for ytelse – Bruk tips med operatoren join for å be serverdel om å distribuere belastning når du kjører ressurskrevende operasjoner. Mer informasjon om koblingstips

    Tilfeldig tips bidrar for eksempel til å forbedre spørringsytelsen når du kobler sammen tabeller ved hjelp av en nøkkel med høy kardinalitet – en nøkkel med mange unike verdier – for eksempel AccountObjectId i spørringen nedenfor:

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

    Kringkastingstipset hjelper når den venstre tabellen er liten (opptil 100 000 poster) og den høyre tabellen er svært stor. Spørringen nedenfor prøver for eksempel å bli med i noen få e-postmeldinger som har bestemte emner med alle meldinger som inneholder koblinger i EmailUrlInfo tabellen:

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

Optimaliser operatoren summarize

Summeringsoperatoren aggregerer innholdet i en tabell. Bruk disse tipsene for å optimalisere spørringer som bruker denne operatoren.

  • Finn distinkte verdier – generelt sett kan du bruke summarize til å finne distinkte verdier som kan være gjentakende. Det kan være unødvendig å bruke den til å aggregere kolonner som ikke har gjentakende verdier.

    Selv om én enkelt e-postmelding kan være en del av flere hendelser, er ikke eksemplet nedenfor en effektiv bruk av fordi en nettverksmeldings-ID for en individuell e-postmelding alltid kommer med en unik avsenderadresse summarize .

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

    Operatoren summarize kan enkelt erstattes med project, noe som gir potensielt de samme resultatene mens du bruker færre ressurser:

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

    Følgende eksempel er en mer effektiv bruk av summarize fordi det kan være flere forskjellige forekomster av en avsenderadresse som sender e-post til samme mottakeradresse. Slike kombinasjoner er mindre distinkte og har sannsynligvis duplikater.

    EmailEvents
    | where Timestamp > ago(1h)
    | summarize by SenderFromAddress, RecipientEmailAddress
    
  • Tilfeldigvis spørringen – Selv summarize om den brukes best i kolonner med gjentakende verdier, kan de samme kolonnene også ha høy kardinalitet eller et stort antall unike verdier. I likhet med operatoren join kan du også bruke tilfeldig tips med summarize for å distribuere behandlingsbelastning og potensielt forbedre ytelsen når du opererer på kolonner med høy kardinalitet.

    Spørringen nedenfor bruker summarize til å telle distinkt mottakers e-postadresse, som kan kjøre i hundretusener i store organisasjoner. For å forbedre ytelsen, inkorporerer hint.shufflekeyden:

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

Spørringsscenarioer

Identifiser unike prosesser med prosess-ID-er

Prosess-ID-er (PIDer) resirkuleres i Windows og brukes på nytt for nye prosesser. På egen hånd kan de ikke fungere som unike identifikatorer for bestemte prosesser.

Hvis du vil ha en unik identifikator for en prosess på en bestemt maskin, kan du bruke prosess-ID-en sammen med prosessens opprettelsestid. Når du kobler sammen eller oppsummerer data rundt prosesser, må du inkludere kolonner for maskinidentifikatoren (enten DeviceId eller DeviceName), prosess-ID -en (ProcessId eller InitiatingProcessId) og prosessopprettingstiden (ProcessCreationTime eller InitiatingProcessCreationTime)

Følgende eksempelspørring finner prosesser som får tilgang til mer enn 10 IP-adresser over port 445 (SMB), muligens skanning etter delte filressurser.

Eksempelspørring:

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

Spørringen oppsummeres av begge InitiatingProcessId og InitiatingProcessCreationTime slik at den ser på én enkelt prosess, uten å blande flere prosesser med samme prosess-ID.

Spørringskommandolinjer

Det finnes mange måter å konstruere en kommandolinje på for å utføre en oppgave. En angriper kan for eksempel referere til en bildefil uten bane, uten filtype, bruk av miljøvariabler eller med anførselstegn. Angriperen kan også endre rekkefølgen på parametere eller legge til flere anførselstegn og mellomrom.

Hvis du vil opprette mer varige spørringer rundt kommandolinjer, kan du bruke følgende fremgangsmåter:

  • Identifiser kjente prosesser (for eksempel net.exe eller psexec.exe) ved å samsvare med filnavnfeltene, i stedet for å filtrere på selve kommandolinjen.
  • Analyser kommandolinjeinndelinger ved hjelp av parse_command_line()-funksjonen
  • Når du spør etter kommandolinjeargumenter, må du ikke se etter et nøyaktig treff på flere ikke-relaterte argumenter i en bestemt rekkefølge. Bruk i stedet vanlige uttrykk eller bruk flere separate inneholderoperatorer.
  • Bruk skille mellom store og små bokstaver. Bruk for =~eksempel , in~og contains i stedet ==for , inog contains_cs.
  • Hvis du vil redusere kommandolinje-obfuscation-teknikker, kan du vurdere å fjerne anførselstegn, erstatte komma med mellomrom og erstatte flere etterfølgende mellomrom med ett mellomrom. Det finnes mer komplekse obfuscation teknikker som krever andre tilnærminger, men disse tweaks kan bidra til å løse vanlige.

Eksemplene nedenfor viser ulike måter å konstruere en spørring på som ser etter filen net.exe for å stoppe brannmurtjenesten 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"

Inntak av data fra eksterne kilder

Hvis du vil inkludere lange lister eller store tabeller i spørringen, bruker du eksterndataoperatoren til å ta inn data fra en angitt URI. Du kan hente data fra filer i TXT-, CSV-, JSON- eller andre formater. Eksemplet nedenfor viser hvordan du kan bruke den omfattende listen over malware SHA-256 hashs levert av MalwareBazaar (abuse.ch) for å sjekke vedlegg på e-postmeldinger:

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

Analyser strenger

Det finnes ulike funksjoner du kan bruke til effektivt å håndtere strenger som må analyseres eller konverteres.

Streng Funksjonen Eksempel på bruk
Kommandolinjer parse_command_line() Trekk ut kommandoen og alle argumentene.
Baner parse_path() Pakk ut inndelingene i en fil- eller mappebane.
Versjonsnumre parse_version() Dekonstruere et versjonsnummer med opptil fire inndelinger og opptil åtte tegn per inndeling. Bruk de analyserte dataene til å sammenligne versjonsalder.
IPv4-adresser parse_ipv4() Konvertere en IPv4-adresse til et langt heltall. Hvis du vil sammenligne IPv4-adresser uten å konvertere dem, kan du bruke ipv4_compare().
IPv6-adresser parse_ipv6() Konverter en IPv4- eller IPv6-adresse til den kanoniske IPv6-notasjonen. Hvis du vil sammenligne IPv6-adresser, kan du bruke ipv6_compare().

Hvis du vil lære om alle støttede analysefunksjoner, kan du lese om Kusto-strengfunksjoner.

Obs!

Noen tabeller i denne artikkelen er kanskje ikke tilgjengelige i Microsoft Defender for endepunkt. Slå på Microsoft Defender XDR for å lete etter trusler ved hjelp av flere datakilder. Du kan flytte avanserte jaktarbeidsflyter fra Microsoft Defender for endepunkt til Microsoft Defender XDR ved å følge trinnene i Overføre avanserte jaktspørringer fra Microsoft Defender for endepunkt.

Tips

Vil du lære mer? Kommuniser med Microsoft Sikkerhet-fellesskapet i det tekniske fellesskapet vårt: Microsoft Defender XDR Tech Community.