Skip to content

Microsoft 365 Advanced Hunting Queries with hotlinks that plug the query right into your tenant

License

Notifications You must be signed in to change notification settings

lawndoc/AdvancedHuntingQueries

Repository files navigation

AdvancedHuntingQueries

My collection of Microsoft 365 Advanced Hunting Queries written in Kusto Query Language (KQL). My queries are public domain (Unlicense), but I'd appreciate a credit/tag if you republish them somewhere.

This repo includes '🔎' icons with hotlinks that plug the queries right into your M365 Security tenant.

Click on a category to start exploring my hunting queries!

Query Categories:

  • Identify the most significant spikes in various activities
  • Kusto queries that can be turned into detection rules to create alerts
  • Hunt for specific exploits being used in your environment
  • Hunt for known IOCs and activity from compromised hosts
  • Identify potential phishing emails in your environment
  • Detection rules I've written that are useful for hunting but not ready to generate alerts
  • Highlight bad operational security practices
  • Queries related to user activity -- not all of them are relevant to security
  • Useful queries that help with identity correlation, metrics, policy building, etc.

Crafting your own queries

Getting started

To get better at KQL, the best starting place is to just explore the data. By exploring the data, your curiosity can lead you down rabbit holes of "how can I find this?" It also helps you understand the data. You can't make your own hunting queries if you don't know what information you have available to you.

Choose a table like DeviceEvents and take a sample of just 10 random events with take 10. This will give you an idea of what data is in that table.

DeviceEvents
| take 10

I find the distinct operator useful for identifying the values I can expect to find in a specific column. That will give me an idea of the ways that I can filter out data or only show specific things.

DeviceEvents
| distinct ActionType

When troubleshooting a query that isn't giving you want you want, the first thing you need to do is identify which line is wrong. Injecting take 10 or a where filter and then a blank line will allow you to check for values you would expect to see or not see.

DeviceProcessEvents
| where ProcessCommandLine contains "iex"
| take 10  // the blank line below will end this 3-line query

| summarize Count = count() by InitiatingProcessFileName  // this line won't execute because of the blank line above

To clean up the output, you can hide columns you don't care about with project, project-away, and project-reorder. It's also helpful to sort by a column like Timestamp or Count. Having an easily digestible output is as important as the query itself.

Try the below queries with and without project and sort

DeviceProcessEvents
| where FileName contains "whoami"
| project Timestamp, DeviceName, AccountName, FileName, InitiatingProcessCommandLine
DeviceProcessEvents
| where FileName == "cmd.exe"
| summarize Count = count() by AccountName
| sort by Count desc