├── AADIds_with_multiple_DeviceNames ├── AntiVirusReporting ├── AzSentinel_AuditLogs_AppPermissions ├── Create Non_intended_user_logon.txt ├── Detect_Possible_Disablement_of_MDE ├── Detect_Possible_Disablement_of_MDE_MDI-Edition ├── Detected new Vuln in Enterprise ├── Example_WorkingWithJSON ├── Executed_Scripts_after_download ├── Join_and_summarize_example ├── Log4J-Reporting ├── Phish Hunting ├── PhishClickSignInOverview └── getAlertsAssociatedWithPhishURLClick ├── Phish-Impersonation ├── ProcessTokenModification ├── Report_Legacy_Software_Usage ├── Report_by_Devicegroup ├── SW-VLN-found-got-email-with-payload.txt ├── SimpleTimespanFileCreation.txt ├── Sort_By_Severity ├── SpringShell ├── asrReportingWithLookup ├── coronamap.txt ├── detect_ETW_Bypassing_Net ├── device_auth_phishing ├── dynamic_lolbin_hunting ├── hunt_for_lolbins ├── hunt_for_ps_download_activity_and_subsequent_process_creation ├── hunt_for_reverse_proxy_tunnels ├── hunting_active_rdp_connections ├── hunting_proc_creation_from_ps_or_cmd ├── report_devices_older_than ├── report_local_admins ├── report_pua ├── search-for-zapped-email ├── which_mailitem_were_accessed ├── which_user_has_vuln_app_installed └── wsreset and new-item events in short timeframe /AADIds_with_multiple_DeviceNames: -------------------------------------------------------------------------------- 1 | // searches for AADDeviceIDs that are assigned to multiple DeviceNames 2 | // Author: @jangeisbauer 3 | 4 | DeviceInfo 5 | | where AadDeviceId != "" 6 | | summarize x=make_set(DeviceName) by AadDeviceId 7 | | project DeviceNameCountByID=array_length(x), AadDeviceId 8 | | where DeviceNameCountByID > 1 9 | -------------------------------------------------------------------------------- /AntiVirusReporting: -------------------------------------------------------------------------------- 1 | // last modified:09/2021 2 | // author:@janvonkirchheim 3 | // id:0de927ab-07ed-44ba-8796-4da314c61bad 4 | // product_family:MDE 5 | // name:Update Antivirus Signatures Report 6 | // category:Report 7 | // description:Reports on "update antivirus signatures == Scid-2011" based on OS Plattform 8 | 9 | DeviceTvmSecureConfigurationAssessment 10 | | where ConfigurationId == "scid-2011" // update antivirus signatures 11 | | join kind=leftouter DeviceTvmSecureConfigurationAssessmentKB on ConfigurationId 12 | | mv-expand e = parse_json(Context) 13 | | project DeviceName, OSPlatform, SignatureVersion=e[0], EngineVersion=e[1] 14 | -------------------------------------------------------------------------------- /AzSentinel_AuditLogs_AppPermissions: -------------------------------------------------------------------------------- 1 | // gets a gist that holds IDs of permissions and permission names 2 | // queries the AuditLogs from AAD for action 'update application' 3 | // extracts the permission IDs and joins it with the gist to get the permission name 4 | // author: @janvonkirchheim 5 | 6 | let aadAppPermissions = (externaldata(permissionID:string,permissionName:string) 7 | [@"https://gist.githubusercontent.com/jangeisbauer/11348bda68550c3d4642c26f8f4bed1e/raw/3b1fc1a991ade3e730d1e99f87133f7705adb0a4/aadAppPermissions"] 8 | with (format="csv")); 9 | AuditLogs 10 | | where OperationName == "Update application" 11 | | extend EntitlementId_ = tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(TargetResources[0].modifiedProperties))[0].newValue))[0].RequiredAppPermissions))[1].EntitlementId) 12 | | join aadAppPermissions on $left.EntitlementId_ == $right.permissionID 13 | -------------------------------------------------------------------------------- /Create Non_intended_user_logon.txt: -------------------------------------------------------------------------------- 1 | // Author: jan geisbauer 2 | // @janvonkirchheim 3 | // ------------------------ 4 | // 5 | // Under some circumstances it is only allowed that users 6 | // from country X logon to devices from country X. 7 | // This query finds logon from users from other countries than X. 8 | // The query requires a property to identify the users from 9 | // country X. In this example a specific Email Address. 10 | 11 | let special_computers= 12 | DeviceInfo 13 | | where MachineGroup == "Special Clients" 14 | | summarize make_set(DeviceName); 15 | let special_users= 16 | AccountInfo 17 | | where Country == "Special" 18 | | summarize make_set(AccountName); 19 | let special_users_upn= 20 | AccountInfo 21 | | where Country == "Special" 22 | | summarize make_set(AccountUpn); 23 | DeviceLogonEvents 24 | | where Timestamp > ago(1d) 25 | | where DeviceName in~ (Special_computers) 26 | | where AccountName !in~ (Special_users) 27 | | where AccountName !in~ (Special_users_upn) 28 | | where AccountName != "" 29 | | where AccountDomain =~ "specialDomain" 30 | -------------------------------------------------------------------------------- /Detect_Possible_Disablement_of_MDE: -------------------------------------------------------------------------------- 1 | // Looks back for last updates of DeviceInfo and compares it to last entries in AADSignInEventBeta 2 | // If there where AAD SignIns in the last couple of days, but not updates to DeviceInfo, records will be shown 3 | // To detect possible disablement of defender for endpoint 4 | // @janvonkirchheim 5 | // 6 | let lookback = timespan(30d); //how log do you want to look back for DeviceInfo and AADSignIns 7 | let timeDiff = timespan(4d); //how many days between last seen by Defender and last seen AAD SignIn 8 | let OnbardedDevices = DeviceInfo 9 | | where OnboardingStatus == "Onboarded" 10 | | summarize T1 = arg_max(Timestamp, *) by DeviceName 11 | | where T1 > ago(lookback) 12 | | extend hostname1 = extract("[^.]*",0, tolower(DeviceName)) 13 | | project D1 = tolower(hostname1), T1; 14 | let AADSignIns = AADSignInEventsBeta 15 | | where Timestamp > ago(lookback) 16 | | project D2 = tolower(DeviceName), Application, Browser, City, Country, ClientAppUsed, DeviceTrustType, IPAddress, IsManaged, OSPlatform, Timestamp; 17 | OnbardedDevices | join AADSignIns on $left.D1 == $right.D2 18 | | extend hostname2 = extract("[^.]*",0, tolower(D2)) 19 | | summarize T2 = arg_max(Timestamp, *) by hostname2 20 | | where T2 - T1 >= timeDiff 21 | | summarize count() by Device = D1, LastSeenByMDE = T1, LastSeenByAAD = T2, Application, Browser, City, Country, ClientAppUsed, DeviceTrustType, IPAddress, IsManaged, OSPlatform 22 | | project-away count_ 23 | -------------------------------------------------------------------------------- /Detect_Possible_Disablement_of_MDE_MDI-Edition: -------------------------------------------------------------------------------- 1 | // Looks back for last updates of DeviceInfo and compares it to last entries in MDI Data 2 | // If there where AD SignIns in the last couple of days, but not updates to DeviceInfo, records will be shown 3 | // To detect possible disablement of defender for endpoint 4 | // @janvonkirchheim 5 | // 6 | let lookback = timespan(30d); //how log do you want to look back for DeviceInfo and IdentityLogonEvents 7 | let timeDiff = timespan(4d); //how many days between last seen by Defender and last seen AD SignIn 8 | let OnbardedDevices = DeviceInfo 9 | | where OnboardingStatus == "Onboarded" 10 | | summarize T1 = arg_max(Timestamp, *) by DeviceName 11 | | where T1 > ago(lookback) 12 | | extend hostname1 = extract("[^.]*",0, tolower(DeviceName)) 13 | | project D1 = tolower(hostname1), T1; 14 | let IdentityLogons = IdentityLogonEvents 15 | | where Timestamp > ago(lookback) 16 | | extend hostname2 = extract("[^.]*",0, tolower(DeviceName)) 17 | | project D2 = tolower(hostname2), Application, IPAddress, OSPlatform, Timestamp; 18 | OnbardedDevices | join IdentityLogons on $left.D1 == $right.D2 19 | | summarize T2 = arg_max(Timestamp, *) by D2 20 | | where T2 - T1 >= timeDiff 21 | | summarize count() by Device = D1, LastSeenByMDI = T1, LastSeenByAAD = T2, Application, IPAddress, OSPlatform 22 | | project-away count_ 23 | -------------------------------------------------------------------------------- /Detected new Vuln in Enterprise: -------------------------------------------------------------------------------- 1 | // Detected new Vuln in Enterprise 2 | // @janvonkirchheim 3 | 4 | let newVuln = 5 | DeviceTvmSoftwareVulnerabilitiesKB 6 | | where VulnerabilitySeverityLevel == "Critical" 7 | | where LastModifiedTime >ago(1day); 8 | DeviceTvmSoftwareInventoryVulnerabilities 9 | | join newVuln on CveId 10 | | summarize dcount(DeviceId) by DeviceName, DeviceId, Timestamp=LastModifiedTime, SoftwareName, SoftwareVendor, SoftwareVersion, VulnerabilitySeverityLevel, CvssScore, IsExploitAvailable 11 | | project Timestamp, DeviceName, SoftwareName, SoftwareVendor, SoftwareVersion, VulnerabilitySeverityLevel, CvssScore, IsExploitAvailable, DeviceId 12 | -------------------------------------------------------------------------------- /Example_WorkingWithJSON: -------------------------------------------------------------------------------- 1 | DeviceAlertEvents 2 | | join DeviceInfo on DeviceId 3 | | mv-expand UserName = parse_json(LoggedOnUsers) 4 | | project UserName.UserName 5 | -------------------------------------------------------------------------------- /Executed_Scripts_after_download: -------------------------------------------------------------------------------- 1 | DeviceProcessEvents 2 | | where InitiatingProcessFileName in ("iexplore.exe","chrome.exe","msedge.exe","firefox.exe") 3 | | where ProcessCommandLine contains "wscript.exe" 4 | -------------------------------------------------------------------------------- /Join_and_summarize_example: -------------------------------------------------------------------------------- 1 | DeviceEvents 2 | | where ActionType == 'ExploitGuardEafViolationAudited' or 3 | ActionType == 'ExploitGuardEafViolationBlocked' or 4 | ActionType == 'ExploitGuardIafViolationAudited' or 5 | ActionType == 'ExploitGuardIafViolationBlocked' 6 | | join DeviceInfo on DeviceId 7 | | summarize make_set(MachineGroup) 8 | -------------------------------------------------------------------------------- /Log4J-Reporting: -------------------------------------------------------------------------------- 1 | // will report all devices with log4j vulnerability 2 | // including reg-paths and disk-paths 3 | // author: @jangeisbauer 4 | 5 | DeviceTvmSoftwareVulnerabilities 6 | | where CveId == "CVE-2021-44228" 7 | | join kind=leftouter DeviceTvmSoftwareEvidenceBeta on SoftwareName, DeviceId 8 | | project DeviceName, LastSeenTime, OSPlatform, SoftwareVendor, SoftwareName, RegistryPaths, DiskPaths 9 | -------------------------------------------------------------------------------- /Phish Hunting/PhishClickSignInOverview: -------------------------------------------------------------------------------- 1 | // Gives an overview of what sign-ins happend after a user clicked on a phishing link 2 | // 3 | // Author: @janvonkirchheim 4 | // 5 | // get all phishing link clicked alerts 6 | let lookBackDuration = 30d; 7 | let clickedAlerts = AlertInfo 8 | | where Timestamp > ago(lookBackDuration) 9 | | where Title contains "click" 10 | | join AlertEvidence on AlertId 11 | | summarize count() by AccountObjectId, AccountUpn, DeviceName, alertTimestamp=Timestamp; 12 | // get logon country distribution from all users involved in the alerts 13 | let logonDistributionCountry = AADSignInEventsBeta 14 | | where Timestamp > ago(30d) 15 | | where AccountObjectId in (clickedAlerts) 16 | | summarize count() by AccountObjectId, Country 17 | | extend p = pack(Country, tostring(count_)) 18 | | summarize logonDistributionByCountry=make_bag(p) by AccountObjectId; 19 | // get logon device distribution from all users involved in the alerts 20 | let logonDistributionDevice = AADSignInEventsBeta 21 | | where Timestamp > ago(30d) 22 | | where AccountObjectId in (clickedAlerts) 23 | | summarize count() by AccountObjectId, DeviceName 24 | | extend p = pack(DeviceName, tostring(count_)) 25 | | summarize logonDistributionByDevice=make_bag(p) by AccountObjectId; 26 | // join all and look at the time shortly after die alerts and check for logon countries and devices while filtering AADjoined devices 27 | clickedAlerts 28 | | join logonDistributionDevice on AccountObjectId 29 | | join logonDistributionCountry on AccountObjectId 30 | | join AADSignInEventsBeta on AccountObjectId 31 | | where Timestamp > ago(30d) 32 | | project-rename signInTime = Timestamp, IP = IPAddress 33 | | where signInTime between (alertTimestamp..datetime_add('hour', 8, alertTimestamp)) 34 | | where DeviceTrustType != "Azure AD joined" 35 | | invoke DeviceFromIP() 36 | | summarize SignInAfterClickErrorCode=make_set(ErrorCode) by AccountDisplayName, RiskState, Country, tostring(logonDistributionByCountry), Device=DeviceName1, DeviceTrustType, tostring(logonDistributionByDevice) 37 | | project-reorder AccountDisplayName, RiskState, SignInAfterClickErrorCode, Country, logonDistributionByCountry, Device, DeviceTrustType, logonDistributionByDevice 38 | | sort by AccountDisplayName asc 39 | -------------------------------------------------------------------------------- /Phish Hunting/getAlertsAssociatedWithPhishURLClick: -------------------------------------------------------------------------------- 1 | // Hunt for other alerts related to User or Device associated with a Spam URL clicked event 2 | // 3 | // Author: @janvonkirchheim 4 | // 5 | // get all alerts by device 6 | let lookBackDuration = 30d; 7 | AlertInfo 8 | | where Timestamp > ago(lookBackDuration) 9 | | where Title contains "click" 10 | | join AlertEvidence on AlertId 11 | | extend p = pack(format_datetime(Timestamp, 'y-M-d h:m'),Title) 12 | | summarize All_Alerts=make_bag(p) by DeviceName 13 | 14 | // get all alerts by user 15 | let lookBackDuration = 30d; 16 | AlertInfo 17 | | where Timestamp > ago(lookBackDuration) 18 | | where Title contains "click" 19 | | join AlertEvidence on AlertId 20 | | extend p = pack(format_datetime(Timestamp, 'y-M-d h:m'),Title) 21 | | summarize All_Alerts=make_bag(p) by AccountUpn 22 | -------------------------------------------------------------------------------- /Phish-Impersonation: -------------------------------------------------------------------------------- 1 | // list all distinct impersonation domains 2 | 3 | EmailEvents 4 | | where DetectionMethods contains "impersonation" 5 | | distinct SenderFromAddress, SenderDisplayName, SenderMailFromDomain, SenderFromDomain, DetectionMethods 6 | -------------------------------------------------------------------------------- /ProcessTokenModification: -------------------------------------------------------------------------------- 1 | // hunt for token modifications in processes. In the below case in particular for SeDebugPrivilege. 2 | // You can change the privilege number in "extend SeDebugPrivilege_ = (CurrentTokenPrivEnabled_ / toint(pow(2, 20))) % 2" (in that case "20") 3 | // accordingly to the privileges in the privilege table 4 | // author: @jangeisbauer 5 | 6 | let Privileges = 7 | [ 8 | '00','SeIncreaseQuotaPrivilege', 9 | '01','SeSecurityPrivilege', 10 | '02','SeTakeOwnershipPrivilege', 11 | '03','SeLoadDriverPrivilege', 12 | '04','SeSystemProfilePrivilege', 13 | '05','SeSystemtimePrivilege', 14 | '06','SeProfileSingleProcessPrivilege', 15 | '07','SeIncreaseBasePriorityPrivilege', 16 | '08','SeCreatePagefilePrivilege', 17 | '09','SeBackupPrivilege', 18 | '10','SeRestorePrivilege', 19 | '11','SeShutdownPrivilege', 20 | '12','SeDebugPrivilege', 21 | '13','SeSystemEnvironmentPrivilege', 22 | '14','SeChangeNotifyPrivilege', 23 | '15','SeRemoteShutdownPrivilege', 24 | '16','SeUndockPrivilege', 25 | '17','SeManageVolumePrivilege', 26 | '18','SeImpersonatePrivilege', 27 | '19','SeCreateGlobalPrivilege', 28 | '20','SeIncreaseWorkingSetPrivilege', 29 | '21','SeTimeZonePrivilege', 30 | '22','SeCreateSymbolicLinkPrivilege', 31 | '23','SeDelegateSessionUserImpersonatePrivilege' 32 | ]; 33 | 34 | DeviceEvents 35 | | where ActionType == "ProcessPrimaryTokenModified" 36 | | extend CurrentTokenIntegrityLevel_ = parse_json(AdditionalFields).CurrentTokenIntegrityLevel 37 | | extend CurrentTokenPointer_ = parse_json(AdditionalFields).CurrentTokenPointer 38 | | extend CurrentTokenPrivEnabled_ = parse_json(AdditionalFields).CurrentTokenPrivEnabled 39 | | extend CurrentTokenSource_ = parse_json(AdditionalFields).CurrentTokenSource 40 | | extend CurrentTokenUserSid_ = parse_json(AdditionalFields).CurrentTokenUserSid 41 | | extend OriginalTokenIntegrityLevel_ = parse_json(AdditionalFields).OriginalTokenIntegrityLevel 42 | | extend OriginalTokenPointer_ = parse_json(AdditionalFields).OriginalTokenPointer 43 | | extend OriginalTokenPrivEnabled_ = parse_json(AdditionalFields).OriginalTokenPrivEnabled 44 | | extend OriginalTokenPrivPresent_ = parse_json(AdditionalFields).OriginalTokenPrivPresent 45 | | extend OriginalTokenSource_ = parse_json(AdditionalFields).OriginalTokenSource 46 | | extend OriginalTokenUserSid_ = parse_json(AdditionalFields).OriginalTokenUserSid 47 | | extend SystemTokenPointer_ = parse_json(AdditionalFields).SystemTokenPointer 48 | | extend currentTokenIntegrityLevelName_ = parse_json(AdditionalFields).currentTokenIntegrityLevelName 49 | | extend TokenModificationProperties = parse_json(parse_json(AdditionalFields).TokenModificationProperties) 50 | | extend tokenChangeDescription_ = extractjson("$.tokenChangeDescription", tostring(TokenModificationProperties)) 51 | | extend privilegesFlags_ = extractjson("$.privilegesFlags", tostring(TokenModificationProperties)) 52 | | extend isChangedToSystemToken_ = extractjson("$.isChangedToSystemToken", tostring(TokenModificationProperties)) 53 | | extend originalTokenIntegrityLevelName_ = extractjson("$.originalTokenIntegrityLevelName", tostring(TokenModificationProperties)) 54 | | extend currentTokenIntegrityLevelName_ = extractjson("$.currentTokenIntegrityLevelName", tostring(TokenModificationProperties)) 55 | | extend SeDebugPrivilege_ = (CurrentTokenPrivEnabled_ / toint(pow(2, 20))) % 2 56 | | project InitiatingProcessFileName, InitiatingProcessCommandLine, CurrentTokenIntegrityLevel_, CurrentTokenPointer_, CurrentTokenPrivEnabled_, CurrentTokenSource=base64_decode_tostring(tostring(CurrentTokenSource_)), CurrentTokenUserSid_, OriginalTokenIntegrityLevel_, OriginalTokenPointer_, OriginalTokenPrivEnabled_, OriginalTokenPrivPresent_, OriginalTokenSource=base64_decode_tostring(tostring(OriginalTokenSource_)), OriginalTokenUserSid_, SystemTokenPointer_, currentTokenIntegrityLevelName_, isChangedToSystemToken_, originalTokenIntegrityLevelName_, privilegesFlags_, tokenChangeDescription_, SeDebugPrivilege=iff(SeDebugPrivilege_==1,"Yes","No") 57 | -------------------------------------------------------------------------------- /Report_Legacy_Software_Usage: -------------------------------------------------------------------------------- 1 | // Searches for office 2010 installations and its executeable paths, then joins this with process events 2 | // to get information about the usage of this legacy software 3 | // Author: @jangeisbauer 4 | 5 | DeviceTvmSoftwareInventory 6 | | where SoftwareName contains "office" and SoftwareName contains "2010" 7 | | join DeviceTvmSoftwareEvidenceBeta on SoftwareName 8 | | mv-expand exe = DiskPaths 9 | | where exe contains "winword" or exe contains "power" or exe contains "access" or exe contains "excel" 10 | | distinct tostring(exe) 11 | | join kind=leftouter DeviceProcessEvents on $left.exe == $right.FolderPath 12 | | distinct FolderPath, FileName, MD5, SHA1, SHA256 13 | -------------------------------------------------------------------------------- /Report_by_Devicegroup: -------------------------------------------------------------------------------- 1 | // KQL to report anything by device group, calculating a factor per devices in the device group 2 | // in this case here I am reporting on critical vulnerabilities per device group relative to the device count of the group 3 | // author: @jangeisbauer 4 | 5 | DeviceInfo 6 | | summarize arg_max(Timestamp,*) by DeviceName 7 | | summarize MachineGroupCount = count()by MachineGroup 8 | | join DeviceInfo on MachineGroup 9 | | join DeviceTvmSoftwareVulnerabilities on DeviceId 10 | | where VulnerabilitySeverityLevel == "Critical" 11 | | summarize CriticalVulnerabilityCount = count() by MachineGroup, MachineGroupCount 12 | | project MachineGroup, DevicesInMachineGroup=MachineGroupCount, CriticalVulnInDeviceGroup=CriticalVulnerabilityCount, CriticalVulnPerDeviceCountFactor = bin((bin(CriticalVulnerabilityCount, 0.01) / bin(MachineGroupCount,0.01))*100, 1) 13 | | order by CriticalVulnPerDeviceCountFactor desc 14 | -------------------------------------------------------------------------------- /SW-VLN-found-got-email-with-payload.txt: -------------------------------------------------------------------------------- 1 | // Author: jan geisbauer 2 | // @janvonkirchheim 3 | // ------------------------ 4 | // 1. A list of all devices that have this vulnerability 5 | // 2. A list of all users that uses those devices 6 | // 3. If these users received .mkv files recently 7 | 8 | let all_computers_with_vlcvln= 9 | DeviceTvmSoftwareInventoryVulnerabilities 10 | | where SoftwareName contains "vlc" 11 | | summarize makelist(DeviceName); 12 | let all_affected_users= 13 | DeviceInfo 14 | | where DeviceName in (all_computers_with_vlcvln) 15 | | mvexpand todynamic(LoggedOnUsers) 16 | | extend ParsedFields = parsejson(LoggedOnUsers) 17 | | project UserName = ParsedFields.UserName 18 | | summarize makelist(tolower(UserName)); 19 | let all_email_addresses_aff_users= 20 | IdentityInfo 21 | | where tolower(AccountName) in (all_affected_users) 22 | | summarize makelist(tolower(EmailAddress)); 23 | EmailAttachmentInfo 24 | | where FileName contains ".mkv" 25 | | where tolower(RecipientEmailAddress) in (all_email_addresses_aff_users) 26 | 27 | 28 | // If these users opened those .mkv files 29 | 30 | let all_computers_with_vlcvln= 31 | DeviceTvmSoftwareInventoryVulnerabilities 32 | | where SoftwareName contains "vlc" 33 | | summarize makelist(DeviceName); 34 | DeviceFileEvents 35 | | where DeviceName in (all_computers_with_vlcvln) 36 | | where FileName contains "mkv" 37 | -------------------------------------------------------------------------------- /SimpleTimespanFileCreation.txt: -------------------------------------------------------------------------------- 1 | DeviceFileEvents 2 | | where DeviceName == "devicename" 3 | | where ActionType == "FileCreated" 4 | | where Timestamp between(datetime(2020-03-13 11:00) .. datetime(2020-03-13 15:00)) 5 | | project FileName , FolderPath , InitiatingProcessCommandLine , InitiatingProcessParentFileName 6 | -------------------------------------------------------------------------------- /Sort_By_Severity: -------------------------------------------------------------------------------- 1 | // Kusto Example to sort by Custom Value - in this case 'Severity' 2 | // Author @janvonkirchheim 3 | // 4 | AlertInfo 5 | | join AlertEvidence on AlertId 6 | | where ServiceSource == "Microsoft Defender for Endpoint" 7 | | summarize count() by AlertId, Timestamp, Title, Severity | project-away AlertId, count_ 8 | | extend AlertSeverity = 9 | case(Severity == "High", 1, 10 | Severity == "Medium", 2, 11 | Severity == "Low",3,4) 12 | | order by AlertSeverity asc 13 | | project-away AlertSeverity 14 | -------------------------------------------------------------------------------- /SpringShell: -------------------------------------------------------------------------------- 1 | // This query will help you narrow down the currently known needed conditions for the exploitation of SpringShell described in 2 | // https://unit42.paloaltonetworks.com/cve-2022-22965-springshell/ 3 | // At least it is looking via MDE for systems that have JDK v9 or higher and Tomcat installed 4 | // author: @jangeisbauer 5 | // April 2022 6 | 7 | let allJDKs = DeviceTvmSoftwareInventory 8 | | where SoftwareVendor contains "oracle" 9 | | where SoftwareName contains "jdk" 10 | | mv-expand version = parse_json(split(SoftwareVersion,".",0)) 11 | | where ['version'] >= 9; 12 | DeviceTvmSoftwareInventory 13 | | where SoftwareName contains "tomcat" 14 | | where DeviceId in (allJDKs) 15 | 16 | 17 | // another idea would be to look for file activity of the .war files, but I am not sure how often that would happen 18 | 19 | DeviceFileEvents 20 | | where FileName endswith ".war" 21 | -------------------------------------------------------------------------------- /asrReportingWithLookup: -------------------------------------------------------------------------------- 1 | // looks up ASR Name and URL to Microsoft Docs for given ASR rules found in the data 2 | // author: @janvonkirchheim 3 | 4 | let asrTable = (externaldata(asrName:string,asrGUID:string,asrLink:string) 5 | [@"https://gist.githubusercontent.com/jangeisbauer/6f779d12a4b6a859da4e40ef62019252/raw/4571b1ff649986773646cb6aa393195c57a519af/gistfile1.txt"] 6 | with (format="CSV")); 7 | DeviceEvents 8 | | where ActionType startswith "asr" 9 | | extend asrGuidDE= tostring(parse_json(AdditionalFields).RuleId) 10 | | join asrTable on $left.asrGuidDE == $right.asrGUID 11 | | project Timestamp, asrGUID, asrName, asrLink, DeviceName, ActionType, FileName, FolderPath, AccountName, ProcessCommandLine, InitiatingProcessCommandLine 12 | -------------------------------------------------------------------------------- /coronamap.txt: -------------------------------------------------------------------------------- 1 | // These are three queries that hunt for IOCs of the Corona Map Info Stealer as 2 | // described here: https://blog.reasonsecurity.com/2020/03/09/covid-19-info-stealer-the-map-of-threats-threat-analysis-report/ 3 | 4 | // All mentioned files in AppData: 5 | DeviceFileEvents 6 | | where FileName matches regex ".*(build|bin|corona|Windows.Globalization.Fontgroups).*\\.(exe|bat)" 7 | | where FolderPath contains "AppData" 8 | 9 | // simple file hash search 10 | DeviceEvents 11 | | where SHA256 == "2b35aa9c70ef66197abfb9bc409952897f9f70818633ab43da85b3825b256307" 12 | 13 | // In this IP list, we see legit IPs and malicious IPs. So we check if only browsers are connecting to those IPs to make it less noisy. Check the reason blog website to see which exes are talking with which of those URLs 14 | DeviceNetworkEvents 15 | | where RemoteIP in ("104.24.103.192", "149.154.167.220", "104.26.9.44","93.184.220","18.205.183.153","54.192.87.49") 16 | | where InitiatingProcessFileName !contains "chrome.exe" 17 | | where InitiatingProcessFileName !contains "iexplore.exe" 18 | | where InitiatingProcessFileName !contains "MicrosoftEdgeCP.exe" 19 | | where InitiatingProcessFileName !contains "firefox.exe" 20 | | where InitiatingProcessFileName !contains "msedge.exe" 21 | | where InitiatingProcessFileName !contains "MicrosoftEdge.exe" 22 | -------------------------------------------------------------------------------- /detect_ETW_Bypassing_Net: -------------------------------------------------------------------------------- 1 | // Ref: https://gist.github.com/Cyb3rWard0g/a4a115fd3ab518a0e593525a379adee3 2 | // Ref: https://blog.xpnsec.com/hiding-your-dotnet-complus-etwenabled/ 3 | 4 | search in (DeviceRegistryEvents, DeviceProcessEvents) 5 | RegistryKey contains "ETWEnabled" or ProcessCommandLine contains "ETWEnabled" 6 | -------------------------------------------------------------------------------- /device_auth_phishing: -------------------------------------------------------------------------------- 1 | // Will detect phishing by the use of device authentication 2 | // Based on Nestori Syynimaa's POC: https://www.youtube.com/watch?v=GFWpd1HCRLs&feature=youtu.be 3 | // author: @janvonkirchheim 4 | 5 | EmailUrlInfo 6 | | where Url =~ "https://login.microsoftonline.com/common/oauth2/deviceauth" or Url contains "microsoft.com/devicelogin" 7 | | join EmailEvents on NetworkMessageId 8 | | project SenderMailFromAddress, SenderFromAddress, SenderIPv4, RecipientEmailAddress, Subject, Url 9 | -------------------------------------------------------------------------------- /dynamic_lolbin_hunting: -------------------------------------------------------------------------------- 1 | // hunting for lolbins with live data from Oddvar Moe's lolbin collection here: https://github.com/LOLBAS-Project/LOLBAS 2 | // checks for lolbins with specified prevelance 3 | // author: @janvonkirchheim 4 | 5 | let x = (externaldata(lolbin:string) 6 | [@"https://raw.githubusercontent.com/api0cradle/LOLBAS/master/LOLBins.md"] with (format="txt")); 7 | let lolbinArray = x 8 | | extend lol = extract_all(@"\[(.*?)\]", lolbin)[0] 9 | | project lol; 10 | DeviceProcessEvents 11 | | where InitiatingProcessParentFileName in (lolbinArray) 12 | | invoke FileProfile(SHA256) 13 | | where GlobalPrevalence < 100 14 | | distinct FileName, GlobalPrevalence 15 | -------------------------------------------------------------------------------- /hunt_for_lolbins: -------------------------------------------------------------------------------- 1 | // hunting for lolbins listed here: https://github.com/api0cradle/LOLBAS/blob/master/LOLBins.md 2 | 3 | DeviceProcessEvents 4 | | where DeviceName == "computer" 5 | | where ProcessCommandLine contains "Atbroker.exe" or 6 | ProcessCommandLine contains "Bash.exe" or 7 | ProcessCommandLine contains "Bitsadmin.exe" or 8 | ProcessCommandLine contains "Certutil.exe" or 9 | ProcessCommandLine contains "Cmdkey.exe" or 10 | ProcessCommandLine contains "Cmstp.exe" or 11 | ProcessCommandLine contains "Control.exe" or 12 | ProcessCommandLine contains "Csc.exe" or 13 | ProcessCommandLine contains "Cscript.exe" or 14 | ProcessCommandLine contains "Dfsvc.exe" or 15 | ProcessCommandLine contains "Diskshadow.exe" or 16 | ProcessCommandLine contains "Dnscmd.exe" or 17 | ProcessCommandLine contains "Esentutl.exe" or 18 | ProcessCommandLine contains "Extexport.exe" or 19 | ProcessCommandLine contains "Extrac32.exe" or 20 | ProcessCommandLine contains "Expand.exe" or 21 | ProcessCommandLine contains "Explorer.exe" or 22 | ProcessCommandLine contains "Findstr.exe" or 23 | ProcessCommandLine contains "Forfiles.exe" or 24 | ProcessCommandLine contains "Gpscript.exe" or 25 | ProcessCommandLine contains "Hh.exe" or 26 | ProcessCommandLine contains "Ieexec.exe" or 27 | ProcessCommandLine contains "Ie4uinit.exe" or 28 | ProcessCommandLine contains "Infdefaultinstall.exe" or 29 | ProcessCommandLine contains "Installutil.exe" or 30 | ProcessCommandLine contains "Makecab.exe" or 31 | ProcessCommandLine contains "Mavinject.exe" or 32 | ProcessCommandLine contains "Msbuild.exe" or 33 | ProcessCommandLine contains "Msconfig.exe" or 34 | ProcessCommandLine contains "Msdt.exe" or 35 | ProcessCommandLine contains "Mshta.exe" or 36 | ProcessCommandLine contains "Msiexec.exe" or 37 | ProcessCommandLine contains "Netsh.exe" or 38 | ProcessCommandLine contains "Nltest.exe" or 39 | ProcessCommandLine contains "Odbcconf.exe" or 40 | ProcessCommandLine contains "Openwith.exe" or 41 | ProcessCommandLine contains "Pcalua.exe" or 42 | ProcessCommandLine contains "Pcwrun.exe" or 43 | ProcessCommandLine contains "Powershell.exe" or 44 | ProcessCommandLine contains "Presentationhost.exe" or 45 | ProcessCommandLine contains "Print.exe" or 46 | ProcessCommandLine contains "Psr.exe" or 47 | ProcessCommandLine contains "Reg.exe" or 48 | ProcessCommandLine contains "Regedit.exe" or 49 | ProcessCommandLine contains "Regasm.exe" or 50 | ProcessCommandLine contains "Register-cimprovider.exe" or 51 | ProcessCommandLine contains "Regsvcs.exe" or 52 | ProcessCommandLine contains "Regsvr32.exe" or 53 | ProcessCommandLine contains "Replace.exe" or 54 | ProcessCommandLine contains "Robocopy.exe" or 55 | ProcessCommandLine contains "Rpcping.exe" or 56 | ProcessCommandLine contains "Rundll32.exe" or 57 | ProcessCommandLine contains "Runonce.exe" or 58 | ProcessCommandLine contains "Runscripthelper.exe" or 59 | ProcessCommandLine contains "Sc.exe" or 60 | ProcessCommandLine contains "Scriptrunner.exe" or 61 | ProcessCommandLine contains "Syncappvpublishingserver.exe" or 62 | ProcessCommandLine contains "Wab.exe" or 63 | ProcessCommandLine contains "Wmic.exe" or 64 | ProcessCommandLine contains "Wscript.exe" or 65 | ProcessCommandLine contains "Xwizard.exe" 66 | | where Timestamp between(datetime(2020-03-13 11:00) .. datetime(2020-03-13 15:00)) 67 | | project Timestamp, ProcessCommandLine, InitiatingProcessCommandLine 68 | -------------------------------------------------------------------------------- /hunt_for_ps_download_activity_and_subsequent_process_creation: -------------------------------------------------------------------------------- 1 | // hunt for powershell download activities, then take a look at process creations from 2 | // ps within the following minutes. Check for global prevalence of the file that are spawend from ps 3 | // author: @janvonkirchheim 4 | 5 | DeviceEvents 6 | | where ActionType == "PowerShellCommand" 7 | | where AdditionalFields contains "invoke-webrequest" or AdditionalFields contains "invoke-restmethod" or AdditionalFields contains "start-bitstransfer" or AdditionalFields contains "[System.Net.WebClient]" 8 | | join DeviceProcessEvents on DeviceId 9 | | where Timestamp1 between (Timestamp..datetime_add("minute",5,Timestamp)) 10 | | where InitiatingProcessParentFileName1 =~ "powershell.exe" 11 | | invoke FileProfile(SHA2561, 100) 12 | | where GlobalPrevalence < 10 13 | | project FileName1, ProcessCommandLine1, InitiatingProcessCommandLine, InitiatingProcessCommandLine1, InitiatingProcessParentFileName, InitiatingProcessParentFileName1, GlobalPrevalence 14 | -------------------------------------------------------------------------------- /hunt_for_reverse_proxy_tunnels: -------------------------------------------------------------------------------- 1 | // is hunting for tools like chisel that have an active connection to the public address space and at the same 2 | // time to an other internal address. With that the attacker can forward (proxy) tools from the attacker machine through 3 | // an internal client to the final target. 4 | // 5 | // author: @jangeisbauer 6 | 7 | DeviceNetworkEvents 8 | | where isnotempty(InitiatingProcessFileName) 9 | | where RemoteIPType != "Loopback" and RemoteIPType != "FourToSixMapping" 10 | | summarize ipSet = make_set(strcat(RemoteIP, " (RemoteIPType: ", RemoteIPType, ")")) by DeviceName, InitiatingProcessFileName, bin(Timestamp, 1s), InitiatingProcessFolderPath 11 | | where array_length(ipSet) > 1 12 | | where InitiatingProcessFolderPath !startswith @"c:\program files" and InitiatingProcessFolderPath !startswith @"c:\windows" and InitiatingProcessFolderPath !startswith @"c:\programdata" 13 | | where ipSet has "private" and ipSet has "public" 14 | -------------------------------------------------------------------------------- /hunting_active_rdp_connections: -------------------------------------------------------------------------------- 1 | // hunts for active rdp connections from public IP addresses 2 | // author: @janvonkirchheim 3 | 4 | let publicIPs = DeviceNetworkEvents 5 | | where RemoteIPType == "Public" 6 | | where InitiatingProcessCommandLine has_any ("TermService","termsvcs") 7 | | project RemoteIP; 8 | DeviceLogonEvents 9 | | where RemoteIP in (publicIPs) 10 | | summarize Failed = countif(ActionType == 'LogonFailed'),Success = countif(ActionType == 'LogonSuccess'), totalip = dcount(RemoteIP ) by DeviceName, RemoteIP 11 | | sort by Failed desc 12 | -------------------------------------------------------------------------------- /hunting_proc_creation_from_ps_or_cmd: -------------------------------------------------------------------------------- 1 | // Build your own baseline, play with the globalPrevelance parameter and 2 | // exclude SignerHashes that are common in your environment to find 3 | // anomalies later on. 4 | // Author: @janvonkirchheim 5 | 6 | DeviceProcessEvents 7 | | where InitiatingProcessFileName =~ "powershell.exe" 8 | | where InitiatingProcessParentFileName != "Code.exe" 9 | | invoke FileProfile() 10 | | where GlobalPrevalence < 5000 11 | | project FileName, AccountName, DeviceName, GlobalFirstSeen, GlobalLastSeen, GlobalPrevalence, Signer, SignatureState 12 | 13 | DeviceProcessEvents 14 | | where InitiatingProcessFileName =~ "cmd.exe" 15 | | invoke FileProfile() 16 | | where GlobalPrevalence < 50 17 | | where SignerHash != "c5bfb27ef9ab20406e5ef5f78726f7f953fdab27" 18 | | project FileName, AccountName, DeviceName, GlobalFirstSeen, GlobalLastSeen, GlobalPrevalence, Signer, SignatureState 19 | -------------------------------------------------------------------------------- /report_devices_older_than: -------------------------------------------------------------------------------- 1 | // this will report devices in MDE that are older than builds starting with 18 2 | // (so everything before 18) 3 | // @janvonkirchheim 4 | 5 | DeviceInfo 6 | | where OSPlatform == "Windows10" 7 | | where toint(substring(OSBuild,0,2)) < 18 8 | | summarize arg_max(Timestamp,*) by DeviceName 9 | -------------------------------------------------------------------------------- /report_local_admins: -------------------------------------------------------------------------------- 1 | DeviceLogonEvents 2 | | where IsLocalAdmin == 1 3 | | where AccountName !startswith "adm" and AccountName !startswith "sys" 4 | | join DeviceInfo on DeviceName 5 | | project AccountName, DeviceName, LoggedOnUsers 6 | | summarize count() by AccountName, DeviceName, LoggedOnUsers 7 | -------------------------------------------------------------------------------- /report_pua: -------------------------------------------------------------------------------- 1 | DeviceAlertEvents 2 | | where Category == "UnwantedSoftware" 3 | | where Timestamp > ago(30d) 4 | | join DeviceInfo on DeviceName 5 | | mv-expand User = parse_json(LoggedOnUsers) 6 | | project Timestamp, DeviceName, Severity, Category, Title, FileName, User=User.UserName 7 | | summarize count() by FileName, DeviceName, tostring(User) 8 | -------------------------------------------------------------------------------- /search-for-zapped-email: -------------------------------------------------------------------------------- 1 | // searches for zapped email with certain attachment 2 | // author: @janvonkirchheim 3 | 4 | EmailAttachmentInfo 5 | | where FileName has "attachment-title" 6 | | join EmailPostDeliveryEvents on NetworkMessageId 7 | | project SenderFromAddress, RecipientEmailAddress, Action, ActionResult 8 | -------------------------------------------------------------------------------- /which_mailitem_were_accessed: -------------------------------------------------------------------------------- 1 | // the accessed mail-item in MCAS does not tell you about the subject 2 | // it only provides you with the InternetMessageId in RawEventData 3 | // This query extracts it from RawEventData and joins it with 4 | // EmailEvents table to get more info about the accessed mail-item 5 | 6 | CloudAppEvents 7 | | where AccountObjectId == "AccountID" 8 | | where Timestamp between (datetime(2021-03-20)..datetime(2021-03-30)) 9 | | where City == "ushuaia" 10 | | where RawEventData contains "InternetMessageId" 11 | | extend e1 = RawEventData.Folders 12 | | mv-expand e2 = parse_json(e1) 13 | | extend e3 = e2.FolderItems 14 | | mv-expand e4 = parse_json(e3) 15 | | extend INetMsgID=tostring(e4.InternetMessageId) 16 | | join EmailEvents on $left.INetMsgID == $right.InternetMessageId 17 | | where SenderMailFromAddress == "Email@Address" or RecipientEmailAddress == "Email@Address" 18 | | distinct Subject, ActionType 19 | -------------------------------------------------------------------------------- /which_user_has_vuln_app_installed: -------------------------------------------------------------------------------- 1 | // I need to write an Email to all the users that have this 2 | // vulnerable Software installed - where do I get all the Email Addresses? 3 | // @janvonkirchheim 4 | 5 | DeviceTvmSoftwareVulnerabilities 6 | | where SoftwareName == "zoom" 7 | | join kind=inner DeviceInfo on DeviceId 8 | | where isnotempty(LoggedOnUsers) 9 | | mv-expand ex = parse_json(LoggedOnUsers) 10 | | extend sid=tostring(ex.Sid) 11 | | join kind=inner IdentityInfo on $left.sid == $right.OnPremSid 12 | | summarize Email=make_set(EmailAddress) by SoftwareName 13 | -------------------------------------------------------------------------------- /wsreset and new-item events in short timeframe: -------------------------------------------------------------------------------- 1 | // wsreset and new-item events in short timeframe 2 | // ARBITRARY FILE DELETE VIA WSRESET.EXE 3 | // more info: https://daniels-it-blog.blogspot.com/2020/07/arbitrary-file-delete-via-wsresetexe.html 4 | // author: @janvonkirchheim 5 | 6 | DeviceProcessEvents 7 | | where ProcessCommandLine contains "wsreset" 8 | | where InitiatingProcessFileName contains "Powershell" or InitiatingProcessFileName contains "cmd" //OPTIONAL: you can try it without this line 9 | |join kind=inner ( 10 | DeviceEvents 11 | | where ActionType contains "PowerShellCommand" 12 | | where AdditionalFields has "New-Item") 13 | on DeviceName 14 | | where Timestamp1 between (datetime_add('minute',-10,Timestamp) .. datetime_add('minute',0,Timestamp)) 15 | 16 | //The Optional Line: without this line, you catch all occurrances of wsreset execution. But it might be dangerous, if wsreset under some circumstances is triggered by the system, 17 | // you might get many alerts ... 18 | --------------------------------------------------------------------------------