Skip to content
KitploitKITPLOIT
ToolsBlog
Einreichen
ToolsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

··Feeds·Kontakt·Datenschutz·© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
Sentinel-Queries — Kuratierte Sammlung von KQL-Abfragen und -Tutorials für Microsoft Sentinel zur Bedrohungssuche, Analyse von Azure AD-Anmeldeprotokollen, Erkennung von Anomalien und Erstellung effizienter Erkennungsmuster. | Kitploit
Tools/GitHubGitHub/reprise99/sentinel-queries
DefensivwerkzeugeBedrohungsanalyseLernen & BildungKuratierte RessourcenAnomalieerkennungLog-Analyse
GitHubreprise99/sentinel-queries

Sentinel-Queries

Kuratierte Sammlung von KQL-Abfragen und -Tutorials für Microsoft Sentinel zur Bedrohungssuche, Analyse von Azure AD-Anmeldeprotokollen, Erkennung von Anomalien und Erstellung effizienter Erkennungsmuster.

Repository anzeigen
1.6k382vor 6 MonatenVon Kitploit geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

KQL für Microsoft Sentinel

Einige Tipps, Tricks und Beispiele für die Verwendung von KQL mit Microsoft Sentinel.

  1. Einleitung
  2. Die Anatomie einer KQL-Abfrage
  3. Die Grundlagen
    1. Zeit-Grundlagen
    2. Where-Grundlagen
    3. Project-Grundlagen
    4. Summarize-Grundlagen
    5. Render-Grundlagen
    6. Parse- und Split-Grundlagen

Einleitung

Kusto Query Language ist die Sprache, die in Azure Monitor, Azure Data Explorer und Azure Log Analytics verwendet wird (was Microsoft Sentinel unter der Haube nutzt). Ich habe diese Visualisierung zu KQL schon immer nützlich gefunden -

KQL visualisiert

Wir wollen KQL verwenden, um genaue und effiziente Abfragen zu erstellen, um Bedrohungen, Erkennungen, Muster und Anomalien in unserem größeren Datensatz zu finden.

Die Anatomie einer KQL-Abfrage

Nehmen Sie die folgende Abfrage als Beispiel```kql SigninLogs | where TimeGenerated > ago(14d) | where UserPrincipalName == "[email protected]" | where ResultType == "0" | where AppDisplayName == "Microsoft Teams" | project TimeGenerated, Location, IPAddress, UserAgent

root@kitploit:~
Wenn wir eine Abfrage wie diese ausführen, teilt uns die erste Zeile mit, in welcher Tabelle Microsoft Sentinel nach Daten suchen soll. In diesem Fall möchten wir also die Tabelle `SigninLogs` durchsuchen, in die die Azure-AD-Anmeldedaten geschrieben werden. Eine Liste der Tabellen findest du [hier](https://docs.microsoft.com/en-us/azure/sentinel/data-source-schema-reference).

Microsoft Sentinel führt deine Abfrage dann sequenziell aus, d. h. jede Zeile wird nacheinander verarbeitet, bis das Ende erreicht ist oder ein Fehler auftritt. Schauen wir uns unsere Abfrage also Zeile für Zeile an.```kql
SigninLogs

Also zuerst haben wir unsere SigninLogs-Tabelle ausgewählt.```kql SigninLogs | where TimeGenerated > ago(14d)

root@kitploit:~
Als Nächstes weisen wir Sentinel an, die Daten der letzten 14 Tage in dieser Tabelle zu betrachten.```kql
SigninLogs
| where TimeGenerated > ago(14d)
| where UserPrincipalName == "[email protected]"

Als Nächstes fordern wir Sentinel auf, nur Protokolle zu finden, bei denen UserPrincipalName gleich "[email protected]" ist.```kql SigninLogs | where TimeGenerated > ago(14d) | where UserPrincipalName == "[email protected]" | where ResultType == "0"

root@kitploit:~
Dann suchen wir nur nach Protokollen, bei denen der ResultType == 0 ist, was eine erfolgreiche Anmeldung bei Azure AD darstellt.```kql
SigninLogs
| where TimeGenerated > ago(14d)
| where UserPrincipalName == "[email protected]"
| where ResultType == "0"
| where AppDisplayName == "Microsoft Teams"

Als Nächstes suchen wir nur nach Anmeldungen bei Microsoft Teams.```kql SigninLogs | where TimeGenerated > ago(14d) | where UserPrincipalName == "[email protected]" | where ResultType == "0" | where AppDisplayName == "Microsoft Teams" | project TimeGenerated, Location, IPAddress, UserAgent

root@kitploit:~
Unsere letzte Zeile verwendet den project-Operator, um nur 4 Felder aus unseren Protokollen zurückzugeben, sodass wir aus unseren SigninLogs-Daten nur TimeGenerated, Location, IPAddress und UserAgent sehen.

So baust du Abfragen auf, jetzt zu den Grundlagen.

## Die Grundlagen

### Zeitliche Grundlagen

Microsoft Sentinel und KQL sind stark für Zeitfilter optimiert. Wenn du also den Zeitraum der Daten kennst, die du durchsuchen möchtest, solltest du den Zeitbereich sofort filtern: die letzten 14 Tage an Protokollen abrufen und dann nach einem Benutzernamen suchen, wie in der folgenden Abfrage -```kql
SigninLogs
| where TimeGenerated > ago(14d)
| where UserPrincipalName == "[email protected]"

Ist viel effizienter, als zuerst nach einem Benutzernamen und dann nach dem Zeitraum zu suchen, etwa so -```kql SigninLogs | where UserPrincipalName == "[email protected]" | where TimeGenerated > ago(14d)

root@kitploit:~
KQL bietet viele Optionen zum Abfragen bestimmter Zeiträume.```kql
SigninLogs
| where TimeGenerated > ago(14d)

Wie im ersten Beispiel sucht dies nach den letzten 14 Tagen.```kql SigninLogs | where TimeGenerated > ago(14h)

root@kitploit:~
Du kannst auch Stunden angeben.```kql
SigninLogs
| where TimeGenerated > ago(14m)

Und Minuten.

KQL unterstützt auch Abfragen zwischen Zeitbereichen -```kql SigninLogs | where TimeGenerated between (ago(14d) .. ago(7d))

root@kitploit:~
Dadurch werden SigninLogs-Daten zwischen vor 14 Tagen und vor 7 Tagen gefunden.```kql
SigninLogs
| where TimeGenerated between (ago(14h) .. ago(7h))

Zwischen vor 14 Stunden und vor 7 Stunden.```kql SigninLogs | where TimeGenerated between (ago(14m) .. ago(7m))

root@kitploit:~
Und zwischen vor 14 Minuten und vor 7 Minuten.

### Where-Grundlagen

Where ist ein Operator, den Sie in praktisch jeder Abfrage verwenden werden. So teilen Sie Microsoft Sentinel mit, nach bestimmten Daten zu suchen. Die Syntax ist beim where-Operator sehr wichtig. Wenn wir unser gleiches Beispiel verwenden.```kql
SigninLogs
| where TimeGenerated > ago(14d)
| where UserPrincipalName == "[email protected]"

Dadurch wird in unserer SigninLogs-Tabelle über die letzten 14 Tage nach exakten Übereinstimmungen gesucht, bei denen unser UserPrincipalName gleich [email protected] ist. In KQL ist == case-sensitive. Wenn du also nach [email protected] suchst und der Benutzername tatsächlich [email protected] lautet, erhältst du keine Ergebnisse. Das nicht case-sensitive Gegenstück ist =```kql SigninLogs | where TimeGenerated > ago(14d) | where UserPrincipalName = "[email protected]"

root@kitploit:~
Dies findet alle Übereinstimmungen für [email protected] unabhängig von der Groß-/Kleinschreibung.

Statt equals können wir auch contains verwenden.```kql
SigninLogs
| where TimeGenerated > ago(14d)
| where UserPrincipalName contains "reprise_99"

Dies findet alle Protokolleinträge, bei denen der UserPrincipalName reprise_99 enthält. Wenn Sie Daten für [email protected] und [email protected] hätten, würde es beide finden. Der contains-Operator ist nicht case-sensitiv, aber Sie können contains_cs verwenden, um ihn case-sensitiv zu machen.

Sie können entweder startswith oder endswith verwenden, wenn Sie nach bestimmten Mustern suchen.```kql SigninLogs | where TimeGenerated > ago(14d) | where UserPrincipalName startswith "reprise_99"

SigninLogs | where TimeGenerated > ago(14d) | where UserPrincipalName endswith "testdomain.com"

root@kitploit:~
Sowohl startswith als auch endswith unterscheiden nicht zwischen Groß- und Kleinschreibung, aber Sie können startswith_cs oder endswith_cs verwenden, um sie case-sensitiv zu machen.

Wenn Sie nach vollständigen Wörtern suchen (mehr als vier Zeichen), können Sie in KQL den has-Operator verwenden. Die Verwendung von 'has' ist effizienter als 'contains', da die Daten für Sie indiziert sind.```kql
SigninLogs
| where TimeGenerated > ago(14d)
| where AppDisplayName has "Teams"

Dadurch werden alle SigninLogs gefunden, bei denen der Anzeigename der Anwendung das Wort Teams enthält. Das kann „Microsoft Teams" und „Microsoft Teams Web Client" einschließen, die beide die Abfrage erfüllen.

Wenn Sie nach mehreren Wörtern suchen, können Sie has_any oder has_all verwenden.```kql SigninLogs | where TimeGenerated > ago(14d) | where AppDisplayName has_any ("Teams","Outlook")

root@kitploit:~
Dies gibt Ergebnisse zurück, bei denen der Anzeigename der Anwendung entweder "Teams" oder "Outlook" enthält.```kql
SigninLogs
| where TimeGenerated > ago(14d)
| where AppDisplayName has_all ("Teams","Outlook")

Dies wird Ergebnisse liefern, bei denen der Anzeigename der Anwendung "Teams" und "Outlook" enthält.

Wenn du nicht weißt, in welchen Feldern du suchen sollst, kannst du auch Platzhalter verwenden. Das ist ineffizient, führt dich aber vielleicht auf die richtige Spur, um zu finden, was du suchst.```kql SigninLogs | where TimeGenerated > ago(14d) | where * contains "reprise_99"

root@kitploit:~
Dadurch wird die Tabelle SigninLogs nach jedem Feld durchsucht, das reprise_99 enthält.

Eine Reihe dieser Optionen unterstützt außerdem die Verwendung von !, um die Abfrage umzukehren und Ergebnisse zu finden, bei denen dies nicht zutrifft.```kql
SigninLogs
| where TimeGenerated > ago(14d)
| where UserPrincipalName != "[email protected]"

Diese Abfrage würde alle SigninLogs finden, bei denen UserPrincipalName nicht gleich [email protected] ist.```kql SigninLogs | where TimeGenerated > ago(14d) | where UserPrincipalName !contains "reprise_99"

root@kitploit:~
Diese Abfrage würde alle SigninLogs finden, bei denen der UserPrincipalName nicht reprise_99 enthält.```kql
SigninLogs
| where TimeGenerated > ago(14d)
| where AppDisplayName !has "Teams"

Diese Abfrage würde SigninLogs finden, bei denen der Anzeigename der Anwendung nicht "Teams" enthält.

Project-Grundlagen

Project ermöglicht es uns, auszuwählen, welche Spalten in unserer Abfrage zurückgegeben werden und in welcher Reihenfolge.```kql SigninLogs | where TimeGenerated > ago(14d) | where UserPrincipalName == "[email protected]" | where ResultType == "0" | where AppDisplayName == "Microsoft Teams" | project TimeGenerated, Location, IPAddress, UserAgent

root@kitploit:~
Diese Abfrage durchsucht die SigninLogs-Daten der letzten 14 Tage nach Einträgen, bei denen UserPrincipalname gleich [email protected] ist, ResultType gleich 0 ist und der Anzeigename der Anwendung gleich "Microsoft Teams" ist. Für jede Übereinstimmung dieser Abfrage werden TimeGenerated, Location, IPAddress und UserAgent zurückgegeben.

Wir können Spalten als Teil derselben Funktion umbenennen.```kql
| project LogTime=TimeGenerated, SigninLocation=Location, IP=IPAddress, Agent=UserAgent

Dies gibt dieselben Daten zurück, benennt die Spalten jedoch in LogTime, SigninLocation, IP und Agent um.

Wir können die Ausgabe sogar inline mit dem project-Operator manipulieren.```kql | project LocalTime=TimeGenerated+5h, Location, IPAddress, UserAgent

root@kitploit:~
Dies gibt dieselben Daten zurück, ändert aber den Namen TimeGenerated zu LocalTime und konvertiert in eine +5h Zeitzone, falls Sie in dieser Zeitzone arbeiten.

project-away ist das Gegenteil von project und entfernt Spalten aus Ihrer Abfrage.```kql
SigninLogs
| where TimeGenerated > ago(14d)
| project-away UserAgent
| where UserPrincipalName == "[email protected]"
| where ResultType == "0"
| where AppDisplayName == "Microsoft Teams"

In dieser Abfrage entfernen wir UserAgent. Denken Sie daran: Wenn Sie eine Spalte entfernen, können Sie später in Ihrer Abfrage nicht mehr darauf zugreifen.

Summarize-Grundlagen

Summarize erzeugt eine Tabelle, die den Inhalt Ihrer Abfrage aggregiert. Summarize verfügt über eine Reihe zugrunde liegender Aggregationsfunktionen. Wenn wir erneut unsere Beispielabfrage nehmen, können wir die Ergebnisse mithilfe von summarize auf verschiedene Weise verändern.```kql SigninLogs | where TimeGenerated > ago(14d) | where UserPrincipalName == "[email protected]" | where ResultType == "0" | summarize count() by AppDisplayName

root@kitploit:~
Diese Abfrage durchsucht die Tabelle SigninLogs nach allen Ereignissen der letzten 14 Tage, nach Übereinstimmungen für [email protected], bei denen das Ergebnis erfolgreich ist (ResultType == 0), und fasst diese Ereignisse anschließend nach dem Anzeigenamen der Anwendung zusammen.

Sie können die Ergebnisspalte optional benennen.```kql
SigninLogs
| where TimeGenerated > ago(14d)
| where UserPrincipalName == "[email protected]"
| where ResultType == "0"
| summarize AppCount=count() by AppDisplayName

Dies gibt dieselben Daten zurück, aktualisiert jedoch den Namen der zurückgegebenen Spalte auf AppCount.

Anstelle einer Gesamtzahl können Sie eine eindeutige Anzahl zusammenfassen.```kql SigninLogs | where TimeGenerated > ago(14d) | where UserPrincipalName == "[email protected]" | where ResultType == "0" | summarize DistinctAppCount=dcount(AppDisplayName) by AppDisplayName

root@kitploit:~
Dies gibt einen einzelnen Datensatz für jede eindeutige Anwendung zurück, bei der [email protected] angemeldet war.

Sie können die Funktionen arg_max und arg_min verwenden, um entweder den neuesten oder den ältesten Datensatz zurückzugeben, der Ihrer Abfrage entspricht.```kql
SigninLogs
| where TimeGenerated > ago(14d)
| where UserPrincipalName == "[email protected]"
| where ResultType == "0"
| summarize arg_max(TimeGenerated, *) by UserPrincipalName

Diese Abfrage sucht nach allen Anmeldeprotokollen der letzten 14 Tage, die [email protected] als UserPrincipalname haben, die erfolgreich sind, und gibt dann den neuesten Datensatz zurück.```kql SigninLogs | where TimeGenerated > ago(14d) | where UserPrincipalName == "[email protected]" | where ResultType == "0" | summarize arg_min(TimeGenerated, *) by UserPrincipalName

root@kitploit:~
Dies ist dasselbe, gibt aber den ältesten Datensatz zurück.

Sie können countif verwenden, um Ihren Summierungen Logik hinzuzufügen.```kql
SigninLogs
| where TimeGenerated > ago(14d)
| where UserPrincipalName == "[email protected]"
| where ResultType == "0"
| summarize TeamsLogons=countif(AppDisplayName has "Teams"), SharePointLogons=countif(AppDisplayName has "SharePoint")

Dies fasst die Daten in zwei neue Spalten zusammen: TeamsLogons, wobei der Anzeigename der Anwendung "Teams" enthält, und SharePointLogons, wobei der Anzeigename der Anwendung "SharePoint" enthält.

Sie können Ihre Daten weiter bearbeiten, indem Sie KQL anweisen, Ihre Daten in Zeit-'bins' zu legen.```kql SigninLogs | where TimeGenerated > ago(14d) | where UserPrincipalName == "[email protected]" | where ResultType == "0" | summarize AppCount=count() by AppDisplayName, bin(TimeGenerated, 1d)

root@kitploit:~
Dies gibt dieselben Daten wie unser erstes summarize-Beispiel zurück und gruppiert diese Daten dann in 1d-Bins.

Sie können diese Funktionen miteinander kombinieren, wo es sinnvoll ist.```kql
SigninLogs
| where TimeGenerated > ago(14d)
| where UserPrincipalName == "[email protected]"
| where ResultType == "0"
| summarize TeamsLogons=countif(AppDisplayName has "Teams"), SharePointLogons=countif(AppDisplayName has "SharePoint") by bin(TimeGenerated, 1d)

Dies ist eine Kombination unserer countif- und bin-Funktionen, bei der wir basierend auf dem Anzeigenamen unserer Anwendung zusammenfassen und die Ergebnisse in 1d-Bins einordnen.

Sie können innerhalb einer Abfrage einen Satz von Elementen erstellen.```kql SigninLogs | where TimeGenerated > ago(14d) | where UserPrincipalName == "[email protected]" | where ResultType == "0" | summarize AppList=make_set(AppDisplayName) by UserPrincipalName

root@kitploit:~
This will output a list of applications that [email protected] has signed into to a list called AppList.

You can combine this with our time bin.```kql
SigninLogs
| where TimeGenerated > ago(14d)
| where UserPrincipalName == "[email protected]"
| where ResultType == "0"
| summarize AppList=make_set(AppDisplayName) by UserPrincipalName, bin(TimeGenerated, 1d)

Dies erstellt eine Liste der Anwendungen, bei denen sich [email protected] angemeldet hat, aufgeteilt in eine Liste pro Tag.

Render-Grundlagen

Der Render-Operator ermöglicht es KQL, Daten in verschiedenen Formaten zu visualisieren, z. B. Kreisdiagrammen, Zeit- oder Flächendiagrammen sowie Säulen- und Balkendiagrammen.

Wenn wir dasselbe Beispiel aus unserer Signinlogs-Tabelle verwenden, können wir sehen, wie wir die Daten auf verschiedene Weise visualisieren können.```kql SigninLogs | where TimeGenerated > ago(14d) | where UserPrincipalName == "[email protected]" | where ResultType == "0" | summarize AppCount=count()by AppDisplayName | render piechart

root@kitploit:~
Diese Abfrage fasst alle Anwendungen zusammen, bei denen sich [email protected] in den letzten 14 Tagen angemeldet hat, und rendert die Ausgabe dann als Kreisdiagramm.

![KQL Piechart](https://raw.githubusercontent.com/reprise99/Sentinel-Queries/main/Diagrams/render-piechart.png?raw=true)

Sie können es auch als Säulendiagramm rendern.```kql
SigninLogs
| where TimeGenerated > ago(14d)
| where UserPrincipalName == "[email protected]"
| where ResultType == "0"
| summarize AppCount=count()by AppDisplayName
| render columnchart

KQL-Säulendiagramm

Oder ein Balkendiagramm.```kql SigninLogs | where TimeGenerated > ago(14d) | where UserPrincipalName == "[email protected]" | where ResultType == "0" | summarize AppCount=count()by AppDisplayName | render barchart

root@kitploit:~
![KQL Bar Chart](https://raw.githubusercontent.com/reprise99/Sentinel-Queries/main/Diagrams/render-barchart.png?raw=true)

Bei Zeitdaten fassen Sie Ihre Daten zunächst in Zeit-'Bins' zusammen, wie im Abschnitt 'summarize' beschrieben, und können Ihre Daten dann über einen Zeitraum visualisieren.```kql
SigninLogs
| where TimeGenerated > ago(14d)
| where UserPrincipalName == "[email protected]"
| where ResultType == "0"
| summarize SigninCount=count() by bin(TimeGenerated, 1d)
| render timechart

Dadurch werden alle Anmeldungen von [email protected] pro Tag der letzten 14 Tage visualisiert und als Zeitdiagramm angezeigt.

KQL Timechart

Sie können render auch als areachart verwenden.```kql SigninLogs | where TimeGenerated > ago(14d) | where UserPrincipalName == "[email protected]" | where ResultType == "0" | summarize SigninCount=count() by bin(TimeGenerated, 1d) | render areachart

root@kitploit:~
![KQL Areachart](https://raw.githubusercontent.com/reprise99/Sentinel-Queries/main/Diagrams/render-areachart.png?raw=true)

Säulendiagramme und Balkendiagramme können ebenfalls mit Zeitdaten verwendet werden. Sie erhalten eine Säule oder einen Balken pro Zeit-'Bin' über Ihren größeren Zeitraum.```kql
SigninLogs
| where TimeGenerated > ago(14d)
| where UserPrincipalName == "[email protected]"
| where ResultType == "0"
| summarize SigninCount=count() by bin(TimeGenerated, 1d)
| render columnchart

Dies ist dieselbe Abfrage wie unser Timechart, aber als Säulendiagramm mit einer Säule pro Tag dargestellt.

KQL Time Column Chart```kql SigninLogs | where TimeGenerated > ago(14d) | where UserPrincipalName == "[email protected]" | where ResultType == "0" | summarize SigninCount=count() by bin(TimeGenerated, 1d) | render barchart

root@kitploit:~
Und ein Balkendiagramm.

![KQL-Zeitbalkendiagramm](https://raw.githubusercontent.com/reprise99/Sentinel-Queries/main/Diagrams/render-timebarchart.png?raw=true)```kql
SigninLogs
| where TimeGenerated > ago(14d)
| where UserPrincipalName == "[email protected]"
| where ResultType == "0"
| summarize SigninCount=count() by AppDisplayName, bin(TimeGenerated, 1d)
| render columnchart

Diese Abfrage findet alle Anmeldungen für unser Konto, zählt die Anmeldungen pro Anwendung und erstellt dann eine einzelne Spalte für jeden Tag.

KQL Time Column Chart Stacked

Wenn Sie möchten, dass jede Anwendung eine eigene Spalte hat, können Sie sie als ungestapelt festlegen.```kql SigninLogs | where TimeGenerated > ago(14d) | where UserPrincipalName == "[email protected]" | where ResultType == "0" | summarize SigninCount=count() by bin(TimeGenerated, 1d) | render columnchart with (kind=unstacked)

root@kitploit:~
![KQL Time Column Chart Unstacked](https://raw.githubusercontent.com/reprise99/Sentinel-Queries/main/Diagrams/render-timecolumnchartunstacked.png?raw=true)

Sie können auch die Achse und den Titel Ihres Diagramms gemäß KQL umbenennen.```kql
SigninLogs
| where TimeGenerated > ago(14d)
| where UserPrincipalName == "[email protected]"
| where ResultType == "0"
| summarize SigninCount=count() by AppDisplayName, bin(TimeGenerated, 1d)
| render columnchart with (kind=unstacked, ytitle="Total Sign Ins", xtitle="Day", title="Application Signins Per Day")

KQL Zeit-Säulendiagramm Nicht gestapelt Umbenannt

Sie können Logik in Ihren summarize-Aktionen kombinieren, um dynamische Inhalte für Ihren render-Operator zu erstellen.```kql SigninLogs | where TimeGenerated > ago(14d) | where ResultType == "0" | summarize TeamsCount=countif(AppDisplayName has "Teams"), OneDrive=countif(AppDisplayName has "OneDrive"), SharePointCount=countif(AppDisplayName has "SharePoint") by bin(TimeGenerated, 1d) | render columnchart with (kind=unstacked, ytitle="Sign In Count", xtitle="Day", title="Teams vs OneDrive vs SharePoint Sign Ins Per Day")

root@kitploit:~
Diese Abfrage durchsucht alle Anmeldungen in Ihrem Mandanten und zählt dann drei Gruppen – eine, bei der der Anzeigename der Anwendung „Teams“ enthält, eine, bei der der Anzeigename der Anwendung „OneDrive“ enthält, und eine, bei der der Anzeigename der Anwendung „SharePoint“ enthält – für jeden Tag der letzten 14 Tage. Anschließend wird das Ergebnis als nicht gestapeltes Säulendiagramm gerendert.

![KQL-Zeit-Säulendiagramm Outlook, OneDrive, SharePoint](https://raw.githubusercontent.com/reprise99/Sentinel-Queries/main/Diagrams/render-timecolumn-outlookonedrivesharepoint.png?raw=true)

### Grundlagen von Parse und Split

Parse und Split sind zwei verschiedene Möglichkeiten, eine Datenzeichenfolge basierend auf Übereinstimmungen in mehrere Spalten zu erweitern. Viele Logs, die in Microsoft Sentinel aufgenommen werden, können als eine einzige lange Zeichenfolge vorliegen (z. B. sysmon). Mit Parse und Split können Sie sie in lesbare Daten umwandeln.

Für diese Beispiele verwenden wir die folgenden Testdaten```kql
let ExampleText = datatable(TestData:string)
[
'Name=Reprise99,UPNSuffix=testdomain.com,AadTenantId=345c1234-a833-43e4-1d34-123440a5bcdd1,AadUserId=cf6f2df6-b754-48dc-b7bc-c8339caf211,DisplayName=Test User,Type=account'
];

Diese Daten sind nur eine einzelne Zeichenfolge, die so aussieht.

Parse

Wir können bestimmte Datenübereinstimmungen mit dem Folgenden herausparsen.```kql let ExampleText = datatable(TestData:string) [ 'Name=Reprise99,UPNSuffix=testdomain.com,AadTenantId=345c1234-a833-43e4-1d34-123440a5bcdd1,AadUserId=cf6f2df6-b754-48dc-b7bc-c8339caf211,DisplayName=Test User,Type=account' ]; ExampleText | parse TestData with * 'Name=' DisplayName ',' * | project DisplayName

root@kitploit:~
Dies parst alle Daten zwischen `Name=` und `,` in eine neue Spalte namens `'DisplayName'`.

![Parse 1](https://raw.githubusercontent.com/reprise99/Sentinel-Queries/main/Diagrams/parse1.png?raw=true)

Sie können mit demselben Befehl mehrere Spalten auslesen, indem Sie entlang der Zeichenfolge abgleichen.```kql
let ExampleText = datatable(TestData:string)
[
'Name=Reprise99,UPNSuffix=testdomain.com,AadTenantId=345c1234-a833-43e4-1d34-123440a5bcdd1,AadUserId=cf6f2df6-b754-48dc-b7bc-c8339caf211,DisplayName=Test User,Type=account'
];
ExampleText
| parse TestData with * 'Name=' DisplayName ',UPNSuffix=' DomainSuffix ',AadTenantId=' AzureADTenantId ',' *
| project DisplayName, DomainSuffix, AzureADTenantId

Dies parst drei neue Spalten – DisplayName, DomainSuffix und AzureADTenantId

Parse 2

Denken Sie daran, dass KQL seine Operationen sequenziell ausführt. Sobald wir parsen, können wir anschließend erneut auf der neu erstellten Spalte parsen.```kql let ExampleText = datatable(TestData:string) [ 'Name=Reprise99,UPNSuffix=testdomain.com,AadTenantId=345c1234-a833-43e4-1d34-123440a5bcdd1,AadUserId=cf6f2df6-b754-48dc-b7bc-c8339caf211,DisplayName=Test User,Type=account', ]; ExampleText | parse TestData with * 'Name=' DisplayName ',UPNSuffix=' DomainSuffix ',AadTenantId=' AzureADTenantId ',' * | project DisplayName, DomainSuffix, AzureADTenantId | parse DomainSuffix with * '.' TopLevelDomain | project DisplayName, DomainSuffix, TopLevelDomain, AzureADTenantId

root@kitploit:~
Dies parst unsere Domain weiter, um die Top-Level-Domain zu finden, in diesem Fall eine .com

![Parse 3](https://raw.githubusercontent.com/reprise99/Sentinel-Queries/main/Diagrams/parse3.png?raw=true)

Bei Verwendung des Parse-Operators durchläuft KQL alle Ihre Datenzeilen und gibt auch Ergebnisse zurück, bei denen keine Übereinstimmung vorliegt. Je nach Ihrer Datenstruktur können Sie also viele Zeilen mit leeren Daten erhalten. Wenn wir unsere Beispieldaten um eine weitere Datenzeile mit anderen Namen erweitern und dieselbe Abfrage ausführen, sehen Sie leere Ergebnisse.```kql
let ExampleText = datatable(TestData:string)
[
'Name=Reprise99,UPNSuffix=testdomain.com,AadTenantId=345c1234-a833-43e4-1d34-123440a5bcdd1,AadUserId=cf6f2df6-b754-48dc-b7bc-c8339caf211,DisplayName=Test User,Type=account',
'Display=Reprise99,UPN=testdomain.com,AadDirectoryId=345c1234-a833-43e4-1d34-123440a5bcdd1,AadObjectId=cf6f2df6-b754-48dc-b7bc-c8339caf211,Name=Test User,AccountType=account'
]
;
ExampleText
| parse TestData with * 'Name=' DisplayName ',UPNSuffix=' DomainSuffix ',AadTenantId=' AzureADTenantId ',' *
| project DisplayName, DomainSuffix, AzureADTenantId
| parse DomainSuffix with * '.' TopLevelDomain
| project DisplayName, DomainSuffix, TopLevelDomain, AzureADTenantId

Parse 4

Um dem entgegenzuwirken, können Sie den Operator 'parse-where' verwenden, der nur Ergebnisse zurückgibt, bei denen Übereinstimmungen mit Ihrer Abfrage vorliegen.```kql let ExampleText = datatable(TestData:string) [ 'Name=Reprise99,UPNSuffix=testdomain.com,AadTenantId=345c1234-a833-43e4-1d34-123440a5bcdd1,AadUserId=cf6f2df6-b754-48dc-b7bc-c8339caf211,DisplayName=Test User,Type=account', 'Display=Reprise99,UPN=testdomain.com,AadDirectoryId=345c1234-a833-43e4-1d34-123440a5bcdd1,AadObjectId=cf6f2df6-b754-48dc-b7bc-c8339caf211,Name=Test User,AccountType=account' ] ; ExampleText | parse-where TestData with * 'Name=' DisplayName ',UPNSuffix=' DomainSuffix ',AadTenantId=' AzureADTenantId ',' * | project DisplayName, DomainSuffix, AzureADTenantId | parse DomainSuffix with * '.' TopLevelDomain | project DisplayName, DomainSuffix, TopLevelDomain, AzureADTenantId

root@kitploit:~
Wir können sehen, dass wir wieder bei einem einzelnen Ergebnis angelangt sind, bei dem wir eine Übereinstimmung mit unserem Parse hatten.

![Parse 5](https://raw.githubusercontent.com/reprise99/Sentinel-Queries/main/Diagrams/parse5.png?raw=true)

Split trennt eine Textzeichenfolge anhand eines Trennzeichens in ein Array. Wenn wir zu unseren ursprünglichen Testdaten zurückgehen, können wir anhand des Kommas trennen.```kql
let ExampleText = datatable(TestData:string)
[
'Name=Reprise99,UPNSuffix=testdomain.com,AadTenantId=345c1234-a833-43e4-1d34-123440a5bcdd1,AadUserId=cf6f2df6-b754-48dc-b7bc-c8339caf211,DisplayName=Test User,Type=account',
]
;
ExampleText
| extend SplitData = split(TestData,',')
| project SplitData

We will be returned an array with our string split out.

Split 1

Split is index aware so if your data is in the same order, you can split directly into new columns.```kql let ExampleText = datatable(TestData:string) [ 'Name=Reprise99,UPNSuffix=testdomain.com,AadTenantId=345c1234-a833-43e4-1d34-123440a5bcdd1,AadUserId=cf6f2df6-b754-48dc-b7bc-c8339caf211,DisplayName=Test User,Type=account', ] ; ExampleText | extend Name = split(TestData,',')[0] | extend DomainSuffix = split(TestData,',')[1] | extend AzureADTenantId = split(TestData,',')[2] | extend AzureADUserId = split(TestData,',')[3] | extend DisplayName = split(TestData,',')[4] | extend AccountType = split(TestData,',')[5] | project Name, DomainSuffix, AzureADTenantId, AzureADUserId, DisplayName, AccountType

root@kitploit:~
Wenn wir die Position unserer Daten innerhalb der Zeichenfolge kennen, können wir sie direkt in benannte Spalten aufteilen.

![Split 2](https://raw.githubusercontent.com/reprise99/Sentinel-Queries/main/Diagrams/split2.png?raw=true)

Sobald wir unsere Daten aufgeteilt haben, können wir sie abfragen, als wären sie von Anfang an strukturiert gewesen. Wenn wir also einen zweiten Datensatz zu unseren Daten hinzufügen und dann nach bestimmten Übereinstimmungen suchen, finden wir, wonach wir suchen.```kql
let ExampleText = datatable(TestData:string)
[
'Name=Reprise99,UPNSuffix=testdomain.com,AadTenantId=345c1234-a833-43e4-1d34-123440a5bcdd1,AadUserId=cf6f2df6-b754-48dc-b7bc-c8339caf211,DisplayName=Test User,Type=account',
'Name=Reprise103,UPNSuffix=testdomain.com,AadTenantId=331c1234-a841-43e5-1d31-12220a5bcee1,AadUserId=cf6f2df6-b754-48dc-b7bc-c8339caf211,DisplayName=Test User 2,Type=account'
]
;
ExampleText
| extend Name = split(TestData,',')[0]
| extend DomainSuffix = split(TestData,',')[1]
| extend AzureADTenantId = split(TestData,',')[2]
| extend AzureADUserId = split(TestData,',')[3]
| extend DisplayName = split(TestData,',')[4]
| extend AccountType = split(TestData,',')[5]
| project Name, DomainSuffix, AzureADTenantId, AzureADUserId, DisplayName, AccountType
| where Name contains "Reprise99"

Wir erhalten nur einen Treffer, bei dem Name "Reprise99" enthält; unser zweiter Datensatz, bei dem Name "Reprise103" enthält, wird nicht gefunden.

Split 3

Tool herunterladen