This repository has been archived by the owner on Nov 16, 2023. It is now read-only.
/
Episode 1 - KQL Fundamentals.txt
353 lines (258 loc) · 10.9 KB
/
Episode 1 - KQL Fundamentals.txt
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
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
print Series = 'Tracking the Adversary with MTP Advanced Hunting', EpisodeNumber = 1, Topic = 'KQL Fundamentals', Presenter = 'Michael Melone, Tali Ash', Company = 'Microsoft'
// Language Reference: https://docs.microsoft.com/en-us/azure/kusto/query/
// Advanced Hunting Reference: https://docs.microsoft.com/en-us/microsoft-365/security/mtp/advanced-hunting-schema-tables?view=o365-worldwide
// ---------------
// What is KQL \ Azure Data Explorer?
// - Write Once, Read Many (WORM) dataset
// - Used in a variety of Microsoft products including
// + Defender ATP Advanced Hunting
// + Microsoft Threat Protection Advanced Hunting
// + Azure Sentinel
// + Azure Data Explorer
// - Tuned to work best with log data
// - Case sensitive
// - Automatically expires records based on a specified interval (up to 10 years)
// ---------------
// When using Kusto datasources
// - If the data source is log-based, try to reduce the timeframe
// - More current data is likely to be in hot storage and will return more quickly
// - Try to reduce data earlier in the query before joining or manipulating it
// ---------------
// Getting Started: Query Format
//
// DataSource
// | filters \ modifiers \ limiters
DeviceProcessEvents
| take 100
// DeviceProcessEvents
// ref: https://docs.microsoft.com/en-us/microsoft-365/security/mtp/advanced-hunting-deviceprocessevents-table?view=o365-worldwide
// Process creation and related events
// - The newly-launched process
// - The process which initiated the process
// + The device the process
// + The identity the process was launched as
// take
// Returns rows up to a pre-set count. Good for testing out your query at a small scale before use.
// Note: There is no order or consistency when using take without sorting!
// SQL Equivalent: SELECT TOP 15 * FROM DeviceProcessEvents
// ---------------
// Data sources can be tables, functions, variables
let foo = "bar";
print foo
// let
// Declares a variable which can be used later in the query.
// - Values can be:
// + Scalar (single value)
// + Tabular (a 2-dimensional table)
// + A function
// + Dynamic (a JSON-formatted object that can be addressed using dotted notation (this.that))
// - A semicolon must exist after every let statement!
// print
// Outputs a scalar value
// ---------------
DeviceLogonEvents
| count
// DeviceLogonEvents
// A table containing a row for each logon a device enrolled in Defender ATP
// Contains
// - Account information associated with the logon
// - The device which the account logged onto
// - The process which performed the logon
// - Network information (for network logons)
// - Timestamp
// count
// Returns the row count for a tablular dataset
// ---------------
AppFileEvents
| take 100
| sort by Timestamp desc
// AppFileEvents
// ref: https://docs.microsoft.com/en-us/microsoft-365/security/mtp/advanced-hunting-appfileevents-table?view=o365-worldwide
// Information regarding activity relating to files stored in cloud services
// monitored by Microsoft Cloud App Security (MCAS), including
// - The cloud application name
// - The type of action performed
// - The item the action was performed on
// - The identity which performed the action
// - The IP address and geolocation
// sort
// Orders the dataset based on the specified column
// SQL Equivalent: SELECT TOP 100 * FROM DeviceFileEvents ORDER BY Timestamp desc
// ---------------
DeviceRegistryEvents
| top 100 by Timestamp desc
// DeviceRegistryEvents
// Registry changes which occurred on a Windows device monitored by Defender ATP
// Contains
// - Registry information (Key, Value, Data)
// - Device information
// - The process which performed the operation
// - Timestamp
// top
// Returns an ordered list of rows based on the column specified
// SQL Equivalent: SELECT TOP 100 * FROM DeviceRegistryEvents ORDER BY Timestamp desc
// ---------------
DeviceNetworkEvents
| take 1000
| distinct RemoteIP, RemoteUrl
// DeviceNetworkEvents
// Table containing inbound and outbound network connections and attempts from a device monitored by Defender ATP
// Contains
// - Networking information (source and destination IP and port, URL, protocol)
// - Device information
// - The process which made or received the connection
// - Timestamp
// distinct
// Returns a table of unique results based on the column(s) specified
// SQL Equivalent: SELECT DISTINCT RemoteIP, RemoteUrl FROM DeviceNetworkEvents
// ---------------
DeviceInfo
| take 100
| project DeviceId, DeviceName, OSPlatform
// DeviceInfo
// Operating information about a device monitored by Defender ATP
// Contains
// - Device name, ID
// - Operating system information
// - Public IP address
// - Logged on user
// - Machine group
// project
// Can be used to
// - Reduce columns returned from a dataset
// - Rename columns in a dataset
// - Create calculated columns
// DataSource
// | project Column1, Column2, Column3 = Column1 + Column2
// SQL Equivalent: The column list in a query statement
// SELECT [this is the project statement] FROM DataSource
DeviceInfo
| project Timestamp, DeviceName, Four = 2 + 2
| take 100
// --------------
DeviceNetworkInfo
| take 100
| project-away Timestamp
// DeviceNetworkInfo
// Local network configurations for a device monitored by Defender ATP
// Other useful project commands:
// project-away
// Removes columns from the dataset
// project-rename
// Renames a column
// project-reorder
// Changes the order of columns in the results making the specified columns first
// No real change to the data, just how its represented
// ---------------
DeviceImageLoadEvents
| take 100
| extend DomainAndUser = strcat(InitiatingProcessAccountDomain, '\\', InitiatingProcessAccountName)
| project-reorder DomainAndUser, InitiatingProcessAccountDomain, InitiatingProcessAccountName
// DeviceImageLoadEvents
// Identifies any DLLs loaded by a process. Useful for tracking DLL sideloading attacks.
// Contains
// - The process that loaded the library
// - The module loaded by the process
// - The device where the load occurred
// - Timestamp
// extend
// Adds a column to the current dataset
// strcat()
// Concatenates two or more strings
// ---------------
AppFileEvents
| where Timestamp > ago(3d)
// where
// Used to filter a tables results based on a Boolean expression
// DataSource
// | where Column == "value"
// SQL Equivalent
// SELECT * FROM SecurityEvent WHERE EventID = 4624
// ago()
// Function used to identify a timespan relative to the current date and time
// Used with one of the following quantifiers:
// d: days
// h: hours
// m: minutes
// s: seconds
// ms: milliseconds
// microsecond: microseconds
// tick: ticks (100 nanosecond intervals)
// Important note: The most effective way to improve query performance in KQL
// is filtering based on time.
// ----------------------------------
// Note that Kusto is a case sensitive language and
// many of the operators are case sensitive.
print IsItEqual = 'TEST' == 'test'
// For a case insensitive string search, use =~
print IsItEqual = 'TEST' =~ 'test'
// Common Operators and their case insensitive counterparts
// __________________________________________________________________
// | Case Sensitive | Case Insensitive | Operation |
// --------------------------------------------------------------------
// | == | =~ | Equality |
// | != | !~ | Inequality |
// | has_cs | has | Term comparison (whole word) |
// | !has_cs | !has | Term comparison (whole word) |
// | hasprefix_cs | hasprefix | Term prefix comparison (any) |
// | !hasprefix_cs | !hasprefix | Term prefix comparison (any) |
// | hassuffix_cs | hassuffix | Term suffix comparison (any) |
// | !hassuffix_cs | !hassuffix | Term suffix comaprison (any) |
// | contains_cs | contains | Substring |
// | !contains_cs | !contains | Substring |
// | startswith_cs | startswith | String prefix |
// | !startswith_cs | !startswith | String prefix |
// | endswith_cs | endswith | String suffix |
// | !endswith_cs | !endswith | String suffix |
// | in | in~ | Array element match |
// | !in | !in~ | Array element match |
// | | has_any | Term array match |
// | matches regex | | Regular expression match |
// --------------------------------------------------------------------
print IsItEqual = "quick" in ("The", "Quick", "Brown", "Fox")
print IsItEqual = pack_array("lorem","ipsum","dolor") has "Dolor"
print IsItEqual = "Microsoft" contains_cs "ICR"
// For a list of all string operators: https://docs.microsoft.com/en-us/azure/kusto/query/datatypes-string-operators
// ---------------
// Special characters \ escaping
// In KQL, the '\' character is the escape character. If you want to use a '\'
// in your query you will need to either escape it by using '\\', or you can
// make it a string literal by prepending '@' before the string
print '\\ This \\ example \\ uses \\ the \\ escape \\ method \\'
// Now using the string literal method
print @'\ This \ example \ uses \ the \ string \ literal \ method \'
// ---------------
// Checking for null or blank values
// isnull(Column) / isnotnull(Column)
// - Checks for null values
// SQL Equivalent: SELECT TimeGenerated, EventData FROM SecurityEvent WHERE EventData IS NOT NULL
print isnull("")
// isempty(Column) / isnotempty(Column)
// - Checks for null values or empty strings
// SQL Equivalent: SELECT TimeGenerated, EventData FROM SecurityEvent WHERE EventData LIKE '%'
IdentityQueryEvents
| where isnotempty(AccountSid)
| take 100
// IdentityQueryEvents
// - contains query activities performed against Active Directory objects, such as users, groups, devices, and domains monitored by Azure ATP
// - Includes SAMR, DNS and LDAP requests
// ---------------
search 'microsoft.com'
| take 10
| project-reorder RemoteUrl
// search
// Searches the entire dataset for a given value
// Can be used to search the entire database (all tables and columns) all at once.
// Columns will be an aggregate of every table that brought back 1+ results, with
// columns having the same name merged together
// No true SQL equivalent (aside from indexing every table and searching the index, or unioning every table and column and searching that... yuck)
IdentityInfo
| search "administrator"
| take 100
| project-reorder AccountUpn, AccountName, AccountDisplayName, Surname, EmailAddress, JobTitle
// IdentityInfo
// - Contains information about users in Azure Active Directory
// Can be used with string equality comparisons. Comparison is row-based
search "administrator" and "cmd"
| take 100
| project-reorder ProcessCommandLine, FileName, AccountName, FolderPath, AccountDisplayName, Surname, EmailAddress, JobTitle, AccountUpn