├── AMAAgent.kql ├── AR-BreakGlassAccount.kql ├── AR-BruteForce.kql ├── AR-CloudShellExecution.kql ├── AR-NSGChanges.kql ├── ARPPoisoning.txt ├── ASCIncidentClosure.txt ├── AZCopy.yaml ├── Account-Created-Addedto-LocalAdministrator.txt ├── ActiveIncidents.txt ├── ActiveUsers.txt ├── ActivityFromInfrequentCountry.txt ├── Activity_Increase_by_date.kql ├── AddClientDataSource.txt ├── AddedorAssignedGlobalAdministratorroleperms.txt ├── AdminConsent.txt ├── AgentInfowithLocation.txt ├── AgentProblems.txt ├── AgentedDevicesnotADJoined.txt ├── AlertContextParser.txt ├── AlertIngestionTime.txt ├── AlertProviderCounts.txt ├── All_IPs_SecurityAlerts.yaml ├── Allexes.txt ├── AnalyticsRuleCreatedorModified.txt ├── AnalyticsRuleCreatedorModifiedwithDisplayName.txt ├── AnalyticsRuleDeleted.txt ├── AnalyticsRuleLastRun.txt ├── AnalyticsRulesRunbyTimes.txt ├── AnomalousAADAccountCreation.txt ├── AnomalousToken.txt ├── AutomationRuleCreation.yaml ├── AutomationRuleDelete.txt ├── AutomationRuleHasRun.txt ├── Azure Runbooks query with correlation.txt ├── AzurePortalLoginErrors.txt ├── AzureServiceIPs.kql ├── BillableDatabyDataType.txt ├── Billabledatavolumebydatatype.txt ├── Billabledatavolumebysolution.txt ├── BitLockerMaliciousEncrypt.txt ├── BookMarkUpdatedBy.txt ├── BookmarkUpdate.txt ├── BookmarksCreatedBy.txt ├── BrowserActivitybyGEO.txt ├── BuiltInFusionCreation.txt ├── CEFDevices.txt ├── CVE-2023-23397-Detection.kql ├── CalculateSumofColumn.txt ├── CaseComments.txt ├── Check4LockedoutUser.txt ├── CheckPointLogs.txt ├── CloudShell.txt ├── CloudShellPart2.txt ├── Cloudshell2.txt ├── CommentDeleted.txt ├── CommonSecurityLogCostsbyVendor.txt ├── CommonSecurityLogThroughput.txt ├── CompareTotalRecordswithValuebyPercentage.txt ├── Conditional access changes new value and old value.txt ├── ConnectorFailures.kql ├── CostPerSubscription.txt ├── CostperEventID.txt ├── CountriesWhereAgentedComputersReportFrom.txt ├── CountryInfoExternal.kql ├── CreateAndQuery.kql ├── Cross resource query.txt ├── DNSActivity_Attempts_Per_Device.txt ├── DarkSideRansomware.txt ├── DataByProvider.txt ├── DataConnectorOpened.txt ├── DataConnectorReqsFailed.txt ├── DataConnectorReqsFailedbyCallerIPOperation.txt ├── DataIngestEstimation.txt ├── DataIngestionNotHappening.txt ├── DataPerComputer.kql ├── DataPerSyslogServer.txt ├── DataRetentionChanges.txt ├── DataTypeUsagePieChart.txt ├── DayofWeek.txt ├── Debugging authentication sign-ins.txt ├── DefenderAVNotSuccessful.txt ├── DefenderExclusions.txt ├── DefenderLiveResponse.txt ├── Defender_Tampering.kql ├── DeviceStopsReporting.txt ├── DirectAgent.kql ├── DirectReport.txt ├── Does a table exist.txt ├── DomainAdminsEnterpriseAdmins.txt ├── DormantAccounts.txt ├── Duration of session.txt ├── EPSforM365AdvancedTables.txt ├── EPSperTable.kql ├── EmailCountbyCountry.kql ├── EmailForwarding.txt ├── EventIDStorageinBytes.txt ├── EventIDsinLastDay.txt ├── EventLogSources.txt ├── EventVolumePerTable.txt ├── ExecutedProcesses.txt ├── ExistingConditionalAccessPolicies.txt ├── ExpiredPassword.txt ├── ExternalAccess.txt ├── ExternalGEOforSecurityEvents.txt ├── FailedLoginsPerAccount.txt ├── FileExecutionOver5Times.txt ├── GEOIPLocation.txt ├── GetTags.txt ├── GreaterThanOneCity.txt ├── GuestAccountAdds.txt ├── GuestsAddedtoRoles.txt ├── Heartbeatnotreceivedinlast30min.txt ├── HighRiskUserSigninResourceGroupCreation.txt ├── HourMinute.txt ├── HowManyAlertsGeneratedByService.txt ├── HowManyHostLogons.txt ├── HowManyQueriesEachPersonRan.txt ├── HuntingBookmarkHealth.txt ├── HuntingQueriesAzureActivitySuccessandFailures.txt ├── Ignite ├── Pre-day.pptx └── Readme.md ├── ImageFiles.kql ├── Images ├── 20220724_144123.jpg ├── 20220724_144304.jpg ├── 20220724_144326.jpg ├── chatgpt30.png ├── failed.jpg ├── readme.md ├── scope.png └── workspacesettings.png ├── ImpossibleTravelKQL.txt ├── ImpossibleTravelMCAS.txt ├── IncidentID2RuleName.txt ├── IncidentOwnerChange.txt ├── IncidentURL.kql ├── Incidents.txt ├── IncidentsBetweenTimeRange.yaml ├── IngestionDelay.txt ├── IngestionDelaySnippet.txt ├── Interactive_web_login.kql ├── Intune-AutoPilotFailedEnrollment1Day.txt ├── Intune-DeviceThreatLevelnotSecured.txt ├── Intune-Enrollmentsabandonedbytheuser.txt ├── IntuneActivityTypes.txt ├── IntuneAuditEvents.txt ├── IntuneAuditEventsTrend.txt ├── IntuneComplianceFailuresbyOperatingSystem.txt ├── IntuneComplianceFailuresbyReason.txt ├── IntuneCountofSuccessfulEnrollmentsbyOS.txt ├── IntuneDevicesNotSupported.txt ├── IntuneDevicesNotinCompliance.txt ├── IntuneEnrollmentEventsTrend.txt ├── IntuneEnrollmentFailurereasons.txt ├── IntuneEnrollmentFailuresbyEnrollmentType.txt ├── IntuneEnrollmentFailuresbyPlatform.txt ├── IntuneEnrollmentStatistics.txt ├── IntuneEnrollmentSuccessbyEnrollmentType.txt ├── IntuneNotCompliant.txt ├── IntuneNotCompliant2.txt ├── IntuneRecentEventsbyAccounts.txt ├── IntuneRemoteactionsbyactiontype.txt ├── IntuneRemoteactionstopusers.txt ├── IntuneSuccessfulSynchedDevice.txt ├── IntuneSummarizebyOperation.txt ├── IntuneTopuserswithauditedactions.txt ├── Intunecomputershutdowns.txt ├── IntuneisCompliantByOSandOSVersion.txt ├── KDCforKRBTGTPassword.txt ├── KaseyaREvil.txt ├── LAG analysis example.txt ├── LabKQL └── LabKQL.md ├── Language demo just for fun and demo pattern replace.txt ├── LastLogin.txt ├── LastTimeDataReceived.txt ├── LastTimeMessageReceived.txt ├── Latency for a Log Analytics example with rolling percentiles.txt ├── LegacyAuthSignin.txt ├── LineNumbers-serialize.txt ├── LinksinTeamsMessages.txt ├── ListofDomains.txt ├── LockedUsers.kql ├── LogSources.txt ├── LoginFailureButPasswordChangeRequired.txt ├── LoginFailureUnknownUserNameorBadPassword.txt ├── LoginLocationNotInUS.txt ├── LoginsByAccountPerLocation.txt ├── LookbackQuery.txt ├── LookingforInstalledKBIDs.txt ├── MDTISourceTI.kql ├── MITRETacticIncident.txt ├── MITRE_ATLAS_csv_parser.kql ├── MITRE_ATLAS_parser.kql ├── MITRE_JSON_Parser.kql ├── MS_Copilots.kql ├── MV-EpandExample.txt ├── Make series to fill in gaps with default for bin by bucket.txt ├── Make-series for gaps.txt ├── MalwareEngShutdown.txt ├── MenuBlade └── Menu.md ├── MerakiConf2.txt ├── MerakiDenialofService.txt ├── MerakiDeviceChanges.txt ├── MerakiDeviceInformation.txt ├── MerakiPKIActivity.txt ├── MerakiParser.txt ├── MerakiSIGRED.txt ├── MidnightBlizzard.kql ├── MimiKatzDetection.txt ├── MostGeneratedIncidents.txt ├── MultipleTablesNoIngest.kql ├── NRTFailed.kql ├── NSGChangesByUser.txt ├── NSGChangesbyUserandResource.txt ├── NetLogonPatchCompliance.txt ├── NewAdmins.txt ├── NewBruteForceAttacks.txt ├── NewYearChampagneGlass.txt ├── NoIncidentsClosedin90.txt ├── NoLogintoAADin90Days.txt ├── NoNewOpenIncidents24hrs.txt ├── NoTotalOpenIncidentsin90.txt ├── NoUnassignedIncidents.txt ├── NotEqual.txt ├── NotLoggedIn.txt ├── NumberofEventsOveraSelectedTime.txt ├── OfficeIngestDelay.kql ├── OfficeUsertoAdminGroup.txt ├── OnlineOffline.txt ├── Overview_Page ├── Automation │ ├── Actions performed.kql │ ├── Automation.png │ ├── Closed incidents.kql │ ├── Readme.md │ └── Time saved.kql ├── Data │ ├── Anomalies.kql │ ├── Data.png │ ├── Readme.md │ ├── TI by type.kql │ ├── Total volume.kql │ └── Unhealthy connectors.kql ├── Incidents │ ├── Incidents by closed classification - last 24 hours.kql │ ├── Incidents by severity - last 24 hours.kql │ ├── Incidents by status - last 24 hours.kql │ ├── Incidents status by creation time - last 24 hours.kql │ ├── Incidents.png │ ├── Mean time to acknowledge - last 48 hours.kql │ ├── Mean time to close.kql │ └── Readme.md ├── Readme.md └── overview.png ├── Overview_Queries.txt ├── PKEXEC.txt ├── PackAllExample.txt ├── PaloAltoStops.kql ├── ParseAnomaliConfidenceScore.txt ├── ParseBetween.txt ├── PlaybookActivity.kql ├── PolicyCreation.txt ├── PolicyExemptions.txt ├── PoorPerfQuery.txt ├── Potentialmaliciouseventsmap.txt ├── PowerShellExecution.txt ├── PowerShellExecutionwithDownload.txt ├── PrintNightmare.txt ├── ProxyShell.txt ├── ProxyShellExchange.txt ├── QueriesEachPersonRan.txt ├── RDP_by_IP.kql ├── README.md ├── RegistryCredentialTheft.txt ├── RemoteLogon.txt ├── RemoteWorkspaceQuery.txt ├── Remote_Actions_By_Compromised_Account.kql ├── ReportNoData.txt ├── RestartShutdownsLast7Days.txt ├── RetentionPerTable.txt ├── RulesRuninLast30d.txt ├── Running total aka cumulative sum.txt ├── SMA and EMA examples.txt ├── SQLServerAuditLogs.txt ├── SecurityChangePasswordResets.txt ├── SecurityIndicentsCreatedinLastDay.txt ├── SecurityLogFileCleared.txt ├── SentinelDataRetention.txt ├── SentinelIncidentURLs- ALL.txt ├── SharePointDownloads.txt ├── SignInbyLocation.txt ├── SignatureVersionPie.txt ├── SigninLogsByBrowserandLocation.txt ├── SigninLogsByDay - parsing UTC.txt ├── SigninLogsNow.txt ├── SocGhoulish.kql ├── Solarwinds_ServerU_Vuln.txt ├── SolutionDataUsage.txt ├── SophosDisabled.txt ├── Sparkles.txt ├── StopPLCIoTDevice.txt ├── StoppedServices.kql ├── Strcat.kql ├── SubsCreatedPerHour.kql ├── SuccessfulRoleAssignments.txt ├── SuspicousARMActivites.txt ├── SysLogDaemon.txt ├── SysmonAMA.txt ├── SysmonEventsStorageSize.txt ├── SysmonParser.txt ├── SystemRestoreDisabled.txt ├── SystemsReportingtoSentinel.txt ├── SystemthatHaveUpdatedintheLast4Hours.txt ├── TableData.kql ├── TableExistence.txt ├── TableUsageandCost.txt ├── TablesNotIngestingDatain3Days.txt ├── TeamsAADSigninLogsRelatedtoTeamOwners.txt ├── TeamsAADSigninsSuccessUnsuccess.txt ├── TeamsBotsorAppsAdded.txt ├── TeamsChannelDeleted.txt ├── TeamsExternalRareUserAccess.txt ├── TeamsExternalSuspiciousAccountsRevokedAccess.txt ├── TeamsKQL.zip ├── TeamsListFederatedUsers.txt ├── TeamsSingleUsersDeleteMultipleTeams.txt ├── TeamsSuspiciousElevationofPrivileges.txt ├── TeamsUserAddedtoTeamsChannel.txt ├── TeamsWasUserRoleChanged.txt ├── ThreatIntelBag.kql ├── ThreatIntelligenceTableCosts.txt ├── ThreatStatus.txt ├── TieFighter.txt ├── TimeBetweenDates.txt ├── TimeRangeExample.txt ├── TooManyRecipients.kql ├── Top N by Group example via top-nested - option 2.txt ├── Top N by group example via LAG - option 1.txt ├── TotalIncidentsInLast6Months.txt ├── Tracking Privileged Account Rare Activity without AWS.txt ├── TrendofRequests.txt ├── TrialExpiration.txt ├── UEBACosts.txt ├── UEBAEstimate.kql ├── UEBA_IsDormant.txt ├── URLDetonation ├── Azure_Sentinel_analytic_rule - URL Detonation.json ├── URLDetonate.png └── URLsWatchlist.csv ├── USB_Copy_7_days.kql ├── UnsuccessfulRulesinLast24.txt ├── UpdateComplianceBarChart.txt ├── UpdateDataConnectors.txt ├── UseCases_by_MITRE.kql ├── UserAccountLockedAAD.txt ├── Usergrantedaccesstoanapp.txt ├── UsersConnectFromMultipleCity.txt ├── UsersIPsPorts.txt ├── WatchListAudit.txt ├── WatchListDelete.txt ├── WatchlistNOTin.txt ├── Watchlist_Basics ├── Watchlist_Item_Delete.kql ├── WatchlistsCosts.txt ├── WebshellPosts.txt ├── WhenUEBAwasEnabledByWho.txt ├── WhiteList-FindWhoAccessedAzureSentinelthatShouldNot.txt ├── WhoChangedConditionalAccessPolicy.txt ├── WhoChangedTheirAADPassword.txt ├── WhoDeletedAlertRule.txt ├── WhoModifiedAnalyticsRule.txt ├── Windows10LoggedInLast7Days.txt ├── WiresharkRSSTraffic.txt ├── WorkWeek.txt ├── WorkbookCreation.txt ├── WorkbookDeletion.txt ├── WorkspaceIDs.kql ├── Workspaces90DaysRetention.kql ├── WorkspacesAndTables.txt ├── ZeroLogon_Ports.txt ├── acrossworkspaceforFunction.txt ├── adminskql.txt ├── allreportingcomputers.txt ├── computersendingmostsecurityalerts.txt ├── computersunhealthystate.txt ├── dataingestionthresholdlimits.txt ├── dataparser.txt ├── dataproviders.txt ├── devices.txt ├── excessivefailedlogins.txt ├── heartbeatforscomagent.txt ├── isempty.txt ├── maxoutputcolumns.kql ├── meraki_GROK.txt ├── multipleLAworkspaces.txt ├── qualys.txt ├── savingperworkbook.kql ├── scalarexpression.txt ├── serversenrolledinWDATP.txt └── thresholds.csv /AMAAgent.kql: -------------------------------------------------------------------------------- 1 | //Systems connected using the AMA agent with Azure Arc 2 | 3 | Heartbeat 4 | | where ResourceProvider == "Microsoft.HybridCompute" 5 | | extend Agent_Version = Version 6 | | distinct Computer, Agent_Version 7 | | order by Computer 8 | -------------------------------------------------------------------------------- /AR-BreakGlassAccount.kql: -------------------------------------------------------------------------------- 1 | //Monitor break-glass account usage 2 | 3 | SigninLogs 4 | | where OperationName == "Sign-in activity" and UserPrincipalName == "youremergencyaccount@domain.com" 5 | | extend AccountCustomEntity = UserPrincipalName 6 | | extend IPCustomEntity = IPAddress 7 | -------------------------------------------------------------------------------- /AR-BruteForce.kql: -------------------------------------------------------------------------------- 1 | //Monitor for Brute Force attack 2 | 3 | SigninLogs 4 | | where ResultType == "50126" or ResultType == "50053" 5 | | extend IPCustomEntity = IPAddress 6 | | extend AccountCustomEntity = UserDisplayName 7 | -------------------------------------------------------------------------------- /AR-CloudShellExecution.kql: -------------------------------------------------------------------------------- 1 | //KQL for Analytics Rule to track Cloud Shell Execution 2 | 3 | AzureActivity 4 | | where ResourceGroup startswith "CLOUD-SHELL" 5 | | where ActivityStatusValue == "Start" 6 | | extend action_ = tostring(parse_json(Authorization).action) 7 | | summarize count() by TimeGenerated , ResourceGroup , Caller , CallerIpAddress , ActivityStatusValue 8 | | extend AccountCustomEntity = Caller 9 | | extend IPCustomEntity = CallerIpAddress 10 | -------------------------------------------------------------------------------- /AR-NSGChanges.kql: -------------------------------------------------------------------------------- 1 | //NSG Changes by Resource and Who did it 2 | 3 | AzureActivity 4 | | where parse_json(Authorization).action == "Microsoft.Network/networkSecurityGroups/securityRules/write" and ActivityStatus == "Succeeded" 5 | | distinct Resource, Caller 6 | | extend AccountCustomEntity = Caller 7 | | extend URLCustomEntity = Resource 8 | -------------------------------------------------------------------------------- /ARPPoisoning.txt: -------------------------------------------------------------------------------- 1 | //Looking for systems that have two different IP addresses that share the same MAC address for potential ARP Poisoning. 2 | //Defender for Endpoint is required for the DeviceNetworkInfo table. 3 | 4 | DeviceNetworkInfo 5 | | where isnotempty(IPv4Dhcp) 6 | | distinct IPv4Dhcp, MacAddress, NetworkAdapterName, DeviceName 7 | | summarize Count=count() by IPv4Dhcp, MacAddress, NetworkAdapterName, DeviceName 8 | -------------------------------------------------------------------------------- /ASCIncidentClosure.txt: -------------------------------------------------------------------------------- 1 | //With AzureActivity connected, check to see who closed out an Incident in ASC/Defender 2 | 3 | AzureActivity 4 | | sort by TimeGenerated desc 5 | | where OperationNameValue == "MICROSOFT.SECURITY/LOCATIONS/ALERTS/DISMISS/ACTION" and ActivityStatusValue == "Success" 6 | | project Caller, CallerIpAddress 7 | -------------------------------------------------------------------------------- /AZCopy.yaml: -------------------------------------------------------------------------------- 1 | //Monitoring AZCopy activity 2 | 3 | SecurityEvent 4 | | where Activity == "4688 - A new process has been created." or Activity == "8002 - A process was allowed to run." 5 | | where NewProcessName contains "azcopy.exe" 6 | | project SubjectAccount, NewProcessName, NewProcessId 7 | -------------------------------------------------------------------------------- /Account-Created-Addedto-LocalAdministrator.txt: -------------------------------------------------------------------------------- 1 | SecurityEvent 2 | | where AccountType == "User" 3 | // Event ID 4720 = A user account was created. Event ID 4732 = A member was added to a security-enabled local group. 4 | | where EventID == "4720" or EventID == "4732" 5 | | project TargetAccount 6 | -------------------------------------------------------------------------------- /ActiveIncidents.txt: -------------------------------------------------------------------------------- 1 | SecurityIncident 2 | | where TimeGenerated > ago(10d) 3 | | where Status == "Active" -------------------------------------------------------------------------------- /ActiveUsers.txt: -------------------------------------------------------------------------------- 1 | //Show you all active user accounts that have logged in within the last 7 days and have a level of 3 or higher 2 | 3 | SigninLogs 4 | | where TimeGenerated >= ago(7d) 5 | | where level >= 3 6 | | project IPAddress, UserDisplayName, Level 7 | -------------------------------------------------------------------------------- /ActivityFromInfrequentCountry.txt: -------------------------------------------------------------------------------- 1 | //Alert - Activity from infrequent country 2 | SecurityAlert 3 | | where SystemAlertId == "eab68468-5057-60f3-2a6b-56b8b1ac9506" 4 | | summarize arg_max(TimeGenerated, *) by SystemAlertId 5 | -------------------------------------------------------------------------------- /Activity_Increase_by_date.kql: -------------------------------------------------------------------------------- 1 | //Identify any increase in activity for a given date range 2 | //This query will pull data from various logs such as AADNonInteractiveUserSignInLogs, PowerBIActivity, AWSGuardDuty, ThreatIntelligenceIndicator, CloudAppEvents, BehaviorAnalytics, Dynamics365Activity, AzureActivity, DeviceEvents, DeviceLogonEvents, Anomalies, AppTraces, AADUserRiskEvents, and IdentityInfo. It will then filter the data based on the time generated between the start and end dates (in this case, from July 1st to July 5th, 2024). The query will then summarize the count of events by day. 3 | 4 | let startDate = datetime(2024-07-01); 5 | let endDate = datetime(2024-07-05); 6 | union AADNonInteractiveUserSignInLogs, PowerBIActivity, AWSGuardDuty, ThreatIntelligenceIndicator, CloudAppEvents, BehaviorAnalytics, Dynamics365Activity, AzureActivity, DeviceEvents, DeviceLogonEvents, Anomalies, AppTraces, AADUserRiskEvents, IdentityInfo 7 | | where TimeGenerated between (startDate .. endDate) 8 | | summarize count() by bin(TimeGenerated, 1d) 9 | | render timechart 10 | -------------------------------------------------------------------------------- /AddClientDataSource.txt: -------------------------------------------------------------------------------- 1 | //Identifies who added new Datasources to the client configuration for the Log Analytics workspace 2 | 3 | AzureActivity 4 | | where OperationNameValue has "DATASOURCES/WRITE" 5 | | where ResourceProviderValue has "MICROSOFT.OPERATIONALINSIGHTS" 6 | | project TimeGenerated, Caller, CallerIpAddress -------------------------------------------------------------------------------- /AddedorAssignedGlobalAdministratorroleperms.txt: -------------------------------------------------------------------------------- 1 | AuditLogs 2 | | where OperationName == "Add member to role" and AADOperationType == "Assign" and Result =="success" 3 | | mv-expand TargetResources 4 | | extend modifiedProperties = parse_json(TargetResources).modifiedProperties 5 | | mv-expand modifiedProperties 6 | | extend DisplayName = tostring(parse_json(modifiedProperties).displayName), GroupName = tostring(parse_json(modifiedProperties).newValue) 7 | | where GroupName == "\"TenantAdmins\"" -------------------------------------------------------------------------------- /AdminConsent.txt: -------------------------------------------------------------------------------- 1 | //The applications an administrator granted admin consent 2 | 3 | AuditLogs 4 | | where OperationName == "Consent to application" 5 | | extend Iby=todynamic(InitiatedBy) 6 | | extend IbyUser=(Iby.user) 7 | | extend TR=todynamic(tostring(TargetResources)) 8 | | mv-expand Targets = TR 9 | | project TimeGenerated,AADTenantId,UPN=IbyUser.userPrincipalName,APPName=Targets.displayName,APPID=Targets.id -------------------------------------------------------------------------------- /AgentInfowithLocation.txt: -------------------------------------------------------------------------------- 1 | //Queries the Heartbeat table to locate installed LA agents and if on-prem or in Azure 2 | 3 | Heartbeat 4 | | where TimeGenerated >= (90d) 5 | | where Category == "Direct Agent" 6 | | where isnotempty(ResourceType) 7 | | extend Cloud = ResourceProvider == "Microsoft.Compute" 8 | | extend Onprem = ResourceProvider == "Microsoft.HybridCompute" 9 | | distinct Computer, ResourceType, Cloud, Onprem 10 | -------------------------------------------------------------------------------- /AgentProblems.txt: -------------------------------------------------------------------------------- 1 | //Detecting Agent problems 2 | //Based on: https://docs.microsoft.com/en-us/azure/azure-monitor/platform/monitor-workspace#_logsoperation-function 3 | 4 | _LogOperation 5 | | where Category == "Agent" 6 | | where Level == "Warning" 7 | | project TimeGenerated, Operation , Computer 8 | -------------------------------------------------------------------------------- /AgentedDevicesnotADJoined.txt: -------------------------------------------------------------------------------- 1 | //Agented devices that are not AD-joined 2 | 3 | SigninLogs 4 | | union Heartbeat 5 | | where Category == "Direct Agent" and DeviceDetail <> "Azure AD joined" 6 | | distinct Computer -------------------------------------------------------------------------------- /AlertContextParser.txt: -------------------------------------------------------------------------------- 1 | //Parser for getting the EventID from the AlertContext column in the Alert table 2 | 3 | Alert 4 | | parse-where AlertContext with * "EventNumber>" EventNo "<" * 5 | | project EventNo 6 | -------------------------------------------------------------------------------- /AlertIngestionTime.txt: -------------------------------------------------------------------------------- 1 | //Tracking how long it takes an Alert to ingest. (in minutes) 2 | 3 | SecurityAlert 4 | | summarize by ProviderName, AlertName,Minutes_ = datetime_diff("minute",ingestion_time(), TimeGenerated) 5 | | order by Minutes_ desc 6 | -------------------------------------------------------------------------------- /AlertProviderCounts.txt: -------------------------------------------------------------------------------- 1 | //Simple query to show the provider where your alerts are coming from most 2 | 3 | SecurityIncident 4 | | summarize count() by ProviderName 5 | -------------------------------------------------------------------------------- /All_IPs_SecurityAlerts.yaml: -------------------------------------------------------------------------------- 1 | //Extract IP addresses from SecurityAlerts 2 | //Author: Randy Pargman 3 | SecurityAlert 4 | // First get lists of IP addresses from ExtendedProperties 5 | | extend properties = parse_json(ExtendedProperties) 6 | | extend IP_list = split(tostring(properties["IP Addresses"]), ",") 7 | | project IP_list 8 | | where isnotempty(IP_list) 9 | | summarize make_set(IP_list) 10 | | mv-expand set_IP_list // get each IP on its own row 11 | | where isnotempty(set_IP_list) 12 | | project IP = tostring(set_IP_list) 13 | // Now get every IP address from Entities that are type "ip" 14 | | union (SecurityAlert 15 | | extend Entities = parse_json(Entities) 16 | | project Entities 17 | | mv-expand Entities 18 | | extend EType = tostring(Entities.Type) 19 | | where EType == "ip" 20 | | extend IP = tostring(Entities.Address) 21 | | project IP) 22 | | order by IP 23 | -------------------------------------------------------------------------------- /Allexes.txt: -------------------------------------------------------------------------------- 1 | //Lists all captures .exe's. For Sentinel or Defender Advanced Hunting 2 | 3 | DeviceProcessEvents 4 | | where Timestamp > ago(7d) 5 | | where FileName endswith ".exe" 6 | | project Timestamp, DeviceName, FileName, AccountSid, AccountName, AccountDomain 7 | | top 100 by Timestamp 8 | -------------------------------------------------------------------------------- /AnalyticsRuleCreatedorModified.txt: -------------------------------------------------------------------------------- 1 | //Analytics Rule to report when someone creates or modifies an Analytics Rule 2 | //Entities: Caller, Caller IP, and Analytics Rule ID 3 | AzureActivity 4 | | where OperationNameValue has "MICROSOFT.SECURITYINSIGHTS/ALERTRULES/WRITE" 5 | | where ActivityStatusValue == "Success" 6 | | extend Analytics_Rule_ID = tostring(parse_json(Properties).resource) 7 | | extend AccountCustomEntity = Caller 8 | | extend IPCustomEntity = CallerIpAddress 9 | | extend URLCustomEntity = Analytics_Rule_ID 10 | -------------------------------------------------------------------------------- /AnalyticsRuleCreatedorModifiedwithDisplayName.txt: -------------------------------------------------------------------------------- 1 | //Analytics Rule to report when someone creates or modifies an Analytics Rule 2 | //Entities: Caller, Caller IP, and Analytics Rule ID 3 | AzureActivity 4 | | where OperationNameValue has "MICROSOFT.SECURITYINSIGHTS/ALERTRULES/WRITE" 5 | | where ActivityStatusValue == "Success" 6 | | extend Analytics_Rule_ID = tostring(parse_json(Properties).resource) 7 | | extend AccountCustomEntity = Caller 8 | | extend IPCustomEntity = CallerIpAddress 9 | | extend URLCustomEntity = Analytics_Rule_ID 10 | // Add logic to detect the name from the RuleID 11 | | extend id_ = tostring(split(Analytics_Rule_ID, '/').[2]) 12 | | join ( 13 | SecurityAlert 14 | | extend id_ = tostring(split(AlertType,'_').[1]) 15 | | project DisplayName, id_ 16 | ) on id_ 17 | | project-away id_1, id_ 18 | -------------------------------------------------------------------------------- /AnalyticsRuleDeleted.txt: -------------------------------------------------------------------------------- 1 | //When an Analytics Rule is Deleted; Alert when an Analytics Rule is deleted and who did it. 2 | 3 | AzureActivity 4 | | where OperationNameValue contains "MICROSOFT.SECURITYINSIGHTS/ALERTRULES/DELETE" 5 | | where ActivityStatusValue == "Success" 6 | | extend Analytics_Rule_ID = tostring(parse_json(Properties).resource) 7 | | extend AccountCustomEntity = Caller 8 | | extend IPCustomEntity = CallerIpAddress 9 | | extend URLCustomEntity = Analytics_Rule_ID -------------------------------------------------------------------------------- /AnalyticsRuleLastRun.txt: -------------------------------------------------------------------------------- 1 | // Last modified time for unique incident numbers = last run time 2 | SecurityIncident 3 | | summarize arg_max(LastModifiedTime,*) by IncidentNumber 4 | -------------------------------------------------------------------------------- /AnalyticsRulesRunbyTimes.txt: -------------------------------------------------------------------------------- 1 | SecurityAlert 2 | | where ProviderName contains "ASI" 3 | | summarize count() by DisplayName 4 | -------------------------------------------------------------------------------- /AnomalousAADAccountCreation.txt: -------------------------------------------------------------------------------- 1 | //Alert - Anomalous AAD Account Creation 2 | SecurityAlert 3 | | where SystemAlertId == "bf45d5cd-2cfc-dff1-8b7d-5440b5089529" 4 | | summarize arg_max(TimeGenerated, *) by SystemAlertId 5 | -------------------------------------------------------------------------------- /AnomalousToken.txt: -------------------------------------------------------------------------------- 1 | SecurityAlert 2 | | where AlertName == "Anomalous Token" 3 | | extend x = todynamic(Entities) 4 | | parse-where x with * '"SessionId":"' RequestId '"' * 5 | | project AlertTime=TimeGenerated, RequestId, CompromisedEntity, AlertName 6 | | join kind=inner ( 7 | AADUserRiskEvents) 8 | on $left.CompromisedEntity == $right.UserPrincipalName, RequestId 9 | | project 10 | RiskTime=TimeGenerated, 11 | AlertTime, 12 | AlertName, 13 | RequestId, 14 | RiskLevel, 15 | RiskState, 16 | DetectionTimingType, 17 | UserPrincipalName, 18 | CorrelationId 19 | | join kind=inner ( 20 | SigninLogs 21 | | where TimeGenerated > ago(14d) 22 | ) 23 | on CorrelationId 24 | | project 25 | SigninTime=TimeGenerated, 26 | RiskTime, 27 | AlertName, 28 | AlertTime, 29 | UserPrincipalName, 30 | AppDisplayName, 31 | Location, 32 | IPAddress, 33 | RiskLevel, 34 | RiskState, 35 | DetectionTimingType, 36 | UserAgent, 37 | ResultType 38 | -------------------------------------------------------------------------------- /AutomationRuleCreation.yaml: -------------------------------------------------------------------------------- 1 | //Who created an Automation Rule 2 | 3 | AzureActivity 4 | | where OperationNameValue == "MICROSOFT.SECURITYINSIGHTS/AUTOMATIONRULES/WRITE" 5 | | project TimeGenerated, Caller, CallerIpAddress 6 | -------------------------------------------------------------------------------- /AutomationRuleDelete.txt: -------------------------------------------------------------------------------- 1 | //Who deleted an Automation Rule 2 | 3 | AzureActivity 4 | | where OperationNameValue == "MICROSOFT.SECURITYINSIGHTS/AUTOMATIONRULES/DELETE" 5 | | project TimeGenerated, Caller, CallerIpAddress 6 | -------------------------------------------------------------------------------- /AutomationRuleHasRun.txt: -------------------------------------------------------------------------------- 1 | //Identify when Automation rules have run. 2 | 3 | SecurityIncident 4 | | where TimeGenerated >= ago(90d) 5 | | where ModifiedBy contains "Automation rule" 6 | | parse-where ModifiedBy with * "rule - " Rule_Name 7 | | distinct Incident_Number = ProviderIncidentId, Rule_Name, TimeGenerated 8 | -------------------------------------------------------------------------------- /Azure Runbooks query with correlation.txt: -------------------------------------------------------------------------------- 1 | let RequestId = toguid("9A07544E-004A-4E14-895D-3348165D7DBD"); 2 | let UPN = "user@domain.com"; 3 | AzureDiagnostics 4 | | join kind= inner ( 5 | AzureDiagnostics 6 | | where TimeGenerated > ago(180d) 7 | | where resultDescription_RequestId_g == RequestId or resultDescription_UPN_s == UPN 8 | | distinct CorrelationId 9 | ) on CorrelationId 10 | | project TimeGenerated,_TimeReceived,Latency=(_TimeReceived-TimeGenerated),RequestId=resultDescription_RequestId_g, RunbookName=RunbookName_s, Status=resultDescription_Status_s,ResultType,UPN=resultDescription_UPN_s,Attempt= 11 | resultDescription_AttemptCount_d,RequestExpectedSuccessCount= 12 | resultDescription_RequestExpectedSuccessCount_d, ExternalEmailAddress=resultDescription_ExternalEmailAddress_s 13 | | summarize CountSuccess = dcountif(RunbookName, Status == "Success"), 14 | CountFailure = dcountif(RunbookName, Status == "Failure"), 15 | CountDistinct = dcountif(RunbookName, Status != "Success"), 16 | RequestExpectedSuccessCount = max(RequestExpectedSuccessCount) by RunbookName 17 | | summarize requestExpectedSuccessCount = max(RequestExpectedSuccessCount), 18 | totalFailed = sum(CountFailure), 19 | totalSuccess = sum(CountSuccess), 20 | totalStarted = sum(CountDistinct) 21 | | extend packedStatistics = pack_all() 22 | | project packedStatistics 23 | -------------------------------------------------------------------------------- /AzurePortalLoginErrors.txt: -------------------------------------------------------------------------------- 1 | //Azure Portal login errors by User, IPAddr, City, State, code, and description 2 | 3 | SigninLogs 4 | | where TimeGenerated > ago(30d) 5 | | where AppDisplayName == "Azure Portal" 6 | | extend errorCode_ = tostring(Status.errorCode) 7 | | where errorCode_ != "0" 8 | | extend city_ = tostring(LocationDetails.city), state_ = tostring(LocationDetails.state) 9 | | project UserDisplayName, IPAddress, city_, state_, errorCode_, ResultDescription -------------------------------------------------------------------------------- /AzureServiceIPs.kql: -------------------------------------------------------------------------------- 1 | let AzurePublicIPs = externaldata( 2 | changeNumber: string, 3 | cloud: string, 4 | values: dynamic, // 'values' should be of type dynamic to hold JSON objects 5 | name: string, 6 | id: string, 7 | properties: dynamic, // 'properties' should also be dynamic if it contains nested JSON 8 | changenumber2: string, 9 | region: string, 10 | regionId: string, 11 | platform: string, 12 | systemService: string, 13 | addressPrefixes: dynamic, // 'addressPrefixes' should be of type dynamic if it's an array 14 | networkFeatures: dynamic) // 'networkFeatures' should be of type dynamic if it's an array or nested JSON 15 | [@"https://download.microsoft.com/download/7/1/D/71D86715-5596-4529-9B13-DA13A5DE5B63/ServiceTags_Public_20240422.json"] with (format="MultiJSON", ingestionMapping='[{"Column":"changeNumber","Properties":{"Path":"$.changeNumber"}},{"Column":"cloud","Properties":{"Path":"$.cloud"}},{"Column":"values","Properties":{"Path":"$.values"}},{"Column":"name","Properties":{"Path":"$.values.name"}},{"Column":"id","Properties":{"Path":"$.values.id"}},{"Column":"properties","Properties":{"Path":"$.values.properties"}},{"Column":"changenumber2","Properties":{"Path":"$.values.properties.changeNumber"}},{"Column":"region","Properties":{"Path":"$.values.properties.region"}},{"Column":"regionId","Properties":{"Path":"$.values.properties.regionId"}},{"Column":"platform","Properties":{"Path":"$.values.properties.platform"}},{"Column":"systemService","Properties":{"Path":"$.values.properties.systemService"}},{"Column":"addressPrefixes","Properties":{"Path":"$.values.properties.addressPrefixes"}},{"Column":"networkFeatures","Properties":{"Path":"$.values.properties.networkFeatures"}}]'); // Ensure this line ends with a single quote 16 | AzurePublicIPs 17 | | mv-expand values to typeof(dynamic) 18 | | extend 19 | valueName = values.name, 20 | valueId = values.id, 21 | valueChangeNumber = values.properties.changeNumber, 22 | valueRegion = values.properties.region, 23 | valueRegionId = values.properties.regionId, 24 | valuePlatform = values.properties.platform, 25 | valueSystemService = values.properties.systemService, 26 | valueAddressPrefixes = values.properties.addressPrefixes, 27 | valueNetworkFeatures = values.properties.networkFeatures 28 | | project 29 | cloud, 30 | changeNumber, 31 | valueName, 32 | valueId, 33 | valueChangeNumber, 34 | valueRegion, 35 | valueRegionId, 36 | valuePlatform, 37 | valueSystemService, 38 | valueAddressPrefixes, 39 | valueNetworkFeatures 40 | -------------------------------------------------------------------------------- /BillableDatabyDataType.txt: -------------------------------------------------------------------------------- 1 | Usage 2 | | where TimeGenerated > ago(32d) 3 | | where StartTime >= startofday(ago(31d)) and EndTime < startofday(now()) 4 | //| where IsBillable == true 5 | | summarize BillableDataGB = sum(Quantity) / 1000. by bin(StartTime, 1d), DataType -------------------------------------------------------------------------------- /Billabledatavolumebydatatype.txt: -------------------------------------------------------------------------------- 1 | //Billable data volume by data type 2 | Usage 3 | | where TimeGenerated > ago(32d) 4 | | where StartTime >= startofday(ago(31d)) and EndTime < startofday(now()) 5 | | where IsBillable == true 6 | | summarize BillableDataGB = sum(Quantity) / 1000. by bin(StartTime, 1d), DataType | render barchart -------------------------------------------------------------------------------- /Billabledatavolumebysolution.txt: -------------------------------------------------------------------------------- 1 | //Billable data volume by solution 2 | Usage 3 | | where TimeGenerated > ago(32d) 4 | | where StartTime >= startofday(ago(31d)) and EndTime < startofday(now()) 5 | | where IsBillable == true 6 | | summarize BillableDataGB = sum(Quantity) / 1000. by bin(StartTime, 1d), Solution | render barchart -------------------------------------------------------------------------------- /BitLockerMaliciousEncrypt.txt: -------------------------------------------------------------------------------- 1 | //Look for potential instances of BitLocker used to encrypt data maliciously. Defender for Endpoint connected to Sentinel. 2 | 3 | DeviceProcessEvents 4 | | where FileName =~ "reg.exe" 5 | and ProcessCommandLine has "EnableBDEWithNoTPM" 6 | and (ProcessCommandLine has "true" or ProcessCommandLine contains "1") 7 | | where InitiatingProcessCommandLine has_all (@"C:\Windows\", ".bat") 8 | -------------------------------------------------------------------------------- /BookMarkUpdatedBy.txt: -------------------------------------------------------------------------------- 1 | HuntingBookmark 2 | | where isnotempty(CreatedBy) 3 | | project BookmarkName , UpdatedBy -------------------------------------------------------------------------------- /BookmarkUpdate.txt: -------------------------------------------------------------------------------- 1 | AzureActivity 2 | | where OperationName == "Update Bookmarks" and ActivityStatusValue == "Succeeded" 3 | | project Caller , EventSubmissionTimestamp -------------------------------------------------------------------------------- /BookmarksCreatedBy.txt: -------------------------------------------------------------------------------- 1 | HuntingBookmark 2 | | sort by CreatedBy 3 | | project BookmarkName , CreatedBy -------------------------------------------------------------------------------- /BrowserActivitybyGEO.txt: -------------------------------------------------------------------------------- 1 | SigninLogs 2 | | where AppDisplayName == "Microsoft Cloud App Security" 3 | | extend UserBrowser_ = tostring(DeviceDetail.browser) 4 | | extend UserOperatingSystem_ = tostring(DeviceDetail.operatingSystem) 5 | | extend UserCountryOrRegion_ = tostring(LocationDetails.countryOrRegion) 6 | | extend UserCity_ = tostring(LocationDetails.city) -------------------------------------------------------------------------------- /BuiltInFusionCreation.txt: -------------------------------------------------------------------------------- 1 | //One way to find out when an Azure Sentinel instance is created is to monitor when the Fusion Analytics Rules is created. Fusion is enabled by default when Azure Sentinel is stood up. 2 | 3 | AzureActivity 4 | | where parse_json(Properties).resource has "builtinfusion" 5 | | where ActivitySubstatusValue =~ "created" 6 | | project TimeGenerated, Caller, CallerIpAddress, ResourceGroup -------------------------------------------------------------------------------- /CEFDevices.txt: -------------------------------------------------------------------------------- 1 | union isfuzzy=true withsource = TableName 2 | // Microsoft 3 | (AzureDiagnostics | where ResourceType == "AZUREFIREWALLS" ), 4 | (WindowsFirewall | summarize count() by FirewallAction ), 5 | // Barracuda GlodGen Syslog 6 | (CGFWFirewallActivity| summarize count() by DeviceName = Computer ), 7 | // CEF section 8 | (CommonSecurityLog | where DeviceVendor == "Barracuda" ), 9 | (CommonSecurityLog | where DeviceVendor == "Fortinet" | summarize count() by DeviceVendor, DeviceName = DeviceExternalID), 10 | (CommonSecurityLog | where DeviceVendor == "TestCommonEventFormat" | summarize count() by DeviceVendor, DeviceName = DeviceExternalID), 11 | (CommonSecurityLog | where DeviceVendor == "Palo Alto Networks" | where isnotempty(DeviceName) | summarize count() by DeviceVendor, DeviceName) 12 | // show devices found 13 | | summarize count() by DeviceName , DeviceVendor 14 | -------------------------------------------------------------------------------- /CVE-2023-23397-Detection.kql: -------------------------------------------------------------------------------- 1 | //CVE-2023-23397 Detection 2 | 3 | DeviceProcessEvents 4 | | where InitiatingProcessFileName == "svchost.exe" 5 | | where FileName == "rundll32.exe" and ProcessCommandLine contains "davclnt.dll" and ProcessCommandLine contains "DavSetCookie" 6 | | where ProcessCommandLine !contains "http://10." 7 | | where ProcessCommandLine !contains "http://192.168." 8 | | extend url = split(ProcessCommandLine, "http://")[1] 9 | | extend domain = split(url, "/")[0] 10 | | where domain contains "." and domain !endswith ".local" 11 | | summarize count() by tostring(domain) 12 | -------------------------------------------------------------------------------- /CalculateSumofColumn.txt: -------------------------------------------------------------------------------- 1 | //An example of how to calculate a column of data. This query retrieves the number of ActivityStatusValue records from the AzureActivity table then shows a single result of the total calculated (sum) value. 2 | 3 | AzureActivity 4 | | summarize count() by ActivityStatusValue 5 | | summarize sum(count_) 6 | 7 | -------------------------------------------------------------------------------- /CaseComments.txt: -------------------------------------------------------------------------------- 1 | //Who added case comments and to which case 2 | 3 | AzureActivity 4 | | where OperationName == "Create Case Comments" 5 | | project Caller, CallerIpAddress, OperationName, _ResourceId -------------------------------------------------------------------------------- /Check4LockedoutUser.txt: -------------------------------------------------------------------------------- 1 | SecurityEvent 2 | | where EventID == 4740 or EventID == 644 //A user account was locked out 3 | | extend LowerAccount=tolower(Account) 4 | | search "username" -------------------------------------------------------------------------------- /CheckPointLogs.txt: -------------------------------------------------------------------------------- 1 | //Check Point logs 2 | 3 | CommonSecurityLog 4 | | extend DeviceProduct = iif(DeviceEventClassID has "geo_protection","Check Point Geo Protection", 5 | iif(DeviceEventClassID has "Log","Check Point Firewall-1 Log","Check Point")) 6 | | sort by TimeGenerated desc 7 | -------------------------------------------------------------------------------- /CloudShell.txt: -------------------------------------------------------------------------------- 1 | AzureActivity 2 | | where TimeGenerated > ago(1d) 3 | | where ResourceGroup contains "cloud-shell" and ActivityStatus == "Started" 4 | | project CallerIpAddress , Caller -------------------------------------------------------------------------------- /CloudShellPart2.txt: -------------------------------------------------------------------------------- 1 | //AzureActivity logs differently between certain instances of Azure. For those environments where the original CloudShell Analytics Rules 2 | //doesn't work. Use this. 3 | //Still attempting to determine why the differences. 4 | 5 | AzureActivity 6 | | where ResourceGroup startswith "CLOUD-SHELL" 7 | | where ResourceProviderValue == "MICROSOFT.STORAGE" 8 | | where ActivityStatusValue == "Start" 9 | | extend action_ = tostring(parse_json(Authorization).action) 10 | | summarize count() by TimeGenerated , ResourceGroup , Caller , CallerIpAddress , ActivityStatusValue 11 | | extend AccountCustomEntity = Caller 12 | | extend IPCustomEntity = CallerIpAddress 13 | -------------------------------------------------------------------------------- /Cloudshell2.txt: -------------------------------------------------------------------------------- 1 | AzureActivity 2 | | where ResourceGroup startswith "CLOUD-SHELL" 3 | | extend action_ = tostring(parse_json(Authorization).action) 4 | | summarize count() by ResourceGroup , Caller , CallerIpAddress , ActivityStatusValue , ActivitySubstatusValue, CategoryValue , action_ 5 | 6 | // List sucess vs. failure 7 | AzureActivity 8 | | where ResourceGroup startswith "CLOUD-SHELL" 9 | | summarize count(ActivityStatus) by Caller, ActivityStatus 10 | -------------------------------------------------------------------------------- /CommentDeleted.txt: -------------------------------------------------------------------------------- 1 | //Query to determine who deleted a comment from an Incident 2 | 3 | AzureActivity 4 | | where OperationNameValue contains "MICROSOFT.SECURITYINSIGHTS/INCIDENTS/COMMENTS/DELETE" 5 | | where ActivityStatusValue == "Success" 6 | | extend clientIpAddress_ = tostring(parse_json(HTTPRequest).clientIpAddress) 7 | | project Caller, clientIpAddress_ 8 | -------------------------------------------------------------------------------- /CommonSecurityLogCostsbyVendor.txt: -------------------------------------------------------------------------------- 1 | //Billing by device for CommonSecurityLog 2 | 3 | let Price = 4.71; // adjust to the region 4 | let TimeRange = 7d; // required time range 5 | CommonSecurityLog 6 | | where TimeGenerated > ago(TimeRange) 7 | | summarize 8 | Entries = count(), 9 | BilledSize = sum(_BilledSize) by DeviceVendor 10 | | extend ['Estimated Price'] = (BilledSize / (1000 * 1000 * 1000)) * Price 11 | | extend Size = format_bytes(BilledSize) 12 | | project DeviceVendor, Entries, Size, ['Estimated Price'] 13 | | order by Size desc 14 | -------------------------------------------------------------------------------- /CommonSecurityLogThroughput.txt: -------------------------------------------------------------------------------- 1 | //Throughput for the Common Security Log 2 | 3 | let Now = now(); 4 | (range TimeGenerated from ago(7d) to Now-1d step 1d 5 | | extend Count = 0 6 | | union isfuzzy=true 7 | (CommonSecurityLog 8 | | summarize Count = count() by bin_at(TimeGenerated, 1m, Now)) 9 | | summarize Count=max(Count) by bin_at(TimeGenerated, 1m, Now) 10 | | sort by TimeGenerated 11 | | project Value = iff(isnull(Count), 0, Count), Time = TimeGenerated, Legend = "Common Security Log") 12 | -------------------------------------------------------------------------------- /CompareTotalRecordswithValuebyPercentage.txt: -------------------------------------------------------------------------------- 1 | //Compare a count of total records in a table for the last 24h to the count of records in the same table with a specific property value to get a % 2 | //Myself and Brian Barrington were schooled by Clive Watson on this one :) 3 | 4 | SigninLogs 5 | | summarize ErrorCount=countif(ResultType == 16000 or ResultType == 50140), TotalCount=countif(isnotempty(ResultType)) 6 | | extend percent = ((toreal(ErrorCount) / toreal(TotalCount))*100) 7 | -------------------------------------------------------------------------------- /Conditional access changes new value and old value.txt: -------------------------------------------------------------------------------- 1 | let operatorUPN = "user@domain.com"; 2 | let lookback = 2d; 3 | AuditLogs 4 | | where TimeGenerated > ago(lookback) 5 | | where LoggedByService == "Core Directory" and OperationName == "Update policy" 6 | | where InitiatedBy has operatorUPN 7 | | extend initator = tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName) 8 | | extend policyName = tostring(TargetResources[0].displayName) 9 | | extend changes = TargetResources[0].modifiedProperties 10 | | project TimeGenerated, initator, policyName, changes 11 | | mvexpand changes 12 | | evaluate bag_unpack(changes) 13 | | where newValue <> "\"\"" 14 | | sort by TimeGenerated, initator, policyName 15 | -------------------------------------------------------------------------------- /ConnectorFailures.kql: -------------------------------------------------------------------------------- 1 | //Detect latest failure events per connector 2 | 3 | SentinelHealth 4 | | where TimeGenerated > ago(3d) 5 | | where OperationName == 'Data fetch status change' 6 | | where Status in ('Success', 'Failure') 7 | | summarize TimeGenerated = arg_max(TimeGenerated,*) by SentinelResourceName, SentinelResourceId 8 | | where Status == 'Failure' 9 | -------------------------------------------------------------------------------- /CostPerSubscription.txt: -------------------------------------------------------------------------------- 1 | //Sentinel cost per subscription 2 | 3 | union withsource=TableName1 * 4 | | where TimeGenerated > ago(30d) 5 | | summarize 6 | Entries = count(), 7 | Size = sumif(_BilledSize, _IsBillable == true), 8 | estimate = sumif(_BilledSize, _IsBillable == true) 9 | by TableName1, _IsBillable, _ResourceId, _SubscriptionId 10 | | project 11 | ['Table Name'] = TableName1, 12 | ['Table Size'] = Size, 13 | ['IsBillable'] = _IsBillable, 14 | ['Estimated Table Price'] = (estimate / (1024 * 1024 * 1024)) * 2.95, 15 | ['Resource'] = _ResourceId, _SubscriptionId 16 | | order by ['Table Size'] desc 17 | | summarize sum(['Estimated Table Price']) by _SubscriptionId 18 | | order by ['sum_Estimated Table Price'] desc 19 | -------------------------------------------------------------------------------- /CostperEventID.txt: -------------------------------------------------------------------------------- 1 | SecurityEvent 2 | | where TimeGenerated >= startofday(ago(1d)) and TimeGenerated < startofday(now()) 3 | | summarize sum(_BilledSize) by EventID 4 | | order by sum__BilledSize desc 5 | -------------------------------------------------------------------------------- /CountriesWhereAgentedComputersReportFrom.txt: -------------------------------------------------------------------------------- 1 | //Countries where your agented computers are reporting from 2 | union isfuzzy=true 3 | (Heartbeat 4 | | extend TrafficDirection = "InboundOrUnknown", Country=RemoteIPCountry, Latitude=RemoteIPLatitude, Longitude=RemoteIPLongitude) 5 | | where TimeGenerated > ago(7d) 6 | | where isnotempty(Country) and isnotempty(Latitude) and isnotempty(Longitude) 7 | | distinct Country -------------------------------------------------------------------------------- /CountryInfoExternal.kql: -------------------------------------------------------------------------------- 1 | //Pulls external data to show many Country information datapoints 2 | 3 | let CountryInfo = externaldata (FIFA:string,Dial:string,ISO31661Alpha3:string,MARC:string,independence:string,ISO31661numeric:string,GAUL:string,FIPS:string,WMO:string,ISO31661Alpha2:string,ITU:string,IOC:string,DS:string,UNTERMSpanishFormal:string,GlobalCode:string,IntermediateRegionCode:string,officialnamefr:string,UNTERMFrenchShort:string,ISO4217currencyname:string,DevelopedDevelopingCountries:string,UNTERMRussianFormal:string,UNTERMEnglishShort:string,ISO4217currencyalphabeticcode:string,SmallIslandDevelopingStates:string,UNTERMSpanishShort:string,ISO4217currencynumericcode:string,UNTERMChineseFormal:string,UNTERMFrenchFormal:string,UNTERMRussianShort:string,M49:string,SubregionCode:string,RegionCode:string,officialnamear:string,ISO4217currencyminorunit:string,UNTERMArabicFormal:string,UNTERMChineseShort:string,LandLockedDevelopingCountries:string,IntermediateRegionName:string,officialnamees:string,UNTERMEnglishFormal:string,officialnamecn:string,officialnameen:string,ISO4217currencycountryname:string,LeastDevelopedCountries:string,RegionName:string,UNTERMArabicShort:string,SubregionName:string,officialnameru:string,GlobalName:string,Capital:string,Continent:string,TLD:string,Languages:string,GeonameID:string,CLDRdisplayname:string,EDGAR:string) [@"https://raw.githubusercontent.com/datasets/country-codes/master/data/country-codes.csv"] with (ignoreFirstRecord=true, format="csv"); 4 | CountryInfo 5 | -------------------------------------------------------------------------------- /CreateAndQuery.kql: -------------------------------------------------------------------------------- 1 | //Create a table, query the table 2 | 3 | let MyTable = datatable (Category:string, Value:long) 4 | [ 5 | "A", 1, 6 | "A", 3, 7 | "A", 5, 8 | "B", 1, 9 | "B", 2 10 | ]; 11 | MyTable 12 | | extend PackedRecord = pack_all() 13 | | summarize Result = make_list(PackedRecord) 14 | -------------------------------------------------------------------------------- /Cross resource query.txt: -------------------------------------------------------------------------------- 1 | let AuditLogsDEV = workspace("9b5dc943-9550-4b95-ab2d-0f1c898956da").AuditLogs; 2 | let start = ago(24h); 3 | AuditLogsDEV 4 | | where TimeGenerated > start 5 | | where OperationName == "Add group" 6 | | project flatten = tostring(TargetResources) 7 | | where flatten contains "Unified" 8 | -------------------------------------------------------------------------------- /DNSActivity_Attempts_Per_Device.txt: -------------------------------------------------------------------------------- 1 | //Joins DnsEvents and DnsInventory to show computer, domain, and IP of device attempts 2 | 3 | DnsEvents 4 | | where TimeGenerated >= (30d) 5 | | join DnsInventory on Computer 6 | | where isnotempty(DomainName) 7 | | sort by TimeGenerated 8 | | summarize Attempts = count() by TimeGenerated, Computer, ClientIP, DomainName 9 | -------------------------------------------------------------------------------- /DarkSideRansomware.txt: -------------------------------------------------------------------------------- 1 | //DarkSide ransomware behavior. Defender for Endpoint connected to Sentinel. 2 | 3 | DeviceProcessEvents 4 | | where FileName =~ "rundll32.exe" 5 | | where ProcessCommandLine matches regex @".dll,#(?:1|3) worker[0-9]\sjob[0-9]-[0-9]{4,}" 6 | -------------------------------------------------------------------------------- /DataByProvider.txt: -------------------------------------------------------------------------------- 1 | SecurityAlert 2 | | where ProviderName == "MCAS" 3 | 4 | 5 | SecurityAlert 6 | | where ProviderName == "Office 365 Security & Compliance" 7 | 8 | 9 | SecurityAlert 10 | | where ProviderName == "MDATP" -------------------------------------------------------------------------------- /DataConnectorOpened.txt: -------------------------------------------------------------------------------- 1 | //Someone opened a Data Connector page 2 | 3 | AzureActivity 4 | | where OperationNameValue contains "dataconnectorscheckrequirements" 5 | | where ActivityStatusValue == "Start" -------------------------------------------------------------------------------- /DataConnectorReqsFailed.txt: -------------------------------------------------------------------------------- 1 | //Data Connector Requirements failed 2 | 3 | AzureActivity 4 | | where OperationNameValue contains "dataconnectorscheckrequirements" 5 | | where ActivityStatusValue != "Success" and ActivityStatusValue != "Start" -------------------------------------------------------------------------------- /DataConnectorReqsFailedbyCallerIPOperation.txt: -------------------------------------------------------------------------------- 1 | //Data Connector page access that failed authorization by caller, caller IP Address, and Operation name 2 | 3 | AzureActivity 4 | | where OperationNameValue contains "dataconnectorscheckrequirements" 5 | | where ActivityStatusValue == "Failed" and ActivitySubstatusValue == "Unauthorized" 6 | | project Caller, CallerIpAddress, OperationName -------------------------------------------------------------------------------- /DataIngestEstimation.txt: -------------------------------------------------------------------------------- 1 | //This solution looks at the average size per record in a table, then take that number and apply it to the logs you want to ingest. 2 | 3 | 4 | //Average size per record. Run this in Log Analytics. 5 | 6 | let TotalSizeInKb = toscalar( Usage 7 | | where TimeGenerated >= ago(30d) 8 | | summarize TotalSizeInKb=sum(Quantity*1024) by DataType 9 | | where DataType == "DeviceEvents" 10 | | project TotalSizeInKb 11 | ); 12 | let NumOfRecords = toscalar( DeviceEvents 13 | | where TimeGenerated >= ago(30d) 14 | | summarize NumOfRecords=count() 15 | ); 16 | let AvgSizeInKb = todecimal(TotalSizeInKb / NumOfRecords); 17 | print AvgSizePerRecordInKb=AvgSizeInKb 18 | 19 | //Take the above number and apply to the total records for the sources you want to ingest. The following example is for Defender for Endpoint. Run it in the Advanced Hunthing area at security.microsoft.com 20 | 21 | DeviceEvents 22 | | union DeviceFileEvents, DeviceInfo, DeviceNetworkInfo, DeviceProcessEvents, DeviceNetworkEvents, DeviceRegistryEvents, DeviceLogonEvents, DeviceImageLoadEvents, DeviceFileCertificateInfo 23 | | count 24 | 25 | 26 | //Using the estimate_data_size to get Log sizes for Defender for Endpoint 27 | DeviceEvents 28 | | union DeviceFileEvents, DeviceInfo, DeviceNetworkInfo, DeviceProcessEvents, DeviceNetworkEvents, DeviceRegistryEvents, DeviceLogonEvents, DeviceImageLoadEvents, DeviceFileCertificateInfo 29 | | project size = estimate_data_size(*) 30 | | summarize TableSizeInMB = sum(size)/1000/1000 31 | -------------------------------------------------------------------------------- /DataIngestionNotHappening.txt: -------------------------------------------------------------------------------- 1 | //Replace the table name with the name you want to track. Create an Analytics Rule and be notified if a table has not received new data in the last 3 days. 2 | //Seconds calculation for last_log is 60 x 60 x 24 x 3 = 259200 3 | //Make sure to set the Lookback to 14 days 4 | 5 | HuntingBookmark 6 | | where TimeGenerated > ago(30d) 7 | | summarize last_log = datetime_diff("second",now(), max(TimeGenerated)) 8 | | where last_log >= 259200 9 | -------------------------------------------------------------------------------- /DataPerComputer.kql: -------------------------------------------------------------------------------- 1 | //Data by agented computer, split by billable, non-billable, and total 2 | 3 | find where TimeGenerated > ago(1d) project _BilledSize, _IsBillable, Computer, _ResourceId 4 | | where _isBillable=true and isnotempty(Computer) 5 | | summarize billedData = sumif(_BilledSize, _IsBillable=~true), 6 | freeData = sumif(_BilledSize, _IsBillable=~false) by Computer 7 | | extend Total_Data = billedData + freeData 8 | | order by billedData desc 9 | 10 | 11 | //Same data, converted to MB 12 | 13 | find where TimeGenerated > ago(1d) project _BilledSize, _IsBillable, Computer, _ResourceId 14 | | where _isBillable=true and isnotempty(Computer)  15 | | summarize billedData = format_bytes(sumif(_BilledSize, _IsBillable=~true)), 16 |             freeData   = format_bytes(sumif(_BilledSize, _IsBillable=~false)), 17 |             billedData1 = sumif(_BilledSize, _IsBillable=~true), 18 |             freeData1  = sumif(_BilledSize, _IsBillable=~false)  19 | by Computer 20 | | extend total_d = billedData1 + freeData1 21 | | extend Total_Data = format_bytes(total_d) 22 | | project-away billedData1, freeData1, total_d             23 | | order by billedData desc 24 | -------------------------------------------------------------------------------- /DataPerSyslogServer.txt: -------------------------------------------------------------------------------- 1 | //Show data received per Syslog server per device that reports to each Syslog server. Change the where DeviceVendor statement for the vendor to look for, or add more based on the devices you know report to each syslog server. 2 | 3 | CommonSecurityLog 4 | | where DeviceVendor == "Fortinet" 5 | | where isnotempty(ReceivedBytes) 6 | | summarize sum(ReceivedBytes) by Computer 7 | -------------------------------------------------------------------------------- /DataRetentionChanges.txt: -------------------------------------------------------------------------------- 1 | //This query produces results that show when data retention on a LAW was changed and who did it 2 | 3 | union Operation 4 | | where OperationStatus == "Succeeded" 5 | | where OperationCategory == "Workspace Configuration" 6 | | project TimeGenerated, Detail 7 | -------------------------------------------------------------------------------- /DataTypeUsagePieChart.txt: -------------------------------------------------------------------------------- 1 | // Usage by data types in a pie chart 2 | Usage 3 | | summarize count_per_type=count() by DataType 4 | | sort by count_per_type desc 5 | | render piechart -------------------------------------------------------------------------------- /DayofWeek.txt: -------------------------------------------------------------------------------- 1 | //Simple KQL query to show day of week when a record was generated. 2 | 3 | // Results Legend: 4 | // Sunday = 0.00:00:00 5 | // Monday = 1.00:00:00 6 | // Tuesday = 2.00:00:00 7 | // Wednesday = 3.00:00:00 8 | // Thursday 4.00:00:00 9 | // Friday = 5.00:00:00 10 | // Saturday = 6.00:00:00 11 | 12 | 13 | SigninLogs 14 | | project TimeGenerated, Day_of_Week = dayofweek(TimeGenerated) 15 | | take 10 16 | -------------------------------------------------------------------------------- /Debugging authentication sign-ins.txt: -------------------------------------------------------------------------------- 1 | SigninLogs 2 | | where UserPrincipalName == "kkilty@microsoft.com" 3 | | extend ClientAppUsed = iff(isempty(ClientAppUsed) == true, "Unknown", ClientAppUsed) 4 | | extend IsLegacyAuth = 5 | case(ClientAppUsed contains "Browser", "No", 6 | ClientAppUsed contains "Mobile Apps and Desktop clients", "No", 7 | ClientAppUsed contains "Exchange ActiveSync", "No", 8 | ClientAppUsed contains "Other clients", "Yes", "Unknown") 9 | | extend errorCode = toint(Status.errorCode) 10 | | extend SigninStatus = 11 | case(errorCode == 0, "Success", 12 | errorCode == 50058, "Interrupt", 13 | errorCode == 50140, "Interrupt", 14 | errorCode == 51006, "Interrupt", 15 | errorCode == 50059, "Interrupt", 16 | errorCode == 65001, "Interrupt", 17 | errorCode == 52004, "Interrupt", 18 | errorCode == 50055, "Interrupt", 19 | errorCode == 50144, "Interrupt", 20 | errorCode == 50072, "Interrupt", 21 | errorCode == 50074, "Interrupt", 22 | errorCode == 16000, "Interrupt", 23 | errorCode == 16001, "Interrupt", 24 | errorCode == 16003, "Interrupt", 25 | errorCode == 50127, "Interrupt", 26 | errorCode == 50125, "Interrupt", 27 | errorCode == 50129, "Interrupt", 28 | errorCode == 50143, "Interrupt", 29 | errorCode == 81010, "Interrupt", 30 | errorCode == 81014, "Interrupt", 31 | errorCode == 81012 ,"Interrupt", 32 | "Failure") 33 | | extend StatusReason = tostring(Status.failureReason) 34 | | extend DeviceOS = DeviceDetail.operatingSystem 35 | | extend DeviceBrowser = extract("([a-zA-Z]+)", 1, tostring(DeviceDetail.browser)) 36 | | extend Country = tostring(LocationDetails.countryOrRegion) 37 | | extend State = tostring(LocationDetails.state) 38 | | extend City = tostring(LocationDetails.city) 39 | | extend conditionalAccessStatusDesc = 40 | case(ConditionalAccessStatus == 0, "Success", 41 | ConditionalAccessStatus == 1, "Failure", 42 | ConditionalAccessStatus == 2, "Not Applied", 43 | ConditionalAccessStatus == "", "Not Applied", 44 | "Unknown") 45 | | project CreatedDateTime, IsLegacyAuth, Id, CorrelationId, ClientAppUsed, AppDisplayName, AppId, UserDisplayName, 46 | UserPrincipalName, UserId, IPAddress, Country, State, City, SigninStatus, StatusReason,DeviceOS, 47 | DeviceBrowser, conditionalAccessStatusDesc, tostring(ConditionalAccessPolicies) 48 | | sort by CreatedDateTime desc 49 | -------------------------------------------------------------------------------- /DefenderAVNotSuccessful.txt: -------------------------------------------------------------------------------- 1 | //Detect if Defender AV is not successful in remediating the detection 2 | 3 | DeviceEvents 4 | | where ActionType == "AntivirusDetection" 5 | | extend ParsedFields=parse_json(AdditionalFields) 6 | | project ThreatName=tostring(ParsedFields.ThreatName), 7 | WasRemediated=tobool(ParsedFields.WasRemediated), 8 | WasExecutingWhileDetected=tobool(ParsedFields.WasExecutingWhileDetected), 9 | FileName, SHA1, InitiatingProcessFileName, InitiatingProcessCommandLine, 10 | DeviceName 11 | // Change "!=" to "==" see all remediated actions 12 | | where WasRemediated != "true" 13 | -------------------------------------------------------------------------------- /DefenderExclusions.txt: -------------------------------------------------------------------------------- 1 | //Monitor changes in exclusions for Windows Defender 2 | 3 | DeviceRegistryEvents 4 | | where ((ActionType == "RegistryValueSet") and (RegistryKey startswith @"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Defender\\Exclusions\\Paths" 5 | or RegistryKey startswith @"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Defender\Exclusions\Extensions" 6 | or RegistryKey startswith @"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Defender\Exclusions\Processes")) 7 | -------------------------------------------------------------------------------- /DefenderLiveResponse.txt: -------------------------------------------------------------------------------- 1 | //Show the user that initiated a Defender Live Response session and against which device, with IP and port. 2 | 3 | 4 | DeviceEvents 5 | | join DeviceNetworkEvents on DeviceName 6 | | where AdditionalFields.RemoteClientsAccess == "AcceptRemote" 7 | | where InitiatingProcessFileName == "msedge.exe" 8 | | project TimeGenerated, DeviceName, InitiatingProcessAccountName, RemoteIP1, RemotePort1 9 | -------------------------------------------------------------------------------- /Defender_Tampering.kql: -------------------------------------------------------------------------------- 1 | //Hunt for Defender tampering attempts 2 | 3 | DeviceRegistryEvents 4 | | where Timestamp >= ago(7d) 5 | | where RegistryKey == "HKEY_LOCAL_MACHINE\\SOFTWARE\\Policies\\Microsoft\\Windows Defender" 6 | | where RegistryValueName == "DisableAntiSpyware" 7 | | where RegistryValueType == "Dword" 8 | | where RegistryValueData == 1 9 | | where IsInitiatingProcessRemoteSession == true 10 | -------------------------------------------------------------------------------- /DeviceStopsReporting.txt: -------------------------------------------------------------------------------- 1 | //Inventory your Devices into a Watchlist making sure MacAddress is one of the columns. Then report when that device is no longer delivering data to Sentinel. 2 | 3 | let watchlist = _GetWatchlist("Your Watchlist Alias") | project MacAddress; 4 | CommonSecurityLog 5 | | where CreatedTime between (datetime(2022-04-01) .. datetime(2022-04-30)) 6 | | where DeviceMacAddress in (watchlist) 7 | | where isempty(DeviceMacAddress) 8 | -------------------------------------------------------------------------------- /DirectAgent.kql: -------------------------------------------------------------------------------- 1 | Heartbeat 2 | | where Category == "Direct Agent" 3 | | distinct Computer , Category , OSType , OSMajorVersion , OSMinorVersion 4 | -------------------------------------------------------------------------------- /DirectReport.txt: -------------------------------------------------------------------------------- 1 | Heartbeat 2 | | project Computer , Category 3 | |where Category contains "Direct" 4 | |distinct Computer 5 | -------------------------------------------------------------------------------- /Does a table exist.txt: -------------------------------------------------------------------------------- 1 | let hasNonEmptyTable = (T:string) 2 | { 3 | toscalar( union isfuzzy=true ( table(T) | count as Count ), (print Count=0) | summarize sum(Count) ) > 0 4 | }; 5 | let TableName = 'AzureDiagnostics'; 6 | print Table=TableName, IsPresent=iif(hasNonEmptyTable(TableName), "Table present", "Table not preset") 7 | -------------------------------------------------------------------------------- /DomainAdminsEnterpriseAdmins.txt: -------------------------------------------------------------------------------- 1 | //New Domain Admins and Enterprise Admins 2 | 3 | Event 4 | | where TimeGenerated > ago(7d) 5 | | extend eventData=parse_json(EventData) 6 | | project TimeGenerated, Computer, EventID, eventData.MemberName, eventData.SubjectDomainName, eventData.SubjectUserName, eventData.TargetUserName 7 | | where eventData_TargetUserName == "Domain Admins" or eventData_TargetUserName == "Enterprise Admins" 8 | -------------------------------------------------------------------------------- /DormantAccounts.txt: -------------------------------------------------------------------------------- 1 | //Show accounts that haven't logged in for 50 days 2 | 3 | let IdleAccountTimeOut = 50d; // Number of days an account must not have logged in for to be considered dormant 4 | let timeHorizon = 90d; // How many days back to check in IdentityInfo 5 | IdentityInfo 6 | | where TimeGenerated >=ago(timeHorizon) 7 | | summarize dcount(AccountObjectId) by AccountObjectId, AccountUPN 8 | | join kind=anti (SigninLogs 9 | | where TimeGenerated >= ago(IdleAccountTimeOut) 10 | | where ResultType==0 11 | //| summarize dcount(UserPrincipalName) by UserPrincipalName 12 | ) on $left.AccountObjectId == $right.UserId 13 | -------------------------------------------------------------------------------- /Duration of session.txt: -------------------------------------------------------------------------------- 1 | let Events=datatable (SessionId:int, TimeGenerated:datetime, Event:string) 2 | [1, datetime(2018-01-01 12:30:00),"Start", 3 | 1, datetime(2018-01-01 13:30:00),"Stop", 4 | 2, datetime(2018-01-02 12:30:00),"Start", 5 | 2, datetime(2018-01-03 13:30:00),"Stop", 6 | 3, datetime(2018-01-01 12:30:00),"Start", 7 | 3, datetime(2018-01-02 12:45:00),"Stop", 8 | 4, datetime(2018-03-03 11:30:00),"Start", 9 | 4, datetime(2018-03-03 12:30:00),"Stop", 10 | 5, datetime(2018-03-03 13:30:00),"Start" 11 | ]; 12 | Events 13 | | where Event == "Start" 14 | | project Event, SessionId, StartTime=TimeGenerated 15 | | join kind=leftouter (Events 16 | | where Event =="Stop" 17 | | project EventRight=Event, SessionId, StopTime=iif(isempty(TimeGenerated),datetime(null),TimeGenerated)) 18 | on SessionId 19 | | project SessionId, StartTime, StopTime, Duration = StopTime - StartTime 20 | | where isnull(StopTime) 21 | -------------------------------------------------------------------------------- /EPSforM365AdvancedTables.txt: -------------------------------------------------------------------------------- 1 | //Getting average EPS and estimated GB per table for the M365 Advanced tables. Run this in Advanced Hunting at security.microsoft.com 2 | 3 | 4 | let bytes_ = 500; 5 | union withsource=MDTables* 6 | | where Timestamp > startofday(ago(1d)) 7 | | summarize count() by bin(Timestamp, 1m), MDTables 8 | | extend EPS = count_ /60 9 | |summarize avg(EPS), estimatedGBytes = (avg(EPS) * bytes_ ) / (1024*1024*1024) by MDTables 10 | | sort by toint(estimatedGBytes) desc 11 | -------------------------------------------------------------------------------- /EPSperTable.kql: -------------------------------------------------------------------------------- 1 | //Average EPS for a table. Change the tablename 2 | 3 | let bytes_ = 500; 4 | SecurityEvent 5 | | where TimeGenerated > startofday(ago(1d)) 6 | | summarize count() by bin(TimeGenerated, 1m) 7 | | extend EPS = count_ /60 8 | |summarize avg(EPS), estimatedGBytes = (avg(EPS) * bytes_ ) / (1024*1024*1024) 9 | | sort by toint(estimatedGBytes) desc 10 | -------------------------------------------------------------------------------- /EmailCountbyCountry.kql: -------------------------------------------------------------------------------- 1 | //Count of emails by country 2 | 3 | EmailEvents 4 | | extend GeoInformation = parse_json(geo_info_from_ip_address(SenderIPv4)) 5 | | extend NwMsgId_Recipient = strcat(NetworkMessageId, "_", RecipientEmailAddress) 6 | | summarize dcount(NwMsgId_Recipient) by tostring(GeoInformation.country) 7 | -------------------------------------------------------------------------------- /EmailForwarding.txt: -------------------------------------------------------------------------------- 1 | //Email forwarding 2 | 3 | OfficeActivity 4 | | where OfficeWorkload == "Exchange" 5 | | where Operation == "Set-Mailbox" 6 | | extend Name_ = tostring(parse_json(Parameters)[2].Name) 7 | | where Name_ == "DeliverToMailboxAndForward" 8 | | extend ForwardingSMTP_Value_ = tostring(parse_json(Parameters)[1].Value) 9 | | where ForwardingSMTP_Value_ != "" 10 | | project TimeGenerated, ForwardingSMTP_Value_, Name_, UserId 11 | -------------------------------------------------------------------------------- /EventIDStorageinBytes.txt: -------------------------------------------------------------------------------- 1 | //Show how much each storage each EventID is taking up in bytes 2 | SecurityEvent 3 | | summarize count() by Activity, EventID 4 | | extend size_in_bytes = count_ * 500 5 | | order by count_ desc 6 | -------------------------------------------------------------------------------- /EventIDsinLastDay.txt: -------------------------------------------------------------------------------- 1 | //Switch to Stacked Display 2 | SecurityEvent 3 | | where TimeGenerated > ago(1d) 4 | | summarize count() by tostring(EventID), AccountType, bin(TimeGenerated, 1h) 5 | 6 | -------------------------------------------------------------------------------- /EventLogSources.txt: -------------------------------------------------------------------------------- 1 | SecurityEvent 2 | | distinct EventSourceName -------------------------------------------------------------------------------- /EventVolumePerTable.txt: -------------------------------------------------------------------------------- 1 | //Event volume per table. Change OfficeActivity to the table you want to query against. 2 | 3 | let Now = now(); 4 | (range TimeGenerated from ago(14d) to Now-1d step 1d 5 | | extend Count = 0 6 | | union isfuzzy=true( 7 | OfficeActivity 8 | | summarize Count = count() by bin_at(TimeGenerated, 1d, Now) 9 | ) 10 | | summarize Count=max(Count) by bin_at(TimeGenerated, 1d, Now) 11 | | sort by TimeGenerated 12 | | project Value = iff(isnull(Count), 0, Count), Time = TimeGenerated, Legend = "Events") 13 | | render timechart -------------------------------------------------------------------------------- /ExecutedProcesses.txt: -------------------------------------------------------------------------------- 1 | //All processes executed and how many times 2 | 3 | search in (SecurityEvent) EventID == 4688 4 | | summarize ExecutionCount = count() by NewProcessName 5 | -------------------------------------------------------------------------------- /ExistingConditionalAccessPolicies.txt: -------------------------------------------------------------------------------- 1 | //Display the existing Conditional Access Policies 2 | 3 | SigninLogs 4 | | mv-expand ConditionalAccessPolicies 5 | | project DisplayName = tostring(ConditionalAccessPolicies.displayName),ID = tostring(ConditionalAccessPolicies.id) 6 | | distinct ID,DisplayName 7 | | order by DisplayName asc -------------------------------------------------------------------------------- /ExpiredPassword.txt: -------------------------------------------------------------------------------- 1 | SigninLogs 2 | | where ResultType == "50055" 3 | | project UserDisplayName, UserPrincipalName -------------------------------------------------------------------------------- /ExternalAccess.txt: -------------------------------------------------------------------------------- 1 | //This is an example line of KQL query for external data retrieval. 2 | //This example queries IP-API with an IP address and returns country, region, regionName, and city. 3 | //This is a way to do this while developing a KQL query in the Logs blade. 4 | //You can also do this (IP-API query) with a Playbook to add additional context to an Incident in the comments 5 | //See: https://secureinfra.blog/2020/09/03/how-to-add-geographical-data-for-ip-addresses-to-an-azure-sentinel-incident/ 6 | 7 | externaldata(status:string, country:string, countryCode:string, region:string, regionName:string, city:string, zip:string, lat:string, lon:string, timezone:string, isp:string, org:string, as:string)[@"http://ip-api.com/json/174.98.173.42"] with(format="json") 8 | -------------------------------------------------------------------------------- /ExternalGEOforSecurityEvents.txt: -------------------------------------------------------------------------------- 1 | //Get you geolocation for your SecurityEvents, using a publicly available IP geolocation file 2 | 3 | let geoData = externaldata 4 | (network:string,geoname_id:string,continent_code:string,continent_name:string, 5 | country_iso_code:string,country_name:string,is_anonymous_proxy:string,is_satellite_provider:string) 6 | [@"https://raw.githubusercontent.com/datasets/geoip2-ipv4/master/data/geoip2-ipv4.csv"] with (ignoreFirstRecord=true, format="csv"); 7 | SecurityEvent 8 | | evaluate ipv4_lookup (geoData, IpAddress, network, false) 9 | -------------------------------------------------------------------------------- /FailedLoginsPerAccount.txt: -------------------------------------------------------------------------------- 1 | // Windows failed logins. Find reports of Windows accounts that failed to login. 2 | 3 | SecurityEvent 4 | | where EventID == 4625 5 | | summarize count() by TargetAccount 6 | | sort by count_ desc 7 | -------------------------------------------------------------------------------- /FileExecutionOver5Times.txt: -------------------------------------------------------------------------------- 1 | //Locating a file that was executed more than 5 times 2 | 3 | search in (SecurityEvent) EventID == 4688 and "" 4 | | summarize ExecutionCount = count() by Computer 5 | | limit 500000 | where ExecutionCount > 5 6 | -------------------------------------------------------------------------------- /GEOIPLocation.txt: -------------------------------------------------------------------------------- 1 | //IP Geo Location, the following will get you geolocation for your SecurityEvents, using a publicly available IP geolocation file: 2 | 3 | let geoData = externaldata 4 | (network:string,geoname_id:string,continent_code:string,continent_name:string, 5 | country_iso_code:string,country_name:string,is_anonymous_proxy:string,is_satellite_provider:string) 6 | [@"https://raw.githubusercontent.com/datasets/geoip2-ipv4/master/data/geoip2-ipv4.csv"] with (ignoreFirstRecord=true, format="csv"); 7 | SecurityEvent 8 | | evaluate ipv4_lookup (geoData, IpAddress, network, false) 9 | -------------------------------------------------------------------------------- /GetTags.txt: -------------------------------------------------------------------------------- 1 | HuntingBookmark 2 | | where isnotempty(Tags) 3 | | project Tags -------------------------------------------------------------------------------- /GreaterThanOneCity.txt: -------------------------------------------------------------------------------- 1 | //Alert - Users with Greater Than 1 City 2 | SecurityAlert 3 | | where SystemAlertId == "7fa76d62-ac52-602a-b748-a28d0b7cabac" 4 | | summarize arg_max(TimeGenerated, *) by SystemAlertId 5 | -------------------------------------------------------------------------------- /GuestAccountAdds.txt: -------------------------------------------------------------------------------- 1 | //Users who added guest accounts to the tenants 2 | 3 | 4 | CloudAppEvents 5 | | where Timestamp > ago(7d) 6 | | where ActionType == "Add user." 7 | | where RawEventData.ResultStatus == "Success" 8 | | where RawEventData has "guest" and RawEventData.ObjectId has "#EXT#" 9 | | mv-expand Property = RawEventData.ModifiedProperties 10 | | where Property.Name == "AccountEnabled" and Property.NewValue has "true" 11 | | project Timestamp, AccountObjectId, AccountDisplayName, newGuestAccount = RawEventData.ObjectId, UserAgent 12 | -------------------------------------------------------------------------------- /GuestsAddedtoRoles.txt: -------------------------------------------------------------------------------- 1 | //New guest accounts that have been promoted to certain AAD roles 2 | 3 | 4 | let Roles = pack_array("Company Administrator"); 5 | let newGuestAccounts = ( 6 | CloudAppEvents 7 | | where Timestamp > ago(7d) 8 | | where ActionType == "Add user." 9 | | where RawEventData.ResultStatus == "Success" 10 | | where RawEventData has "guest" and RawEventData.ObjectId has "#EXT#" 11 | | mv-expand Property = RawEventData.ModifiedProperties 12 | | where Property.Name == "AccountEnabled" and Property.NewValue has "true" 13 | | project CreationTimestamp = Timestamp, AccountObjectId, AccountDisplayName, newGuestAccount = RawEventData.ObjectId,newGuestAccountObjectId = tostring(RawEventData.Target[1].ID), UserAgent); 14 | let promotedAccounts = ( 15 | CloudAppEvents 16 | | where Timestamp > ago(7d) 17 | | where isnotempty(AccountObjectId) 18 | | where ActionType == "Add member to role." 19 | | where RawEventData.ResultStatus == "Success" 20 | | where RawEventData has_any(Roles) 21 | | where RawEventData.Actor has "User" 22 | | project PromoteTimestamp = Timestamp, PromotedUserAccountObjectId = tostring(RawEventData.Target[1].ID)); 23 | //join the two tables 24 | newGuestAccounts 25 | | join promotedAccounts on $left.newGuestAccountObjectId == $right.PromotedUserAccountObjectId 26 | | where PromoteTimestamp > CreationTimestamp 27 | | project CreationTimestamp, PromoteTimestamp, PromotedUserAccountObjectId, newGuestAccount, newGuestAccountObjectId 28 | -------------------------------------------------------------------------------- /Heartbeatnotreceivedinlast30min.txt: -------------------------------------------------------------------------------- 1 | //Systems that might have missed sending heartbeat to log analytics workspace for the last 30 min 2 | 3 | 4 | Heartbeat 5 | | summarize count() by bin(TimeGenerated, 1h),Computer 6 | | extend Heartbeats = iff((count_ <= 30),"missing Heartbeats","received all heartbeats") 7 | -------------------------------------------------------------------------------- /HighRiskUserSigninResourceGroupCreation.txt: -------------------------------------------------------------------------------- 1 | //Users with have high risk sign-in activity that have created a resource group 2 | 3 | 4 | let riskyAzureSignIns = ( 5 | AADSignInEventsBeta 6 | | where Timestamp > ago(7d) 7 | | where ErrorCode == 0 8 | | where Application == "Azure Portal" 9 | | where RiskLevelAggregated == 100 or RiskLevelDuringSignIn == 100 10 | | project AccountObjectId, RiskySignInTimestamp = Timestamp); 11 | let resourceGroupCreation = ( 12 | CloudAppEvents 13 | | where Timestamp > ago(7d) 14 | | where Application == "Microsoft Azure" 15 | | where ActionType == "Write ResourceGroup" 16 | | project AccountObjectId, ResourceGroupCreation = Timestamp); 17 | //join the tables 18 | riskyAzureSignIns 19 | | join resourceGroupCreation on AccountObjectId 20 | | where ResourceGroupCreation between (RiskySignInTimestamp .. (RiskySignInTimestamp + 12h)) 21 | -------------------------------------------------------------------------------- /HourMinute.txt: -------------------------------------------------------------------------------- 1 | //Convert time into hour or min 2 | 3 | print TimeTaken=time(10:11:02) 4 | | extend TimeTakenInMins = TimeTaken / 1m 5 | -------------------------------------------------------------------------------- /HowManyAlertsGeneratedByService.txt: -------------------------------------------------------------------------------- 1 | //Show how many alerts have been generated by a specific service. Example here is MCAS. Change Product to the service you want info on. 2 | 3 | SecurityIncident 4 | | extend Product = todynamic((parse_json(tostring(AdditionalData.alertProductNames))[0])) 5 | | where Product has "Microsoft Cloud App Security" 6 | | summarize count() by tostring(AlertIds) 7 | | summarize sum(count_) -------------------------------------------------------------------------------- /HowManyHostLogons.txt: -------------------------------------------------------------------------------- 1 | // Shows the count of logons per device 2 | 3 | SecurityEvent 4 | | where EventID == 4624 5 | | summarize LogonCount = count() by Computer 6 | | where LogonCount > 10 7 | -------------------------------------------------------------------------------- /HowManyQueriesEachPersonRan.txt: -------------------------------------------------------------------------------- 1 | //How many queries each person ran in the last 7 days 2 | //Enabling the Diag Setting for the Audit log is required to expose the LAQueryLogs table 3 | 4 | LAQueryLogs 5 | | where TimeGenerated > ago(7d) 6 | | summarize events_count=count() by AADEmail 7 | | extend UserPrincipalName = AADEmail, Queries = events_count 8 | | join kind= leftouter ( 9 | SigninLogs) 10 | on UserPrincipalName 11 | | project UserDisplayName, UserPrincipalName, Queries 12 | | summarize arg_max(Queries, *) by UserPrincipalName 13 | | sort by Queries desc -------------------------------------------------------------------------------- /HuntingBookmarkHealth.txt: -------------------------------------------------------------------------------- 1 | //Bookmark health 2 | 3 | HuntingBookmark 4 | | where TimeGenerated > ago(30d) 5 | | summarize last_log = datetime_diff("second",now(), max(TimeGenerated)) 6 | | where last_log >= 259200 7 | -------------------------------------------------------------------------------- /HuntingQueriesAzureActivitySuccessandFailures.txt: -------------------------------------------------------------------------------- 1 | //Hunting query to detect Azure Activity successes and show who did it 2 | 3 | AzureActivity 4 | | where TimeGenerated > ago(1d) 5 | | where OperationNameValue has "Action" 6 | | where ActivityStatusValue == "Success" 7 | | extend AccountCustomEntity = Caller 8 | | extend IPCustomEntity = CallerIpAddress 9 | | extend URLCustomEntity = OperationNameValue 10 | 11 | //Hunting query to detect Azure Activity failures and show who did it 12 | 13 | AzureActivity 14 | | where TimeGenerated > ago(1d) 15 | | where OperationNameValue has "Action" 16 | | where ActivityStatusValue == "Failure" 17 | | extend AccountCustomEntity = Caller 18 | | extend IPCustomEntity = CallerIpAddress 19 | | extend URLCustomEntity = OperationNameValue -------------------------------------------------------------------------------- /Ignite/Pre-day.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rod-trent/SentinelKQL/f0569a91c2b5ed823e6253b7ec7cf3d3638621c3/Ignite/Pre-day.pptx -------------------------------------------------------------------------------- /Ignite/Readme.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /ImageFiles.kql: -------------------------------------------------------------------------------- 1 | //Looking for image files in emails 2 | 3 | let image_extensions = dynamic(["jpg", "jpeg", "png", "bmp", "gif"]); 4 | EmailAttachmentInfo 5 | | where FileType in (image_extensions) 6 | -------------------------------------------------------------------------------- /Images/20220724_144123.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rod-trent/SentinelKQL/f0569a91c2b5ed823e6253b7ec7cf3d3638621c3/Images/20220724_144123.jpg -------------------------------------------------------------------------------- /Images/20220724_144304.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rod-trent/SentinelKQL/f0569a91c2b5ed823e6253b7ec7cf3d3638621c3/Images/20220724_144304.jpg -------------------------------------------------------------------------------- /Images/20220724_144326.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rod-trent/SentinelKQL/f0569a91c2b5ed823e6253b7ec7cf3d3638621c3/Images/20220724_144326.jpg -------------------------------------------------------------------------------- /Images/chatgpt30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rod-trent/SentinelKQL/f0569a91c2b5ed823e6253b7ec7cf3d3638621c3/Images/chatgpt30.png -------------------------------------------------------------------------------- /Images/failed.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rod-trent/SentinelKQL/f0569a91c2b5ed823e6253b7ec7cf3d3638621c3/Images/failed.jpg -------------------------------------------------------------------------------- /Images/readme.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Images/scope.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rod-trent/SentinelKQL/f0569a91c2b5ed823e6253b7ec7cf3d3638621c3/Images/scope.png -------------------------------------------------------------------------------- /Images/workspacesettings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rod-trent/SentinelKQL/f0569a91c2b5ed823e6253b7ec7cf3d3638621c3/Images/workspacesettings.png -------------------------------------------------------------------------------- /ImpossibleTravelKQL.txt: -------------------------------------------------------------------------------- 1 | SecurityAlert 2 | | where AlertName == "Impossible travel activity" 3 | | project (parse_json(Entities)[1].Name), Entities 4 | | extend Name_ = tostring(parse_json(Entities)[3].Name) -------------------------------------------------------------------------------- /ImpossibleTravelMCAS.txt: -------------------------------------------------------------------------------- 1 | //MCAS connection required. Just shows all Impossible Travel alerts 2 | 3 | SecurityAlert 4 | | where ProductName == "Microsoft Cloud App Security" 5 | | summarize arg_max(TimeGenerated, *) by SystemAlertId 6 | | where DisplayName == "Impossible travel activity" 7 | | sort by TimeGenerated 8 | -------------------------------------------------------------------------------- /IncidentID2RuleName.txt: -------------------------------------------------------------------------------- 1 | //Getting the Analytics Rule name from the Incident ID 2 | 3 | SecurityIncident 4 | | where TimeGenerated >= ago(90d) 5 | | where IncidentNumber == toint("") // Example: "118831" 6 | | summarize arg_max(TimeGenerated, IncidentNumber, AlertIds) 7 | | mv-expand AlertIds to typeof(string) 8 | | join kind=leftouter( 9 | SecurityAlert 10 | | where TimeGenerated >= ago(90d) 11 | | project 12 | AnalyticsRuleId = tostring(todynamic(tostring(todynamic(ExtendedProperties)["Analytic Rule Ids"]))[0]), 13 | AnalyticsRuleName = tostring(todynamic(ExtendedProperties)["Analytic Rule Name"]), 14 | AlertName, 15 | SystemAlertId 16 | ) on $left.AlertIds == $right.SystemAlertId 17 | | distinct AnalyticsRuleName, AlertName 18 | -------------------------------------------------------------------------------- /IncidentOwnerChange.txt: -------------------------------------------------------------------------------- 1 | //Shows when the owner of an Incident has changed. From Gary Bushey. Details here: https://cda.ms/3Z8 2 | 3 | SecurityIncident 4 | | order by TimeGenerated asc 5 | | serialize 6 | | extend NewOwner = Owner.email 7 | | extend PreIncidentNumber = prev(IncidentNumber) 8 | | extend PrevEmail = iif (PreIncidentNumber == IncidentNumber, prev(NewOwner), "") 9 | | where PrevEmail != NewOwner 10 | | order by IncidentNumber, TimeGenerated desc 11 | | summarize arg_max(TimeGenerated, *) by IncidentNumber 12 | | project TimeGenerated, NewOwner, IncidentNumber, IncidentUrl, Severity 13 | -------------------------------------------------------------------------------- /IncidentURL.kql: -------------------------------------------------------------------------------- 1 | //Using KQL's strcat to create a URL to an Incident on another domain 2 | 3 | 4 | let new_URL = "domain.com"; 5 | let portal_URL = "https://portal.azure.com/"; 6 | let subscription = "your_subscription"; 7 | let resource_group = "your_resource_group"; 8 | let workspace = "your_workspace"; 9 | SecurityIncident 10 | | where TimeGenerated >= ago(90d) 11 | | where Severity == 'High' 12 | | where Title has "Suspicious" 13 | | extend Updated_URL = strcat(portal_URL, new_URL, "/", "#asset/Microsoft_Azure_Security_Insights/Incident/subscriptions/", subscription, "/", "resourceGroups/", resource_group, "/", "providers/Microsoft.OperationalInsights/workspaces/", workspace, "/", "providers/Microsoft.SecurityInsights/Incidents/", IncidentName) 14 | | project Updated_URL 15 | 16 | -------------------------------------------------------------------------------- /Incidents.txt: -------------------------------------------------------------------------------- 1 | AzureActivity 2 | | where _ResourceId contains "SecurityInsights" and _ResourceId contains "incidents" 3 | -------------------------------------------------------------------------------- /IncidentsBetweenTimeRange.yaml: -------------------------------------------------------------------------------- 1 | //Incidents created between a time range in a chart 2 | 3 | SecurityIncident 4 | | where CreatedTime between (datetime(2021-04-01) .. datetime(2021-04-30)) 5 | | summarize arg_max(TimeGenerated, Status, Severity, Owner, AdditionalData,CreatedTime) by IncidentNumber 6 | | summarize count() by bin(CreatedTime, 1h) 7 | | render columnchart 8 | -------------------------------------------------------------------------------- /IngestionDelay.txt: -------------------------------------------------------------------------------- 1 | //Identifying ingestion delay between tables 2 | 3 | union SigninLogs, AuditLogs 4 | | extend E2EIngestionLatencyMin = todouble(datetime_diff("Second",ingestion_time(),TimeGenerated))/60 5 | | summarize avg(E2EIngestionLatencyMin), min(E2EIngestionLatencyMin), max(E2EIngestionLatencyMin) by bin(TimeGenerated,1h),ingestion_time(), Type 6 | | summarize lessthanOneMin = countif(avg_E2EIngestionLatencyMin < 60), gtrthanOneMin=countif(avg_E2EIngestionLatencyMin > 60) by Type 7 | -------------------------------------------------------------------------------- /IngestionDelaySnippet.txt: -------------------------------------------------------------------------------- 1 | //Ingestion Delay snippet for Analytics Rules 2 | 3 | let ingestion_delay = 2min; 4 | let rule_look_back = 5min; 5 | 6 | | where TimeGenerated >= ago(ingestion_delay + rule_look_back) 7 | | where ingestion_time() > ago(rule_look_back) 8 | -------------------------------------------------------------------------------- /Interactive_web_login.kql: -------------------------------------------------------------------------------- 1 | //Logging into a website/interactive login 2 | 3 | SigninLogs 4 | | where IsInteractive == 1 5 | | extend City = LocationDetails.city 6 | | extend State = LocationDetails.state 7 | | extend Lat = parse_json(tostring(LocationDetails.geoCoordinates)).latitude 8 | | extend Long = parse_json(tostring(LocationDetails.geoCoordinates)).longitude 9 | | project UserPrincipalName, UserType, AppDisplayName, ResourceDisplayName, City, State, Location, Lat, Long 10 | -------------------------------------------------------------------------------- /Intune-AutoPilotFailedEnrollment1Day.txt: -------------------------------------------------------------------------------- 1 | //Autopilot devices that failed enrollment in the last day 2 | 3 | IntuneOperationalLogs 4 | | where TimeGenerated > ago(24h) 5 | | extend IsAutopilot_ = tostring(parse_json(Properties).IsAutopilot) 6 | | extend DeviceName_ = tostring(parse_json(Properties).DeviceName) 7 | | where IsAutopilot_ == "True" 8 | | where OperationName == "Enrollment" and Result == "Failure" -------------------------------------------------------------------------------- /Intune-DeviceThreatLevelnotSecured.txt: -------------------------------------------------------------------------------- 1 | //Intune Device Threat Level not Secured 2 | 3 | IntuneDeviceComplianceOrg 4 | | where isnotempty(DeviceHealthThreatLevel) 5 | | where DeviceHealthThreatLevel != "Secured" 6 | | project TimeGenerated , DeviceName , DeviceId , OS , UserName , DeviceHealthThreatLevel -------------------------------------------------------------------------------- /Intune-Enrollmentsabandonedbytheuser.txt: -------------------------------------------------------------------------------- 1 | //Enrollments abandoned by the user 2 | //For details, see (https://docs.microsoft.com/en-us/mem/intune/enrollment/enrollment-report-company-portal-abandon) 3 | 4 | IntuneOperationalLogs 5 | | where OperationName == "Enrollment" 6 | | where Result == "Fail" 7 | | extend myJson=todynamic(Properties) 8 | | extend FailureReason = tostring(myJson ["FailureReason"]) 9 | | extend Os_ = tostring(parse_json(Properties).Os) 10 | | extend IntuneUserId_ = tostring(parse_json(Properties).IntuneUserId) 11 | | where FailureReason == "UserAbandonment" 12 | | summarize OperationCount=count() by FailureReason , IntuneUserId_ , Os_ 13 | | sort by OperationCount desc 14 | -------------------------------------------------------------------------------- /IntuneActivityTypes.txt: -------------------------------------------------------------------------------- 1 | //Activity Types 2 | IntuneAuditLogs 3 | | summarize OperationCount=count() by OperationName 4 | | sort by OperationCount desc -------------------------------------------------------------------------------- /IntuneAuditEvents.txt: -------------------------------------------------------------------------------- 1 | IntuneAuditLogs 2 | |summarize Auditevents = count() by OperationName 3 | | sort by Auditevents -------------------------------------------------------------------------------- /IntuneAuditEventsTrend.txt: -------------------------------------------------------------------------------- 1 | //Audit Events Trend 2 | IntuneAuditLogs 3 | | summarize count() by bin(TimeGenerated, {TimeRange:grain}) -------------------------------------------------------------------------------- /IntuneComplianceFailuresbyOperatingSystem.txt: -------------------------------------------------------------------------------- 1 | //Compliance Failures by Operating System 2 | let ComplianceLogs= 3 | IntuneOperationalLogs 4 | | where OperationName == "Compliance" 5 | | project TimeGenerated, Properties; 6 | ComplianceLogs 7 | | sort by TimeGenerated desc 8 | | join ( 9 | ComplianceLogs 10 | | extend myJson = todynamic(Properties) 11 | | project-away Properties 12 | | extend IntuneDeviceId=tostring(myJson["IntuneDeviceId"]) 13 | | project TimeGenerated, IntuneDeviceId 14 | | summarize TimeGenerated=max(TimeGenerated) by IntuneDeviceId 15 | ) on TimeGenerated 16 | | project-away TimeGenerated1, IntuneDeviceId 17 | | extend myJson=todynamic(Properties) 18 | | project-away Properties 19 | | extend DeviceOperatingSystem=tostring(myJson["DeviceOperatingSystem"]) 20 | | summarize FailureCount=count() by DeviceOperatingSystem 21 | | sort by FailureCount desc -------------------------------------------------------------------------------- /IntuneComplianceFailuresbyReason.txt: -------------------------------------------------------------------------------- 1 | //Compliance Failures by Failure Reason 2 | let ComplianceLogs= 3 | IntuneOperationalLogs 4 | | where OperationName == "Compliance" 5 | | project TimeGenerated, Properties; 6 | ComplianceLogs 7 | | sort by TimeGenerated desc 8 | | join ( 9 | ComplianceLogs 10 | | extend myJson = todynamic(Properties) 11 | | project-away Properties 12 | | extend IntuneDeviceId=tostring(myJson["IntuneDeviceId"]) 13 | | project TimeGenerated, IntuneDeviceId 14 | | summarize TimeGenerated=max(TimeGenerated) by IntuneDeviceId 15 | ) on TimeGenerated 16 | | project-away TimeGenerated1, IntuneDeviceId 17 | | extend myJson=todynamic(Properties) 18 | | project-away Properties 19 | | extend Description=tostring(myJson["Description"]) 20 | | extend Description=tostring(extract("(.*?)_IID_.*", 1, tostring(Description))) 21 | | extend Reason = tostring(extract("(.*?)\\.(.*)", 2, tostring(Description))) 22 | | summarize FailureCount=count() by Reason 23 | | sort by FailureCount desc -------------------------------------------------------------------------------- /IntuneCountofSuccessfulEnrollmentsbyOS.txt: -------------------------------------------------------------------------------- 1 | //Count of Successful Enrollments by OS 2 | IntuneOperationalLogs 3 | | where OperationName == "Enrollment" and Result == "Success" 4 | | extend Os_ = tostring(parse_json(Properties).Os) 5 | | summarize count() by Os_ -------------------------------------------------------------------------------- /IntuneDevicesNotSupported.txt: -------------------------------------------------------------------------------- 1 | //Devices not supported by time, failure type, and operating system 2 | 3 | IntuneOperationalLogs 4 | | extend FailureCategory_ = tostring(parse_json(Properties).FailureCategory) 5 | | where FailureCategory_ == "DeviceNotSupported" 6 | | extend Os_ = tostring(parse_json(Properties).Os) 7 | | project TimeGenerated , FailureCategory_ , Os_ 8 | -------------------------------------------------------------------------------- /IntuneDevicesNotinCompliance.txt: -------------------------------------------------------------------------------- 1 | let ComplianceLogs= 2 | IntuneOperationalLogs 3 | | where OperationName == "Compliance" 4 | | project TimeGenerated, Properties; 5 | ComplianceLogs 6 | | sort by TimeGenerated desc 7 | | join ( 8 | ComplianceLogs 9 | | extend myJson = todynamic(Properties) 10 | | project-away Properties 11 | | extend IntuneDeviceId=tostring(myJson["IntuneDeviceId"]) 12 | | project TimeGenerated, IntuneDeviceId 13 | | summarize TimeGenerated=max(TimeGenerated) by IntuneDeviceId 14 | ) on TimeGenerated 15 | | project-away TimeGenerated1, IntuneDeviceId 16 | | summarize EventCount=count() by bin(TimeGenerated, {TimeRange:grain}) -------------------------------------------------------------------------------- /IntuneEnrollmentEventsTrend.txt: -------------------------------------------------------------------------------- 1 | //Enrollment Events Trend 2 | IntuneOperationalLogs 3 | | where OperationName=="Enrollment" 4 | | summarize OperationCount=count() by bin(TimeGenerated, {TimeRange:grain}) -------------------------------------------------------------------------------- /IntuneEnrollmentFailurereasons.txt: -------------------------------------------------------------------------------- 1 | //Enrollment Failure reasons 2 | IntuneOperationalLogs 3 | | where OperationName == "Enrollment" 4 | | where Result == "Fail" 5 | | extend myJson=todynamic(Properties) 6 | | extend FailureReason = tostring(myJson ["FailureReason"]) 7 | | summarize OperationCount=count() by FailureReason 8 | | sort by OperationCount desc -------------------------------------------------------------------------------- /IntuneEnrollmentFailuresbyEnrollmentType.txt: -------------------------------------------------------------------------------- 1 | //Enrollment Failures by Enrollment Type 2 | IntuneOperationalLogs 3 | | where OperationName == "Enrollment" 4 | | where Result == "Fail" 5 | | extend myJson=todynamic(Properties) 6 | | extend EnrollmentType = tostring(myJson ["EnrollmentType"]) 7 | | summarize OperationCount=count() by EnrollmentType 8 | | sort by OperationCount desc -------------------------------------------------------------------------------- /IntuneEnrollmentFailuresbyPlatform.txt: -------------------------------------------------------------------------------- 1 | //Enrollment Failures by Platform 2 | IntuneOperationalLogs 3 | | where OperationName == "Enrollment" 4 | | where Result == "Fail" 5 | | extend myJson=todynamic(Properties) 6 | | extend Platform = tostring(myJson ["Os"]) 7 | | summarize OperationCount=count() by Platform 8 | | sort by OperationCount desc -------------------------------------------------------------------------------- /IntuneEnrollmentStatistics.txt: -------------------------------------------------------------------------------- 1 | //Enrollment Statistics 2 | IntuneOperationalLogs 3 | | where OperationName == "Enrollment" 4 | | summarize count() by Result -------------------------------------------------------------------------------- /IntuneEnrollmentSuccessbyEnrollmentType.txt: -------------------------------------------------------------------------------- 1 | //Enrollment Success by Enrollment Type 2 | IntuneOperationalLogs 3 | | where OperationName == "Enrollment" 4 | | where Result == "Success" 5 | | extend myJson=todynamic(Properties) 6 | | extend EnrollmentType = tostring(myJson ["EnrollmentType"]) 7 | | summarize OperationCount=count() by EnrollmentType 8 | | sort by OperationCount desc -------------------------------------------------------------------------------- /IntuneNotCompliant.txt: -------------------------------------------------------------------------------- 1 | IntuneDeviceComplianceOrg 2 | | where ComplianceState <> "Not Compliant" and isnotempty(ComplianceState) 3 | | project TimeGenerated , ComplianceState , DeviceName , DeviceId , OS , UserName , UserEmail 4 | -------------------------------------------------------------------------------- /IntuneNotCompliant2.txt: -------------------------------------------------------------------------------- 1 | //Intune Devices Not Compliant 2 | 3 | IntuneDeviceComplianceOrg 4 | | where isnotempty(DeviceHealthThreatLevel) 5 | | where ComplianceState != "Compliant" 6 | | project TimeGenerated , ComplianceState , DeviceName , DeviceId , OS , UserName , UserEmail -------------------------------------------------------------------------------- /IntuneRecentEventsbyAccounts.txt: -------------------------------------------------------------------------------- 1 | IntuneAuditLogs 2 | | top 10 by TimeGenerated 3 | | project Identity, OperationName -------------------------------------------------------------------------------- /IntuneRemoteactionsbyactiontype.txt: -------------------------------------------------------------------------------- 1 | //Remote actions by action type 2 | IntuneAuditLogs 3 | | where OperationName contains "ManagedDevice" 4 | | summarize OperationCount=count() by OperationName 5 | | sort by OperationCount desc -------------------------------------------------------------------------------- /IntuneRemoteactionstopusers.txt: -------------------------------------------------------------------------------- 1 | //Remote actions top users 2 | IntuneAuditLogs 3 | | where OperationName contains "ManagedDevice" 4 | | summarize OperationCount=count() by Identity 5 | | sort by OperationCount desc -------------------------------------------------------------------------------- /IntuneSuccessfulSynchedDevice.txt: -------------------------------------------------------------------------------- 1 | IntuneAuditLogs 2 | | where OperationName == " syncDevice ManagedDevice" and ResultType == "Success" -------------------------------------------------------------------------------- /IntuneSummarizebyOperation.txt: -------------------------------------------------------------------------------- 1 | IntuneAuditLogs 2 | | summarize count() by OperationName -------------------------------------------------------------------------------- /IntuneTopuserswithauditedactions.txt: -------------------------------------------------------------------------------- 1 | //Top users with audited actions 2 | IntuneAuditLogs 3 | | extend myJson=todynamic(Properties) 4 | | summarize OperationCount=count() by Identity 5 | | sort by OperationCount desc -------------------------------------------------------------------------------- /Intunecomputershutdowns.txt: -------------------------------------------------------------------------------- 1 | // Computers restarts/shutdowns 2 | // List restart and shutdowns events for all monitored computers. 3 | Event 4 | | where EventLog == "System" and Source == "User32" and EventID == 1074 5 | | search "shutdown" 6 | | sort by TimeGenerated desc 7 | | project TimeGenerated, Computer -------------------------------------------------------------------------------- /IntuneisCompliantByOSandOSVersion.txt: -------------------------------------------------------------------------------- 1 | //Intune devices that are compliant with OS, OS Version, and number of existing 2 | IntuneDeviceComplianceOrg 3 | | where isnotempty(DeviceName) 4 | | where ComplianceState == "Compliant" 5 | | summarize count() by OSDescription, OSVersion -------------------------------------------------------------------------------- /KDCforKRBTGTPassword.txt: -------------------------------------------------------------------------------- 1 | name: KDC for KRBTGT Password 2 | description: | 3 | 'KDC Changes Alert when KRBTGT was changed.' 4 | severity: High 5 | requiredDataConnectors: 6 | - Azure ATP 7 | - Security Events 8 | dataTypes: 9 | - SecurityEvent 10 | - Event 11 | queryFrequency: 1h 12 | queryPeriod: 1h 13 | triggerOperator: gt 14 | triggerThreshold: 0 15 | tactics: 16 | - Impact 17 | - Persistence 18 | query: | 19 | 20 | //KDC for KRBTGT Password 21 | // Details: https://www.eshlomo.us/azure-sentinel-and-krbtgt/ 22 | 23 | union SecurityEvent, Event 24 | | where TimeGenerated >= ago(5d) 25 | | where EventID in (10,14) //KDC Reset 26 | | where EventID == "4769" //TGT After Reset 27 | -------------------------------------------------------------------------------- /KaseyaREvil.txt: -------------------------------------------------------------------------------- 1 | //KQL query for the Kaseya REvil detection. Can be used as an Analytics Rule or Hunting query. 2 | 3 | SecurityEvent 4 | | where EventID == 4688 5 | | where ((CommandLine has @'C:\\Windows\\cert.exe' or CommandLine contains 'Set-MpPreference -DisableRealtimeMonitoring $true -DisableIntrusionPreventionSystem $true -DisableIOAVProtection $true -DisableScriptScanning $true -EnableControlledFolderAccess Disabled -EnableNetworkProtection AuditMode -Force -MAPSReporting Disabled' or CommandLine has @'del /q /f c:\\kworking\\agent.crt' or CommandLine has 'Kaseya VSA Agent Hot-fix' or CommandLine has @'\\AppData\\Local\\Temp\\MsMpEng.exe') and (FilePath == @'C:\\Windows\\MsMpEng.exe' or FilePath == @'C:\\Windows\\cert.exe' or FilePath == @'C:\\kworking\\agent.exe')) 6 | -------------------------------------------------------------------------------- /LAG analysis example.txt: -------------------------------------------------------------------------------- 1 | requests 2 | | serialize 3 | | extend RequestId = toguid(customDimensions.RequestId) 4 | | project-away resultCode, id, itemType, operation_Name, client_Type, client_IP, operation_SyntheticSource, appId, itemId, itemCount, source, url, performanceBucket 5 | | sort by RequestId, timestamp desc 6 | | extend rn = row_number() 7 | | extend rncr = row_number(1, prev(RequestId,1,0) != RequestId) 8 | | extend previousTimestamp = iif(prev(RequestId,1,0) != RequestId, timestamp, prev(timestamp,1,0)) 9 | | extend deltaInMin = datetime_diff('minute', previousTimestamp, timestamp) 10 | | project rncr, timestamp, RequestId, name, success, deltaInMin, duration, customDimensions, operation_Id, operation_ParentId, cloud_RoleInstance, appName 11 | 12 | let SampleData = datatable (user:string, rowValue: int) ["A",5,"B",12,"B",15,"A",3,"A",9,"A",19,"B",7]; 13 | SampleData 14 | | serialize 15 | | extend rowNumber = row_number() 16 | | extend rowNumberCurrentUser = row_number(1, prev(user,1,0) != user) 17 | | extend previousValue = strcat("Previous value was ", prev(rowValue,1,0)) 18 | | extend nextValue = strcat("Next value was ", next(rowNumber,1,0)) 19 | | extend runningTotal = row_cumsum(rowValue) 20 | | project rowNumber, rowNumberCurrentUser, user, rowValue, previousValue, nextValue, runningTotal 21 | -------------------------------------------------------------------------------- /Language demo just for fun and demo pattern replace.txt: -------------------------------------------------------------------------------- 1 | print a=' 🐋🐨🐠🐾🐀🐧😚😥👲💭💢💜💬💾🤑🍔🍋🍙🚙👙' 2 | | extend a=extractall('(.)', a) 3 | | mvexpand a 4 | | extend a=substring(base64_encodestring(strcat('abracadabra', a)), 19) 5 | | summarize Message=replace(@'[+]', ' ', replace(@'[[",\]]', "", tostring(makelist(a)))) 6 | -------------------------------------------------------------------------------- /LastLogin.txt: -------------------------------------------------------------------------------- 1 | //Shows active accounts and days from last login 2 | 3 | SigninLogs 4 | | where TimeGenerated > ago(365d) 5 | | where ResultType == "0" 6 | | summarize arg_max(TimeGenerated, *) by UserPrincipalName 7 | | project TimeGenerated, UserPrincipalName, UserType, ['Days Since Last Logon']=toint(datetime_diff("day", now(),TimeGenerated)) 8 | -------------------------------------------------------------------------------- /LastTimeDataReceived.txt: -------------------------------------------------------------------------------- 1 | // Last time a Data Connector received data 2 | 3 | union withsource=TableName1 * 4 | | where TimeGenerated > ago(2d) 5 | | project TimeGenerated, TableName1, DeviceVendor,ProviderName 6 | | summarize last_log = datetime_diff("second", now(), max(TimeGenerated)),last_event_received = max(TimeGenerated) by TableName1, DeviceVendor,ProviderName 7 | | project ['Table Name'] = TableName1, ['Latest Record Created'] = last_log, ['Time'] = last_event_received, DeviceVendor, ProviderName 8 | | order by Time desc 9 | -------------------------------------------------------------------------------- /LastTimeMessageReceived.txt: -------------------------------------------------------------------------------- 1 | //Use to show when there's a potential gap or stoppage in data flow 2 | 3 | Syslog 4 | | where SyslogMessage contains "rhost" 5 | | extend rhost = extract("rhost=(.*) ", 1, SyslogMessage) 6 | | summarize max(TimeGenerated), count() by rhost 7 | | extend secondsDiff = datetime_diff('second',max_TimeGenerated, now()) 8 | -------------------------------------------------------------------------------- /Latency for a Log Analytics example with rolling percentiles.txt: -------------------------------------------------------------------------------- 1 | let latencyCachedData = materialize(SigninLogs 2 | | where TimeGenerated > ago(24h) 3 | | project TimeGenerated, IngestionLatency = (_TimeReceived - TimeGenerated) 4 | | extend IngestionLatencyInMinutes = (IngestionLatency / 1m)); 5 | union 6 | (latencyCachedData 7 | | evaluate rolling_percentile(IngestionLatencyInMinutes, 95, TimeGenerated, 15m, 5) 8 | | extend pcnt=95), 9 | (latencyCachedData 10 | | evaluate rolling_percentile(IngestionLatencyInMinutes, 99, TimeGenerated, 15m, 5) 11 | | extend pcnt=99) 12 | -------------------------------------------------------------------------------- /LegacyAuthSignin.txt: -------------------------------------------------------------------------------- 1 | //Sign in Legacy authentication Azure AD 2 | 3 | SigninLogs 4 | | where TimeGenerated > ago(2d) 5 | | where not(ClientAppUsed has "Mobile Apps and Desktop clients") 6 | | where not(ClientAppUsed has "Browser") 7 | | where (ClientAppUsed has "Exchange Web Services") 8 | | summarize arg_max(TimeGenerated,*) by UserPrincipalName 9 | -------------------------------------------------------------------------------- /LineNumbers-serialize.txt: -------------------------------------------------------------------------------- 1 | let timeframe = 1d; 2 | SecurityEvent 3 | | where TimeGenerated >= ago(timeframe) 4 | | where EventID in (4624, 4625) 5 | | where AccountType == 'User' 6 | | summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated), Amount = count() by LogonTypeName 7 | | extend timestamp = StartTimeUtc 8 | | serialize Num = row_number() //using the serialize operator to generate line numbers -------------------------------------------------------------------------------- /LinksinTeamsMessages.txt: -------------------------------------------------------------------------------- 1 | //This will produce results to show when links have been created in Teams chats and channels. Will not show actual link, though. Still working on that. 2 | 3 | OfficeActivity 4 | | where OfficeWorkload =~ "MicrosoftTeams" 5 | | where Operation in ("MessageCreatedHasLink", "MessageEditedHasLink") 6 | -------------------------------------------------------------------------------- /ListofDomains.txt: -------------------------------------------------------------------------------- 1 | //Using make_set to build a list of unique user domains from the UserPrincipalName column 2 | 3 | SigninLogs 4 | | extend UserDomains = split(UserPrincipalName,'@')[1] 5 | | summarize UserDomains = make_set(UserDomains) 6 | -------------------------------------------------------------------------------- /LockedUsers.kql: -------------------------------------------------------------------------------- 1 | // A user account was locked out. 2 | 3 | SecurityEvent 4 | | where EventID == 4740 5 | | summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), LockoutsCount = count() by Activity, Account, TargetSid, TargetDomainName, SourceComputerId, SourceDomainController = Computer 6 | | extend timestamp = StartTime, AccountCustomEntity = Account, HostCustomEntity = TargetDomainName 7 | -------------------------------------------------------------------------------- /LogSources.txt: -------------------------------------------------------------------------------- 1 | //Get the active log sources 2 | 3 | set maxoutputcolumns=5000; //Last seen 4 | union withsource=TableName1 * 5 | | summarize arg_min(TimeGenerated, *) by TableName1 6 | 7 | //Get the count of active log sources 8 | set maxoutputcolumns=5000; //Actvice tables count 9 | union withsource=TableName1 * 10 | | where TimeGenerated > ago(30min) 11 | | summarize arg_max(TimeGenerated, *) by TableName1 12 | | count 13 | -------------------------------------------------------------------------------- /LoginFailureButPasswordChangeRequired.txt: -------------------------------------------------------------------------------- 1 | //Users with login failure due but required to change password at next logon 2 | 3 | SecurityEvent 4 | | where EventID == 4624 and SubStatus == "0XC0000224" 5 | -------------------------------------------------------------------------------- /LoginFailureUnknownUserNameorBadPassword.txt: -------------------------------------------------------------------------------- 1 | //Users with login failure due to Unknown user name or bad password 2 | 3 | SecurityEvent 4 | | where EventID == 4625 and FailureReason == "%%2313" 5 | | distinct Account 6 | -------------------------------------------------------------------------------- /LoginLocationNotInUS.txt: -------------------------------------------------------------------------------- 1 | //Retrieves all non-US based logins 2 | 3 | SigninLogs 4 | | extend city_ = tostring(LocationDetails.city) 5 | | extend state_ = tostring(LocationDetails.state) 6 | | extend countryOrRegion_ = tostring(LocationDetails.countryOrRegion) 7 | | where countryOrRegion_ != "US" 8 | | distinct TimeGenerated, Identity, city_, state_, countryOrRegion_, IPAddress 9 | -------------------------------------------------------------------------------- /LoginsByAccountPerLocation.txt: -------------------------------------------------------------------------------- 1 | //Show each separate login per person and their location and IP 2 | 3 | SigninLogs 4 | | extend city_ = tostring(LocationDetails.city) 5 | | extend state_ = tostring(LocationDetails.state) 6 | | extend countryOrRegion_ = tostring(LocationDetails.countryOrRegion) 7 | | distinct TimeGenerated, Identity, city_, state_, countryOrRegion_, IPAddress 8 | -------------------------------------------------------------------------------- /LookbackQuery.txt: -------------------------------------------------------------------------------- 1 | //Example of a lookback query 2 | 3 | Heartbeat 4 | | where TimeGenerated between (now(-2h) .. now()) 5 | //| summarize min(TimeGenerated), max(TimeGenerated) 6 | | where Computer startswith "S" 7 | | distinct Computer 8 | // 9 | // Now do the same for the past 14days minus the last 2 hours - this is key so we dont process the same data!!! 10 | // 11 | | join kind=rightanti 12 | ( 13 | Heartbeat 14 | | where TimeGenerated between (ago(14d) .. ago(2h)) 15 | //| summarize min(TimeGenerated), max(TimeGenerated) 16 | | where Computer startswith "S" 17 | | distinct Computer 18 | ) on Computer​ 19 | -------------------------------------------------------------------------------- /LookingforInstalledKBIDs.txt: -------------------------------------------------------------------------------- 1 | //Looking for Installed KBIDs 2 | Update 3 | | where KBID == "4565511" or KBID == "4558998" or KBID == "4565483" or KBID == "4565503" 4 | | distinct Computer, Product, KBID -------------------------------------------------------------------------------- /MDTISourceTI.kql: -------------------------------------------------------------------------------- 1 | //Show TI from the MDTI connector 2 | 3 | ThreatIntelligenceIndicator 4 | | where SourceSystem in ("Microsoft Defender Threat Intelligence", "Microsoft Emerging Threat Feed") 5 | -------------------------------------------------------------------------------- /MITRETacticIncident.txt: -------------------------------------------------------------------------------- 1 | //Displaying the MITRE tactics assigned to Incidents 2 | 3 | SecurityIncident 4 | | extend MITRE_ = tostring(parse_json(tostring(AdditionalData.tactics))[0]) 5 | | project IncidentNumber, Title, MITRE_ 6 | -------------------------------------------------------------------------------- /MITRE_ATLAS_csv_parser.kql: -------------------------------------------------------------------------------- 1 | let ATLAS = externaldata (source_name:string,url:string,external_id:string,name:string,description:string,x_mitre_shortname:string,created_by_ref:string,object_marking_refs:string,type:string,id:string,created:string,modified:string) [@"https://raw.githubusercontent.com/rod-trent/Copilot-for-Security/main/Plugins/Data/atlas.csv"] with (ignoreFirstRecord=true, format="csv"); ATLAS | distinct external_id, name, description, type, url 2 | -------------------------------------------------------------------------------- /MITRE_ATLAS_parser.kql: -------------------------------------------------------------------------------- 1 | //Using externaldata to parse the MITRE ATLAS json located at: https://github.com/mitre/atlas-navigator/blob/01181c265655c4f01bda28a0b1e0a41ec7090f77/assets/atlas-2.0-stix.json 2 | 3 | let ATLAS = externaldata(objects:string,name:string,description:string,external_references:string,url:string,external_id:string,x_mitre_shortname:string,created_by_ref:string,object_marking_refs:string,type:string,id:string,created:datetime,modified:datetime) 4 | [@"https://raw.githubusercontent.com/mitre/atlas-navigator/01181c265655c4f01bda28a0b1e0a41ec7090f77/assets/atlas-2.0-stix.json"] 5 | with (format="MultiJSON", ingestionMapping='[{"Column":"objects","Properties":{"Path":"$.objects"}},{"Column":"name","Properties":{"Path":"$.objects.name"}},{"Column":"description","Properties":{"Path":"$.objects.description"}},{"Column":"external_references","Properties":{"Path":"$.objects.external_references.source_name"}},{"Column":"url","Properties":{"Path":"$.objects.external_references.url"}},{"Column":"external_id","Properties":{"Path":"$.objects.external_references.external_id"}},{"Column":"x_mitre_shortname","Properties":{"Path":"$.objects.x_mitre_shortname"}},{"Column":"created_by_ref","Properties":{"Path":"$.objects.created_by_ref"}},{"Column":"object_marking_refs","Properties":{"Path":"$.objects.object_marking_refs"}},{"Column":"type","Properties":{"Path":"$.objects.type"}},{"Column":"id","Properties":{"Path":"$.objects.id"}},{"Column":"created","Properties":{"Path":"$.objects.created"}},{"Column":"modified","Properties":{"Path":"$.objects.modified"}},]'); 6 | ATLAS 7 | -------------------------------------------------------------------------------- /MITRE_JSON_Parser.kql: -------------------------------------------------------------------------------- 1 | //Parses MITRE's Enterprise Attack json 2 | 3 | let MITRE = externaldata(object_marking_refs:string,id:string,type:string,created:string,created_by_ref:string,external_references:string,source_name:string,url:string,external_id:string,modified:string,name:string,description:string,x_mitre_deprecated:string,x_mitre_version:string,x_mitre_modified_by_ref:string) 4 | [@"https://github.com/mitre/cti/blob/master/enterprise-attack/enterprise-attack.json"] 5 | with (format="MultiJSON", ingestionMapping='[{"Column":"type","Properties":{"Path":"$.type"}},{"Column":"id","Properties":{"Path":"$.id"}},{"Column":"objects","Properties":{"Path":"$.objects"}},{"Column":"x_mitre_domains","Properties":{"Path":"$.objects.x_mitre_domains"}},{"Column":"object_marking_refs","Properties":{"Path":"$.objects.object_marking_refs"}},{"Column":"id","Properties":{"Path":"$.objects.id"}},{"Column":"type","Properties":{"Path":"$.objects.type"}},{"Column":"created","Properties":{"Path":"$.objects.created"}},{"Column":"created_by_ref","Properties":{"Path":"$.objects.created_by_ref"}},{"Column":"external_references","Properties":{"Path":"$.objects.external_references"}},{"Column":"source_name","Properties":{"Path":"$.objects.external_references.source_name"}},{"Column":"url","Properties":{"Path":"$.objects.external_references.url"}},{"Column":"external_id","Properties":{"Path":"$.objects.external_references.external_id"}},{"Column":"modified","Properties":{"Path":"$.objects.modified"}},{"Column":"name","Properties":{"Path":"$.objects.name"}},{"Column":"description","Properties":{"Path":"$.objects.description"}},{"Column":"x_mitre_deprecated","Properties":{"Path":"$.objects.x_mitre_deprecated"}},{"Column":"x_mitre_version","Properties":{"Path":"$.objects.x_mitre_version"}},{"Column":"x_mitre_modified_by_ref","Properties":{"Path":"$.objects.x_mitre_modified_by_ref"}},]'); 6 | MITRE 7 | -------------------------------------------------------------------------------- /MS_Copilots.kql: -------------------------------------------------------------------------------- 1 | //This a list of locating Copilot usage in the SecurityEvent table. 2 | 3 | //Copilot in Microsoft Edge 4 | SecurityEvent 5 | | where CommandLine has "ux=copilot" 6 | | where Process == "msedge.exe" 7 | 8 | //Copilot in Excel 9 | SecurityEvent 10 | | where CommandLine has "copilot" 11 | | where NewProcessName has "EXCEL.EXE" 12 | 13 | //Copilot in PowerPoint 14 | SecurityEvent 15 | | where CommandLine has "copilot" 16 | | where NewProcessName has "POWERPNT.EXE" 17 | 18 | //Copilot in Visual Studio 19 | SecurityEvent 20 | | where CommandLine has "copilot" 21 | | where NewProcessName has "vsce-sign.exe" 22 | -------------------------------------------------------------------------------- /MV-EpandExample.txt: -------------------------------------------------------------------------------- 1 | AuditLogs 2 | | mv-expand TargetResources 3 | | extend modifiedProperties = parse_json(TargetResources).modifiedProperties 4 | | mv-expand modifiedProperties 5 | | extend DisplayName = tostring(parse_json(modifiedProperties).displayName), GroupName = tostring(parse_json(modifiedProperties).newValue) 6 | | project DisplayName, GroupName, TargetResources 7 | -------------------------------------------------------------------------------- /Make series to fill in gaps with default for bin by bucket.txt: -------------------------------------------------------------------------------- 1 | let window = 1d; 2 | let bucket = 1h; 3 | let min_t = toscalar(customMetrics | where timestamp > ago(window) | summarize min(timestamp)); 4 | let max_t = toscalar(customMetrics | where timestamp > ago(window) | summarize max(timestamp)); 5 | customMetrics 6 | | where timestamp > ago(window) 7 | | make-series totalHeartbeatCountByHour=count() default=0 on timestamp in range(min_t, max_t, bucket) 8 | | mvexpand timestamp to typeof(datetime), 9 | totalHeartbeatCountByHour to typeof(double) 10 | | sort by timestamp desc 11 | -------------------------------------------------------------------------------- /Make-series for gaps.txt: -------------------------------------------------------------------------------- 1 | // Example to perform a aggregation by period where they may be no data for a given period. 2 | let startdate = todatetime("2016-11-01"); 3 | let enddate = todatetime("2018-11-15"); 4 | OfficeActivity 5 | | where TimeGenerated between (startdate .. enddate) 6 | | make-series count(Operation) default=0 7 | on TimeGenerated in range(startdate, enddate, 1d) 8 | by OfficeWorkload 9 | | mvexpand TimeGenerated to typeof(datetime), 10 | count_Operation to typeof(double) 11 | 12 | // Same as above however using a numbers table approach similar to the method used in SQL 13 | let startdate = todatetime("2018-11-01"); 14 | let startdate2 = todatetime("2018-11-07"); 15 | let enddate = todatetime("2018-11-15"); 16 | range Day from startdate to enddate step 1d 17 | | extend CountOfSomething = 0 18 | | join kind=fullouter 19 | (range Day from startdate2 to enddate step 1d 20 | | extend CountOfActual = 1 21 | ) on Day 22 | | project Day,Value=iff(isnull(CountOfActual), CountOfSomething, CountOfActual) 23 | -------------------------------------------------------------------------------- /MalwareEngShutdown.txt: -------------------------------------------------------------------------------- 1 | //Accounts that shutdown the Microsoft antimalware engine 2 | 3 | search in (SecurityEvent) EventID == 4689 and "MsMpEng.exe" 4 | | summarize TerminationCount = count() by Account 5 | -------------------------------------------------------------------------------- /MenuBlade/Menu.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /MerakiDenialofService.txt: -------------------------------------------------------------------------------- 1 | //Looking for denial of service 2 | 3 | Cisco_Meraki_CL 4 | | where (* contains "shutdown" or * contains "config-register 0x2100" or * contains "config-register 0x2142") 5 | -------------------------------------------------------------------------------- /MerakiDeviceChanges.txt: -------------------------------------------------------------------------------- 1 | //Looking for config changes on Meraki MX devices 2 | 3 | Cisco_Meraki_CL 4 | | where (* contains "ip http server" or * contains "ip https server" or * contains "kron policy-list" or * contains "kron occurrence" or * contains "policy-list" or * contains "access-list" or * contains "ip access-group" or * contains "archive maximum") -------------------------------------------------------------------------------- /MerakiDeviceInformation.txt: -------------------------------------------------------------------------------- 1 | //Looking for additional device information for Meraki MX devices 2 | 3 | Cisco_Meraki_CL 4 | | where (* contains "dir" or * contains "show processes" or * contains "show arp" or * contains "show cdp" or * contains "show version" or * contains "show ip route" or * contains "show ip interface" or * contains "show ip sockets" or * contains "show users" or * contains "show ssh" or * contains "show clock") -------------------------------------------------------------------------------- /MerakiPKIActivity.txt: -------------------------------------------------------------------------------- 1 | //Looking for private key transaction or distribution of new certificates 2 | 3 | Cisco_Meraki_CL 4 | | where (* contains "crypto pki export" or * contains "crypto pki import" or * contains "crypto pki trustpoint") 5 | -------------------------------------------------------------------------------- /MerakiParser.txt: -------------------------------------------------------------------------------- 1 | //Available columns: ['host','devicename','type','hostname','src_ip','log_type','contents','dst_ip','src_port','dst_port','protocol','mac_address','request_type','uri','translated_src_ip','translated_dst_ip','pattern','translated_port','agent','message','@timestamp'] 2 | 3 | Cisco_Meraki_CL 4 | | where TimeGenerated > ago(10d) 5 | | extend ParseFields = split(RawData, ' ') 6 | | extend EventMonth = tostring(ParseFields[0]) 7 | | extend EventDay = tostring(ParseFields[1]) 8 | | extend Time = tostring(ParseFields[2]) 9 | | extend DeviceIP = tostring(ParseFields[3]) 10 | | extend Fluff_1 = tostring(ParseFields[4]) 11 | | extend Addr = tostring(ParseFields[5]) 12 | | extend Server = tostring(ParseFields[6]) 13 | | extend Method = tostring(ParseFields[7]) 14 | | extend Source = tostring(ParseFields[8]) 15 | | extend Destination = tostring(ParseFields[9]) 16 | | extend MAC = tostring(ParseFields[10]) 17 | | extend Protocol = tostring(ParseFields[11]) 18 | | extend S_Port = tostring(ParseFields[12]) 19 | | extend D_Port = tostring(ParseFields[13]) 20 | | extend Fluff_2 = tostring(ParseFields[14]) 21 | | extend Pattern = tostring(ParseFields[15]) 22 | -------------------------------------------------------------------------------- /MerakiSIGRED.txt: -------------------------------------------------------------------------------- 1 | //Looking for SIGRED 2 | 3 | Cisco_Meraki_CL 4 | | where ((record_type == "SIG" or record_type == "sig" or record_type == "RRSIG" or record_type == "rrsig") and network_protocol == "tcp") 5 | | summarize dcount_query = dcount(query) by SourceIp | where dcount_query < 15 6 | -------------------------------------------------------------------------------- /MidnightBlizzard.kql: -------------------------------------------------------------------------------- 1 | //Checking for Midnight Blizzard impact in environment 2 | 3 | union 4 | ( 5 | BehaviorEntities 6 | | where ThreatFamily contains "Midnight Blizzard" 7 | | project Timestamp, BehaviorId, ActionType, Categories, ServiceSource, DetectionSource, DataSources, EntityType, EntityRole, DetailedEntityRole 8 | ), 9 | ( 10 | AlertEvidence 11 | | where ThreatFamily contains "Midnight Blizzard" 12 | | project Timestamp, AlertId, Title, Categories, AttackTechniques, ServiceSource, DetectionSource, EntityType, EvidenceRole, EvidenceDirection, Severity 13 | ) 14 | -------------------------------------------------------------------------------- /MimiKatzDetection.txt: -------------------------------------------------------------------------------- 1 | //Detects Mimikatz has been found and shows compromise host. Requires Microsoft Defender for Endpoint connection. 2 | 3 | SecurityAlert 4 | | where Tactics == "CredentialAccess" 5 | | where Entities contains "mimikatz" 6 | | where DisplayName == "Possible attempt to steal credentials" or AlertName == "Malicious credential theft tool execution detected" 7 | | where Status == "New" 8 | | distinct CompromisedEntity, TimeGenerated 9 | -------------------------------------------------------------------------------- /MostGeneratedIncidents.txt: -------------------------------------------------------------------------------- 1 | //Display the Incidents generated in the last 90 days, but show which ones are generated the most. Good data to help tune your SOC responses and automation. 2 | 3 | SecurityIncident 4 | | where TimeGenerated >= (90d) 5 | | summarize count() by Title 6 | | distinct Title, count_ 7 | | order by count_ desc 8 | -------------------------------------------------------------------------------- /MultipleTablesNoIngest.kql: -------------------------------------------------------------------------------- 1 | //Reporting on Multiple tables that are not ingesting data. 2 | //Replace the tables with the tables you want to monitor. 3 | //Want to add more tables? Just copy, paste, and modify the let block to your heart's content. 4 | 5 | let table1= OfficeActivity 6 | | where isnotempty(Type) 7 | | summarize maxTimeGenerated=max(TimeGenerated) by Type 8 | | where maxTimeGenerated < ago(48h); 9 | let table2= SecurityAlert 10 | | where isnotempty(Type) 11 | | summarize maxTimeGenerated=max(TimeGenerated) by Type 12 | | where maxTimeGenerated < ago(72h); 13 | let table3= DeviceInfo 14 | | where isnotempty(Type) 15 | | summarize maxTimeGenerated=max(TimeGenerated) by Type 16 | | where maxTimeGenerated < ago(72h); 17 | let table4= SigninLogs 18 | | where isnotempty(Type) 19 | | summarize maxTimeGenerated=max(TimeGenerated) by Type 20 | | where maxTimeGenerated < ago(14d); 21 | union isfuzzy=true 22 | table1,table2,table3,table4 23 | -------------------------------------------------------------------------------- /NRTFailed.kql: -------------------------------------------------------------------------------- 1 | //Shows when an NRT rule failed to run and supplies the reason. 2 | 3 | 4 | SentinelHealth 5 | | where OperationName == "NRT analytics rule run" 6 | | where Status == "Failure" 7 | | project SentinelResourceName, Status, Description 8 | -------------------------------------------------------------------------------- /NSGChangesByUser.txt: -------------------------------------------------------------------------------- 1 | AzureActivity 2 | | where parse_json(Authorization).action == "Microsoft.Network/networkSecurityGroups/securityRules/write" and ActivityStatus == "Succeeded" 3 | | make-series count() default=0 on TimeGenerated in range(ago(7d), now(), 1d) by Caller 4 | |render barchart -------------------------------------------------------------------------------- /NSGChangesbyUserandResource.txt: -------------------------------------------------------------------------------- 1 | //NSG Changes by Resource and Who did it 2 | 3 | AzureActivity 4 | | where parse_json(Authorization).action == "Microsoft.Network/networkSecurityGroups/securityRules/write" and ActivityStatus == "Succeeded" 5 | | distinct Resource, Caller 6 | -------------------------------------------------------------------------------- /NetLogonPatchCompliance.txt: -------------------------------------------------------------------------------- 1 | //Choose which to track (compliance or non-compliance) and remove the comment 2 | //Based on https://support.microsoft.com/en-us/help/4557222/how-to-manage-the-changes-in-netlogon-secure-channel-connections-assoc 3 | 4 | SecurityEvent 5 | | join Heartbeat on Computer 6 | //| where EventID == "5829" //Tracking NetLogon Non-Compliance 7 | //| where EventID == "5827" or EventID == "5828" //Tracking NetLogon Compliance 8 | | distinct Computer, OSType, OSMajorVersion, Version 9 | -------------------------------------------------------------------------------- /NewAdmins.txt: -------------------------------------------------------------------------------- 1 | //Discover new admin account activity 2 | 3 | let starttime = 14d; 4 | let endtime = 1d; 5 | let historicalActivity= 6 | OfficeActivity 7 | | where TimeGenerated between(ago(starttime)..ago(endtime)) 8 | | where RecordType=="ExchangeAdmin" and UserType in ("Admin","DcAdmin") 9 | | summarize historicalCount=count() by UserId; 10 | let recentActivity = OfficeActivity 11 | | where TimeGenerated > ago(endtime) 12 | | where UserType in ("Admin","DcAdmin") 13 | | summarize recentCount=count() by UserId; 14 | recentActivity | join kind = leftanti ( 15 | historicalActivity 16 | ) on UserId 17 | | project UserId,recentCount 18 | | order by recentCount asc, UserId 19 | | join kind = rightsemi 20 | (OfficeActivity 21 | | where TimeGenerated >= ago(endtime) 22 | | where RecordType == "ExchangeAdmin" | where UserType in ("Admin","DcAdmin")) 23 | on UserId 24 | | summarize StartTime = max(TimeGenerated), EndTime = min(TimeGenerated), count() by RecordType, Operation, UserType, UserId, OriginatingServer, ResultStatus 25 | | extend timestamp = StartTime, AccountCustomEntity = UserId 26 | | project AccountCustomEntity 27 | -------------------------------------------------------------------------------- /NewBruteForceAttacks.txt: -------------------------------------------------------------------------------- 1 | let ExcludedIP = dynamic ([ 2 | '172.24.1.4' 3 | ]); 4 | let PreviousFailures = SecurityEvent 5 | | where TimeGenerated between (ago(60m) .. ago(10m)) 6 | | where EventID == 4625 7 | | where SubStatus != "0xc0000064" 8 | | where AccountType != 'Machine' 9 | | where IpAddress !in (ExcludedIP) 10 | | summarize FailureCount=count() by TargetAccount, IpAddress, bin(TimeGenerated, 50m) 11 | | where FailureCount >= 50 12 | | summarize make_set(strcat(TargetAccount, ' ', IpAddress)); 13 | SecurityEvent 14 | | where TimeGenerated > ago(10m) 15 | | where EventID == 4625 16 | | where SubStatus != "0xc0000064" 17 | | where AccountType != 'Machine' 18 | | where IpAddress !in (ExcludedIP) 19 | | summarize FailureCount=count() by TargetAccount, IpAddress, bin(TimeGenerated, 10m) 20 | | where FailureCount >= 10 21 | | where strcat(TargetAccount, ' ', IpAddress) !in (PreviousFailures) 22 | -------------------------------------------------------------------------------- /NewYearChampagneGlass.txt: -------------------------------------------------------------------------------- 1 | //Usage of datatable and make_list to create a silly glass 2 | 3 | let line1 = datatable (name: string) 4 | [ 5 | "✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ " 6 | ]; 7 | let line2 = datatable (name: string) 8 | [ 9 | " ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ " 10 | ]; 11 | let line3 = datatable (name: string) 12 | [ 13 | " ✨ ✨ ✨ ✨ ✨ ✨ ✨ " 14 | ]; 15 | let line4 = datatable (name: string) 16 | [ 17 | " ✨✨ " 18 | ]; 19 | let line5 = datatable (name: string) 20 | [ 21 | " ✨✨ " 22 | ]; 23 | let line6 = datatable (name: string) 24 | [ 25 | " ✨✨ " 26 | ]; 27 | let line7 = datatable (name: string) 28 | [ 29 | " ✨ ✨ ✨ ✨ ✨ ✨ ✨ " 30 | ]; 31 | line1 32 | | union line2, line3, line4, line5, line6, line7 33 | | summarize mylist = make_list(name) 34 | | project Happy_New_Year=strcat_array(mylist, '\n') 35 | -------------------------------------------------------------------------------- /NoIncidentsClosedin90.txt: -------------------------------------------------------------------------------- 1 | //Number of Incidents closed in the last 90 days 2 | 3 | SecurityIncident 4 | | where TimeGenerated > startofday(ago(90d)) 5 | | where ProviderName == "Azure Sentinel" // Commenting out this line provides SecurityIncidents from both Azure Sentinel and Microsoft 365 Defender Incidents. 6 | | summarize arg_max(TimeGenerated, Status, Severity, Owner, AdditionalData) by IncidentNumber 7 | | where Status == "Closed" 8 | | summarize count() by Status 9 | -------------------------------------------------------------------------------- /NoLogintoAADin90Days.txt: -------------------------------------------------------------------------------- 1 | //AAD users that haven’t performed a successful/failed login to AAD in the last 90 days 2 | 3 | IdentityInfo 4 | | where TimeGenerated > ago(30d) 5 | | summarize arg_max(TimeGenerated, *) by AccountObjectId 6 | | join kind=leftanti ( 7 | SigninLogs 8 | | where TimeGenerated > ago(90d) 9 | ) on $left.AccountObjectId == $right.UserId 10 | -------------------------------------------------------------------------------- /NoNewOpenIncidents24hrs.txt: -------------------------------------------------------------------------------- 1 | //Number of new, open Incidents in the last 24 hours 2 | 3 | SecurityIncident 4 | | where TimeGenerated > ago(1d) 5 | | summarize arg_max(TimeGenerated, Status, Severity, Owner, AdditionalData) by IncidentNumber 6 | | where Status == "New" 7 | | summarize count() by Status 8 | -------------------------------------------------------------------------------- /NoTotalOpenIncidentsin90.txt: -------------------------------------------------------------------------------- 1 | //Number of total open Incidents in the last 90 days 2 | 3 | SecurityIncident 4 | | where TimeGenerated > startofday(ago(90d)) 5 | | where ProviderName == "Azure Sentinel" // Commenting out this line provides SecurityIncidents from both Azure Sentinel and Microsoft 365 Defender Incidents. 6 | | summarize arg_max(TimeGenerated, Status, Severity, Owner, AdditionalData) by IncidentNumber 7 | | where Status != "Closed" 8 | | summarize count() by Status 9 | -------------------------------------------------------------------------------- /NoUnassignedIncidents.txt: -------------------------------------------------------------------------------- 1 | //Number of unassigned Incidents in Last 24 hours 2 | 3 | SecurityIncident 4 | | where TimeGenerated > ago(1d) 5 | | where ProviderName == "Azure Sentinel" // Commenting out this line provides SecurityIncidents from both Azure Sentinel and Microsoft 365 Defender Incidents. 6 | | summarize arg_max(TimeGenerated, Status, Severity, Owner, AdditionalData) by IncidentNumber 7 | | where Owner != "Unassigned" 8 | | where Status == "New" or Status == "Active" 9 | | summarize count() by Status 10 | -------------------------------------------------------------------------------- /NotEqual.txt: -------------------------------------------------------------------------------- 1 | //Not Equal example 2 | SecurityAlert 3 | | where DisplayName == "An event log was cleared" 4 | | where EndTime != "7/15/2020, 5:55:31.000 PM" and ProviderName != "IPC" and SystemAlertId != "e3f60b59-3c5c-5b5d-8213-698a58fa39aa" -------------------------------------------------------------------------------- /NotLoggedIn.txt: -------------------------------------------------------------------------------- 1 | //With UEBA enabled, look for users that have not logged in 2 | 3 | BehaviorAnalytics 4 | | where UsersInsights.IsDormantAccount == true 5 | -------------------------------------------------------------------------------- /NumberofEventsOveraSelectedTime.txt: -------------------------------------------------------------------------------- 1 | //Number of events over selected time 2 | 3 | union withsource=TableName * 4 | | where 'All Tables' == 'All Tables' or TableName == 'All Tables' 5 | | summarize count() by bin(TimeGenerated, 3h), Type 6 | | project ['Table name'] = Type, ['Time generated'] = TimeGenerated, ['Number of events'] = count_ -------------------------------------------------------------------------------- /OfficeIngestDelay.kql: -------------------------------------------------------------------------------- 1 | //This Alert counts all OfficeActivity logs for the last hour and triggers on a result of 0. 2 | 3 | OfficeActivity 4 | | where TimeGenerated > ago(2h) 5 | | summarize count() 6 | | where count_ == 0 7 | -------------------------------------------------------------------------------- /OfficeUsertoAdminGroup.txt: -------------------------------------------------------------------------------- 1 | //Office 365: Add a User to an Admin Group 2 | 3 | OfficeActivity 4 | | where ((Operation == "Add member to group") and (ResultStatus == "Success") and (ModifiedProperties contains "admin")) 5 | -------------------------------------------------------------------------------- /OnlineOffline.txt: -------------------------------------------------------------------------------- 1 | //Show (with indicators) if a Computer is online or not 2 | 3 | Update 4 | | extend ResourceId = iif(isempty(ResourceId), Computer, ResourceId) 5 | | summarize arg_max(TimeGenerated, *) by ResourceId 6 | | extend Online = iif(TimeGenerated < ago(1h),"⚫","🟢") 7 | | project LastSeen=TimeGenerated, Online, Computer, OS = iif(OSType == "Linux", "Linux", "Windows") 8 | | sort by LastSeen 9 | -------------------------------------------------------------------------------- /Overview_Page/Automation/Actions performed.kql: -------------------------------------------------------------------------------- 1 | let IncidentsData = materialize(SecurityIncident 2 | | order by IncidentName asc, todatetime(TimeGenerated) asc 3 | | extend rowNumber = row_number(0, IncidentName != prev(IncidentName)) 4 | | extend prevRowNumber = rowNumber - 1 5 | | project TimeGenerated, IncidentName, 6 | ModifiedBy, rowNumber, prevRowNumber, Severity, Status, Comments, Owner); 7 | IncidentsData 8 | | where ModifiedBy has 'Automation rule' or ModifiedBy startswith 'playbook' 9 | | join IncidentsData on $left.prevRowNumber == $right.rowNumber and 10 | $left.IncidentName == $right.IncidentName 11 | | project TimeGenerated, ModifiedBy, 12 | IncidentName, 13 | Severity, PrevSeverity = Severity1, 14 | Status, PrevStatus = Status1, 15 | Comments, PrevComments = Comments1, 16 | Owner, PrevOwner = Owner1 17 | | extend isSeverityChanged = Severity != PrevSeverity 18 | | extend isStatusChanged = Status != PrevStatus 19 | | extend isCommentsChanged = tostring(Comments) != tostring(PrevComments) 20 | | extend isOwnerChanged = tostring(Owner.objectId) != tostring(PrevOwner.objectId) 21 | | summarize Severity = dcountif(IncidentName, isSeverityChanged), 22 | Status = dcountif(IncidentName, isStatusChanged), 23 | Comments = dcountif(IncidentName, isCommentsChanged), 24 | Owner = dcountif(IncidentName, isOwnerChanged) 25 | -------------------------------------------------------------------------------- /Overview_Page/Automation/Automation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rod-trent/SentinelKQL/f0569a91c2b5ed823e6253b7ec7cf3d3638621c3/Overview_Page/Automation/Automation.png -------------------------------------------------------------------------------- /Overview_Page/Automation/Closed incidents.kql: -------------------------------------------------------------------------------- 1 | SecurityIncident 2 | | where Status == 'Closed' 3 | | summarize arg_min(LastModifiedTime, ModifiedBy) by IncidentName 4 | | where ModifiedBy has 'Automation rule' 5 | | summarize Count = count() 6 | -------------------------------------------------------------------------------- /Overview_Page/Automation/Readme.md: -------------------------------------------------------------------------------- 1 | 2 | ![Automation Module](https://github.com/rod-trent/SentinelKQL/blob/master/Overview_Page/Automation/Automation.png "Automation Module") 3 | -------------------------------------------------------------------------------- /Overview_Page/Automation/Time saved.kql: -------------------------------------------------------------------------------- 1 | SecurityIncident 2 | | where Status == 'Closed' 3 | | summarize arg_min(LastModifiedTime, ClosedTime, CreatedTime, ModifiedBy) by IncidentName 4 | | extend timeToClose = datetime_diff('Minute',ClosedTime, CreatedTime) 5 | | extend IsClosedByAutomation = iff(ModifiedBy has 'Automation rule','ClosedByAutomation', 'NotClosedByAutomation') 6 | | summarize MeanTimeToClose = percentiles(timeToClose, 50) by IsClosedByAutomation 7 | -------------------------------------------------------------------------------- /Overview_Page/Data/Anomalies.kql: -------------------------------------------------------------------------------- 1 | let endTime = now(); 2 | let startTime = ago(1d); 3 | let emptyTableAnoamliesVolume = datatable(TimeGenerated:datetime, RecordCount:int)[]; 4 | emptyTableAnoamliesVolume 5 | | union isfuzzy=true 6 | ( Anomalies 7 | | where TimeGenerated between (StartTimeAnomalies..EndTimeAnomalies) 8 | | make-series RecordCount = count() default=0 on TimeGenerated from StartTimeAnomalies to EndTimeAnomalies step 4h 9 | | mv-expand RecordCount to typeof(int), TimeGenerated to typeof(datetime)) 10 | | project Result = pack_all() 11 | -------------------------------------------------------------------------------- /Overview_Page/Data/Data.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rod-trent/SentinelKQL/f0569a91c2b5ed823e6253b7ec7cf3d3638621c3/Overview_Page/Data/Data.png -------------------------------------------------------------------------------- /Overview_Page/Data/Readme.md: -------------------------------------------------------------------------------- 1 | 2 | ![Data Module](https://github.com/rod-trent/SentinelKQL/blob/master/Overview_Page/Data/Data.png "Data Module") 3 | -------------------------------------------------------------------------------- /Overview_Page/Data/TI by type.kql: -------------------------------------------------------------------------------- 1 | ThreatIntelligenceIndicator 2 | | where ExpirationDateTime > now() 3 | | summarize arg_max(TimeGenerated, *) by IndicatorId 4 | | where Active == true 5 | | extend IndicatorType = 6 | iif(isnotempty(EmailSourceIpAddress) or isnotempty(NetworkDestinationIP) or isnotempty(NetworkIP) or isnotempty(NetworkSourceIP) or isnotempty(NetworkCidrBlock), 'IP', 7 | iff(isnotempty(Url), 'URL', 8 | iff(isnotempty(EmailRecipient) or isnotempty(EmailSenderAddress), 'Email', 9 | iff(isnotempty(FileHashValue), 'File', 10 | iff(isnotempty(DomainName) or isnotempty(EmailSourceDomain), 'Domain', 11 | 'Other'))))) 12 | | summarize IndicatorCount = count() by IndicatorType 13 | -------------------------------------------------------------------------------- /Overview_Page/Data/Total volume.kql: -------------------------------------------------------------------------------- 1 | let endTime = now(); 2 | let startTime = ago(2d); 3 | search * 4 | | where TimeGenerated between (startTime..endTime) 5 | | make-series RecordCount = count() default=0 on TimeGenerated from startTime to endTime step 4h 6 | | mv-expand RecordCount to typeof(int), TimeGenerated to typeof(datetime) 7 | | project Result = pack_all() 8 | -------------------------------------------------------------------------------- /Overview_Page/Data/Unhealthy connectors.kql: -------------------------------------------------------------------------------- 1 | SentinelHealth 2 | | where OperationName == 'Data fetch status change' 3 | | summarize arg_max(TimeGenerated, *) by SentinelResourceId, SentinelResourceKind, SentinelResourceName 4 | | where Status == "Failure" 5 | -------------------------------------------------------------------------------- /Overview_Page/Incidents/Incidents by closed classification - last 24 hours.kql: -------------------------------------------------------------------------------- 1 | SecurityIncident 2 | | where Status == 'Closed' 3 | | where isnotempty(Classification) 4 | | summarize arg_max(LastModifiedTime, Classification) by IncidentName 5 | | summarize Count = count() by Classification 6 | -------------------------------------------------------------------------------- /Overview_Page/Incidents/Incidents by severity - last 24 hours.kql: -------------------------------------------------------------------------------- 1 | SecurityIncident 2 | | summarize arg_max(LastModifiedTime,Severity) by IncidentName 3 | | summarize Count = count() by Severity 4 | -------------------------------------------------------------------------------- /Overview_Page/Incidents/Incidents by status - last 24 hours.kql: -------------------------------------------------------------------------------- 1 | SecurityIncident 2 | | summarize arg_max(LastModifiedTime, Status) by IncidentName 3 | | summarize Count = count() by Status 4 | -------------------------------------------------------------------------------- /Overview_Page/Incidents/Incidents status by creation time - last 24 hours.kql: -------------------------------------------------------------------------------- 1 | SecurityIncident 2 | | where CreatedTime > ago(1d) 3 | | summarize arg_max(LastModifiedTime, Status, CreatedTime) by IncidentName 4 | | summarize Count = count() by Status, bin(CreatedTime, 4h) 5 | | extend StatusCount = pack(Status, Count) 6 | | summarize StatusCountArray = make_bag(StatusCount) by CreatedTime 7 | | evaluate bag_unpack(StatusCountArray) 8 | | project Result = pack_all() 9 | -------------------------------------------------------------------------------- /Overview_Page/Incidents/Incidents.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rod-trent/SentinelKQL/f0569a91c2b5ed823e6253b7ec7cf3d3638621c3/Overview_Page/Incidents/Incidents.png -------------------------------------------------------------------------------- /Overview_Page/Incidents/Mean time to acknowledge - last 48 hours.kql: -------------------------------------------------------------------------------- 1 | let MeanTimeToAck = SecurityIncident 2 | | where Status == 'Active' 3 | | summarize arg_min(LastModifiedTime, CreatedTime, TimeGenerated) by IncidentName 4 | | extend timeToAck = datetime_diff('Minute', LastModifiedTime, CreatedTime) 5 | | summarize MeanTime = percentiles(timeToAck, 50) by HalfQueryPeriodTime = bin_at(TimeGenerated, 24h, ago(48h)) 6 | | order by HalfQueryPeriodTime asc; 7 | MeanTimeToAck 8 | | serialize HalfQueryPeriodTime 9 | | extend MeanTime = MeanTime/todouble(60) 10 | | extend Trend = (MeanTime - prev(MeanTime))/todouble(60) 11 | | order by HalfQueryPeriodTime desc 12 | | project MeanTime, Trend 13 | -------------------------------------------------------------------------------- /Overview_Page/Incidents/Mean time to close.kql: -------------------------------------------------------------------------------- 1 | let MeanTimeToClose = SecurityIncident 2 | | where Status == 'Closed' 3 | | summarize arg_min(LastModifiedTime, ClosedTime, CreatedTime, TimeGenerated) by IncidentName 4 | | extend timeToClose = datetime_diff('Minute', ClosedTime, CreatedTime) 5 | | summarize MeanTime = percentiles(timeToClose, 50) 6 | by HalfQueryPeriodTime = bin_at(TimeGenerated, 24h, ago(48h)) 7 | | order by HalfQueryPeriodTime asc; 8 | MeanTimeToClose 9 | | serialize HalfQueryPeriodTime 10 | | extend MeanTime = MeanTime/todouble(60) 11 | | extend Trend = (MeanTime - prev(MeanTime))/todouble(60) 12 | | order by HalfQueryPeriodTime desc 13 | | project MeanTime, Trend 14 | -------------------------------------------------------------------------------- /Overview_Page/Incidents/Readme.md: -------------------------------------------------------------------------------- 1 | ![Incidents Module](https://github.com/rod-trent/SentinelKQL/blob/master/Overview_Page/Incidents/Incidents.png "Incidents Module") 2 | -------------------------------------------------------------------------------- /Overview_Page/Readme.md: -------------------------------------------------------------------------------- 1 | ## Microsoft Sentinel Overview Page Queries 2 | 3 | The Overview Page in Microsoft Sentinel is intended to serve as a main dashboard and give a high-level of Sentinel main areas, including data collection, analytics, incidents, and automation. 4 | 5 | This repo contains the queries behind the various Overview Page modules. 6 | 7 | P.S. Some have asked why there are no queries supplied for the Analytics widget. The Analytics widget uses the API instead of a KQL query. 8 | 9 | ![Overview Page](https://github.com/rod-trent/SentinelKQL/blob/master/Overview_Page/overview.png "Overview Page") 10 | -------------------------------------------------------------------------------- /Overview_Page/overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rod-trent/SentinelKQL/f0569a91c2b5ed823e6253b7ec7cf3d3638621c3/Overview_Page/overview.png -------------------------------------------------------------------------------- /Overview_Queries.txt: -------------------------------------------------------------------------------- 1 | //The following is the query that produces the 'Recent Incidents' display on the Overview page 2 | 3 | let startTime = datetime(2021-05-07T06:47:22.396Z); 4 | let endTime = datetime(2021-05-09T06:47:22.396Z); 5 | let binSize=1h; 6 | range TimeGenerated from startTime to endTime step binSize 7 | | summarize by bin_at(TimeGenerated, binSize, endTime) 8 | | join kind=fullouter (SecurityAlert | where ProviderName == 'ASI Scheduled Alerts' or ProviderName == 'CustomAlertRule' 9 | | summarize Count=count() by bin_at(TimeGenerated, binSize, endTime), DisplayName) on TimeGenerated 10 | | project Count=iff(isnull(Count), 0, Count), TimeGenerated, DisplayName, Type = "SecurityAlert" 11 | | order by TimeGenerated asc 12 | 13 | 14 | //The following is the query that produces the 'Events and alerts overtime' dispaly on the Overview page 15 | 16 | search * 17 | | where not(Type == 'SecurityAlert' and (ProviderName == 'ASI Scheduled Alerts' or ProviderName == 'CustomAlertRule')) 18 | | summarize Count=count() by Type, bin_at(TimeGenerated, 1h , datetime(2021-05-09T06:47:22.396Z)) 19 | -------------------------------------------------------------------------------- /PKEXEC.txt: -------------------------------------------------------------------------------- 1 | //Looking for pkexec command-lines run by root 2 | 3 | DeviceProcessEvents 4 | | where ProcessCommandLine has "pkexec" and AccountName == "root" 5 | | project DeviceName, ProcessCommandLine, InitiatingProcessCommandLine, InitiatingProcessParentFileName 6 | -------------------------------------------------------------------------------- /PackAllExample.txt: -------------------------------------------------------------------------------- 1 | //Example of using Pack All to put results into a single column. Can also be used with Extend operator 2 | 3 | 4 | let StartTime=ago(24h); 5 | let StopTime=now(); 6 | SecurityEvent 7 | | where TimeGenerated >StartTime and TimeGenerated <=StopTime 8 | | project pack_all() 9 | -------------------------------------------------------------------------------- /PaloAltoStops.kql: -------------------------------------------------------------------------------- 1 | //You can create an Analytics Rule with the following to alert when Palo Alto data stops flowing. 2 | 3 | 4 | CommonSecurityLog 5 | | where TimeGenerated > ago(2h) 6 | | where DeviceVendor == "Palo Alto Networks" 7 | | where DeviceProduct has "PAN-OS" 8 | | summarize count() 9 | where count_ == 0 10 | -------------------------------------------------------------------------------- /ParseAnomaliConfidenceScore.txt: -------------------------------------------------------------------------------- 1 | //Parses out the confidence score for the Anomali feeds 2 | 3 | ThreatIntelligenceIndicator 4 | | parse-where ThreatType with * "confidence-" Confidence_Score 5 | | project NetworkIP, ThreatType, Confidence_Score, SourceSystem 6 | -------------------------------------------------------------------------------- /ParseBetween.txt: -------------------------------------------------------------------------------- 1 | \\Example that uses the Parse operator to generate a column of data from between specific strings. Return value is "Microsoft System Center" 2 | 3 | print input = 'C:\\Program Files\\Microsoft System Center\\Server\\Microsoft.Mom.Sdk.ServiceHost.exe' 4 | | parse input with * "s\\" Process_Host_Name "\\S" * 5 | -------------------------------------------------------------------------------- /PlaybookActivity.kql: -------------------------------------------------------------------------------- 1 | //Watch Playbook execution and display Playbook name, which action was invoked, and who did it 2 | 3 | AzureDiagnostics 4 | | join AzureActivity on ResourceGroup 5 | | where ResourceProvider == "MICROSOFT.LOGIC" 6 | | extend PlaybookName = resource_workflowName_s 7 | | extend Action = Resource 8 | | distinct Caller, PlaybookName, Action, CallerIpAddress 9 | -------------------------------------------------------------------------------- /PolicyCreation.txt: -------------------------------------------------------------------------------- 1 | //Who created a new policy against which resource group and the type of policy created 2 | 3 | AzureActivity 4 | | where ResourceProviderValue == "MICROSOFT.POLICYINSIGHTS" 5 | | where ActivitySubstatusValue == "Created" 6 | | project Caller, CallerIpAddress, ResourceGroup, Type 7 | -------------------------------------------------------------------------------- /PolicyExemptions.txt: -------------------------------------------------------------------------------- 1 | AzureActivity 2 | | where OperationNameValue contains "MICROSOFT.AUTHORIZATION/POLICYEXEMPTIONS" 3 | | where ActivityStatusValue == "Start" or ActivityStatusValue == "Success" 4 | | extend resource_ = tostring(parse_json(Properties).resource) 5 | | project Caller, CallerIpAddress, resource_ 6 | -------------------------------------------------------------------------------- /PoorPerfQuery.txt: -------------------------------------------------------------------------------- 1 | //Identifying possibly poor performing queries 2 | 3 | LAQueryLogs 4 | | where ResponseRowCount < 200 and ResponseDurationMs > 5000 5 | -------------------------------------------------------------------------------- /Potentialmaliciouseventsmap.txt: -------------------------------------------------------------------------------- 1 | //This is the query that produces the Potential Malicious Events map on the entry page for Microsoft Sentinel 2 | 3 | union isfuzzy=true 4 | (W3CIISLog 5 | | extend 6 | TrafficDirection = "InboundOrUnknown", 7 | Country=RemoteIPCountry, 8 | Latitude=RemoteIPLatitude, 9 | Longitude=RemoteIPLongitude), 10 | (DnsEvents 11 | | extend 12 | TrafficDirection = "InboundOrUnknown", 13 | Country= RemoteIPCountry, 14 | Latitude = RemoteIPLatitude, 15 | Longitude = RemoteIPLongitude), 16 | (WireData 17 | | extend 18 | TrafficDirection = iff(Direction != "Outbound", "InboundOrUnknown", "Outbound"), 19 | Country=RemoteIPCountry, 20 | Latitude=RemoteIPLatitude, 21 | Longitude=RemoteIPLongitude), 22 | (WindowsFirewall 23 | | extend 24 | TrafficDirection = iff(CommunicationDirection != "SEND", "InboundOrUnknown", "Outbound"), 25 | Country=MaliciousIPCountry, 26 | Latitude=MaliciousIPLatitude, 27 | Longitude=MaliciousIPLongitude), 28 | (CommonSecurityLog 29 | | extend 30 | TrafficDirection = iff(CommunicationDirection !in ("Outbound", "1"), "InboundOrUnknown", "Outbound"), 31 | Country=MaliciousIPCountry, 32 | Latitude=MaliciousIPLatitude, 33 | Longitude=MaliciousIPLongitude, 34 | Confidence=ThreatDescription, 35 | Description=ThreatDescription), 36 | (VMConnection 37 | | where Type == "VMConnection" 38 | | extend 39 | TrafficDirection = iff(Direction != "outbound", "InboundOrUnknown", "Outbound"), 40 | Country=RemoteCountry, 41 | Latitude=RemoteLatitude, 42 | Longitude=RemoteLongitude, 43 | MaliciousIP=MaliciousIp) 44 | | where isnotempty(MaliciousIP) 45 | and isnotempty(Country) 46 | and isnotempty(Latitude) 47 | and isnotempty(Longitude) 48 | -------------------------------------------------------------------------------- /PowerShellExecution.txt: -------------------------------------------------------------------------------- 1 | SecurityEvent 2 | | where ProcessName has "powershell.exe" or ProcessName has "powershell_ise.exe" 3 | | project TimeGenerated, Computer, SubjectUserName, SubjectDomainName, Process, CommandLine, ParentProcessName 4 | -------------------------------------------------------------------------------- /PowerShellExecutionwithDownload.txt: -------------------------------------------------------------------------------- 1 | //Requires the Microsoft 365 Defender Connector 2 | //Identify PowerShell executions that could have initiated a download request 3 | 4 | //Query: 5 | 6 | union DeviceProcessEvents, DeviceNetworkEvents 7 | | where Timestamp > ago(7d) 8 | | where FileName in~ ("powershell.exe", "powershell_ise.exe") 9 | | where ProcessCommandLine has_any("WebClient", "DownloadFile", "DownloadData", "DownloadString", "WebRequest", "Shellcode", "http", "https") 10 | | project Timestamp, DeviceName, InitiatingProcessFileName, InitiatingProcessCommandLine, FileName, ProcessCommandLine, RemoteIP, RemoteUrl, RemotePort, RemoteIPType 11 | 12 | //For an Analytics Rule: 13 | 14 | union DeviceProcessEvents, DeviceNetworkEvents, DeviceEvents 15 | | where Timestamp > ago(7d) 16 | | where FileName in~ ("powershell.exe", "powershell_ise.exe") 17 | | where ProcessCommandLine has_any("WebClient", "DownloadFile", "DownloadData", "DownloadString", "WebRequest", "Shellcode", "http", "https") 18 | | project Timestamp, DeviceName, InitiatingProcessFileName, InitiatingProcessCommandLine, FileName, ProcessCommandLine, RemoteIP, RemoteUrl, RemotePort, RemoteIPType 19 | | extend IPCustomEntity = RemoteIP 20 | | extend URLCustomEntity = RemoteUrl 21 | | extend HostCustomEntity = DeviceName 22 | -------------------------------------------------------------------------------- /PrintNightmare.txt: -------------------------------------------------------------------------------- 1 | //PrintNightmare CVE-2021-1675 2 | 3 | DeviceFileEvents 4 | | where Timestamp > ago(1d) 5 | | where FolderPath matches regex @'\\Windows\\System32\\spool\\drivers\\x64\\3\\old\\([^1|2].*\.dll)|\\(MyExploit|evil|addCube|rev|rev2|main64|mimilib)\.dll$' 6 | -------------------------------------------------------------------------------- /ProxyShell.txt: -------------------------------------------------------------------------------- 1 | //Searching for evidence of Microsoft Exchange ProxyShell Flaws. Requires Microsoft Defender for Endpoints connected. 2 | 3 | DeviceFileEvents 4 | | where FolderPath == "C:\\inetpub\\wwwroot\\aspnet_client\\488617229.aspx" or FolderPath == "C:\\inetpub\\wwwroot\\aspnet_client\\654253568.aspx" or FolderPath == "C:\\inetpub\\wwwroot\\aspnet_client\\668544844.aspx" or FolderPath == "C:\\inetpub\\wwwroot\\aspnet_client\\731294981.aspx" or FolderPath == "C:\\inetpub\\wwwroot\\aspnet_client\\CYCESRYBAJPREELGQOQ.aspx" or FolderPath == "C:\\inetpub\\wwwroot\\aspnet_client\\CYSCPPUOWK.aspx" or FolderPath == "C:\\inetpub\\wwwroot\\aspnet_client\\JVSTGMTCIPJCGR.aspx" or FolderPath == "C:\\inetpub\\wwwroot\\aspnet_client\\MQMYUVTNMSZJQEUB.aspx" or FolderPath == "C:\\inetpub\\wwwroot\\aspnet_client\\MWWJJRXXQWDKQGURFMQ.aspx" or FolderPath == "C:\\inetpub\\wwwroot\\aspnet_client\\PFLIYH.aspx" or FolderPath == "C:\\inetpub\\wwwroot\\aspnet_client\\RLDVMAGKRJV.aspx" or FolderPath == "C:\\inetpub\\wwwroot\\aspnet_client\\RWXJGN.aspx" or FolderPath == "C:\\inetpub\\wwwroot\\aspnet_client\\TDIVOXVL.aspx" or FolderPath == "C:\\inetpub\\wwwroot\\aspnet_client\\VQJMZXKL.aspx" or FolderPath == "C:\\inetpub\\wwwroot\\aspnet_client\\XETUQDFHBZXAR.aspx" or FolderPath == "C:\\inetpub\\wwwroot\\aspnet_client\\apfpprmunlpzyhom.aspx" or FolderPath == "C:\\inetpub\\wwwroot\\aspnet_client\\czhlxfrdbhuqxljd.aspx" or FolderPath == "C:\\inetpub\\wwwroot\\aspnet_client\\dxtfc.aspx" or FolderPath == "C:\\inetpub\\wwwroot\\aspnet_client\\eewiq.aspx" or FolderPath == "C:\\inetpub\\wwwroot\\aspnet_client\\febvx.aspx" or FolderPath == "C:\\inetpub\\wwwroot\\aspnet_client\\ksrgd.aspx" or FolderPath =="C:\\inetpub\\wwwroot\\aspnet_client\\lsdiv.aspx" 5 | 6 | //Reference: Microsoft Exchange Servers Still Vulnerable to ProxyShell Exploit - https://cda.ms/2qP 7 | -------------------------------------------------------------------------------- /ProxyShellExchange.txt: -------------------------------------------------------------------------------- 1 | //Check the Exchange Server for ProxyShell vulnerability scanning 2 | 3 | W3CIISLog 4 | | where csUriStem == "/autodiscover/autodiscover.json" 5 | | where csUriQuery has "PowerShell" | where csMethod == "POST" 6 | -------------------------------------------------------------------------------- /QueriesEachPersonRan.txt: -------------------------------------------------------------------------------- 1 | //The actual KQL queries that each person ran in the last 7 days 2 | //Enabling the Diag Setting for the Audit log is required to expose the LAQueryLogs table 3 | 4 | LAQueryLogs 5 | | where TimeGenerated > ago(7d) 6 | | project AADEmail, QueryText -------------------------------------------------------------------------------- /RDP_by_IP.kql: -------------------------------------------------------------------------------- 1 | //Display all processes initiated by a source IP during an RDP session. 2 | 3 | DeviceProcessEvents 4 | | where Timestamp >= ago(1d) 5 | | where IsInitiatingProcessRemoteSession == "True" 6 | | where InitiatingProcessRemoteSessionIP == "X.X.X.X" // Insert your IP Address here 7 | | project InitiatingProcessFileName, InitiatingProcessAccountSid, InitiatingProcessCommandLine, FileName, ProcessCommandLine 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SentinelKQL 2 | 3 | This section is dedicated to KQL queries that I've developed at customer request. 4 | -------------------------------------------------------------------------------- /RegistryCredentialTheft.txt: -------------------------------------------------------------------------------- 1 | //Credential theft from registry. Defender for Endpoint connected to Sentinel. 2 | 3 | DeviceProcessEvents 4 | | where FileName =~ 'reg.exe' 5 | | where ProcessCommandLine has_all('save','hklm','sam') 6 | | project DeviceId, Timestamp, InitiatingProcessId, InitiatingProcessFileName, ProcessId, FileName, ProcessCommandLine 7 | -------------------------------------------------------------------------------- /RemoteLogon.txt: -------------------------------------------------------------------------------- 1 | //Accounts that logged on remotely to specified computer, and how many times 2 | 3 | search in (SecurityEvent) EventID == 4624 and (LogonTypeName == "3 - Network" or LogonTypeName == "10 - RemoteInteractive") and Computer == "" 4 | | summarize RemoteLogonCount = count() by Account 5 | -------------------------------------------------------------------------------- /RemoteWorkspaceQuery.txt: -------------------------------------------------------------------------------- 1 | //Query a remote workspace for usage. Just enter your remote workspace. 2 | 3 | workspace("yourremoteworkspace").Usage 4 | -------------------------------------------------------------------------------- /Remote_Actions_By_Compromised_Account.kql: -------------------------------------------------------------------------------- 1 | //Highlight actions performed remotely by a compromised account. 2 | 3 | DeviceProcessEvents 4 | | where Timestamp >= ago(7d) 5 | | where InitiatingProcessAccountSid == "SID" // Insert the compromised account SID here 6 | | where IsInitiatingProcessRemoteSession == "True" 7 | | project InitiatingProcessFileName, InitiatingProcessAccountSid, InitiatingProcessCommandLine, FileName, ProcessCommandLine 8 | -------------------------------------------------------------------------------- /ReportNoData.txt: -------------------------------------------------------------------------------- 1 | //Reporting on a Connector that isn't reporting data in the last hour. 2 | //The example below is for the OfficeActivity table. Delay for that table may need to be 2 hours. 3 | //The table will depend on the associated Data Connector. 4 | //Create an Analytics Rule to be alerted. 5 | 6 | OfficeActivity 7 | | where TimeGenerated > ago(1h) 8 | | summarize count() 9 | | where count_ == 0 10 | -------------------------------------------------------------------------------- /RestartShutdownsLast7Days.txt: -------------------------------------------------------------------------------- 1 | // List restart and shutdowns events for the last 7 days for all agented computers. 2 | Event 3 | | where TimeGenerated > ago(7d) 4 | | where EventLog == "System" and Source == "User32" and EventID == 1074 5 | | search "shutdown" 6 | | sort by TimeGenerated desc 7 | | project TimeGenerated, Computer -------------------------------------------------------------------------------- /RetentionPerTable.txt: -------------------------------------------------------------------------------- 1 | //Show when data retention is changed per table, who did it and their IP address 2 | 3 | 4 | AzureActivity 5 | | where OperationNameValue == "MICROSOFT.OPERATIONALINSIGHTS/WORKSPACES/TABLES/WRITE" 6 | | extend table = parse_json(Properties).entity 7 | | parse-where table with * "/tables/" Changed_Table 8 | | distinct Changed_Table, Changed_by = Caller, User_IP = CallerIpAddress, Time_it_Happened = TimeGenerated 9 | -------------------------------------------------------------------------------- /RulesRuninLast30d.txt: -------------------------------------------------------------------------------- 1 | //Analytics Rules that generated alerts (and how many) in the last 30 days 2 | 3 | SecurityAlert 4 | | where TimeGenerated >= (30d) 5 | | where ProviderName contains "ASI" 6 | | summarize count() by DisplayName 7 | -------------------------------------------------------------------------------- /Running total aka cumulative sum.txt: -------------------------------------------------------------------------------- 1 | let SampleData = datatable (user:string, rowValue: int) ["A",5,"B",12,"B",15,"A",3,"A",9,"A",19,"B",7]; 2 | SampleData 3 | | serialize 4 | | extend rowNumber = row_number() 5 | | extend rowNumberCurrentUser = row_number(1, prev(user,1,0) != user) 6 | | extend previousValue = strcat("Previous value was ", prev(rowValue,1,0)) 7 | | extend nextValue = strcat("Next value was ", next(rowNumber,1,0)) 8 | | extend runningTotal = row_cumsum(rowValue) 9 | | project rowNumber, rowNumberCurrentUser, user, rowValue, previousValue, nextValue, runningTotal 10 | -------------------------------------------------------------------------------- /SMA and EMA examples.txt: -------------------------------------------------------------------------------- 1 | // Simple moving average (SMA) version, curve smoothing. 2 | let window = 7d; 3 | let bucket = 1d; 4 | let min_t = toscalar(OfficeActivity 5 | | where TimeGenerated > ago(window) 6 | | summarize min(TimeGenerated)); 7 | let max_t = toscalar(OfficeActivity 8 | | where TimeGenerated > ago(window) 9 | | summarize max(TimeGenerated)); 10 | OfficeActivity 11 | | make-series totalAuditCountByDay=count() default=0 on TimeGenerated in range(min_t, max_t, bucket) 12 | | extend buckets=range(min_t, max_t, bucket) 13 | | extend 3d_SimpleMovingAvg=series_fir(totalAuditCountByDay, dynamic([1,1,1])), 3d_SimpleMovingAvg_centered=series_fir(totalAuditCountByDay, dynamic([1,1,1]), true, true), 5d_SimpleMovingAvg=series_fir(totalAuditCountByDay, dynamic([1,1,1,1,1])) 14 | | project buckets,3d_SimpleMovingAvg, 3d_SimpleMovingAvg_centered, 5d_SimpleMovingAvg 15 | | render timechart 16 | 17 | // Exponential moving average (EMA) version over X days 18 | // l sub p is the estimate or smoothed value of the data, smoothing coefficient more aggressive towards 0 19 | let window = 30d; 20 | let bucket = 1d; 21 | let min_t = toscalar(OfficeActivity | where TimeGenerated > ago(window) | summarize min(TimeGenerated)); 22 | let max_t = toscalar(OfficeActivity | where TimeGenerated > ago(window) | summarize max(TimeGenerated)); 23 | let series_exp_smooth = (series:dynamic, alpha:real) 24 | { 25 | series_iir(series, pack_array(alpha), pack_array(1, alpha-1)) 26 | }; 27 | OfficeActivity 28 | | make-series totalAuditCountByDay=count() default=0 on TimeGenerated in range(min_t, max_t, bucket) 29 | | extend lp_num1 = series_exp_smooth(totalAuditCountByDay, 0.6) 30 | | extend lp_num2 = series_exp_smooth(totalAuditCountByDay, 0.5) 31 | | extend lp_num3 = series_exp_smooth(totalAuditCountByDay, 0.4) 32 | | render timechart 33 | -------------------------------------------------------------------------------- /SQLServerAuditLogs.txt: -------------------------------------------------------------------------------- 1 | //Azure SQL Server Audit Logs 2 | //Requires Azure SQL Server auditing enabled: https://azurecloudai.blog/2020/10/29/how-to-send-azure-sql-server-audit-logs-to-azure-sentinel/ 3 | 4 | AzureDiagnostics 5 | | where TimeGenerated > ago(24h) 6 | | where Category == "SQLSecurityAuditEvents" -------------------------------------------------------------------------------- /SecurityChangePasswordResets.txt: -------------------------------------------------------------------------------- 1 | // Security Change or Reset Passwords Attempts 2 | // Counts change/reset paswords attempts per target account. 3 | SecurityEvent 4 | | where EventID in (4723, 4724) 5 | | summarize count() by TargetAccount -------------------------------------------------------------------------------- /SecurityIndicentsCreatedinLastDay.txt: -------------------------------------------------------------------------------- 1 | SecurityIncident 2 | | where TimeGenerated > ago(1d) 3 | | where Status == "New" 4 | | project TimeGenerated, Title, Description, Severity, IncidentUrl 5 | -------------------------------------------------------------------------------- /SecurityLogFileCleared.txt: -------------------------------------------------------------------------------- 1 | //Computers where the Security log file has been cleared 2 | 3 | search in (SecurityEvent) EventID == 1102 4 | | summarize LogClearedCount = count() by Computer | limit 500000 5 | -------------------------------------------------------------------------------- /SentinelDataRetention.txt: -------------------------------------------------------------------------------- 1 | //Must be run in Resource Graph Explorer to expose the resources table. 2 | 3 | 4 | resources 5 | | where type =~ 'microsoft.operationalinsights/workspaces' 6 | | extend state = trim(' ', tostring(properties.provisioningState)) 7 | ,sku = trim(' ', tostring(properties.sku.name)) 8 | ,skuUpdate = trim(' ', tostring(properties.sku.lastSkuUpdate)) 9 | ,retentionDays = trim(' ', tostring(properties.retentionInDays)) 10 | ,dailyquotaGB = trim(' ', tostring(properties.workspaceCapping.dailyQuotaGb)) 11 | | extend dailyquotaGB = iif(dailyquotaGB !=-1.0, dailyquotaGB,"Not set") 12 | | extend skuUpdate = iif(strlen(skuUpdate) > 0, skuUpdate,"Unknown") 13 | | extend sentinel = iif(toint(retentionDays) < 90,"If you have Sentinel, you can change your retention to 90days (free)?","") 14 | | project ['Log Analytics Workspace Name']=id, ['Resource Group']=resourceGroup, location, ['Data Retention(days)']=retentionDays, ['Last known SKU update']=skuUpdate, ['Daily Data Cap']=dailyquotaGB, ['Licence']=sku, ['Commitment Tier']=properties.sku.capacityReservationLevel, ['Notes'] = sentinel 15 | -------------------------------------------------------------------------------- /SentinelIncidentURLs- ALL.txt: -------------------------------------------------------------------------------- 1 | let IncidentURL = "https://portal.azure.com/#asset/Microsoft_Azure_Security_Insights/Incident"; 2 | AzureActivity 3 | | where _ResourceId has "Microsoft.SecurityInsights" and _ResourceId has "incidents" 4 | | summarize by _ResourceId 5 | | extend IncidentLINK = strcat(IncidentURL, _ResourceId) 6 | | distinct IncidentLINK 7 | -------------------------------------------------------------------------------- /SharePointDownloads.txt: -------------------------------------------------------------------------------- 1 | OfficeActivity 2 | | where RecordType == "SharePointFileOperation" 3 | | where Operation == "FileDownloaded" or Operation == "FileSyncDownloadedFull" 4 | | join kind= inner ( 5 | Heartbeat 6 | | summarize arg_max(TimeGenerated, *) by ComputerIP 7 | | extend ClientIP = tostring(ComputerIP), Computer 8 | ) on ClientIP 9 | | project TimeGenerated, ClientIP, Computer, Operation, OfficeWorkload, UserId, SourceFileName, OfficeObjectId 10 | | sort by TimeGenerated desc -------------------------------------------------------------------------------- /SignInbyLocation.txt: -------------------------------------------------------------------------------- 1 | SigninLogs 2 | | where TimeGenerated > ago(120d) 3 | | where UserDisplayName !="On-Premises Directory Synchronization Service Account" 4 | | extend city_ = tostring(LocationDetails.city) 5 | | extend state_ = tostring(LocationDetails.state) 6 | | extend countryOrRegion_ = tostring(LocationDetails.countryOrRegion) 7 | | extend latitude_ = tostring(parse_json(tostring(LocationDetails.geoCoordinates)).latitude) 8 | | extend longitude_ = tostring(parse_json(tostring(LocationDetails.geoCoordinates)).longitude) 9 | | order by TimeGenerated asc , city_ asc 10 | | serialize 11 | | extend pLat = prev(latitude_,1) 12 | | extend pLon = prev(longitude_,1) 13 | | extend distance_in_miles = iif(isnotempty(pLat),tostring(round(geo_distance_2points(todouble(longitude_), todouble(latitude_), todouble(pLon), todouble(pLat))/1609.344 ,2)),"FirstLocation") 14 | | where distance_in_miles !="0.0" 15 | | summarize count() by bin(TimeGenerated, 24h), 16 | userNameLocation = strcat(UserDisplayName," 👤 " ,city_ , " 🗺️ ", 17 | countryOrRegion_), 18 | visit_order = strcat(row_number(), ".",city_), 19 | MilesTravelled=distance_in_miles 20 | | project-away count_ 21 | | order by TimeGenerated asc, visit_order asc -------------------------------------------------------------------------------- /SignatureVersionPie.txt: -------------------------------------------------------------------------------- 1 | //Creates a PIE chart showing the threat protection signature versions. 2 | 3 | ProtectionStatus 4 | | project DeviceName, ThreatStatus, TenantId, ProtectionStatus, SignatureVersion, ScanDate, ProtectionStatusDetails 5 | | summarize sig_count=count() by SignatureVersion 6 | | render piechart by sig_count 7 | -------------------------------------------------------------------------------- /SigninLogsByBrowserandLocation.txt: -------------------------------------------------------------------------------- 1 | SigninLogs 2 | | where AppDisplayName == "Microsoft Cloud App Security" 3 | | extend UserBrowser_ = tostring(DeviceDetail.browser) 4 | | extend UserOperatingSystem_ = tostring(DeviceDetail.operatingSystem) 5 | | extend UserCountryOrRegion_ = tostring(LocationDetails.countryOrRegion) 6 | | extend UserCity_ = tostring(LocationDetails.city) -------------------------------------------------------------------------------- /SigninLogsByDay - parsing UTC.txt: -------------------------------------------------------------------------------- 1 | //Sign-ins - how many per day - different ways to get the day split out 2 | 3 | SigninLogs 4 | | where AuthenticationRequirement == "multiFactorAuthentication" 5 | | summarize count() by bin(TimeGenerated, 1d) 6 | | extend myDAY = format_datetime(TimeGenerated, 'yyyy-MM-dd') //using datetime 7 | //| extend myDAY = format_datetime(TimeGenerated, 'dd') //using datetime, just the day 8 | //| extend myDAY = bin(TimeGenerated, 1d) //using bin, but still displays the time, too 9 | //| extend myDAY = split(TimeGenerated, "T", 0) //using split to parse 10 | | order by TimeGenerated asc 11 | | project myDAY, count_ 12 | -------------------------------------------------------------------------------- /SigninLogsNow.txt: -------------------------------------------------------------------------------- 1 | // 2 | 3 | 4 | SigninLogs 5 | | where TimeGenerated >= ago(24h) 6 | | where ResultType == 0 and UserPrincipalName !contains "yourdomainname" 7 | | project UserPrincipalName, AppDisplayName, IPAddress 8 | | summarize count() by UserPrincipalName, AppDisplayName, IPAddress 9 | | where count_ < 2 10 | -------------------------------------------------------------------------------- /SocGhoulish.kql: -------------------------------------------------------------------------------- 1 | //Detects SocGhoulish which does the following: 2 | //1. browsers spawning the Windows Scripting Host (wscript.exe) process 3 | //2. running the whoami command and redirecting the output to a file 4 | //3. domain trust discovery checks with nltest and related commands 5 | 6 | DeviceProcessEvents 7 | | where InitiatingProcessFileName in~ ("chrome.exe", "firefox.exe", "iexplore.exe", "edge.exe") and InitiatingProcessCommandLine has "wscript.exe" 8 | or InitiatingProcessCommandLine has "whoami" and InitiatingProcessCommandLine has ">" 9 | or InitiatingProcessCommandLine has "nltest" 10 | | project TimeGenerated, DeviceName, InitiatingProcessFileName, InitiatingProcessCommandLine 11 | -------------------------------------------------------------------------------- /Solarwinds_ServerU_Vuln.txt: -------------------------------------------------------------------------------- 1 | //Based on SolarWinds IOCs: https://www.solarwinds.com/trust-center/security-advisories/cve-2021-35211 2 | 3 | let SolarU_IPs = pack_array("98.176.196.89", "68.235.178.32", "208,113,35,58"); 4 | DeviceNetworkEvents 5 | | where TimeGenerated >= (7d) 6 | | where RemotePort == 443 7 | | where Protocol == "Tcp" and ActionType == "ConnectionSuccess" 8 | | where RemoteIP in(SolarU_IPs) 9 | -------------------------------------------------------------------------------- /SolutionDataUsage.txt: -------------------------------------------------------------------------------- 1 | //Monitoring data usage by solution. Produces a piechart 2 | 3 | Usage 4 | | where TimeGenerated > startofday(ago(31d)) 5 | | where IsBillable == true 6 | | summarize TotalVolumeGB = sum(Quantity) / 1000. by bin(TimeGenerated, 1d), Solution 7 | | sort by TotalVolumeGB desc 8 | | render piechart 9 | -------------------------------------------------------------------------------- /SophosDisabled.txt: -------------------------------------------------------------------------------- 1 | CommonSecurityLog 2 | | where DeviceVendor == "sophos" and LogSeverity == 8 and Activity !in ("Real time protection disabled") 3 | | sort by TimeGenerated 4 | | project TimeGenerated, Activity, DestinationHostName, SourceUserName, LogSeverity 5 | | extend HostCustomEntity = DestinationHostName 6 | | extend AccountCustomEntity = SourceUserName -------------------------------------------------------------------------------- /Sparkles.txt: -------------------------------------------------------------------------------- 1 | //Working with Emoji in queries. See https://cda.ms/3wh for Emoji code reference. 2 | 3 | let L=14; 4 | range x from 1 to L step 1 5 | | project t=make_string(10024, 10024, 10024, 10024, 10024, 10024, 10024, 10024, 10024, 10024, 10024, 10024, 10024, 10024, 10024, 10024, 10024, 10024, 10024, 10024, 10024, 10024, 10024, 10024, 10024, 10024, 10024, 10024, 10024, 10024, 10024, 10024, 10024, 10024, 10024, 10024, 10024, 10024, 10024, 10024, 10024, 10024, 10024) 6 | | summarize Sparkles=make_list(t) 7 | | project Sparkles=array_concat(pack_array(strcat(strrep(' ', L-1))), Sparkles) 8 | | project Happy_New_Year=strcat_array(Sparkles, '\n') 9 | -------------------------------------------------------------------------------- /StopPLCIoTDevice.txt: -------------------------------------------------------------------------------- 1 | //Stop PLC Command for an IoT device 2 | 3 | SecurityAlert 4 | | where TimeGenerated > ago(7d) 5 | | where AlertName == "An S7 Stop PLC Command was Sent" 6 | | extend SourceDeviceAddress_ = tostring(parse_json(ExtendedProperties).SourceDeviceAddress) 7 | | extend DestinationDeviceAddress_ = tostring(parse_json(ExtendedProperties).DestinationDeviceAddress) 8 | -------------------------------------------------------------------------------- /StoppedServices.kql: -------------------------------------------------------------------------------- 1 | //Stopped services 2 | 3 | SecurityEvent 4 | | where EventID == 7045 5 | | where EventData contains "stopped" 6 | | project TimeGenerated, Computer, EventData 7 | -------------------------------------------------------------------------------- /Strcat.kql: -------------------------------------------------------------------------------- 1 | Using KQL Strcat 2 | 3 | let new_URL = "domain.com"; 4 | SecurityIncident 5 | | where TimeGenerated >= ago(90d) 6 | | where Severity == 'High' 7 | | where Title has "Suspicious" 8 | | extend Updated_URL = strcat("https://portal.azure.com/", new_URL, "/", IncidentName) 9 | | project Updated_URL 10 | -------------------------------------------------------------------------------- /SubsCreatedPerHour.kql: -------------------------------------------------------------------------------- 1 | //Counts the number of subscription creation events per hour and returns a table with two columns: TimeGenerated and count_. 2 | 3 | 4 | AzureActivity 5 | | where OperationNameValue == "Microsoft.Resources/subscriptions/write" 6 | | summarize count() by bin(TimeGenerated, 1h) 7 | -------------------------------------------------------------------------------- /SuccessfulRoleAssignments.txt: -------------------------------------------------------------------------------- 1 | //Show the count of successful role assignments per user. 2 | 3 | AzureActivity 4 | | where TimeGenerated > ago(90d) and Authorization contains "Microsoft.Authorization/roleAssignments/write" and ActivityStatusValue == "Success" 5 | | parse ResourceId with * "/providers/" TargetResourceAuthProvider "/" * 6 | | summarize count(), makeset(Caller) by TargetResourceAuthProvider 7 | -------------------------------------------------------------------------------- /SuspicousARMActivites.txt: -------------------------------------------------------------------------------- 1 | //Suspicious ARM activies 2 | 3 | let threshold = 3; 4 | let newGuestAccounts = ( 5 | CloudAppEvents 6 | | where Timestamp > ago(7d) 7 | | where ActionType == "Add user." 8 | | where RawEventData.ResultStatus == "Success" 9 | | where RawEventData has "guest" and RawEventData.ObjectId has "#EXT#" 10 | | mv-expand Property = RawEventData.ModifiedProperties 11 | | where Property.Name == "AccountEnabled" and Property.NewValue has "true" 12 | | project newGuestAccountObjectId = tostring(RawEventData.Target[1].ID) 13 | | distinct newGuestAccountObjectId); 14 | CloudAppEvents 15 | | where Timestamp > ago(7d) 16 | | where isnotempty(toscalar(newGuestAccounts)) 17 | | where Application == "Microsoft Azure" 18 | | where ActionType == "Validate Deployments" 19 | | where RawEventData contains "createVm" 20 | | where AccountObjectId in (newGuestAccounts) 21 | | summarize VMCreationCount = count() by AccountObjectId 22 | | where VMCreationCount > threshold 23 | -------------------------------------------------------------------------------- /SysLogDaemon.txt: -------------------------------------------------------------------------------- 1 | //Syslog Daemon activity 2 | 3 | Syslog 4 | | where Facility == "daemon" 5 | | summarize count() by Computer, SourceSystem, Facility, ProcessName 6 | | sort by count_ desc 7 | -------------------------------------------------------------------------------- /SysmonAMA.txt: -------------------------------------------------------------------------------- 1 | //Computers using the AMA sending Sysmon data to Sentinel 2 | 3 | 4 | SecurityEvent 5 | | join Heartbeat on Computer 6 | | where TimeGenerated >= ago(1h) 7 | | where Category == "Azure Monitor Agent" 8 | | where EventSourceName == "Microsoft-Windows-Sysmon" 9 | | distinct Computer, Category, EventSourceName 10 | -------------------------------------------------------------------------------- /SysmonEventsStorageSize.txt: -------------------------------------------------------------------------------- 1 | //Sysmon Events by storage size by bytes 2 | 3 | Event 4 | | where Source == "Microsoft-Windows-Sysmon" 5 | | summarize count() by EventID 6 | | extend size_in_bytes = count_ * 500 7 | | order by size_in_bytes desc -------------------------------------------------------------------------------- /SystemRestoreDisabled.txt: -------------------------------------------------------------------------------- 1 | //Attempts to stop System Restore and prevent the system from creating restore point. Defender for Endpoint connected to Sentinel. 2 | 3 | DeviceProcessEvents 4 | | where InitiatingProcessFileName =~ 'rundll32.exe' 5 | and InitiatingProcessCommandLine !contains " " and InitiatingProcessCommandLine != "" 6 | and FileName in~ ('schtasks.exe') 7 | and ProcessCommandLine has 'Change' and ProcessCommandLine has 'SystemRestore' 8 | and ProcessCommandLine has 'disable' 9 | -------------------------------------------------------------------------------- /SystemsReportingtoSentinel.txt: -------------------------------------------------------------------------------- 1 | //Agented systems reporting to Azure Sentinel 2 | 3 | SigninLogs 4 | | union Heartbeat 5 | | where Category == "Direct Agent" 6 | | distinct Computer -------------------------------------------------------------------------------- /SystemthatHaveUpdatedintheLast4Hours.txt: -------------------------------------------------------------------------------- 1 | //Systems that have updated in the last 4 hours 2 | Update 3 | | where TimeGenerated < ago(4h) 4 | | where UpdateState != 'Installed' 5 | | extend Resource = Computer 6 | | summarize count() by Resource 7 | | sort by count_ desc -------------------------------------------------------------------------------- /TableData.kql: -------------------------------------------------------------------------------- 1 | //Produces results for Table Size, Number of Table Entries, Size per Entry, If the table is billable or not, Last record that was received, and Estimated Table Price 2 | 3 | 4 | union withsource=TableName1 * 5 | | where TimeGenerated > ago(31d) 6 | | summarize 7 | Entries = count(), 8 | Size = sum(_BilledSize), 9 | last_log = datetime_diff("second", now(), max(TimeGenerated)), 10 | estimate = sumif(_BilledSize, _IsBillable == true) 11 | by TableName1, _IsBillable 12 | | project 13 | ['Table Name'] = TableName1, 14 | ['Table Size'] = Size, 15 | ['Table Entries'] = Entries, 16 | ['Size per Entry'] = 1.0 * Size / Entries, 17 | ['IsBillable'] = _IsBillable, 18 | ['Last Record Received'] = last_log, 19 | ['Estimated Table Price'] = (estimate / (1024 * 1024 * 1024)) * 4.0 20 | | order by ['Table Size'] desc 21 | -------------------------------------------------------------------------------- /TableExistence.txt: -------------------------------------------------------------------------------- 1 | //Checking to see if a table (or tables) exist or not 2 | 3 | let hasNonEmptyTable = (T:string, T2:string) 4 | { 5 | toscalar( 6 | union isfuzzy=true 7 | ( table(T) | take 1 | count as Count ), 8 | ( table(T2) | take 1 | count as Count), 9 | (print Count=0) 10 | | summarize sum(Count) 11 | ) > 1 12 | }; 13 | let TableName = 'AzureActivity'; 14 | let TableName2 = 'SecurityEvent'; 15 | print IsPresent=iif(hasNonEmptyTable(TableName,TableName2 ), "present", "not present") 16 | -------------------------------------------------------------------------------- /TableUsageandCost.txt: -------------------------------------------------------------------------------- 1 | //Shows Tables by Table size and how much it costs 2 | //For the 0.0 - Enter your price (tip. Use the Azure Pricing Calculator, enter a value of 1GB and divide by 30days) 3 | 4 | union withsource=TableName1 * 5 | | where TimeGenerated > ago(30d) 6 | | summarize Entries = count(), Size = sum(_BilledSize), last_log = datetime_diff("second",now(), max(TimeGenerated)), estimate = sumif(_BilledSize, _IsBillable==true) by TableName1, _IsBillable 7 | | project ['Table Name'] = TableName1, ['Table Entries'] = Entries, ['Table Size'] = Size, 8 | ['Size per Entry'] = 1.0 * Size / Entries, ['IsBillable'] = _IsBillable, ['Last Record Received'] = last_log , ['Estimated Table Price'] = (estimate/(1024*1024*1024)) * 0.0 9 | | order by ['Table Size'] desc 10 | 11 | -------------------------------------------------------------------------------- /TablesNotIngestingDatain3Days.txt: -------------------------------------------------------------------------------- 1 | //Check all Tables to see which ones have not ingested data in 3 days or more 2 | 3 | union withsource=BadTable * 4 | | where TimeGenerated > ago(3d) 5 | | summarize Entries = count(), last_log = datetime_diff("second",now(), max(TimeGenerated)), estimate = sumif(_BilledSize, _IsBillable==true) by BadTable 6 | | where last_log >= 259200 7 | | project BadTable 8 | -------------------------------------------------------------------------------- /TeamsAADSigninsSuccessUnsuccess.txt: -------------------------------------------------------------------------------- 1 | //Tracking Teams sign-ins for successful/unsuccesful logins 2 | 3 | let timeFrame = 1d; 4 | let logonDiff = 10m; 5 | SigninLogs 6 | | where TimeGenerated >= ago(timeFrame) 7 | | where ResultType == "0" 8 | | where AppDisplayName startswith "Microsoft Teams" 9 | | project SuccessLogonTime = TimeGenerated, UserPrincipalName, SuccessIPAddress = IPAddress, AppDisplayName, SuccessIPBlock = strcat(split(IPAddress, ".")[0], ".", split(IPAddress, ".")[1]) 10 | | join kind= inner ( 11 | SigninLogs 12 | | where TimeGenerated >= ago(timeFrame) 13 | | where ResultType !in ("0", "50140") 14 | | where ResultDescription !~ "Other" 15 | | where AppDisplayName startswith "Microsoft Teams" 16 | | project FailedLogonTime = TimeGenerated, UserPrincipalName, FailedIPAddress = IPAddress, AppDisplayName, ResultType, ResultDescription 17 | ) on UserPrincipalName, AppDisplayName 18 | | where SuccessLogonTime < FailedLogonTime and FailedLogonTime - SuccessLogonTime <= logonDiff and FailedIPAddress !startswith SuccessIPBlock 19 | | summarize FailedLogonTime = max(FailedLogonTime), SuccessLogonTime = max(SuccessLogonTime) by UserPrincipalName, SuccessIPAddress, AppDisplayName, FailedIPAddress, ResultType, ResultDescription 20 | | extend timestamp = SuccessLogonTime, AccountCustomEntity = UserPrincipalName, IPCustomEntity = SuccessIPAddress -------------------------------------------------------------------------------- /TeamsBotsorAppsAdded.txt: -------------------------------------------------------------------------------- 1 | //Hunt for apps or bots that are new to Teams 2 | 3 | // If you have more than 14 days worth of Teams data change this value 4 | let data_date = 14d; 5 | let historical_bots = ( 6 | TeamsData 7 | | where TimeGenerated > ago(data_date) 8 | | where isnotempty(AddOnName) 9 | | project AddOnName); 10 | OfficeActivity 11 | | where TimeGenerated > ago(1d) 12 | // Look for add-ins we have never seen before 13 | | where AddOnName in (historical_bots) 14 | // Uncomment the following line to map query entities is you plan to use this as a detection query 15 | //| extend timestamp = TimeGenerated, AccountCustomEntity = UserId -------------------------------------------------------------------------------- /TeamsChannelDeleted.txt: -------------------------------------------------------------------------------- 1 | //When a Microsoft Teams channel is deleted 2 | 3 | OfficeActivity 4 | | where RecordType == "MicrosoftTeams" 5 | | where Operation == "ChannelDeleted" 6 | -------------------------------------------------------------------------------- /TeamsExternalRareUserAccess.txt: -------------------------------------------------------------------------------- 1 | //External users added to teams who come from organizations that haven't been seen or added before 2 | 3 | // If you have more than 14 days worth of Teams data change this value 4 | let data_date = 14d; 5 | // If you want to look at users further back than the last day change this value 6 | let lookback_data = 1d; 7 | let known_orgs = ( 8 | OfficeActivity 9 | | where TimeGenerated > ago(data_date) 10 | | where Operation =~ "MemberAdded" or Operation =~ "TeamsSessionStarted" 11 | // Extract the correct UPN and parse our external organization domain 12 | | extend UPN = iif(Operation == "MemberAdded", tostring(parse_json(Members)[0].UPN), UserId) 13 | | extend Organization = tostring(split(split(UPN, "_")[1], "#")[0]) 14 | | where isnotempty(Organization) 15 | | summarize by Organization); 16 | OfficeActivity 17 | | where TimeGenerated > ago(lookback_data) 18 | | where Operation =~ "MemberAdded" 19 | | extend UPN = tostring(parse_json(Members)[0].UPN) 20 | | extend Organization = tostring(split(split(UPN, "_")[1], "#")[0]) 21 | | where isnotempty(Organization) 22 | | where Organization !in (known_orgs) 23 | // Uncomment the following line to map query entities is you plan to use this as a detection query 24 | //| extend timestamp = TimeGenerated, AccountCustomEntity = UPN -------------------------------------------------------------------------------- /TeamsExternalSuspiciousAccountsRevokedAccess.txt: -------------------------------------------------------------------------------- 1 | //Hunt for external accounts that are added to Teams and swiftly removed to help identify suspicious behavior 2 | 3 | // If you want to look at user added further than 7 days ago adjust this value 4 | let time_ago = 7d; 5 | // If you want to change the timeframe of how quickly accounts need to be added and removed change this value 6 | let time_delta = 1h; 7 | OfficeActivity 8 | | where TimeGenerated > ago(time_ago) 9 | | where Operation =~ "MemberAdded" 10 | | extend UPN = tostring(parse_json(Members)[0].UPN) 11 | | project TimeAdded=TimeGenerated, Operation, UPN, UserWhoAdded = UserId, TeamName, TeamGuid = tostring(Details.TeamGuid) 12 | | join ( 13 | OfficeActivity 14 | | where TimeGenerated > ago(time_ago) 15 | | where Operation =~ "MemberRemoved" 16 | | extend UPN = tostring(parse_json(Members)[0].UPN) 17 | | project TimeDeleted=TimeGenerated, Operation, UPN, UserWhoDeleted = UserId, TeamName, TeamGuid = tostring(Details.TeamGuid)) on UPN, TeamGuid 18 | | where TimeDeleted < (TimeAdded + time_delta) 19 | | project TimeAdded, TimeDeleted, UPN, UserWhoAdded, UserWhoDeleted, TeamName, TeamGuid 20 | // Uncomment the following line to map query entities is you plan to use this as a detection query 21 | //| extend timestamp = TimeAdded, AccountCustomEntity = UPN -------------------------------------------------------------------------------- /TeamsKQL.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rod-trent/SentinelKQL/f0569a91c2b5ed823e6253b7ec7cf3d3638621c3/TeamsKQL.zip -------------------------------------------------------------------------------- /TeamsListFederatedUsers.txt: -------------------------------------------------------------------------------- 1 | //List of Teams sites that have federated external users 2 | 3 | OfficeActivity 4 | | where TimeGenerated > ago(7d) 5 | | where Operation =~ "MemberAdded" 6 | | extend UPN = tostring(parse_json(Members)[0].Upn) 7 | | where UPN !endswith "sixmilliondollarman.onmicrosoft.com" 8 | | where parse_json(Members)[0].Role == 3 9 | | project TeamName, Operation, UserId, Members, UPN -------------------------------------------------------------------------------- /TeamsSingleUsersDeleteMultipleTeams.txt: -------------------------------------------------------------------------------- 1 | //Single users who delete multiple teams 2 | 3 | // Adjust this value to change how many Teams should be deleted before including 4 | let max_delete = 3; 5 | // Adjust this value to change the timewindow the query runs over 6 | let time_window = 1d; 7 | let deleting_users = ( 8 | OfficeActivity 9 | | where TimeGenerated > ago(time_window) 10 | | where Operation =~ "TeamDeleted" 11 | | summarize count() by UserId 12 | | where count_ > max_delete 13 | | project UserId); 14 | OfficeActivity 15 | | where TimeGenerated > ago(time_window) 16 | | where Operation =~ "TeamDeleted" 17 | | where UserId in (deleting_users) 18 | | extend TeamGuid = tostring(Details.TeamGuid) 19 | | project-away AddOnName, Members, Settings 20 | // Uncomment the following line to map query entities is you plan to use this as a detection query 21 | //| extend timestamp = TimeGenerated, AccountCustomEntity = UserId -------------------------------------------------------------------------------- /TeamsSuspiciousElevationofPrivileges.txt: -------------------------------------------------------------------------------- 1 | //Suspicious behaviour related to elevation of Teams privileges 2 | 3 | // Adjust this value to change how many teams a user is made owner of before detecting 4 | let max_owner_count = 3; 5 | // Change this value to adjust how larger timeframe the query is run over. 6 | let time_window = 1d; 7 | let high_owner_count = (OfficeActivity 8 | | where TimeGenerated > ago(time_window) 9 | | where Operation =~ "MemberRoleChanged" 10 | | extend Member = tostring(parse_json(Members)[0].UPN) 11 | | extend NewRole = toint(parse_json(Members)[0].Role) 12 | | where NewRole == 2 13 | | summarize dcount(TeamName) by Member 14 | | where dcount_TeamName > max_owner_count 15 | | project Member); 16 | OfficeActivity 17 | | where TimeGenerated > ago(time_window) 18 | | where Operation =~ "MemberRoleChanged" 19 | | extend Member = tostring(parse_json(Members)[0].UPN) 20 | | extend NewRole = toint(parse_json(Members)[0].Role) 21 | | where NewRole == 2 22 | | where Member in (high_owner_count) 23 | | extend TeamGuid = tostring(Details.TeamGuid) 24 | // Uncomment the following line to map query entities is you plan to use this as a detection query 25 | //| extend timestamp = TimeGenerated, AccountCustomEntity = Member -------------------------------------------------------------------------------- /TeamsUserAddedtoTeamsChannel.txt: -------------------------------------------------------------------------------- 1 | //Query a specific user to check if they were added to a Teams channel in the last 7 days 2 | 3 | OfficeActivity 4 | | where TimeGenerated > ago(7d) 5 | | where Operation =~ "MemberAdded" 6 | | where Members contains "UserName" -------------------------------------------------------------------------------- /TeamsWasUserRoleChanged.txt: -------------------------------------------------------------------------------- 1 | //Was a user's role changed for a Team in the last 7 days 2 | 3 | OfficeActivity 4 | | where TimeGenerated > ago(7d) 5 | | where Operation =~ "MemberRoleChanged" 6 | | where Members contains "Role" and Members contains "1" -------------------------------------------------------------------------------- /ThreatIntelBag.kql: -------------------------------------------------------------------------------- 1 | //Snippet of KQL query to create a bag of TI to reference later in the query 2 | 3 | let TI_Bag = ThreatIntelligenceIndicator | where isnotempty(NetworkSourceIP) | project NetworkSourceIP; 4 | -------------------------------------------------------------------------------- /ThreatIntelligenceTableCosts.txt: -------------------------------------------------------------------------------- 1 | //The cost of the Threat Intelligence table is nominal, but this query will show costs per month. 2 | 3 | Usage 4 | | where DataType == "ThreatIntelligenceIndicator" 5 | | where TimeGenerated > ago(90d) 6 | | summarize BillableDataGB = sum(Quantity) / 1000. by Year = tostring(bin(datepart("Year", TimeGenerated), 1)), Month = bin(datepart("Month", TimeGenerated), 1) 7 | | sort by Year, Month asc 8 | -------------------------------------------------------------------------------- /ThreatStatus.txt: -------------------------------------------------------------------------------- 1 | //Starting to develop a SOC "Threat Score." Based on Number of open Incidents + Numerical values for Status + Numerical values for Severity. A work in progress. 2 | 3 | SecurityIncident 4 | | where Status != "Closed" 5 | | summarize count() by Severity, Status 6 | -------------------------------------------------------------------------------- /TieFighter.txt: -------------------------------------------------------------------------------- 1 | //KQL query to display a Tie Figther (from Star Wars) 2 | 3 | let line1 = datatable (name: string) 4 | [ 5 | " ✨ ✨ ✨ ✨" 6 | ]; 7 | let line2 = datatable (name: string) 8 | [ 9 | " ✨ ✨ ✨ ✨ ✨" 10 | ]; 11 | let line3 = datatable (name: string) 12 | [ 13 | " ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ " 14 | ]; 15 | let line4 = datatable (name: string) 16 | [ 17 | " ✨ ✨ ✨ ✨ ✨" 18 | ]; 19 | let line5 = datatable (name: string) 20 | [ 21 | " ✨ ✨ ✨ ✨" 22 | ]; 23 | line1 24 | | union line2, line3, line4, line5 25 | | summarize mylist = make_list(name) 26 | | project May_the_Force_be_with_you=strcat_array(mylist, '\n') 27 | 28 | -------------------------------------------------------------------------------- /TimeBetweenDates.txt: -------------------------------------------------------------------------------- 1 | SecurityEvent 2 | | where TimeGenerated between(datetime("2020-04-01 22:46:42") .. datetime("2020-04-30 00:57:27")) -------------------------------------------------------------------------------- /TimeRangeExample.txt: -------------------------------------------------------------------------------- 1 | //Example of setting time range between two values 2 | 3 | let StartTime=ago(24h); 4 | let StopTime=now(); 5 | SecurityEvent 6 | | where TimeGenerated >StartTime and TimeGenerated <=StopTime 7 | -------------------------------------------------------------------------------- /TooManyRecipients.kql: -------------------------------------------------------------------------------- 1 | //Identify emails sent to more than 100 recipients 2 | 3 | EmailEvents 4 | | where array_length(split(RecipientEmailAddress, ",")) > 100 5 | | project Timestamp, NetworkMessageId, SenderMailFromAddress, RecipientEmailAddress, Subject 6 | -------------------------------------------------------------------------------- /Top N by Group example via top-nested - option 2.txt: -------------------------------------------------------------------------------- 1 | let SampleUserData=datatable (UserId:int, OperationDate:datetime) 2 | [1, datetime(2018-01-01 12:30:00), 3 | 1, datetime(2018-01-01 13:30:00), 4 | 2, datetime(2018-01-02 12:30:00), 5 | 2, datetime(2018-01-03 13:30:00), 6 | 3, datetime(2018-01-02 12:30:00), 7 | 3, datetime(2018-01-01 12:30:00), 8 | 3, datetime(2018-02-02 13:30:00), 9 | 1, datetime(2018-02-02 12:30:00), 10 | 1, datetime(2018-02-03 12:30:00), 11 | 3, datetime(2018-03-01 12:30:00), 12 | 3, datetime(2018-03-02 12:30:00), 13 | 2, datetime(2018-03-02 12:30:00), 14 | 1, datetime(2018-03-03 11:30:00), 15 | 1, datetime(2018-03-03 12:30:00), 16 | 1, datetime(2018-03-03 13:30:00) 17 | ]; 18 | let SampleUserData2 = 19 | SampleUserData 20 | | extend MonthNum = datetime_part("Month", OperationDate); 21 | SampleUserData2 22 | | top-nested toscalar(SampleUserData2 | summarize dcount(MonthNum)) of MonthNum by max(1), top-nested 2 of UserId by count() 23 | -------------------------------------------------------------------------------- /Top N by group example via LAG - option 1.txt: -------------------------------------------------------------------------------- 1 | let SampleUserData=datatable (UserId:int, OperationDate:datetime) 2 | [1, datetime(2018-01-01 12:30:00), 3 | 1, datetime(2018-01-01 13:30:00), 4 | 2, datetime(2018-01-02 12:30:00), 5 | 2, datetime(2018-01-03 13:30:00), 6 | 3, datetime(2018-01-02 12:30:00), 7 | 3, datetime(2018-01-01 12:30:00), 8 | 3, datetime(2018-02-02 13:30:00), 9 | 1, datetime(2018-02-02 12:30:00), 10 | 1, datetime(2018-02-03 12:30:00), 11 | 3, datetime(2018-03-01 12:30:00), 12 | 3, datetime(2018-03-02 12:30:00), 13 | 2, datetime(2018-03-02 12:30:00), 14 | 1, datetime(2018-03-03 11:30:00), 15 | 1, datetime(2018-03-03 12:30:00), 16 | 1, datetime(2018-03-03 13:30:00) 17 | ]; 18 | SampleUserData 19 | | extend MonthNum = datetime_part("Month", OperationDate) 20 | | summarize CountByMonthNumUserId = count() by MonthNum,UserId 21 | | order by MonthNum asc, UserId asc, CountByMonthNumUserId desc 22 | | extend RowNum = row_number(1, prev(MonthNum) != MonthNum) 23 | | extend CountIsSameAsPrev = CountByMonthNumUserId == prev(CountByMonthNumUserId) 24 | | where RowNum in (1,2) or CountIsSameAsPrev 25 | | project-away RowNum, CountIsSameAsPrev 26 | -------------------------------------------------------------------------------- /TotalIncidentsInLast6Months.txt: -------------------------------------------------------------------------------- 1 | //Total incidents generated each month for the last 6 months 2 | 3 | SecurityIncident 4 | | where TimeGenerated between(startofmonth(now(),-7) ..endofmonth(endofmonth(now(),-1)) ) 5 | | extend yy = datepart("Year", TimeGenerated) 6 | | extend mm = datepart("Month", TimeGenerated) 7 | | summarize count() by month=bin(datepart("Month", TimeGenerated), 1), tostring(yy), mm 8 | | extend month = case(month==1,strcat('Jan/',yy),month==2,strcat('Feb/',yy),month==3, strcat('Mar/',yy),month==4,strcat('Apr/',yy),month==5,strcat('May/',yy),month==6,strcat('Jun/',yy),month==7, strcat('Jul/',yy),month==8,strcat('Aug/',yy),month==9,strcat('Sep/',yy),month==10,strcat('Oct/',yy),month==11,strcat('Nov/',yy),month==12,strcat('Dec/',yy),"error") 9 | | order by yy asc, mm asc 10 | | project-away yy,mm 11 | | render columnchart title='Incident by Month' 12 | -------------------------------------------------------------------------------- /TrendofRequests.txt: -------------------------------------------------------------------------------- 1 | //Example shows the trend of requests to an app over the previous days 2 | 3 | OfficeActivity 4 | | make-series Requests = count() default = 0 on TimeGenerated from ago(1d) to now() step 1h 5 | -------------------------------------------------------------------------------- /TrialExpiration.txt: -------------------------------------------------------------------------------- 1 | //This query reports on the end date and how many days left for the Sentinel 31-day trail. Modify "TrialTest" with your Log Analytics Workspace name. 2 | //One use case: You can use this in a Playbook to receive an email reminder every day of how many trial days are left. 3 | 4 | 5 | let workspace = "TrialTest"; 6 | let Trial = 31d; 7 | AzureActivity 8 | | where TimeGenerated >= ago(90d) 9 | | where OperationNameValue == "MICROSOFT.RESOURCES/DEPLOYMENTS/WRITE" 10 | | where ActivitySubstatusValue == "Created" 11 | | where Authorization contains workspace 12 | | extend End_Date = TimeGenerated + Trial 13 | | extend Date_Created = TimeGenerated 14 | | extend Created_By = Caller 15 | | project workspace, Date_Created, End_Date, Days_Left = End_Date - Date_Created, Created_By 16 | -------------------------------------------------------------------------------- /UEBACosts.txt: -------------------------------------------------------------------------------- 1 | union withsource=TableName1 * 2 | | where TimeGenerated > ago(30d) //In the last 30 days 3 | | summarize Entries = count(), Size = sumif(_BilledSize, _IsBillable == true), last_log = datetime_diff("second", now(), max(TimeGenerated)), estimate = sumif(_BilledSize, _IsBillable == true) by TableName1, _IsBillable 4 | | project ['Table Name'] = TableName1, ['Table Size'] = Size, ['% of Total GiB'] = (Size / (1024 * 1024 * 1024)) / 10.04 * 100, ['IsBillable'] = _IsBillable, ['Last Record Received'] = last_log, ['Estimated Table Price'] = (estimate / (1024 * 1024 * 1024)) * 4.0 //Cost may be different. Then, alter the 4.0 5 | | where ['Table Name'] == "BehaviorAnalytics" or ['Table Name'] == "IdentityInfo" or ['Table Name'] == "UserAccessAnalytics" or ['Table Name'] == "UserPeerAnalytics" //The four data tables utilized by UEBA 6 | | serialize TotalCost=row_cumsum(['Estimated Table Price']) //This starts at the bottom result row and adds all table prices for a final TotalCost value at the top 7 | | order by ['Table Size'] desc 8 | -------------------------------------------------------------------------------- /UEBAEstimate.kql: -------------------------------------------------------------------------------- 1 | //UEBA Estimation for enabling SigninLogs 2 | 3 | SigninLogs //Data Source 4 | | where TimeGenerated > ago(30d) 5 | | where _IsBillable == true 6 | | summarize sum(_BilledSize) 7 | | extend TotalGB = sum__BilledSize / 1024 8 | | extend UEBAGB = 0.07*TotalGB 9 | | project UEBAGB 10 | -------------------------------------------------------------------------------- /UEBA_IsDormant.txt: -------------------------------------------------------------------------------- 1 | //This KQL query uses the UEBA data enrichment values to show Dormant user accounts. 2 | //See the following for the explanation: https://azurecloudai.blog/2021/06/07/how-to-use-the-ueba-enrichments-in-azure-sentinel/ 3 | 4 | BehaviorAnalytics 5 | | where UsersInsights.IsDormantAccount == true 6 | | project TimeGenerated, UserName, ActionType 7 | -------------------------------------------------------------------------------- /URLDetonation/Azure_Sentinel_analytic_rule - URL Detonation.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "workspace": { 6 | "type": "String" 7 | } 8 | }, 9 | "resources": [ 10 | { 11 | "id": "[concat(resourceId('Microsoft.OperationalInsights/workspaces/providers', parameters('workspace'), 'Microsoft.SecurityInsights'),'/alertRules/eccf97a5-2205-41f3-8861-bcbdc9dd09cf')]", 12 | "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/eccf97a5-2205-41f3-8861-bcbdc9dd09cf')]", 13 | "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules", 14 | "kind": "Scheduled", 15 | "apiVersion": "2022-10-01-preview", 16 | "properties": { 17 | "displayName": "URL Detonation Demo", 18 | "description": "URL Detonation Demo", 19 | "severity": "Informational", 20 | "enabled": true, 21 | "query": "_GetWatchlist('URLs2Detonate')", 22 | "queryFrequency": "P1D", 23 | "queryPeriod": "P1D", 24 | "triggerOperator": "GreaterThan", 25 | "triggerThreshold": 0, 26 | "suppressionDuration": "PT5H", 27 | "suppressionEnabled": false, 28 | "tactics": [], 29 | "techniques": [], 30 | "alertRuleTemplateName": null, 31 | "incidentConfiguration": { 32 | "createIncident": true, 33 | "groupingConfiguration": { 34 | "enabled": false, 35 | "reopenClosedIncident": false, 36 | "lookbackDuration": "PT5H", 37 | "matchingMethod": "AllEntities", 38 | "groupByEntities": [], 39 | "groupByAlertDetails": [], 40 | "groupByCustomDetails": [] 41 | } 42 | }, 43 | "eventGroupingSettings": { 44 | "aggregationKind": "SingleAlert" 45 | }, 46 | "alertDetailsOverride": null, 47 | "customDetails": null, 48 | "entityMappings": [ 49 | { 50 | "entityType": "URL", 51 | "fieldMappings": [ 52 | { 53 | "identifier": "Url", 54 | "columnName": "URLs2Detonate" 55 | } 56 | ] 57 | } 58 | ], 59 | "sentinelEntitiesMappings": null 60 | } 61 | } 62 | ] 63 | } 64 | -------------------------------------------------------------------------------- /URLDetonation/URLDetonate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rod-trent/SentinelKQL/f0569a91c2b5ed823e6253b7ec7cf3d3638621c3/URLDetonation/URLDetonate.png -------------------------------------------------------------------------------- /URLDetonation/URLsWatchlist.csv: -------------------------------------------------------------------------------- 1 | SearchKey,URLs2Detonate 2 | "https://www.bing.com","https://www.bing.com" 3 | "https://www.msn.com/","https://www.msn.com/" 4 | "http://hmpg.net/","http://hmpg.net/" 5 | "https://bing.com","https://bing.com" 6 | "https://www.bing.com/","https://www.bing.com/" 7 | "http://omgitstehhax0rz.com/","http://omgitstehhax0rz.com/" 8 | "https://msn.com","https://msn.com" 9 | -------------------------------------------------------------------------------- /USB_Copy_7_days.kql: -------------------------------------------------------------------------------- 1 | DeviceFileEvents 2 | | where ActionType in ("FileCreated", "FileModified") 3 | | where FolderPath startswith "D:\\" 4 | | where Timestamp > ago(7d) 5 | | project Timestamp, DeviceId, DeviceName, FileName, FolderPath 6 | -------------------------------------------------------------------------------- /UnsuccessfulRulesinLast24.txt: -------------------------------------------------------------------------------- 1 | //Sentinel Health must be enabled (https://cda.ms/3Fd), but this shows rules that have not executed successfully in the last 24 hours and how many times it failed. 2 | 3 | //General query version to show Analytics Rules not firing or not firing completely (partial success) 4 | SentinelHealth 5 | | where TimeGenerated >= ago(1d) 6 | | where OperationName == "Scheduled analytics rule run" 7 | | where Status != "Success" 8 | | distinct SentinelResourceName 9 | | summarize count() by SentinelResourceName 10 | 11 | 12 | //Analytics Rule version to show partial success. See: https://urlcoming 13 | SentinelHealth 14 | | where TimeGenerated >= ago(1d) 15 | | where OperationName == "Scheduled analytics rule run" 16 | | where Status != "Success" 17 | 18 | 19 | //Analytics Rule version to show complete failure. See: https://urlcoming 20 | SentinelHealth 21 | | where TimeGenerated >= ago(1d) 22 | | where OperationName == "Scheduled analytics rule run" 23 | | where Status == "Failure" 24 | -------------------------------------------------------------------------------- /UpdateComplianceBarChart.txt: -------------------------------------------------------------------------------- 1 | //Update Compliance with Barchart 2 | 3 | Update 4 | | join UpdateSummary on Computer 5 | | where UpdateState != 'Installed' 6 | | extend Resource = Computer 7 | | extend IsUpdateNeeded = UpdateState 8 | | extend UpdateTitle = Title 9 | | extend UpdateType = Classification 10 | | extend KB = KBID 11 | | distinct Computer, OsVersion, UpdateState, Title, Classification, KBID 12 | | sort by Computer asc 13 | | summarize count() by Computer 14 | | render barchart 15 | -------------------------------------------------------------------------------- /UpdateDataConnectors.txt: -------------------------------------------------------------------------------- 1 | AzureActivity 2 | | where OperationName == "Update Data Connectors" and ActivityStatus == "Succeeded" 3 | | project Caller , CallerIpAddress, EventSubmissionTimestamp -------------------------------------------------------------------------------- /UseCases_by_MITRE.kql: -------------------------------------------------------------------------------- 1 | //Shows Sentinel use cases count by MITRE tactics. 2 | 3 | Anomalies 4 | | extend tactics = split(Tactics, ",") 5 | | mv-expand tactics 6 | | summarize UseCasesCount = count() by tostring(tactics) 7 | | order by UseCasesCount desc 8 | -------------------------------------------------------------------------------- /UserAccountLockedAAD.txt: -------------------------------------------------------------------------------- 1 | SigninLogs 2 | | where TimeGenerated > ago(4h) 3 | | where ResultType == "50053" 4 | | project UserDisplayName -------------------------------------------------------------------------------- /Usergrantedaccesstoanapp.txt: -------------------------------------------------------------------------------- 1 | //Alert - User granted access to an app 2 | SecurityAlert 3 | | where SystemAlertId == "2032d776-50b6-16ca-dcd1-15d79414e3f4" 4 | | summarize arg_max(TimeGenerated, *) by SystemAlertId 5 | -------------------------------------------------------------------------------- /UsersConnectFromMultipleCity.txt: -------------------------------------------------------------------------------- 1 | //Reports users who have connected from more than 1 location 2 | 3 | AADNonInteractiveUserSignInLogs 4 | | where TimeGenerated > ago(1d) 5 | | extend City = parse_json(LocationDetails).city 6 | | summarize CountPerCity = dcount(tostring(City)) by UserPrincipalName 7 | | where CountPerCity > 2 8 | | order by CountPerCity desc 9 | -------------------------------------------------------------------------------- /UsersIPsPorts.txt: -------------------------------------------------------------------------------- 1 | //Shows users, IPs, and ports used 2 | 3 | let timeframe = 7d; //Setting the time frame variable to look at 7 days of data 4 | SecurityEvent //the table 5 | | where TimeGenerated >= ago(timeframe) //applying the timeframe variable 6 | | where isnotempty(SubjectUserName) //making sure we return actual data, not blank fields 7 | | where SubjectUserName != "-" and IpAddress != "-" and IpPort != "-" //eliminating the dash character from results 8 | | where isnotempty(IpAddress) //making sure we return actual data, not blank fields 9 | | where isnotempty(IpPort) //making sure we return actual data, not blank fields 10 | | distinct SubjectUserName, IpAddress, IpPort //showing distinct records 11 | -------------------------------------------------------------------------------- /WatchListAudit.txt: -------------------------------------------------------------------------------- 1 | //Here's where to find auditing for Microsoft Sentinel Watchlists 2 | 3 | AzureActivity 4 | | where TimeGenerated > ago(90d) 5 | | where OperationNameValue has "MICROSOFT.SECURITYINSIGHTS/WATCHLISTS/" 6 | 7 | 8 | //Get the actual Watchlist name 9 | 10 | AzureActivity 11 | | where TimeGenerated > ago(90d) 12 | | where OperationNameValue has "MICROSOFT.SECURITYINSIGHTS/WATCHLISTS/" 13 | | extend resource_ = tostring(parse_json(Properties).resource) 14 | -------------------------------------------------------------------------------- /WatchListDelete.txt: -------------------------------------------------------------------------------- 1 | //When was a Watchlist deleted and who deleted it 2 | 3 | AzureActivity 4 | | where OperationNameValue == "MICROSOFT.SECURITYINSIGHTS/WATCHLISTS/DELETE" 5 | | project TimeGenerated, Caller, CallerIpAddress 6 | -------------------------------------------------------------------------------- /WatchlistNOTin.txt: -------------------------------------------------------------------------------- 1 | //Just a simple KQL query to use as a template to use a Watchlist to show where something is NOT in the Watchlist 2 | 3 | let watchlist = _GetWatchlist("Your Watchlist Alias") 4 | | project IP; 5 | let timeframe = 1d; 6 | let threshold = 15; 7 | TableName 8 | | where TimeGenerated >= ago(timeframe) 9 | | where ip !in (watchlist) 10 | | project user, ip, port, SyslogMessage, EventTime -------------------------------------------------------------------------------- /Watchlist_Basics: -------------------------------------------------------------------------------- 1 | //Watchlist as a variable, where the requested data is in the list 2 | let watchlist = (_GetWatchlist('FeodoTracker') | project DstIP); 3 | Heartbeat 4 | | where ComputerIP in (watchlist) 5 | 6 | //Watchlist as a variable, where the requested data is not in the list 7 | let watchlist = (_GetWatchlist('FeodoTracker') | project DstIP); 8 | Heartbeat 9 | | where ComputerIP !in (watchlist) 10 | 11 | 12 | //Watchlist inline with the query, where the requested data is in the list 13 | Heartbeat 14 | | where ComputerIP in ( 15 | (_GetWatchlist('FeodoTracker') 16 | | project DstIP) 17 | ) 18 | 19 | //Watchlist inline with the query, where the requested data is not in the list 20 | Heartbeat 21 | | where ComputerIP !in ( 22 | (_GetWatchlist('FeodoTracker') 23 | | project DstIP) 24 | ) 25 | -------------------------------------------------------------------------------- /Watchlist_Item_Delete.kql: -------------------------------------------------------------------------------- 1 | // Identifies when an item was deleted from any Watchlist 2 | 3 | Watchlist 4 | | where _DTItemStatus == "Delete" 5 | -------------------------------------------------------------------------------- /WatchlistsCosts.txt: -------------------------------------------------------------------------------- 1 | //Query to show cost of each Microsoft Sentinel Watchlist. Watchlist costs come directly from ingestion. 2 | 3 | Usage 4 | | where StartTime >= startofday(ago(365d)) and EndTime < startofday(now()) 5 | | where IsBillable == true 6 | | where DataType == "Watchlist" 7 | | summarize BillableDataGB = sum(Quantity) / 1000. by bin(StartTime, 1d), DataType 8 | -------------------------------------------------------------------------------- /WebshellPosts.txt: -------------------------------------------------------------------------------- 1 | //Looking for suspicious posts 2 | 3 | W3CIISLog 4 | | where csUriStem == "/autodiscover/autodiscover.json" 5 | | where csUriQuery has "PowerShell" | where csMethod == "POST" 6 | -------------------------------------------------------------------------------- /WhenUEBAwasEnabledByWho.txt: -------------------------------------------------------------------------------- 1 | //When UEBA was enabled and by who 2 | 3 | AzureActivity 4 | | where Properties_d has "microsoft.securityinsights/ueba" 5 | | extend WhoDidIt = Caller 6 | | project WhoDidIt, CallerIpAddress, EventSubmissionTimestamp 7 | -------------------------------------------------------------------------------- /WhiteList-FindWhoAccessedAzureSentinelthatShouldNot.txt: -------------------------------------------------------------------------------- 1 | //Create a whitelist of users who should be able to access Azure Sentinel, then check to see if unauthorized users have performed activities. 2 | //Replace the users in the variable for AuthorizedUser with authorized accounts. Authorized account format is gleaned from AzureActivity/Caller 3 | let List = datatable(AuthorizedUser: string)["user1@domain.com", "user2@domain.com", "user3@domain.com"]; 4 | let timeframe = 1d; 5 | AzureActivity 6 | | where OperationNameValue has "MICROSOFT.SECURITYINSIGHTS" 7 | | where ActivityStatusValue == "Success" 8 | | where CategoryValue == "Administrative" 9 | | join kind= leftanti ( 10 | List 11 | | project Caller = tolower(AuthorizedUser) 12 | ) 13 | on Caller 14 | | extend AccountCustomEntity = Caller 15 | | extend IPCustomEntity = CallerIpAddress 16 | -------------------------------------------------------------------------------- /WhoChangedConditionalAccessPolicy.txt: -------------------------------------------------------------------------------- 1 | //Reporting when a Conditional Access Policy is updated and who did it 2 | 3 | AuditLogs 4 | | where OperationName == "Update policy" 5 | | extend Person = tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName) 6 | | project Person -------------------------------------------------------------------------------- /WhoChangedTheirAADPassword.txt: -------------------------------------------------------------------------------- 1 | AuditLogs 2 | | where OperationName contains "self-service" 3 | | where Result == "success" 4 | | extend userPrincipalName_ = tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName) 5 | | project userPrincipalName_ 6 | -------------------------------------------------------------------------------- /WhoDeletedAlertRule.txt: -------------------------------------------------------------------------------- 1 | AzureActivity 2 | | where OperationName == "Delete Alert Rules" and ActivityStatusValue == "Succeeded" 3 | | project Caller , EventSubmissionTimestamp -------------------------------------------------------------------------------- /WhoModifiedAnalyticsRule.txt: -------------------------------------------------------------------------------- 1 | //Standard query 2 | 3 | AzureActivity 4 | | where OperationNameValue contains "MICROSOFT.SECURITYINSIGHTS/ALERTRULES/WRITE" 5 | | where ActivityStatusValue == "Success" 6 | | extend Analytics_Rule_ID = tostring(parse_json(Properties).resource) 7 | | project TimeGenerated , CallerIpAddress , Caller , Analytics_Rule_ID 8 | 9 | //Analytics Rule 10 | 11 | AzureActivity 12 | | where OperationNameValue contains "MICROSOFT.SECURITYINSIGHTS/ALERTRULES/WRITE" 13 | | where ActivityStatusValue == "Success" 14 | | extend Analytics_Rule_ID = tostring(parse_json(Properties).resource) 15 | | extend AccountCustomEntity = Caller 16 | | extend IPCustomEntity = CallerIpAddress 17 | -------------------------------------------------------------------------------- /Windows10LoggedInLast7Days.txt: -------------------------------------------------------------------------------- 1 | //Shows the Windows 10 computers that have logged in over the last 7 days 2 | 3 | let nonInteractive = AADNonInteractiveUserSignInLogs | extend LocationDetails = parse_json(LocationDetails), Status = parse_json(Status), DeviceDetail = parse_json(DeviceDetail); 4 | union SigninLogs,nonInteractive 5 | | extend errorCode = Status.errorCode 6 | | extend SigninStatus = case(errorCode == 0, "Success", errorCode == 50058, "Pending user action", errorCode == 50140, "Pending user action", errorCode == 51006, "Pending user action", errorCode == 50059, "Pending user action", errorCode == 65001, "Pending user action", errorCode == 52004, "Pending user action", errorCode == 50055, "Pending user action", errorCode == 50144, "Pending user action", errorCode == 50072, "Pending user action", errorCode == 50074, "Pending user action", errorCode == 16000, "Pending user action", errorCode == 16001, "Pending user action", errorCode == 16003, "Pending user action", errorCode == 50127, "Pending user action", errorCode == 50125, "Pending user action", errorCode == 50129, "Pending user action", errorCode == 50143, "Pending user action", errorCode == 81010, "Pending user action", errorCode == 81014, "Pending user action", errorCode == 81012, "Pending user action", "Failure") 7 | | where TimeGenerated >= (7d) 8 | | extend Os = tostring(DeviceDetail.operatingSystem) 9 | | extend Computer = tostring(DeviceDetail.displayName) 10 | | where SigninStatus == "Success" 11 | | where Os == "Windows10" 12 | | where isnotempty(Computer) 13 | | summarize count() by Computer 14 | -------------------------------------------------------------------------------- /WiresharkRSSTraffic.txt: -------------------------------------------------------------------------------- 1 | //RSS traffic 2 | Wireshark_CL 3 | | where TimeGenerated > ago(1d) 4 | | where RawData contains "rss.channel.item.link" 5 | | distinct RawData -------------------------------------------------------------------------------- /WorkWeek.txt: -------------------------------------------------------------------------------- 1 | //Query to show events in just the workweek 2 | 3 | let workweek = datatable(dayOfWeekTimespan:int, dayOfWeekDayDisplayName:string, firstH:int, lastH:int) [ 0, "Sunday", 9, 18, 1, "Monday", 9, 18, 2, "Tuesday", 9, 18, 3, "Wednesday", 9, 18, 4, "Thursday", 9, 18, 5, "Friday", 9, 18, 6, "Saturday", 9, 18, ]; 4 | let startDate = ago(60d); let endDate = now(); 5 | SecurityEvent 6 | | where TimeGenerated between (startDate .. endDate) 7 | | extend dayOfWeekTimespan = toint(substring(tostring(dayofweek(TimeGenerated)), 0, 1)) 8 | | where dayOfWeekTimespan in (1, 2, 3, 4, 5) 9 | | lookup kind=leftouter workweek on dayOfWeekTimespan 10 | | where datetime_part("Hour",TimeGenerated) between (firstH .. lastH) 11 | | project TimeGenerated, Computer, dayOfWeekDayDisplayName 12 | | sort by TimeGenerated asc 13 | -------------------------------------------------------------------------------- /WorkbookCreation.txt: -------------------------------------------------------------------------------- 1 | // 2 | 3 | CloudAppEvents 4 | | where ActionType == "Write Workbooks" 5 | | project AccountDisplayName, IPAddress, DeviceType, ISP, City, CountryCode 6 | -------------------------------------------------------------------------------- /WorkbookDeletion.txt: -------------------------------------------------------------------------------- 1 | //Who deleted a Microsoft Sentinel workbook 2 | 3 | AzureActivity 4 | | where OperationNameValue == "MICROSOFT.INSIGHTS/WORKBOOKS/DELETE" 5 | | distinct Caller, CallerIpAddress, EventSubmissionTimestamp, OperationName, OperationNameValue, Resource 6 | -------------------------------------------------------------------------------- /WorkspaceIDs.kql: -------------------------------------------------------------------------------- 1 | //Run the following in Azure Resource Graph Explorer to show all Workspace IDs. From LucyIsOpal (https://twitter.com/LucyIsOpal) 2 | 3 | resources 4 | | where type == "microsoft.operationalinsights/workspaces" 5 | | where properties['retentionInDays'] == "90" 6 | | project properties['customerId'] 7 | -------------------------------------------------------------------------------- /Workspaces90DaysRetention.kql: -------------------------------------------------------------------------------- 1 | //Run the following in Azure Resource Graph Explorer to show all existing Workspaces set to 90 days retention 2 | 3 | resources 4 | | where type == "microsoft.operationalinsights/workspaces" 5 | | where properties['retentionInDays'] == 90 6 | -------------------------------------------------------------------------------- /WorkspacesAndTables.txt: -------------------------------------------------------------------------------- 1 | //This query will display the tables from any/all workspaces across a tenant. Just need to modify the scope on a workspace to include the additional workspaces (as shown in the image) 2 | //Image link: https://raw.githubusercontent.com/rod-trent/SentinelKQL/master/Images/scope.png 3 | 4 | 5 | Usage 6 | | where StartTime > ago(1d) 7 | | extend workspaceName = tostring(split(ResourceUri, "/")[-1]) 8 | | extend subscription = tostring(split(ResourceUri, "/")[2]) 9 | | extend resourceGroup = tostring(split(ResourceUri, "/")[4]) 10 | | summarize ['Table Size'] =sum(Quantity) / 1000 by TenantId, subscription, resourceGroup, workspaceName, ['Table Name'] =DataType, ['IsBillable'] =IsBillable 11 | | distinct workspaceName, ['Table Name'] 12 | 13 | 14 | //Adding below the Solution column, i.e., where the table comes from 15 | 16 | Usage 17 | | where StartTime > ago(1d) 18 | | extend workspaceName = tostring(split(ResourceUri, "/")[-1]) 19 | | extend subscription = tostring(split(ResourceUri, "/")[2]) 20 | | extend resourceGroup = tostring(split(ResourceUri, "/")[4]) 21 | | summarize ['Table Size'] =sum(Quantity) / 1000 by TenantId, subscription, resourceGroup, workspaceName, ['Table Name'] =DataType, ['IsBillable'] =IsBillable, Solution 22 | | distinct workspaceName, ['Table Name'], Solution 23 | | sort by Solution asc 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ZeroLogon_Ports.txt: -------------------------------------------------------------------------------- 1 | //Ports accessed by Zerologon 2 | 3 | DeviceNetworkEvents 4 | | where RemotePort == 135 or RemotePort between (49670 .. 49680) 5 | | summarize (Timestamp, InitiatingProcessFileName, InitiatingProcessCommandLine, InitiatingProcessAccountSid)=arg_min(ReportId, Timestamp, InitiatingProcessFileName, InitiatingProcessCommandLine, InitiatingProcessAccountSid), TargetDevicePorts=make_set(RemotePort) by DeviceId, DeviceName, RemoteIP, RemoteUrl 6 | | project-rename SourceComputerName=DeviceName, SourceDeviceId=DeviceId, TargetDeviceIP=RemoteIP, TargetComputerName=RemoteUrl -------------------------------------------------------------------------------- /acrossworkspaceforFunction.txt: -------------------------------------------------------------------------------- 1 | union Update, workspace("contosoretail-it").Update, workspace("b459b4u5-912x-46d5-9cb1-p43069212nb4").Update 2 | | where TimeGenerated >= ago(1h) 3 | | where UpdateState == "Needed" 4 | | summarize dcount(Computer) by Classification -------------------------------------------------------------------------------- /adminskql.txt: -------------------------------------------------------------------------------- 1 | WindowsEvent 2 | | where TimeGenerated > ago(7d) 3 | | extend eventData-parse_json(Data) 4 | | project TimeGenerated, Computer, EventID, Data.MemberName, Data.SubjectDomainName, Data.SubjetUserName, Data.TargetUserName 5 | | where Data_TargetUserName == "Domain Admins" or Data_TargetUserName == "Enterprise Admins" -------------------------------------------------------------------------------- /allreportingcomputers.txt: -------------------------------------------------------------------------------- 1 | union withsource = TableName * 2 | | distinct Computer 3 | | where isnotempty(Computer) 4 | | summarize by Computer -------------------------------------------------------------------------------- /computersendingmostsecurityalerts.txt: -------------------------------------------------------------------------------- 1 | //Show Computers sending the most Security Alerts 2 | 3 | union withsource = tt * 4 | | where TimeGenerated > startofday(ago(7d)) and TimeGenerated < startofday(now()) 5 | | where _IsBillable == true 6 | | where tt == "SecurityEvent" 7 | | summarize GBytes=round(sum(_BilledSize/(1024*1024*1024)),2) by Solution=tt, Computer 8 | | sort by GBytes nulls last 9 | | render barchart kind=unstacked 10 | -------------------------------------------------------------------------------- /computersunhealthystate.txt: -------------------------------------------------------------------------------- 1 | let timeRangeQuery = 1h; 2 | let UnhealthyCriteria = 1m; 3 | Heartbeat 4 | | where TimeGenerated > startofday(ago(timeRangeQuery)) 5 | | summarize LastHeartbeat = max(TimeGenerated) by Computer, OSType, OSName 6 | | extend State = iff(LastHeartbeat < ago(UnhealthyCriteria), 'Unhealthy', 'Healthy') 7 | | extend TimeFromNow = now() - LastHeartbeat 8 | | extend ["TimeAgo"] = strcat(toint(TimeFromNow / 1s), ' seconds') 9 | | project Computer, State, TimeAgo, TimeFromNow, OSType 10 | | order by TimeAgo desc, State desc -------------------------------------------------------------------------------- /dataingestionthresholdlimits.txt: -------------------------------------------------------------------------------- 1 | //Data ingestion crossed the limit 2 | Operation 3 | |where OperationCategory == "Ingestion" 4 | |where Detail startswith "The data ingestion volume rate crossed the threshold" 5 | 6 | //Data ingestion crossed 80% of the limit 7 | Operation 8 | |where OperationCategory == "Ingestion" 9 | |where Detail startswith "The data ingestion volume rate crossed 80% of the threshold" -------------------------------------------------------------------------------- /dataparser.txt: -------------------------------------------------------------------------------- 1 | MyCustomCSVLog_CL 2 | | extend CSVFields = split(RawData, ',') 3 | | extend EventTime = todatetime(CSVFields[0]) 4 | | extend Code = toint(CSVFields[1]) 5 | | extend Status = tostring(CSVFields[2]) 6 | | extend Message = tostring(CSVFields[3]) 7 | | where getyear(EventTime) == 2018 8 | | summarize count() by Status,Code -------------------------------------------------------------------------------- /dataproviders.txt: -------------------------------------------------------------------------------- 1 | //Listing all Data providers 2 | SecurityAlert 3 | | where isnotempty(ProviderName) 4 | | distinct ProviderName -------------------------------------------------------------------------------- /devices.txt: -------------------------------------------------------------------------------- 1 | // find Azure Firewalls 2 | 3 | AzureDiagnostics 4 | | where ResourceType == "AZUREFIREWALLS" 5 | 6 | //Windows Firewall 7 | WindowsFirewall 8 | | summarize count() by FirewallAction 9 | 10 | //Barracuda 11 | CGFWFirewallActivity 12 | 13 | //Barracuda WAF 14 | CommonSecurityLog​ 15 | | where DeviceVendor == "Barracuda" 16 | 17 | //CommonSecurityLog​ 18 | | where DeviceVendor == "Check Point" 19 | 20 | CommonSecurityLog​ 21 | | where DeviceVendor == "Cisco" 22 | | where DeviceProduct == "ASA" -------------------------------------------------------------------------------- /excessivefailedlogins.txt: -------------------------------------------------------------------------------- 1 | SecurityEvent 2 | | where TimeGenerated < startofday(ago(1d)) 3 | | where EventID in (4625) and Status=="0xc000006d" 4 | | summarize min(TimeGenerated), EventCount = count() by bin_at(TimeGenerated, 1h,now()) 5 | | order by TimeGenerated asc 6 | -------------------------------------------------------------------------------- /heartbeatforscomagent.txt: -------------------------------------------------------------------------------- 1 | Heartbeat 2 | | project Computer , Category 3 | |where Category contains "Scom agent" 4 | |distinct Computer// 5 | -------------------------------------------------------------------------------- /isempty.txt: -------------------------------------------------------------------------------- 1 | SecurityAlert 2 | | where isempty(ProviderName) 3 | | project AlertName, SourceComputerId, ProviderName -------------------------------------------------------------------------------- /maxoutputcolumns.kql: -------------------------------------------------------------------------------- 1 | //Using the maxoutputcolumns. Overrides the default maximum number of columns a query is allowed to produce. 2 | 3 | set maxoutputcolumns=4677; 4 | search "rotrent" 5 | | distinct $table 6 | -------------------------------------------------------------------------------- /multipleLAworkspaces.txt: -------------------------------------------------------------------------------- 1 | union Update, workspace("1stLAWorkspace").Update, workspace("2ndLAWorkspace").Update 2 | | where TimeGenerated >= ago(1h) 3 | | where UpdateState == "Needed" 4 | -------------------------------------------------------------------------------- /qualys.txt: -------------------------------------------------------------------------------- 1 | SecurityAlert 2 | | where ProviderName contains "asc" and ExtendedProperties contains "qualys" 3 | | project RemediationSteps -------------------------------------------------------------------------------- /savingperworkbook.kql: -------------------------------------------------------------------------------- 1 | //For the Cost workbook. Shows E5 savings per workspace 2 | 3 | let DailyMaxDiscountGB = ((5*toreal({TotalE5Seats}))/1024); 4 | Usage 5 | | where IsBillable == true 6 | | where DataType in ("SigninLogs", 7 | "AuditLogs", 8 | "AADNonInteractiveUserSignInLogs", 9 | "AADServicePrincipalSignInLogs", 10 | "AADManagedIdentitySignInLogs", 11 | "AADProvisioningLogs", 12 | "ADFSSignInLogs", 13 | "McasShadowItReporting", 14 | "InformationProtectionLogs_CL", 15 | "DeviceEvents",  16 | "DeviceFileEvents",  17 | "DeviceImageLoadEvents",  18 | "DeviceInfo",  19 | "DeviceLogonEvents",  20 | "DeviceNetworkEvents",  21 | "DeviceNetworkInfo",  22 | "DeviceProcessEvents",  23 | "DeviceRegistryEvents", 24 | "DeviceFileCertificateInfo",  25 | "EmailAttachmentInfo",  26 | "EmailEvents",  27 | "EmailPostDeliveryEvents",  28 | "EmailUrlInfo", 29 | "IdentityLogonEvents", 30 | "IdentityQueryEvents", 31 | "IdentityDirectoryEvents", 32 | "AlertEvidence", 33 | "CloudAppEvents")   34 | | extend workspaceName = tostring(split(ResourceUri, "/")[-1]) 35 | | extend subscription = tostring(split(ResourceUri, "/")[2]) 36 | | extend resourceGroup = tostring(split(ResourceUri, "/")[4]) 37 | | summarize DailyBillableGB = toreal(sum(Quantity))/ 1024 by format_datetime(TimeGenerated, 'yy-MM-dd'), workspaceName 38 | | summarize TotalEligibleGB = sum(iif(toreal(DailyBillableGB)>toreal(DailyMaxDiscountGB),toreal(DailyMaxDiscountGB),DailyBillableGB)) by workspaceName 39 | | extend TotalDiscount = toreal(TotalEligibleGB)*{Price} 40 | | project workspaceName, TotalDiscount 41 | -------------------------------------------------------------------------------- /scalarexpression.txt: -------------------------------------------------------------------------------- 1 | let numdays=3; 2 | let newnumdays=toscalar(numdays*3); 3 | SecurityAlert 4 | | where DisplayName contains "svchost" 5 | | project AlertName , newnumdays -------------------------------------------------------------------------------- /serversenrolledinWDATP.txt: -------------------------------------------------------------------------------- 1 | MachineInfo 2 | |where OSPlatform contains "server" 3 | |project ComputerName, OSPlatform 4 | |distinct ComputerName, OSPlatform 5 | -------------------------------------------------------------------------------- /thresholds.csv: -------------------------------------------------------------------------------- 1 | Computer,Threshold 2 | Rod,100 3 | --------------------------------------------------------------------------------