Azure Sentinel und Microsoft TeamsAzure Sentinel and Microsoft Teams

Teams spielt eine zentrale Rolle sowohl bei der Kommunikation als auch bei der Datenfreigabe in der Microsoft 365 Cloud.Teams serves a central role in both communication and data sharing in the Microsoft 365 Cloud. Da der Teams-Dienst Berührungspunkte mit so vielen zugrunde liegenden Technologien in der Cloud hat, kann er sowohl von menschlicher als auch automatisierter Analyse profitieren, nicht nur wenn es um das Suchen in Protokollen geht, sondern auch bei der Überwachung von Besprechungen in Echtzeit.Because the Teams service touches on so many underlying technologies in the Cloud, it can benefit from human and automated analysis not only when it comes to hunting in logs, but also in real-time monitoring of meetings. Azure Sentinel bietet Administratoren diese Lösungen.Azure Sentinel offers admins these solutions.

Hinweis

Benötigen Sie eine Auffrischung zu Azure Sentinel?Need a refresher on Azure Sentinel? Genau so etwas finden Sie in diesem Artikel.This article is just the thing.

Sentinel und Microsoft Teams-AktivitätsprotokolleSentinel and Microsoft Teams Activity Logs

Dieser Artikel befasst sich hauptsächlich mit dem Sammeln von Team-Aktivitätsprotokollen in Azure Sentinel.This article focuses on collecting Teams activity logs in Azure Sentinel. Abgesehen davon, dass Administratoren mithilfe von Sentinel-Arbeitsmappen und Runbooks die Sicherheitsverwaltung an einer zentralen Stelle durchführen können (einschließlich aller ausgewählten Geräte von Drittanbietern, Microsoft Threat Protection und anderen Microsoft 365-Workloads), können sie damit auch die Sicherheitsüberwachung systematisieren.Aside from allowing administrators to put security management under one pane of glass (including any selected 3rd party devices, Microsoft Threat Protection, and other Microsoft 365 Workloads), Sentinel workbooks, and runbooks can make security monitoring systematic. Ein guter erster Schritt bei dieser Vorgehensweise ist das Sammeln der erforderlichen Protokolle für die Analyse.A good first step in this process is collecting the needed logs for analysis.

Hinweis

Es kann mehr als ein Microsoft 365-Abonnement in derselben Instanz von Azure Sentinel vorkommen.More than one Microsoft 365 subscription can be surfaced in the same instance of Azure Sentinel. Dies gestattet Echtzeitüberwachung und die Suche nach Bedrohungen in historischen Protokolldateien.This will allow for realtime monitoring and hunting for threats in historical log file s. Administratoren können mithilfe von ressourcenübergreifenden Abfragen suchen, d.h. innerhalb einer einzelnen Ressourcengruppe, über Ressourcengruppen hinweg oder in einem anderen Abonnement.Administrators will be able to hunt using cross-resource queries, that is within a single resource group, across resource groups, or in another subscription.

Schritt 1: Sammeln von Teams-ProtokollenStep 1: Collect Teams logs

Dieser Abschnitt besteht aus drei Teilen:This section has three parts:

  1. Aktivieren von Überwachungsprotokollen in Microsoft 365 (M365).Enabling Audit Logs in Microsoft 365 (M365).
  2. Registrieren einer App bei Microsoft Azure, um die Authentifizierung und Autorisierung für die Protokollsammlung zuzulassen.Registering an App in Microsoft Azure to permit authentication and authorization for log collection.
  3. Registrieren des API-Abonnements, das die Protokollsammlung über die M365-API mittels PowerShell zulassen soll.Registering the API subscription that will allow log collection via M365 API via PowerShell.

Aktivieren von Überwachungsprotokollen in M365Enable Audit logs in M365

Da Teams Aktivitäten über M365 protokolliert, werden Überwachungsprotokolle nicht standardmäßig gesammelt.Because Teams logs activity through M365, audit logs aren't collected by default. Aktivieren Sie diese Funktion mithilfe dieser Schritte.Turn on this feature via these steps. Teams-Daten werden in der M365-Überwachung unter Audit.General gesammelt.Teams data is collected in the M365 audit under Audit.General.

Registrieren einer App bei Microsoft Azure für die ProtokollsammlungRegister an App in Microsoft Azure for log collection

Tipp

Bevor Sie beginnen, müssen Sie Ihre Anwendungs-ID/Client-ID und ihre Mandanten-ID für die spätere Verwendung aufzeichnen.Before you begin, you will need to record you Application ID / Client ID, and your Tenant ID for later use. Stellen Sie sicher, dass Sie sie erfassen, während Sie die unten beschriebenen Schritte zur App-Registrierung absolvieren.Be sure to capture them as you walk through app registration steps below. Beide IDs werden angezeigt.You will see both IDs.

  • Nachdem Ihre App erstellt wurde, klicken Sie auf der Schnellstart-Randleiste auf „App-Registrierung“, suchen Sie den Anzeigenamen Ihrer neuen App, und kopieren Sie die Anwendungs (Client)-ID.After your app is created, click App Registration on the quick launch side-bar > Find your new app's display name > copy the Application (client) ID.
  • Klicken Sie auf der Schnellstart-Randleiste auf „Übersicht“, und kopieren Sie die Verzeichnis (Mandanten)-ID.Click Overview on the quick launch side-bar > copy the Directory (tenant) ID.

Authentifizieren und autorisieren Sie eine Azure Active Directory-App (Azure AD) für das Sammeln von Protokolldaten aus der API.Authenticate and authorize an Azure Active Directory (Azure AD) app to collect log data from the API.

  1. Navigieren Sie im Azure-Portal zum Blatt Azure AD.Navigate to your Azure AD blade in the Azure portal.
  2. Klicken Sie auf der Schnellstart-Randleiste auf App-Registrierungen.Click on App registrations in the quick launch side-bar.
  3. Wählen Sie Neue Registrierung aus.Select New registration.
  4. Benennen Sie Ihre App zum Sammeln von Teams-Protokollen, und klicken Sie auf Registrieren.Name your Teams log collecting app and click Register.
  5. Klicken Sie entlang dieses Pfads auf: API-Berechtigungen > Berechtigung hinzufügen > Office 365-Verwaltungs-APIs > Anwendungsberechtigungen.Click along this path: API Permissions > Add a permission > Office 365 Management APIs > Application permissions.
  6. Erweitern Sie den Aktivitätsfeed, und aktivieren Sie ActivityFeed.Read.Expand Activity Feed and check ActivityFeed.Read.
  7. Wählen Sie hier Administratoreinwilligung erteilen aus.Choose Grand admin consent here. Klicken Sie auf „Ja“, wenn Sie gefragt werden, ob Sie das möchten.Click Yes when prompted asking if you mean it.
  8. Klicken Sie auf der Randleiste auf Zertifikate und Geheimnisse und dann auf die Schaltfläche Neuer geheimer Clientschlüssel.Click Certificates and Secrets in the side-bar> New client secret button.
  9. Geben Sie im Fenster „Neuer geheimer Clientschlüssel“ eine Beschreibung für den neuen geheimen Clientschlüssel ein, stellen Sie sicher, dass Sie als „Ablauf“ den Wert „Nie“ auswählen, und klicken Sie auf Hinzufügen.On the New client secret window, enter a description for the new Client Secret, make sure you choose 'Never' for Expiration, and click Add.

Wichtig

Es ist von kritischer Bedeutung, den neuen geheimen Clientschlüssel in einen Kennwort-Manager-Eintrag zu kopieren, der den Namen der neu erstellten App trägt.It's critical to copy the new client secret into a password manager entry that goes under the name of the newly created app. Sie können nicht mehr dorthin zurückkehren, um sich dieses Geheimnis anzusehen, nachdem das Azure-Blatt geschlossen wurde (Blatt (blade) ist in Azure die Bezeichnung für „Fenster“).You won't be able to get back to look at this secret after the closing out of the Azure blade (blade being the Azure term for window).

Registrieren der API bei PowerShell zum Sammeln von Team-ProtokollenRegister the API with PowerShell to collect Teams logs

Der letzte Schritt bei der Einrichtung besteht darin, das API-Abonnement zu sammeln und zu registrieren, damit Sie Ihre Protokolldaten sammeln können.The final step in setup is to collect and register the API subscription so that you can collect your log data. Dies geschieht über PowerShell-REST-Aufrufe der M365-Verwaltungsaktivitäts-API.This is done via PowerShell REST calls to the M365 Management Activity API.

Halten Sie die Werte für die Anwendungs (Client)-ID, den neuen geheimen Clientschlüssel, Ihre URL-Domäne für M365 und die Verzeichnis (Mandanten)-ID bereit, um sie unten in dem PowerShell-Cmdlet bereitzustellen.Be ready to supply Application (client) ID, the new Client Secret, your URL domain for M365, and Directory (tenant) ID values in the PowerShell cmdlet below.

$ClientID = "<Application (client) ID>"  
$ClientSecret = "<Client secret>"  
$loginURL = "https://login.microsoftonline.com/"  
$tenantdomain = "<domain>.onmicrosoft.com"  

$TenantGUID = "<Directory (tenant) ID>"  
$resource = "https://manage.office.com"  
$body = @{grant_type="client_credentials";resource=$resource;client_id=$ClientID;client_secret=$ClientSecret}
$oauth = Invoke-RestMethod -Method Post -Uri $loginURL/$tenantdomain/oauth2/token?api-version=1.0 -Body $body  
$headerParams = @{'Authorization'="$($oauth.token_type) $($oauth.access_token)"}
$publisher = New-Guid
Invoke-WebRequest -Method Post -Headers $headerParams -Uri "https://manage.office.com/api/v1.0/$tenantGuid/activity/feed/subscriptions/start?contentType=Audit.General&PublisherIdentifier=$Publisher"

Schritt 2: Bereitstellen eines Sentinel-Playbooks zum Erfassen der Teams-ProtokolleStep 2: Deploy a Sentinel Playbook to ingest the Teams logs

Azure Sentinel-Playbooks (auch als Logik-Apps bezeichnet) gestatten Azure das Erfassen Ihrer gesammelten Teams-Daten.Azure Sentinel Playbooks (also called Logic Apps) will allow Azure to ingest your collected Teams data. Die Logik-App fragt Office 365 ab, um die Überwachungsdaten zu finden, die es in den Azure Sentinel-Arbeitsbereich schreibt.The Logic App queries Office 365 to find the audit data it writes into the Azure Sentinel workspace.

Verwenden Sie diese ARM-Vorlage, um Ihr Sentinel-Playbook bereitzustellen.Use this ARM template to deploy your Sentinel Playbook.

Aspekte, die Beachtung verdienen:Things to remember:

  1. Sie müssen die ARM-Vorlage durchgehen und bestimmte Werte durch Werte ersetzen, die für Ihre eigene Umgebung geeignet sind.You will need to walk through the ARM template and replace certain of the values with values appropriate for your own environment.

  2. Sie müssen zwischen der Erfassung von Protokollen und dem Anzeigen von Ergebnissen in Azure Sentinel Zeit vergehen lassen.You will need to allow time between the ingestion of logs and looking at the results in Azure Sentinel.

    Warten Sie 5 bis 10 Minuten, weil sonst, wenn es innerhalb der letzten 5 Minuten keine Daten vorhanden waren, eine Fehlermeldung angezeigt wird.Wait for 5 to 10 minutes, understanding that if there is no data within the past 5 minutes you will see an error message. Überprüfen Sie die Überwachungsprotokolle, und denken Sie daran, dass, weil sich die Teams-Informationen in den „Audit.General“-Ereignissen befinden, in denen mehr als die Teams-Protokolle gesammelt wird, die Ergebnisse innerhalb von 5 bis 10 Minuten auf Systemen angezeigt werden sollten, die gerade verwendet werden.Check Audit logs and keep in mind that because Teams information is in the Audit.General events, which collects more than Teams logs, results should appear within 5 to 10 minutes on systems that are in use. Wenn Sie eine Textumgebung verwenden, stellen Sie sicher, dass Sie Teams verwenden, um die Protokollierung zu generieren.If using a text environment, be certain to use Teams in order to generate logging.

Eine Grafik, die die Logik-App-Klassen zeigt.

Erläuterung der Aktionen in der Grafik:Explanation of actions in the graphic:

• „Wiederholung“ ist der Logik-App-Trigger, der den Workflow veranlasst, dass er stündlich ausgeführt wird.• Recurrence is the Logic App Trigger that tells the workflow to run every hour.

• Die Aktion „Aktuelle Zeit“ ist sehr einfach und ruft lediglich die aktuelle Uhrzeit ab.• The Current Time action is very basic and just gets the current time.

• „Variable initialisieren“ erstellt eine Variable namens „NextPage“ und legt diese auf „1“ fest.• Initialize Variable creates a variable called NextPage and sets it to 1. Diese wird später verwendet, um die Paginierung aus der O365-API zu verarbeiten.This will be used later in order to handle pagination from the O365 API.

• „Variable 2 initialisieren“ erstellt eine leere Variable namens „Start Time“ (Startzeit).• Initialize Variable 2 creates an empty variable called Start Time.

• „Abfrage ausführen und Ergebnisse auflisten“ ist eine Azure Monitor-Aktion, die im Arbeitsbereich das letzte O365-Protokoll abfragt, das von der Logik-App eingegeben wurde.• Run Query and list results is an Azure Monitor action that will query the workspace for the last O365 log that was entered from the Logic App.

• „Bedingung 4“ wird verwendet, um zu überprüfen, ob die Abfrage „Abfrage ausführen und Ergebnisse auflisten“ Daten zurückgegeben hat.• Condition 4 is used to check whether the Run Query and list results query returned any data. Dies geschieht, um zu überprüfen, ob dies das erste Mal ist, dass die Logik-App verwendet wurde.This is done to check if this is the very first time the Logic App has been used. Wenn keine Daten zurückgegeben werden, wird die Variable „StartTime“ auf „Now – 24 Hours“ (Jetzt – 24 Stunden) festgelegt.If no data is returned, StartTime variable is set to Now – 24 hours. Wenn Daten zurückgegeben werden, wird „StartTime“ auf die „TimeGenerated“ des letzten Datensatzes festgelegt.If data is returned, StartTime is set to the last record TimeGenerated. Dies geschieht, damit die Abfrage mit der Abfrage der O365-API Daten ab dem letzten Eintrag bis jetzt abrufen kann, oder innerhalb der letzten 24 Stunden, wenn dies die erste Ausführung ist.This is done so that the query can get data from the last entry till now in the poll against the O365 API, or in the last 24 hours if this is the first run.

• „Variable 3 initialisieren“ erstellt eine Variable namens „AvailableUri“ (Verfügbarer URI).• Initialize Variable 3 creates a variable called AvailableUri. Hierbei handelt es sich um eine Zeichenfolge mit der URL, die mit „StartTime“ und „CurrentTime“ als Start- bzw. Endzeit erstellt wurde.This is a string with the URL built using the StartTime and CurrentTime as start and end times, respectively.

• Die Bedingung „Until“ (Bis) ist eine Schleife, durch die die Logik-App weiterhin die API abrufen kann, um festzustellen, ob weitere Daten vorhanden sind (Paginierung).• The Until condition is a loop that allows the logic app to keep polling the API to see if there is more data (pagination). Solange die Variable „NextPage“ (Nächste Seite) den Wert „1“ hat, wird die Schleife fortgesetzt.As long as NextPage variable is 1 the loop will continue. Später wird diese Variable aktualisiert, wenn keine weiteren Seiten mehr zum Abrufen vorhanden sind.Later this variable will be updated if there are no more pages left to retrieve.

• Innerhalb der „Until“-Schleife stellt der erste HTTP-Schritt eine Verbindung mit dem „AvailableURI“ her.• Inside the Until loop, the first HTTP step Connects to the AvailableURI. Dieser URI gibt eine Liste verfügbarer Inhalte und der einzelnen Inhalts-URIs zurück.This URI returns a list of available content and each contents URI. Weitere Informationen zu dieser Funktionsweise finden Sie unter dieser URL: https://docs.microsoft.com/office/office-365-management-api/office-365-management-activity-api-reference#list-available-content.There's more on how this works at this URL: https://docs.microsoft.com/office/office-365-management-api/office-365-management-activity-api-reference#list-available-content.

• Als Nächstes wird ein Test ausgeführt, um sicherzustellen, dass Daten zurückgegeben werden.• Next a check is run to make sure data is returned. Mit der „Condition“ (Bedingung) wird überprüft, ob die Länge des Texts „0“ beträgt.The Condition checks if the length of the body is 0. Ist dies der Fall, gibt es keine Daten, die in Log Analytics geschrieben werden könnten.If so there is no data to write to Log Analytics. Ist der Wert größer als 0, sind zu verarbeitende Daten vorhanden.If the value is greater than 0, there is data to process.

• Wenn Daten erkannt werden, müssen diese als Nächstes verarbeitet werden.• If data is detected, it must next be processed. „JSON analysieren“ definiert ein Schema der zurückgegebenen Daten.Parse JSON defines a schema of the returned data. Damit können Logik-Apps die analysierten Daten in späteren Schritten als dynamische Inhalte verwenden.This allows logic apps to use the parsed data as Dynamic content in later steps.

• Da es sich bei der zurückgegebenen Liste verfügbarer Daten um ein Array handelt, wird eine „For Each“-Aktion verwendet, um die Liste der verfügbaren Inhalte als Schleife zu durchlaufen.• Since the returned list of available data is an Array, a For Each action is used to loop through the list of available content.

• Als Nächstes wird der Inhalt extrahiert.• Next is grabbing the content. HTTP wird erneut verwendet, um den „contentUri“ (eine dynamische Eigenschaft, die mittels „JSON analysieren“ erstellt wurde) abzurufen, der die URL der abzurufenden Daten ist.HTTP is used again to get the contentUri (a dynamic property created from Parse JSON), which is the URL of the data to retrieve.

• „JSON analysieren“ auch verwendet, um die zurückgegebenen Daten zu analysieren.• Parse JSON is also used to parse the returned data. Einige Beispielinhalte können Sie unter dieser URL finden: https://docs.microsoft.com/office/office-365-management-api/office-365-management-activity-api-reference#list-available-content.You can find some sample content at this URL: https://docs.microsoft.com/office/office-365-management-api/office-365-management-activity-api-reference#list-available-content.

• Die zurückgegebenen Daten sind ebenfalls ein Array.• The data returned is also an array. Hier kann auch eine „For Each“-Schleife verwendet werden.A For Each loop can be used here as well. In dieser Schleife nimmt der Workflow das aktuelle Datenelement und verwendet die Aktion „Daten senden“, um die Daten in Log Analytics zu schreiben.In this loop, the workflow takes the current item of data and uses the Send Data action to write the data to Log Analytics.

• Da es mehrere Seiten verfügbarer Inhalte geben kann, wird mit einer Bedingung überprüft, ob der „NextPageUri“ nicht NULL ist.• Since there may be multiple pages of available content, a condition checks if the NextPageUri is not NULL. Wenn er NULL oder leer ist, wird „NextPage“ auf „0“ festgelegt, wodurch die „Until“-Schleife beendet wird.If it is NULL, or empty, NextPage is set to 0, which ends the Until loop. Enthält er eine URL, wird die Variable „AvaibleUri“ auf diese URL aktualisiert.If it contains a URL, the AvaibleUri variable is updated to that URL. Auf diese Weise wird bei der nächsten Ausführung der „Until“-Schleife die nächste verfügbare URL verwendet, nicht die Anfangs-URL.This way, the next run of the Until loop uses a next available URL, and not the starting URL.

Tipp

Sie können stattdessen eine Azure-Funktion verwenden, um diese Protokolle zu erfassen, und wenn Sie dies tun, finden Sie die Informationen zum Bereitstellen hier oder hier, je nach Ihren Wünschen.You may choose to use an Azure Function to ingest those logs, instead, and if you do, the information on how to deploy is here, or here, depending on your preference.

Während der Connector ausgeführt wird (egal welche der obigen Optionen Sie ausgewählt haben), sollte im Azure Sentinel-Arbeitsbereich eine benutzerdefinierte Tabelle namens „O365API_CL“ angezeigt werden.With the connector (whichever of the options above you chose) running, you should see a custom table called O365API_CL in the Azure Sentinel workspace. Diese nimmt Ihre Teams-Protokolle auf.This will house your Teams logs.

Schritt 3: Verwenden von Sentinel zum Überwachen von Microsoft TeamsStep 3: Use Sentinel to monitor Microsoft Teams

Die Identität ist ein wichtiger zu überwachender Angriffsvektor, wenn es um Microsoft Teams geht.Identity is an important attack vector to monitor when it comes to Microsoft Teams. Da Azure Active Directory (Azure AD) die Unterstützung des Microsoft 365-Verzeichnisses, einschließlich Teams, ist, ist das Sammeln von und Suchen nach Bedrohungen in Azure AD-Protokollen im Zusammenhang mit Authentifizierung hilfreich, um verdächtiges Verhalten in Bezug auf Identitäten zu erfassen.Because Azure Active Directory (Azure AD) is the underpinning of Microsoft 365's directory, including Teams, collecting and hunting for threats in Azure AD logs around authentication will be useful in capturing suspicious behaviour around identity. Sie können den integrierten Connector verwenden, um Azure AD-Daten in Azure Sentinel zu pullen, und diese Erkennungs- und Such-Abfragen, um nach Problemen zu suchen.You can use the built-in connector to pull Azure AD data into Azure Sentinel, and use these detection and hunting queries to look for problems.

In Bezug auf für Microsoft Teams spezifische Angriffe, z. B. die Bedrohung von Daten, verfügt Azure Sentinel auch über Mittel, um diese zu überwachen und sie aufzuspüren.Regarding attacks specific to Microsoft Teams, threats to data, for example, Azure Sentinel also has means to monitor for them and hunt them down.

Erstellen eines Parsers für Ihre DatenCreate a parser for your data

Der erste Schritt, um die große Menge gesammelter Daten sinnvoll zu interpretieren, besteht darin, ihm durch Analyse Bedeutung zu verleihen.The first thing to do in order to make sense of the large set of collected data is to give it meaning by parsing it. Dies erfolgt mittels einer KQL-Funktion (Kusto Query Language), wodurch sich die Daten einfacher verwenden lassen.This is done with a Kusto Query Language (KQL) Function that makes the data easier to use.

Hinweis

KQL-Funktionen sind KQL-Abfragen, die als Datentyp „Funktion“ gespeichert werden.KQL functions are KQL queries saved as a data-type called 'function'. KQL-Funktionen besitzen einen Alias, der in Sentinel in das Abfragefeld eingegeben werden kann, um die Abfrage schnell erneut auszuführen.KQL functions have an alias that can be entered into the query box in Sentinel to quickly run the query again. Weitere Informationen zu KQL-Funktionen und zum Erstellen einer Parser-Funktion finden Sie in diesem Tech-Community-Artikel.For more about KQL functions and how to build a parser function, read this Tech Community article.

Der folgende Parser ist ein anpassbares Beispiel, das auf die Auswahl einer Teilmenge der Office 365-Verwaltungs-API-Felder abzielt, die für Teams relevant sind.The parser below is a customizable example aimed at selecting a subset of the Office 365 Management API fields relevant to Teams. Außerdem gibt es ein empfohlenes GitHub für Parser, aber der nachstehende Parser kann geändert werden, um unterschiedliche Anforderungen und Vorlieben zu erfüllen.There is also a suggested parser GitHub, but the parser below can be modified to fit different needs and preferences.

O365API_CL
| where Workload_s =~ "MicrosoftTeams"
| project TimeGenerated,
          Workload=Workload_s,
          Operation=Operation_s,
          TeamName=columnifexists('TeamName_s', ""),
          UserId=columnifexists('UserId_s', ""),
          AddOnName=columnifexists('AddOnName_s', AddOnGuid_g),
          Members=columnifexists('Members_s', ""),
          Settings=iif(Operation_s contains "Setting", pack("Name", columnifexists('Name_s', ""), "Old Value", columnifexists('OldValue_s', ""), "New Value", columnifexists('NewValue_s', "")),""),
          Details=pack("Id", columnifexists('Id_g', ""),  "OrganizationId", columnifexists('OrganizationId_g', ""), "UserType", columnifexists('UserType_d', ""), "UserKey", columnifexists('UserKey_g', ""), "TeamGuid", columnifexists('TeamGuid_s', "")) 

Speichern Sie den Parser als KQL-Funktion mit dem Alias „TeamsData“.Save the parser as a KQL function, with an alias of TeamsData. Er wird in den folgenden Abfragen verwendet.It will be used for the queries to follow. Details zum Konfigurieren und Verwenden einer KQL-Funktion als Parser finden Sie in diesem Tech-Community-Artikel.Details on configuring and using a KQL function as a parser can be found in this Tech Community article.

Hilfreiche KQL-SuchabfragenHelfpul hunting KQL queries

Verwenden Sie diese Abfragen, um sich mit Ihren Teams-Daten und der Teams-Umgebung vertraut zu machen.Use these queries to familiarize yourself with your Teams data and Teams environment. Die Kenntnis, wie die Umgebung aussehen und sich verhalten sollte, ist ein guter erster Schritt, um verdächtige Aktivitäten zu erkennen.Knowing how the environment should look and behave is a good first step in recognizing suspicious activity. Von hier aus können Sie weiter zur Bedrohungssuche verzweigen.From there, you can branch out into threat hunting.

Abfrage für externe VerbundbenutzerFederated external users query

Rufen Sie die Liste der Teams-Sites ab, auf denen es externe Verbundbenutzer gibt.Get the list of Teams sites that have federated external users. Diese Benutzer verfügen über einen Domänennamen bzw. ein UPN-Suffix, der/das nicht im Besitz Ihrer Organisation ist.These users will have a domain name / UPN suffix that isn't owned by your organization. In dieser Beispielabfrage besitzt die Organisation „contoso.com“.In this example query, the organization owns contoso.com.

TeamsData
| where TimeGenerated > ago(7d)
| where Operation =~ "MemberAdded"
| extend UPN = tostring(parse_json(Members)[0].Upn)
| where UPN !endswith "contoso.com"
| where parse_json(Members)[0].Role == 3
| project TeamName, Operation, UserId, Members, UPN

Tipp

Informationen zu den Zugriffstypen „Extern“ und „Gast“ in Teams finden Sie in diesem Artikel oder im Abschnitt Teilnehmertypen des Sicherheitshandbuchs für Teams.To learn more about External and Guest access types in Teams see this article, or the Participant Types section in the Teams Security Guide.

Jüngste Beitritte/Jüngste RollenänderungenWho recently joined / Whose role changed

Fragen Sie einen bestimmten Benutzer ab, um zu überprüfen, ob er einem Teams-Kanal in den letzten 7 Tagen oder innerhalb einer Woche hinzugefügt wurde:Query a specific user to check if they were added to a Teams channel in the last 7 days, or within a week:

TeamsData
| where TimeGenerated > ago(7d)
| where Operation =~ "MemberAdded"
| where Members contains "UserName"

Wurde die Rolle eines Benutzers in den letzten 7 Tagen für ein Team geändert:Was a user's role changed for a Team in the last 7 days:

TeamsData
| where TimeGenerated > ago(7d)
| where Operation =~ "MemberRoleChanged"
| where Members contains "Role" and Members contains "1"

Externe Benutzer aus unbekannten oder neuen OrganisationenExternal users from unknown or new organizations

In Teams können Sie Ihrer Umgebung oder Ihren Kanälen externe Benutzer hinzufügen.In Teams, you can add external users to your environment or channels. Organisationen verfügen häufig über eine begrenzte Anzahl wichtiger Partnerschaften und fügen Benutzer aus dem Kreis dieser Partner hinzu.Organizations often have a limited number of key partnerships and add users from among these partners. Diese KQL-Abfrage sucht nach externen Benutzern, die Teams hinzugefügt wurden, die aus Organisationen stammen, die zuvor noch nicht gesehen oder hinzugefügt wurden.This KQL looks at external users added to teams who come from organizations that haven't been seen or added before.

// If you have more than 14 days worth of Teams data change this value 
let data_date = 14d; 
// If you want to look at users further back than the last day change this value 
let lookback_data = 1d; 
let known_orgs = ( 
TeamsData  
| where TimeGenerated > ago(data_date) 
| where Operation =~ "MemberAdded" or Operation =~ "TeamsSessionStarted" 
// Extract the correct UPN and parse our external organization domain 
| extend UPN = iif(Operation == "MemberAdded", tostring(parse_json(Members)[0].UPN), UserId) 
| extend Organization = tostring(split(split(UPN, "_")[1], "#")[0]) 
| where isnotempty(Organization) 
| summarize by Organization); 
TeamsData  
| where TimeGenerated > ago(lookback_data) 
| where Operation =~ "MemberAdded" 
| extend UPN = tostring(parse_json(Members)[0].UPN) 
| extend Organization = tostring(split(split(UPN, "_")[1], "#")[0]) 
| where isnotempty(Organization) 
| where Organization !in (known_orgs) 
// Uncomment the following line to map query entities is you plan to use this as a detection query 
//| extend timestamp = TimeGenerated, AccountCustomEntity = UPN 

Externe Benutzer, die hinzugefügt und dann entfernt wurdenExternal users who were added and then removed

Angreifer, die bereits über den Zugriff auf einer bestimmten Ebene verfügen, können in Teams ein neues externes Konto hinzufügen, um auf Daten zuzugreifen und diese zu exfiltrieren.Attackers with some level of existing access may add a new external account to Teams to access and exfiltrate data. Sie können diesen Benutzer auch schnell wieder entfernen, um zu verbergen, dass dieser Zugriff stattgefunden hat.They may also quickly remove that user to hide that they made access. Diese Abfrage sucht nach externen Konten, die Teams hinzugefügt und schnell wieder entfernt wurden, um bei der Identifizierung verdächtigen Verhaltens zu helfen.This query hunts for external accounts that are added to Teams and swiftly removed to help identify suspicious behavior.

// If you want to look at user added further than 7 days ago adjust this value 
let time_ago = 7d; 
// If you want to change the timeframe of how quickly accounts need to be added and removed change this value 
let time_delta = 1h; 
TeamsData  
| where TimeGenerated > ago(time_ago) 
| where Operation =~ "MemberAdded" 
| extend UPN = tostring(parse_json(Members)[0].UPN) 
| project TimeAdded=TimeGenerated, Operation, UPN, UserWhoAdded = UserId, TeamName, TeamGuid = tostring(Details.TeamGuid) 
| join ( 
TeamsData  
| where TimeGenerated > ago(time_ago) 
| where Operation =~ "MemberRemoved" 
| extend UPN = tostring(parse_json(Members)[0].UPN) 
| project TimeDeleted=TimeGenerated, Operation, UPN, UserWhoDeleted = UserId, TeamName, TeamGuid = tostring(Details.TeamGuid)) on UPN, TeamGuid 
| where TimeDeleted < (TimeAdded + time_delta) 
| project TimeAdded, TimeDeleted, UPN, UserWhoAdded, UserWhoDeleted, TeamName, TeamGuid 
// Uncomment the following line to map query entities is you plan to use this as a detection query 
//| extend timestamp = TimeAdded, AccountCustomEntity = UPN 

Neuer Bot oder neue Anwendung hinzugefügtNew bot or application added

In Teams gibt es die Möglichkeit, Apps oder Bots in ein Team aufzunehmen, um den Funktionsumfang zu erweitern.Teams has the ability to include apps or bots in a Team to extend the feature set. Dies umfasst auch benutzerdefinierte Apps und Bots.This includes custom apps and bots. In manchen Fällen könnte eine App oder ein Bot dazu verwendet werden, Persistenz in Teams herzustellen, ohne ein Benutzerkonto zu benötigen, sowie um auf Dateien und andere Daten zuzugreifen.In some cases, an app or bot could be used to establish persistence in Teams without needing a user account, as well as access files and other data. Diese Abfrage sucht nach Apps oder Bots, die neu in Teams sind.This query hunts for apps or bots that are new to Teams.

// If you have more than 14 days worth of Teams data change this value 
let data_date = 14d; 
let historical_bots = ( 
TeamsData 
| where TimeGenerated > ago(data_date) 
| where isnotempty(AddOnName) 
| project AddOnName); 
TeamsData 
| where TimeGenerated > ago(1d) 
// Look for add-ins we have never seen before 
| where AddOnName in (historical_bots) 
// Uncomment the following line to map query entities is you plan to use this as a detection query 
//| extend timestamp = TimeGenerated, AccountCustomEntity = UserId 

Benutzerkonten, die Besitzer einer großen Anzahl von Teams sindUser accounts who are Owners of large numbers of Teams

Angreifer, die ihre Rechte erhöhen möchten, können sich selbst Besitzerrechte für eine große Anzahl verschiedener Teams zuweisen, während Benutzer in der Regel nur eine kleine Anzahl von Teams zu bestimmten Themen erstellen und besitzen.Attackers looking to elevate their privileges may assign themselves Owner privileges of a large number of diverse Teams, when, usually, users create and own a small number of Teams around specific topics. Diese KQL-Abfrage sucht nach verdächtigem Verhalten.This KQL query looks for suspicious behaviour.

// Adjust this value to change how many teams a user is made owner of before detecting 
let max_owner_count = 3; 
// Change this value to adjust how larger timeframe the query is run over. 
let time_window = 1d; 
let high_owner_count = (TeamsData 
| where TimeGenerated > ago(time_window) 
| where Operation =~ "MemberRoleChanged" 
| extend Member = tostring(parse_json(Members)[0].UPN)  
| extend NewRole = toint(parse_json(Members)[0].Role)  
| where NewRole == 2 
| summarize dcount(TeamName) by Member 
| where dcount_TeamName > max_owner_count 
| project Member); 
TeamsData 
| where TimeGenerated > ago(time_window) 
| where Operation =~ "MemberRoleChanged" 
| extend Member = tostring(parse_json(Members)[0].UPN)  
| extend NewRole = toint(parse_json(Members)[0].Role)  
| where NewRole == 2 
| where Member in (high_owner_count) 
| extend TeamGuid = tostring(Details.TeamGuid) 
// Uncomment the following line to map query entities is you plan to use this as a detection query 
//| extend timestamp = TimeGenerated, AccountCustomEntity = Member 

Viele Löschungen von Teams durch einen einzelnen BenutzerMany Team deletions by a single user

Angreifer können Unterbrechungen auslösen und Projekte und Daten gefährden, indem sie mehrere Teams löschen.Attackers can cause disruptions and jeopardize projects and data by deleting multiple teams. Da Teams in der Regel von einzelnen Besitzern gelöscht werden, kann das zentrale Löschen vieler Teams ein Anzeichen für Schwierigkeiten sein.Because teams are generally deleted by individual Owners, a central deletion of many teams can be a sign of trouble. Diese KQL-Abfrage sucht nach einzelnen Benutzern, die mehrere Teams löschen.This KQL looks for single users who delete multiple teams.

 // Adjust this value to change how many Teams should be deleted before including
 let max_delete = 3;
 // Adjust this value to change the timewindow the query runs over
 let time_window = 1d;
 let deleting_users = (
 TeamsData 
 | where TimeGenerated > ago(time_window)
 | where Operation =~ "TeamDeleted"
 | summarize count() by UserId
 | where count_ > max_delete
 | project UserId);
 TeamsData
 | where TimeGenerated > ago(time_window)
 | where Operation =~ "TeamDeleted"
 | where UserId in (deleting_users)
 | extend TeamGuid = tostring(Details.TeamGuid)
 | project-away AddOnName, Members, Settings
 // Uncomment the following line to map query entities is you plan to use this as a detection query
 //| extend timestamp = TimeGenerated, AccountCustomEntity = UserId

Erweitern Ihrer Möglichkeiten für die BedrohungssucheExpanding your thread hunting opportunities

Sie können Ihre Suche erweitern, indem Sie Abfragen aus Ressourcen wie Azure Active Directory (Azure AD) oder anderen Office 365-Workloads mit ihren Teams-Abfragen kombinieren.You can expand your hunting by combining queries from resources like Azure Active Directory (Azure AD), or other Office 365 workloads with your Teams queries. Ein Beispiel hierfür ist die Kombination der Erkennung verdächtiger Muster in Azure AD-Anmeldeprotokollen (SigninLogs) mit der Verwendung dieser Informationen bei der Suche nach Teams-Besitzern.One example is combining detection of suspicious patterns in Azure AD SigninLogs, and using that information while hunting for Team Owners.

let timeRange = 1d;
let lookBack = 7d;
let threshold_Failed = 5;
let threshold_FailedwithSingleIP = 20;
let threshold_IPAddressCount = 2;
let isGUID = "[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}";
let azPortalSignins = SigninLogs
| where TimeGenerated >= ago(timeRange)
// Azure Portal only and exclude non-failure Result Types
| where AppDisplayName has "Azure Portal" and ResultType !in ("0", "50125", "50140")
// Tagging identities not resolved to friendly names
| extend Unresolved = iff(Identity matches regex isGUID, true, false);
// Lookup up resolved identities from last 7 days
let identityLookup = SigninLogs
| where TimeGenerated >= ago(lookBack)
| where not(Identity matches regex isGUID)
| summarize by UserId, lu_UserDisplayName = UserDisplayName, lu_UserPrincipalName = UserPrincipalName;
// Join resolved names to unresolved list from portal signins
let unresolvedNames = azPortalSignins | where Unresolved == true | join kind= inner (
   identityLookup ) on UserId
| extend UserDisplayName = lu_UserDisplayName, UserPrincipalName = lu_UserPrincipalName
| project-away lu_UserDisplayName, lu_UserPrincipalName;
// Join Signins that had resolved names with list of unresolved that now have a resolved name
let u_azPortalSignins = azPortalSignins | where Unresolved == false | union unresolvedNames;
let failed_signins = (u_azPortalSignins
| extend Status = strcat(ResultType, ": ", ResultDescription), OS = tostring(DeviceDetail.operatingSystem), Browser = tostring(DeviceDetail.browser)
| extend FullLocation = strcat(Location,'|', LocationDetails.state, '|', LocationDetails.city)
| summarize TimeGenerated = makelist(TimeGenerated), Status = makelist(Status), IPAddresses = makelist(IPAddress), IPAddressCount = dcount(IPAddress), FailedLogonCount = count()
by UserPrincipalName, UserId, UserDisplayName, AppDisplayName, Browser, OS, FullLocation
| mvexpand TimeGenerated, IPAddresses, Status
| extend TimeGenerated = todatetime(tostring(TimeGenerated)), IPAddress = tostring(IPAddresses), Status = tostring(Status)
| project-away IPAddresses
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by UserPrincipalName, UserId, UserDisplayName, Status, FailedLogonCount, IPAddress, IPAddressCount, AppDisplayName, Browser, OS, FullLocation
| where (IPAddressCount >= threshold_IPAddressCount and FailedLogonCount >= threshold_Failed) or FailedLogonCount >= threshold_FailedwithSingleIP
| project UserPrincipalName);
TeamsData
| where TimeGenerated > ago(time_window)
| where Operation =~ "MemberRoleChanged"
| extend Member = tostring(parse_json(Members)[0].UPN) 
| extend NewRole = toint(parse_json(Members)[0].Role) 
| where NewRole == 2
| where Member in (failed_signins)
| extend TeamGuid = tostring(Details.TeamGuid)

Sie können die SigninLogs-Erkennungen auch für Teams spezifisch vornehmen, indem Sie einen Filter für nur Teams-basierte Anmeldungen hinzufügen, indem Sie Folgendes verwenden:Also, you can make the SigninLogs detections specific to Teams by adding a filter for only Teams-based sign-ins by using:

| where AppDisplayName startswith "Microsoft Teams"

Um die Verwendung von where AppDisplayName starts with "Microsoft Teams" noch besser zu erläutern, veranschaulicht die unten stehende KQL-Abfrage eine erfolgreiche Anmeldung von einer IP-Adresse und eine mit einem Fehler von einer anderen IP-Adresse, wobei der Gültigkeitsbereich aber nur Teams ist:To help explain using where AppDisplayName starts with "Microsoft Teams" further, the KQL below demonstrates a successful logon from one IP address with failure from a different IP address, but scoped only to Teams sign-ins:

let timeFrame = 1d;
let logonDiff = 10m;
SigninLogs 
  | where TimeGenerated >= ago(timeFrame) 
  | where ResultType == "0" 
  | where AppDisplayName startswith "Microsoft Teams"
  | project SuccessLogonTime = TimeGenerated, UserPrincipalName, SuccessIPAddress = IPAddress, AppDisplayName, SuccessIPBlock = strcat(split(IPAddress, ".")[0], ".", split(IPAddress, ".")[1])
  | join kind= inner (
      SigninLogs 
      | where TimeGenerated >= ago(timeFrame) 
      | where ResultType !in ("0", "50140") 
      | where ResultDescription !~ "Other"  
      | where AppDisplayName startswith "Microsoft Teams"
      | project FailedLogonTime = TimeGenerated, UserPrincipalName, FailedIPAddress = IPAddress, AppDisplayName, ResultType, ResultDescription
  ) on UserPrincipalName, AppDisplayName 
  | where SuccessLogonTime < FailedLogonTime and FailedLogonTime - SuccessLogonTime <= logonDiff and FailedIPAddress !startswith SuccessIPBlock
  | summarize FailedLogonTime = max(FailedLogonTime), SuccessLogonTime = max(SuccessLogonTime) by UserPrincipalName, SuccessIPAddress, AppDisplayName, FailedIPAddress, ResultType, ResultDescription 
  | extend timestamp = SuccessLogonTime, AccountCustomEntity = UserPrincipalName, IPCustomEntity = SuccessIPAddress

Wichtige Informationen und UpdatesImportant information and updates

Vielen Dank für die inhaltliche Zusammenarbeit an Pete Bryan, Nicholas DiCola und Matthew Lowe.Thank you for content collaboration, Pete Bryan, Nicholas DiCola, and Matthew Lowe. Pete Bryan und die Personen, mit denen er zusammenarbeitet, werden weiterhin Erkennungs- und Suchabfragen für Teams entwickeln. Bleiben Sie also für Updates in Verbindung mit diesem GitHub-Repository.Pete Bryan and the people he collaborates with will continue to develop detection and hunting queries for Teams, so keep in touch with this GitHub repository for updates. Überprüfen Sie regelmäßig auf Updates für den in diesem Artikel verwendeten Parser bzw. für die verwendete Logik-App.Monitor for updates to the parser and logic app used in this article. Sie können auch der Azure Sentinel-Community beitreten und daran mitwirken.You can also join and contribute to the Azure Sentinel community. Vielen Dank!Thank you! Fröhliches Suchen.Happy hunting.

Registrieren Ihrer Anwendung in Azure ADRegistering your application in Azure AD

Aktivieren oder Deaktivieren der ÜberwachungsprotokollsucheTurn audit log search on or off

Was ist Azure Sentinel?What is Azure Sentinel