-
Notifications
You must be signed in to change notification settings - Fork 272
Expand file tree
/
Copy pathKQL_ChatProtection.yml
More file actions
286 lines (277 loc) · 18.9 KB
/
KQL_ChatProtection.yml
File metadata and controls
286 lines (277 loc) · 18.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
Descriptor:
Name: ChatCommunicationProtection
DisplayName: Chat and Communication Protection plugin
Description: Data Security skills to query Teams chat DLP events, communication compliance violations, meeting transcript analysis, and cross-channel sensitive data exposure for investigation and response
SkillGroups:
- Format: KQL
Skills:
- Name: ChatDLPGetTeamsChatAlerts
DisplayName: Get DLP alerts triggered in Teams chat messages
Description: Fetches all DLP policy violations that occurred in Teams chat messages, including private chats and group chats, with details on the policy matched, sensitive information types detected, and actions taken
Inputs:
- Name: User
Description: The user UPN associated with the Teams chat DLP alert
Required: false
- Name: LookbackDays
Description: Number of days to look back for alerts (default 7)
Required: false
Settings:
Target: Defender
Template: |-
let user = '{{User}}';
let lookback = iff(isempty('{{LookbackDays}}'), 7, toint('{{LookbackDays}}'));
CloudAppEvents
| where Timestamp >= ago(totimespan(strcat(tostring(lookback), "d")))
| where ActionType has "DlpRuleMatch"
| where RawEventData.Workload == "MicrosoftTeams"
| where isempty(user) or tolower(RawEventData.UserId) has tolower(user)
| extend PolicyName = tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].PolicyName)
| extend RuleName = tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].RuleName)
| extend Severity = tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].Severity)
| extend SensitiveInfoType = tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].ConditionsMatched)).SensitiveInformation))[0].SensitiveInformationTypeName)
| extend Action = tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].Actions))[0])
| extend MessageType = case(
RawEventData.MessageType == "Chat", "Private Chat",
RawEventData.MessageType == "Channel", "Channel Message",
RawEventData.MessageType == "Meeting", "Meeting Chat",
tostring(RawEventData.MessageType))
| extend UserId = tostring(RawEventData.UserId)
| extend Recipients = tostring(RawEventData.Members)
| project Timestamp, UserId, MessageType, PolicyName, RuleName, Severity, SensitiveInfoType, Action, Recipients
| sort by Timestamp desc
- Name: ChatDLPGetChannelViolations
DisplayName: Get DLP violations in Teams channels
Description: Fetches DLP policy violations in Teams channel messages with details on the channel, team, policy triggered, and sensitive content detected
Inputs:
- Name: LookbackDays
Description: Number of days to look back for violations (default 7)
Required: false
Settings:
Target: Defender
Template: |-
let lookback = iff(isempty('{{LookbackDays}}'), 7, toint('{{LookbackDays}}'));
CloudAppEvents
| where Timestamp >= ago(totimespan(strcat(tostring(lookback), "d")))
| where ActionType has "DlpRuleMatch"
| where RawEventData.Workload == "MicrosoftTeams"
| where RawEventData.MessageType == "Channel"
| extend PolicyName = tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].PolicyName)
| extend SensitiveInfoType = tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].ConditionsMatched)).SensitiveInformation))[0].SensitiveInformationTypeName)
| extend Severity = tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].Severity)
| extend Action = tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].Actions))[0])
| extend UserId = tostring(RawEventData.UserId)
| extend TeamName = tostring(RawEventData.TeamName)
| extend ChannelName = tostring(RawEventData.ChannelName)
| project Timestamp, UserId, TeamName, ChannelName, PolicyName, Severity, SensitiveInfoType, Action
| summarize AlertCount = count(), LatestAlert = max(Timestamp) by TeamName, ChannelName, PolicyName, SensitiveInfoType
| sort by AlertCount desc
- Name: ChatDLPGetExternalSharingInTeams
DisplayName: Get sensitive data shared with external users in Teams
Description: Identifies instances where sensitive information was shared with external or guest users through Teams chats, channels, or file sharing
Inputs:
- Name: User
Description: The internal user UPN to investigate
Required: false
- Name: LookbackDays
Description: Number of days to look back (default 14)
Required: false
Settings:
Target: Defender
Template: |-
let user = '{{User}}';
let lookback = iff(isempty('{{LookbackDays}}'), 14, toint('{{LookbackDays}}'));
CloudAppEvents
| where Timestamp >= ago(totimespan(strcat(tostring(lookback), "d")))
| where RawEventData.Workload == "MicrosoftTeams"
| where isempty(user) or tolower(RawEventData.UserId) has tolower(user)
| where RawEventData.Members has "#EXT#" or RawEventData.Members has "guest"
| extend UserId = tostring(RawEventData.UserId)
| extend MessageType = tostring(RawEventData.MessageType)
| extend ExternalRecipients = RawEventData.Members
| extend HasDLPMatch = iff(ActionType has "DlpRuleMatch", "Yes", "No")
| extend PolicyName = iff(HasDLPMatch == "Yes", tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].PolicyName), "N/A")
| extend SensitiveInfoType = iff(HasDLPMatch == "Yes", tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].ConditionsMatched)).SensitiveInformation))[0].SensitiveInformationTypeName), "N/A")
| project Timestamp, UserId, MessageType, ExternalRecipients, HasDLPMatch, PolicyName, SensitiveInfoType
| sort by Timestamp desc
- Name: ChatDLPGetMeetingChatViolations
DisplayName: Get DLP violations in Teams meeting chats
Description: Fetches DLP alerts that were triggered during Teams meeting chat sessions, helping analysts identify sensitive data disclosed during meetings
Inputs:
- Name: LookbackDays
Description: Number of days to look back for meeting violations (default 7)
Required: false
Settings:
Target: Defender
Template: |-
let lookback = iff(isempty('{{LookbackDays}}'), 7, toint('{{LookbackDays}}'));
CloudAppEvents
| where Timestamp >= ago(totimespan(strcat(tostring(lookback), "d")))
| where ActionType has "DlpRuleMatch"
| where RawEventData.Workload == "MicrosoftTeams"
| where RawEventData.MessageType == "Meeting"
| extend PolicyName = tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].PolicyName)
| extend SensitiveInfoType = tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].ConditionsMatched)).SensitiveInformation))[0].SensitiveInformationTypeName)
| extend Severity = tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].Severity)
| extend UserId = tostring(RawEventData.UserId)
| extend MeetingId = tostring(RawEventData.MeetingId)
| extend Action = tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].Actions))[0])
| project Timestamp, UserId, MeetingId, PolicyName, Severity, SensitiveInfoType, Action
| sort by Timestamp desc
- Name: ChatDLPGetUserOverrides
DisplayName: Get DLP policy overrides by users in Teams
Description: Identifies instances where users overrode DLP policy warnings in Teams, indicating potential intentional data sharing of sensitive content
Inputs:
- Name: User
Description: The user UPN to check for overrides
Required: false
- Name: LookbackDays
Description: Number of days to look back (default 30)
Required: false
Settings:
Target: Defender
Template: |-
let user = '{{User}}';
let lookback = iff(isempty('{{LookbackDays}}'), 30, toint('{{LookbackDays}}'));
CloudAppEvents
| where Timestamp >= ago(totimespan(strcat(tostring(lookback), "d")))
| where ActionType has "DlpRuleUndo"
| where RawEventData.Workload == "MicrosoftTeams"
| where isempty(user) or tolower(RawEventData.UserId) has tolower(user)
| extend UserId = tostring(RawEventData.UserId)
| extend PolicyName = tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].PolicyName)
| extend RuleName = tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].RuleName)
| extend Justification = tostring(RawEventData.Justification)
| extend MessageType = tostring(RawEventData.MessageType)
| project Timestamp, UserId, MessageType, PolicyName, RuleName, Justification
| summarize OverrideCount = count(), LatestOverride = max(Timestamp), Justifications = make_set(Justification) by UserId, PolicyName
| sort by OverrideCount desc
- Name: ChatDLPGetCommunicationComplianceSummary
DisplayName: Get communication compliance violation summary
Description: Provides a summary of communication compliance events across Teams, Exchange, and other communication channels including policy violations related to offensive language, regulatory compliance, and conflict of interest
Inputs:
- Name: User
Description: The user UPN to investigate
Required: false
- Name: LookbackDays
Description: Number of days to look back (default 30)
Required: false
Settings:
Target: Defender
Template: |-
let user = '{{User}}';
let lookback = iff(isempty('{{LookbackDays}}'), 30, toint('{{LookbackDays}}'));
CloudAppEvents
| where Timestamp >= ago(totimespan(strcat(tostring(lookback), "d")))
| where ActionType has "SupervisoryReviewPolicyMatch" or ActionType has "CommunicationCompliancePolicyMatch"
| where isempty(user) or tolower(RawEventData.UserId) has tolower(user)
| extend UserId = tostring(RawEventData.UserId)
| extend PolicyName = tostring(RawEventData.PolicyName)
| extend Workload = tostring(RawEventData.Workload)
| extend MessageType = case(
Workload == "MicrosoftTeams", "Teams Message",
Workload == "Exchange", "Email",
Workload)
| extend ViolationType = tostring(RawEventData.ClassifierType)
| extend Severity = tostring(RawEventData.Severity)
| project Timestamp, UserId, Workload, MessageType, PolicyName, ViolationType, Severity
| summarize ViolationCount = count(), LatestViolation = max(Timestamp) by UserId, Workload, PolicyName, ViolationType
| sort by ViolationCount desc
- Name: ChatDLPGetSensitiveDataInChats
DisplayName: Get sensitive information types detected in Teams chats
Description: Identifies and summarizes the types of sensitive information detected in Teams chat messages, grouped by sensitive information type and user
Inputs:
- Name: LookbackDays
Description: Number of days to look back (default 7)
Required: false
Settings:
Target: Defender
Template: |-
let lookback = iff(isempty('{{LookbackDays}}'), 7, toint('{{LookbackDays}}'));
CloudAppEvents
| where Timestamp >= ago(totimespan(strcat(tostring(lookback), "d")))
| where ActionType has "DlpRuleMatch"
| where RawEventData.Workload == "MicrosoftTeams"
| extend UserId = tostring(RawEventData.UserId)
| extend PolicyName = tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].PolicyName)
| extend SensitiveInfoType = tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].ConditionsMatched)).SensitiveInformation))[0].SensitiveInformationTypeName)
| extend Confidence = tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].ConditionsMatched)).SensitiveInformation))[0].Confidence)
| extend Count = toint(parse_json(tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].ConditionsMatched)).SensitiveInformation))[0].Count)
| extend MessageType = tostring(RawEventData.MessageType)
| project Timestamp, UserId, MessageType, SensitiveInfoType, Confidence, Count, PolicyName
| summarize TotalDetections = sum(Count), UniqueUsers = dcount(UserId), LatestDetection = max(Timestamp) by SensitiveInfoType, PolicyName
| sort by TotalDetections desc
- Name: ChatDLPGetChatExfiltrationTimeline
DisplayName: Get timeline of potential data exfiltration via Teams chat
Description: Builds a chronological timeline of a user's sensitive data activities across Teams chat to help identify patterns of data exfiltration through chat channels
Inputs:
- Name: User
Description: The user UPN to investigate for exfiltration patterns
Required: true
- Name: LookbackDays
Description: Number of days to look back (default 14)
Required: false
Settings:
Target: Defender
Template: |-
let user = '{{User}}';
let lookback = iff(isempty('{{LookbackDays}}'), 14, toint('{{LookbackDays}}'));
let teamsDLP = CloudAppEvents
| where Timestamp >= ago(totimespan(strcat(tostring(lookback), "d")))
| where RawEventData.Workload == "MicrosoftTeams"
| where tolower(RawEventData.UserId) has tolower(user)
| where ActionType has "DlpRuleMatch" or ActionType has "DlpRuleUndo"
| extend EventType = iff(ActionType has "DlpRuleUndo", "DLP Override", "DLP Match")
| extend PolicyName = tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].PolicyName)
| extend SensitiveInfoType = tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].ConditionsMatched)).SensitiveInformation))[0].SensitiveInformationTypeName)
| extend MessageType = tostring(RawEventData.MessageType)
| extend HasExternalRecipient = iff(RawEventData.Members has "#EXT#" or RawEventData.Members has "guest", "Yes", "No")
| project Timestamp, EventType, MessageType, PolicyName, SensitiveInfoType, HasExternalRecipient;
let teamsFileShare = CloudAppEvents
| where Timestamp >= ago(totimespan(strcat(tostring(lookback), "d")))
| where RawEventData.Workload == "MicrosoftTeams"
| where tolower(RawEventData.UserId) has tolower(user)
| where ActionType in ("FileUploaded", "FileShared", "FileDownloaded", "FileCopied")
| extend EventType = strcat("File: ", ActionType)
| extend FileName = tostring(RawEventData.SourceFileName)
| extend MessageType = "File Operation"
| extend PolicyName = ""
| extend SensitiveInfoType = ""
| extend HasExternalRecipient = iff(RawEventData.TargetUserOrGroupName has "#EXT#", "Yes", "No")
| project Timestamp, EventType, MessageType, PolicyName, SensitiveInfoType, HasExternalRecipient;
union teamsDLP, teamsFileShare
| sort by Timestamp asc
- Name: ChatDLPGetTeamsPolicyCoverage
DisplayName: Get Teams DLP policy coverage analysis
Description: Analyzes the current DLP policy coverage for Teams communications, identifying which policies are actively matching and potential coverage gaps
Inputs:
- Name: LookbackDays
Description: Number of days to analyze for policy coverage (default 30)
Required: false
Settings:
Target: Defender
Template: |-
let lookback = iff(isempty('{{LookbackDays}}'), 30, toint('{{LookbackDays}}'));
CloudAppEvents
| where Timestamp >= ago(totimespan(strcat(tostring(lookback), "d")))
| where ActionType has "DlpRuleMatch"
| where RawEventData.Workload == "MicrosoftTeams"
| extend PolicyName = tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].PolicyName)
| extend RuleName = tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].RuleName)
| extend Severity = tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].Severity)
| extend Action = tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].Actions))[0])
| extend SensitiveInfoType = tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].ConditionsMatched)).SensitiveInformation))[0].SensitiveInformationTypeName)
| extend MessageType = case(
RawEventData.MessageType == "Chat", "Private Chat",
RawEventData.MessageType == "Channel", "Channel Message",
RawEventData.MessageType == "Meeting", "Meeting Chat",
tostring(RawEventData.MessageType))
| summarize
TotalMatches = count(),
UniqueUsers = dcount(tostring(RawEventData.UserId)),
MessageTypes = make_set(MessageType),
SensitiveTypes = make_set(SensitiveInfoType),
Actions = make_set(Action),
FirstMatch = min(Timestamp),
LastMatch = max(Timestamp)
by PolicyName, RuleName, Severity
| sort by TotalMatches desc