Een ASIM-parser maken

Voltooid

ASIM-gebruikers (Advanced Security Information Model) gebruiken parsers in plaats van tabelnamen in hun query's om gegevens in een genormaliseerde indeling weer te geven en alle gegevens op te nemen die relevant zijn voor het schema in de query. Samenvattende parsers gebruiken op hun beurt bronspecifieke parsers om de specifieke details van elke bron te verwerken.

Microsoft Sentinel biedt ingebouwde, bronspecifieke parsers voor veel gegevensbronnen. In de volgende situaties kunt u deze bronspecifieke parsers wijzigen of ontwikkelen:

Wanneer uw apparaat gebeurtenissen bevat die passen bij een ASIM-schema, maar een bronspecifieke parser voor uw apparaat en het relevante schema niet beschikbaar is in Microsoft Sentinel.

Wanneer ASIM-bronspecifieke parsers beschikbaar zijn voor uw apparaat, maar uw apparaat gebeurtenissen verzendt in een methode of een andere indeling dan verwacht door de ASIM-parsers. Voorbeeld:

Uw bronapparaat kan worden geconfigureerd voor het verzenden van gebeurtenissen op een niet-standaard manier.

Uw apparaat heeft mogelijk een andere versie dan de versie die wordt ondersteund door de ASIM-parser.

De gebeurtenissen kunnen worden verzameld, gewijzigd en doorgestuurd door een intermediair systeem.

Ontwikkelingsproces voor aangepaste parser

In de volgende werkstroom worden de stappen op hoog niveau beschreven voor het ontwikkelen van een aangepaste ASIM, bronspecifieke parser:

  1. Verzamel voorbeeldlogboeken.

  2. Identificeer de schema's of schema's die door de gebeurtenissen die vanuit de bron worden verzonden.

  3. Wijs de bron gebeurtenisvelden toe aan het geïdentificeerde schema of schema's.

  4. Ontwikkel een of meer ASIM-parsers voor uw bron. U moet een filterparser en een parameterloze parser ontwikkelen voor elk schema dat relevant is voor de bron.

  5. Test uw parser.

  6. Implementeer de parsers in uw Microsoft Sentinel-werkruimten.

  7. Werk de relevante ASIM-parser bij om te verwijzen naar de nieuwe aangepaste parser.

  8. Mogelijk wilt u uw parsers ook bijdragen aan de primaire ASIM-distributie. Bijgedragen parsers kunnen ook beschikbaar worden gesteld in alle werkruimten als ingebouwde parsers.

Voorbeeldlogboeken verzamelen

Voor het bouwen van effectieve ASIM-parsers hebt u een representatieve set logboeken nodig. In de meeste gevallen moet u het bronsysteem instellen en deze verbinden met Microsoft Sentinel. Als u het bronapparaat niet beschikbaar hebt, kunt u met cloudservices betalen per gebruik veel apparaten implementeren voor ontwikkeling en testen.

Daarnaast kunt u de documentatie en voorbeelden van leveranciers voor de logboeken vinden om de ontwikkeling te versnellen en fouten te verminderen door een brede dekking van de logboekindeling te garanderen.

Een representatieve set logboeken moet het volgende omvatten:

  • Gebeurtenissen met verschillende gebeurtenisresultaten.
  • Gebeurtenissen met verschillende antwoordacties.
  • Verschillende indelingen voor gebruikersnaam, hostnaam en id's en andere velden waarvoor waardenormalisatie is vereist.

Toewijzing

Voordat u een parser ontwikkelt, moet u de informatie die beschikbaar is in de bron gebeurtenis of gebeurtenissen toewijzen aan het schema dat u hebt geïdentificeerd:

  • Wijs alle verplichte velden en bij voorkeur ook aanbevolen velden toe.
  • Probeer alle beschikbare informatie van de bron toe te wijzen aan genormaliseerde velden. Als dit niet beschikbaar is als onderdeel van het geselecteerde schema, kunt u overwegen om toe te wijzen aan velden die beschikbaar zijn in andere schema's.
  • Wijs waarden voor velden aan de bron toe aan de genormaliseerde waarden die zijn toegestaan door ASIM. De oorspronkelijke waarde wordt opgeslagen in een afzonderlijk veld, zoals EventOriginalResultDetails.

Parsers ontwikkelen

Ontwikkel zowel een filter als een parameterloze parser voor elk relevant schema.

Een aangepaste parser is een KQL-query die is ontwikkeld op de pagina Microsoft Sentinel-logboeken. De parserquery heeft drie delen:

Velden > parseren > voorbereiden filteren

De relevante records filteren

In veel gevallen bevat een tabel in Microsoft Sentinel meerdere typen gebeurtenissen. Voorbeeld:

  • De Syslog-tabel bevat gegevens uit meerdere bronnen.
  • Aangepaste tabellen kunnen informatie bevatten uit één bron die meer dan één gebeurtenistype biedt en verschillende schema's kan aanpassen.

Daarom moet een parser eerst alleen de records filteren die relevant zijn voor het doelschema.

Filteren in KQL wordt uitgevoerd met behulp van de where-operator . Sysmon-gebeurtenis 1 rapporteert bijvoorbeeld proces maken en wordt daarom genormaliseerd naar het ProcessEvent-schema. De Sysmon-gebeurtenis 1 maakt deel uit van de gebeurtenistabel, dus u gebruikt het volgende filter:

Event | where Source == "Microsoft-Windows-Sysmon" and EventID == 1

Belangrijk

Een parser mag niet op tijd filteren. De query die gebruikmaakt van de parser, past een tijdsbereik toe.

Filteren op brontype met behulp van een volglijst

In sommige gevallen bevat de gebeurtenis zelf geen informatie die filteren voor specifieke brontypen toestaat.

Infoblox DNS-gebeurtenissen worden bijvoorbeeld verzonden als Syslog-berichten en zijn moeilijk te onderscheiden van Syslog-berichten die worden verzonden vanuit andere bronnen. In dergelijke gevallen is de parser afhankelijk van een lijst met bronnen die de relevante gebeurtenissen definiëren. Deze lijst wordt onderhouden in de ASimSourceType-watchlist.

De ASimSourceType-watchlist gebruiken in uw parsers:

  • Neem de volgende regel op aan het begin van de parser:
let Sources_by_SourceType=(sourcetype:string){_GetWatchlist('ASimSourceType') | where SearchKey == tostring(sourcetype) | extend Source=column_ifexists('Source','') | where isnotempty(Source)| distinct Source };
  • Voeg een filter toe dat gebruikmaakt van de volglijst in de sectie parserfiltering. De Infoblox DNS-parser bevat bijvoorbeeld het volgende in de filtersectie:
| where Computer in (Sources_by_SourceType('InfobloxNIOS'))

Ga als volgt te werk om dit voorbeeld in uw parser te gebruiken:

  • Vervang Computer door de naam van het veld dat de brongegevens voor uw bron bevat. U kunt dit bewaren als computer voor alle parsers op basis van Syslog.

  • Vervang het InfobloxNIOS-token door een waarde van uw keuze voor uw parser. Informeer parsergebruikers dat ze de ASimSourceType-watchlist moeten bijwerken met behulp van uw geselecteerde waarde en de lijst met bronnen die gebeurtenissen van dit type verzenden.

Filteren op basis van parserparameters

Zorg er bij het ontwikkelen van filterparsers voor dat de parser de filterparameters voor het relevante schema accepteert, zoals beschreven in het referentieartikel voor dat schema. Als u een bestaande parser als uitgangspunt gebruikt, zorgt u ervoor dat uw parser de juiste functiehandtekening bevat. In de meeste gevallen is de werkelijke filtercode ook vergelijkbaar voor het filteren van parsers voor hetzelfde schema.

Zorg er bij het filteren voor dat u het volgende doet:

  • Filter voordat u gegevens parseert met behulp van fysieke velden. Als de gefilterde resultaten niet nauwkeurig genoeg zijn, herhaalt u de test na het parseren om de resultaten af te stemmen. Zie filteroptimalisatie voor meer informatie.
  • Filter niet als de parameter niet is gedefinieerd en nog steeds de standaardwaarde heeft.

In de volgende voorbeelden ziet u hoe u filters voor een tekenreeksparameter implementeert, waarbij de standaardwaarde meestal '*' is en voor een lijstparameter, waarbij de standaardwaarde meestal een lege lijst is.

srcipaddr=='*' or ClientIP==srcipaddr
array_length(domain_has_any) == 0 or Name has_any (domain_has_any)

Optimalisatie van filteren

Let op de volgende filteraankopen om de prestaties van de parser te garanderen:

  • Filter altijd op ingebouwde velden in plaats van geparseerde velden. Hoewel het soms eenvoudiger is om te filteren met geparseerde velden, is dit van invloed op de prestaties.
  • Gebruik operators die geoptimaliseerde prestaties bieden. Met name = = heeft en begint met. Het gebruik van operators zoals contains of matches regex heeft ook aanzienlijk invloed op de prestaties.

Het filteren van aanbevelingen voor prestaties is mogelijk niet altijd eenvoudig te volgen. Het gebruik van has is bijvoorbeeld minder nauwkeurig dan bevat. In andere gevallen is het vergelijken van het ingebouwde veld, zoals SyslogMessage, minder nauwkeurig dan het vergelijken van een geëxtraheerd veld, zoals DvcAction. In dergelijke gevallen raden we u aan om nog steeds vooraf te filteren met behulp van een operator voor het optimaliseren van prestaties boven een ingebouwd veld en het filter te herhalen met behulp van nauwkeurigere voorwaarden na het parseren.

Zie het volgende Infoblox DNS-parserfragment voor een voorbeeld. De parser controleert eerst of het veld SyslogMessage het woord client heeft. De term kan echter op een andere plaats in het bericht worden gebruikt, dus na het parseren van het Log_Type veld controleert de parser opnieuw of het woord client inderdaad de waarde van het veld was.

Syslog | where ProcessName == "named" and SyslogMessage has "client"
…
      | extend Log_Type = tostring(Parser[1]),
      | where Log_Type == "client"

Parseren

Zodra de query de relevante records selecteert, moet deze mogelijk worden geparseerd. Parseren is doorgaans nodig als meerdere gebeurtenisvelden in één tekstveld worden overgebracht.

De KQL-operators die parseren uitvoeren, worden hieronder vermeld, gesorteerd op basis van hun prestatieoptimalisatie. De eerste biedt de meest geoptimaliseerde prestaties, terwijl de laatste de minst geoptimaliseerde prestaties biedt.

Operator Beschrijving
split Parseren van een tekenreeks met gescheiden waarden.
parse_csv Parseert een tekenreeks met waarden die zijn opgemaakt als een CSV-regel (door komma's gescheiden waarden).
parseren Meerdere waarden van een willekeurige tekenreeks parseren met behulp van een patroon, dat een vereenvoudigd patroon kan zijn met betere prestaties of een reguliere expressie.
extract_all Parseren van enkele waarden uit een willekeurige tekenreeks met behulp van een reguliere expressie. extract_all een vergelijkbare prestaties heeft om te parseren als de laatste een reguliere expressie gebruikt.
Extract Extraheer één waarde uit een willekeurige tekenreeks met behulp van een reguliere expressie. Het gebruik van extract biedt betere prestaties dan parseren of extract_all als er één waarde nodig is. Het gebruik van meerdere activeringen van extracten via dezelfde brontekenreeks is echter minder efficiënt dan één parsering of extract_all en moet worden vermeden.
parse_json Parseren van de waarden in een tekenreeks die is opgemaakt als JSON. Als er slechts een paar waarden nodig zijn uit de JSON, biedt het gebruik van parseren, extraheren of extract_all betere prestaties.
parse_xml Parseren van de waarden in een tekenreeks die is opgemaakt als XML. Als er slechts een paar waarden nodig zijn uit de XML, biedt het gebruik van parseren, extraheren of extract_all betere prestaties.

Naast het parseren van tekenreeksen kan voor de parseringsfase meer verwerking van de oorspronkelijke waarden nodig zijn, waaronder:

  • Opmaak en typeconversie. Het bronveld, nadat het is geëxtraheerd, moet mogelijk worden opgemaakt om het doelschemaveld aan te passen. U moet bijvoorbeeld een tekenreeks converteren die datum en tijd vertegenwoordigt naar een datum/tijd-veld. Functies zoals todatetime en tohex zijn handig in deze gevallen.

  • Waardezoekactie. De waarde van het bronveld, nadat het is geëxtraheerd, moet mogelijk worden toegewezen aan de set waarden die zijn opgegeven voor het doelschemaveld. Sommige bronnen rapporteren bijvoorbeeld numerieke DNS-antwoordcodes, terwijl het schema de meer algemene tekstantwoordcodes vereist. De functies en hoofdletters kunnen handig zijn om een paar waarden toe te wijzen.

    De Microsoft DNS-parser wijst bijvoorbeeld als volgt het veld EventResult toe op basis van de gebeurtenis-id en antwoordcode met behulp van een iff-instructie:

    extend EventResult = iff(EventId==257 and ResponseCode==0 ,'Success','Failure')
    

    Gebruik voor verschillende waarden gegevenstabel en zoekactie, zoals wordt weergegeven in dezelfde DNS-parser:

    let RCodeTable = datatable(ResponseCode:int,ResponseCodeName:string) [ 0, 'NOERROR', 1, 'FORMERR'....];
    ...
     | lookup RCodeTable on ResponseCode
     | extend EventResultDetails = case (
     isnotempty(ResponseCodeName), ResponseCodeName,
     ResponseCode between (3841 .. 4095), 'Reserved for Private Use',
     'Unassigned')
    

Toewijzingswaarden

In veel gevallen moet de oorspronkelijke geëxtraheerde waarde worden genormaliseerd. In ASIM gebruikt een MAC-adres bijvoorbeeld dubbele punten als scheidingsteken, terwijl de bron mogelijk een met afbreekstreepjes gescheiden MAC-adres verzendt. De primaire operator voor het transformeren van waarden wordt uitgebreid, naast een brede set KQL-tekenreeksen, numerieke en datumfuncties, zoals wordt weergegeven in de sectie Parseren hierboven.

Use-case-, iff- en opzoekinstructies wanneer een set waarden moet worden toegewezen aan de waarden die door het doelveld zijn toegestaan.

Wanneer elke bronwaarde wordt toegewezen aan een doelwaarde, definieert u de toewijzing met behulp van de gegevenstabeloperator en zoekactie om toe te wijzen. Bijvoorbeeld

let NetworkProtocolLookup = datatable(Proto:real, NetworkProtocol:string)[
        6, 'TCP',
        17, 'UDP'
   ];
    let DnsResponseCodeLookup=datatable(DnsResponseCode:int,DnsResponseCodeName:string)[
      0,'NOERROR',
      1,'FORMERR',
      2,'SERVFAIL',
      3,'NXDOMAIN',
      ...
   ];
   ...
   | lookup DnsResponseCodeLookup on DnsResponseCode
   | lookup NetworkProtocolLookup on Proto

U ziet dat opzoeken nuttig en efficiënt is, ook wanneer de toewijzing slechts twee mogelijke waarden heeft.

Wanneer de toewijzingsvoorwaarden complexer zijn, gebruikt u de functies iff of case . Met de functie iff kunt u twee waarden toewijzen:

| extend EventResult = 
      iff(EventId==257 and ResponseCode==0,'Success','Failure’)

De casefunctie ondersteunt meer dan twee doelwaarden. In het onderstaande voorbeeld ziet u hoe u lookup en case combineert. In het bovenstaande opzoekvoorbeeld wordt een lege waarde in het veld DnsResponseCodeName geretourneerd als de opzoekwaarde niet wordt gevonden. In het onderstaande voorbeeld wordt dit vergroot met behulp van het resultaat van de opzoekbewerking , indien beschikbaar, en door andere aanvullende voorwaarden op te geven.

| extend DnsResponseCodeName = 
      case (
        DnsResponseCodeName != "", DnsResponseCodeName,
        DnsResponseCode between (3841 .. 4095), 'Reserved for Private Use',
        'Unassigned'
      )

Velden in de resultatenset voorbereiden

De parser moet de velden in de resultatenset voorbereiden om ervoor te zorgen dat de genormaliseerde velden worden gebruikt.

De volgende KQL-operators worden gebruikt om velden in uw resultatenset voor te bereiden:

Operator Beschrijving Wanneer gebruikt u in een parser
projectnaam wijzigen Hiermee wijzigt u de naam van velden. Als er een veld in de werkelijke gebeurtenis bestaat en alleen de naam ervan hoeft te worden gewijzigd, gebruikt u projectnaam. Het hernoemde veld gedraagt zich nog steeds als een ingebouwd veld en bewerkingen op het veld hebben veel betere prestaties.
project-away Hiermee verwijdert u velden. Gebruik project-afwezig voor specifieke velden die u uit de resultatenset wilt verwijderen. Het is raadzaam om de oorspronkelijke velden die niet zijn genormaliseerd uit de resultatenset te verwijderen, tenzij ze verwarring veroorzaken of erg groot zijn en mogelijk gevolgen hebben voor de prestaties.
project Selecteert velden die eerder bestonden of die zijn gemaakt als onderdeel van de instructie en verwijdert alle andere velden. Niet aanbevolen voor gebruik in een parser, omdat de parser geen andere velden mag verwijderen die niet zijn genormaliseerd. Als u specifieke velden, zoals tijdelijke waarden die tijdens het parseren worden gebruikt, wilt verwijderen, kunt u deze verwijderen uit de resultaten.
uitbreiden Aliassen toevoegen. Afgezien van de rol in het genereren van berekende velden, wordt de operator voor uitbreiden ook gebruikt om aliassen te maken.

Parseringsvarianten afhandelen

In veel gevallen bevatten gebeurtenissen in een gebeurtenisstroom varianten waarvoor verschillende parseringslogica is vereist. Als u verschillende varianten in één parser wilt parseren, gebruikt u voorwaardelijke instructies, zoals iff en case, of gebruikt u een samenvoegstructuur.

Als u union wilt gebruiken om meerdere varianten af te handelen, maakt u een afzonderlijke functie voor elke variant en gebruikt u de samenvoegingsinstructie om de resultaten te combineren:

let AzureFirewallNetworkRuleLogs = AzureDiagnostics
    | where Category == "AzureFirewallNetworkRule"
    | where isnotempty(msg_s);
let parseLogs = AzureFirewallNetworkRuleLogs
    | where msg_s has_any("TCP", "UDP")
    | parse-where
        msg_s with           networkProtocol:string 
        " request from "     srcIpAddr:string
        ":"                  srcPortNumber:int
    …
    | project-away msg_s;
let parseLogsWithUrls = AzureFirewallNetworkRuleLogs
    | where msg_s has_all ("Url:","ThreatIntel:")
    | parse-where
        msg_s with           networkProtocol:string 
        " request from "     srcIpAddr:string
        " to "               dstIpAddr:string
    …
union parseLogs,  parseLogsWithUrls…

Als u dubbele gebeurtenissen en overmatige verwerking wilt voorkomen, moet u ervoor zorgen dat elke functie begint met filteren, met behulp van systeemeigen velden, alleen de gebeurtenissen die zijn bedoeld om te parseren. Gebruik, indien nodig, ook project-away bij elke vertakking, vóór de samenvoeging.

Parsers implementeren

Implementeer parsers handmatig door ze naar de azure Monitor-logboekpagina te kopiëren en de query op te slaan als een functie. Deze methode is handig voor het testen. Zie Een functie maken voor meer informatie.

Als u een groot aantal parsers wilt implementeren, wordt u aangeraden arm-sjablonen voor parser als volgt te gebruiken:

  1. Maak een YAML-bestand op basis van de relevante sjabloon voor elk schema en voeg daarin uw query toe. Begin met de YAML-sjabloon die relevant is voor uw schema en parsertype, filteren of parameterloos.

  2. Gebruik het ASIM Yaml-conversieprogramma voor ARM-sjablonen om uw YAML-bestand te converteren naar een ARM-sjabloon.

  3. Als u een update implementeert, verwijdert u oudere versies van de functies met behulp van de portal of het PowerShell-hulpprogramma.

  4. Implementeer uw sjabloon met behulp van Azure Portal of PowerShell.

U kunt ook meerdere sjablonen combineren tot één implementatieproces met behulp van gekoppelde sjablonen.