[
  {
    "path": "Code-and-Queries/Alert_Signin_After_180_Days.kql",
    "content": "//Create an alert when a user who has not signed in for more than 180 days signs in again\n\nSigninLogs\n| where TimeGenerated > ago(30d)\n| summarize arg_max(TimeGenerated, *) by UserPrincipalName\n| project UserPrincipalName, TimeGenerated\n| join kind=leftouter (\n    externaldata(displayName:string,lastSignInDateTime:datetime)\n    [@\"https://graph.microsoft.com/v1.0/users?$select=displayName,signInActivity\"]\n    with(format=\"json\", ingestionMapping=[{\"column\":\"displayName\",\"path\":\"displayName\"},{\"column\":\"lastSignInDateTime\",\"path\":\"signInActivity/lastSignInDateTime\"}])\n    on $left.UserPrincipalName == $right.displayName\n)\non UserPrincipalName\n| project UserPrincipalName, TimeGenerated, lastSignInDateTime\n| where lastSignInDateTime < ago(180d)\n| extend AccountCustomEntity = UserPrincipalName\n"
  },
  {
    "path": "Code-and-Queries/All-legacy-auth.kql",
    "content": "view all legacy authentication events:\n\nSecurityEvent\n| where EventID == 4624 and TargetLogonId != 0x0  \n| extend LegacyAuthentication = iif((LogonProcessName =~ \"Advapi\" or LogonProcessName =~ \"Ssp\"), \"True\", \"False\")  \n| where LegacyAuthentication == \"True\"  \n"
  },
  {
    "path": "Code-and-Queries/BruteForcePorts.kql",
    "content": "detect brute force attacks targeting RDP or SSH management ports could be:\n\nSecurityEvent\n| where EventID == 4625\n| where (SubStatus == \"0xc000006A\" or SubStatus == \"0xc0000064\")\n| project TimeGenerated, EventID, WorkstationName, Computer, Account, LogonTypeName, LogonType, LogonProcessName, SubStatus, Activity\n"
  },
  {
    "path": "Code-and-Queries/DNSLookup.kql",
    "content": "//Identifies IP addresses performing DNS lookups associated with common ToR proxies\nDnsEvents\n| where Name contains \".\"\n| where Name has_any (\"tor2web.org\", \"tor2web.com\", \"torlink.co\", \"onion.to\", \"onion.ink\", \"onion.cab\", \"onion.nu\", \"onion.link\", \"onion.it\", \"onion.city\", \"onion.direct\", \"onion.top\", \"onion.casa\", \"onion.plus\", \"onion.rip\", \"onion.dog\", \"tor2web.fi\", \"tor2web.blutmagie.de\", \"onion.sh\", \"onion.lu\", \"onion.pet\", \"t2w.pw\", \"tor2web.ae.org\", \"tor2web.io\", \"tor2web.xyz\", \"onion.lt\", \"s1.tor-gateways.de\", \"s2.tor-gateways.de\", \"s3.tor-gateways.de\", \"s4.tor-gateways.de\", \"s5.tor-gateways.de\", \"hiddenservice.net\")\n| extend timestamp = TimeGenerated, IPCustomEntity = ClientIP, HostCustomEntity = Computer\n"
  },
  {
    "path": "Code-and-Queries/DetectZeroDay.kql",
    "content": "//Based on available IOCs, the following KQL query example detects CVE-2023-23397\nDeviceProcessEvents\n| where InitiatingProcessFileName == \"svchost.exe\"\n| where FileName == \"rundll32.exe\" and ProcessCommandLine contains \"davclnt.dll\" and ProcessCommandLine contains \"DavSetCookie\"\n| where ProcessCommandLine !contains \"http://10.\"\n| where ProcessCommandLine !contains \"http://192.168.\"\n| extend url = split(ProcessCommandLine, \"http://\")[1]\n| extend domain = split(url, \"/\")[0]\n| where domain contains \".\" and domain !endswith \".local\"\n| summarize count() by tostring(domain)\n"
  },
  {
    "path": "Code-and-Queries/Detect_Multiple_Teams_Delete_IP.kql",
    "content": "//Detecting multiple Teams deletion from a single IP address\n\nOfficeActivity\n| where TimeGenerated > ago(1h)\n| where Operation =~ \\\"TeamDeleted\\\"\n| summarize count() by ClientIP\n| where count_ > 5\n"
  },
  {
    "path": "Code-and-Queries/Detect_Multiple_Teams_Delete_User.kql",
    "content": "//Detecting multiple Teams deletion by a single user\n\nOfficeActivity\n| where TimeGenerated > ago(1h)\n| where Operation =~ \\\"TeamDeleted\\\"\n| summarize count() by UserId\n| where count_ > 5\n"
  },
  {
    "path": "Code-and-Queries/DoS-IoT.kql",
    "content": "//KQL Example of DoS attack against an IoT device\n\nSecurityAlert\n| where ProductName == \"Azure Security Center for IoT\"\n| where AlertName == \"Suspicion of Denial Of Service Attack\"\n| where TimeGenerated <= ProcessingEndTime + 60m\n| extend DeviceId = tostring(parse_json(ExtendedProperties).DeviceId)\n| extend SourceDeviceAddress = tostring(parse_json(ExtendedProperties).SourceDeviceAddress)\n| extend DestDeviceAddress = tostring(parse_json(ExtendedProperties).DestinationDeviceAddress)\n| extend RemediationSteps = tostring(parse_json(RemediationSteps)[0])\n| extend Protocol = tostring(parse_json(ExtendedProperties).Protocol)\n| extend AlertManagementUri = tostring(parse_json(ExtendedProperties).AlertManagementUri)\n| project TimeGenerated, DeviceId, ProductName, ProductComponentName, AlertSeverity, AlertName, Description, Protocol, SourceDeviceAddress, DestDeviceAddress, RemediationSteps, Tactics, Entities, VendorOriginalId, AlertLink, AlertManagementUri\n"
  },
  {
    "path": "Code-and-Queries/DoSWebApp.kql",
    "content": "//KQL Example of DoS attack against a web application\n\n//This query will return a table with the following columns:\n//TimeGenerated: The timestamp of the web request\n//clientIP_s: The IP address of the client that made the web request\n//requestUri_s: The URI of the web request\n//httpStatus_d: The HTTP status code of the web response\n//Requests: The number of requests made by the client IP address in the time range\n\n// Set the time range to look for potential DoS attacks\nlet timeRange = 1h;\n// Set the threshold for the number of requests per IP address that indicates a DoS attack\nlet threshold = 1000;\n// Get the web requests from the AzureDiagnostics table\nlet webRequests = AzureDiagnostics\n| where TimeGenerated > ago(timeRange)\n| where Category == \"ApplicationGatewayAccessLog\"\n| project TimeGenerated, clientIP_s, requestUri_s, httpStatus_d;\n// Group the web requests by IP address and count the number of requests per IP\nlet ipCounts = webRequests\n| summarize Requests = count() by clientIP_s\n| where Requests > threshold;\n// Join the ipCounts with the webRequests to get the details of the requests from the potential attackers\nipCounts\n| join kind=inner webRequests on clientIP_s\n| project TimeGenerated, clientIP_s, requestUri_s, httpStatus_d, Requests\n| order by TimeGenerated desc\n"
  },
  {
    "path": "Code-and-Queries/DomainEntropy.kql",
    "content": "//Detect rare domains seen in the Office 365 audit logs\n\nOfficeActivity\n| where TimeGenerated > ago(30d)\n| where Operation in (\"Send\", \"Receive\", \"Download\", \"Upload\", \"Accessed\", \"Modified\", \"Renamed\", \"Deleted\", \"Shared\", \"Unshared\")\n| summarize Users=dcount(UserId), UserAgents=dcount(UserAgent), Records=count() by OrganizationName\n| extend DomainLength = strlen(OrganizationName)\n| extend Entropy = DomainLength * 1.0 / array_length(split(OrganizationName, \"\"))\n| where Entropy > 3.5\n| order by Users asc\n| take 10\n"
  },
  {
    "path": "Code-and-Queries/ElevatedAccounts.ps1",
    "content": "# Get list of elevated accounts in Entra ID (AzureAD)\n\nGet-AzureADDirectoryRoleMember -ObjectId (Get-AzureADDirectoryRole | Where-Object {$_.displayName -eq \"Global Administrator\"}).ObjectId\n"
  },
  {
    "path": "Code-and-Queries/Emails-from-malicious-IPs.kql",
    "content": "This query determines emails sent by top malicious/bad IP addresses.\n\nlet cutoff = 5;\nEmailEvents\n| where ThreatTypes has \"Malware\" or ThreatTypes has \"Phish\"\n| summarize count() by SenderIPv4\n| where count_ > cutoff // Arbitrary cutoff, increase or decrease as needed\n| join EmailEvents on SenderIPv4  \n| where DeliveryAction =~ \"Delivered\"\n"
  },
  {
    "path": "Code-and-Queries/FailedLogins.kql",
    "content": "SigninLogs\n| where ResultType == \"50126\" // Failed sign-in due to bad username or password\n| where UserPrincipalName in ((Get-AzureADDirectoryRoleMember -ObjectId (Get-AzureADDirectoryRole | Where-Object {$_.displayName -eq \"Global Administrator\"}).ObjectId).UserPrincipalName) // Filter by global administrators\n| summarize count() by UserPrincipalName // Count the number of failed sign-in attempts by user\n| where count_ > 6 // Filter by users who have more than 6 failed sign-in attempts\n| join kind=inner ( // Join with the original sign-in logs table\n    SigninLogs\n    | where ResultType == \"50126\"\n    | where UserPrincipalName in ((Get-AzureADDirectoryRoleMember -ObjectId (Get-AzureADDirectoryRole | Where-Object {$_.displayName -eq \"Global Administrator\"}).ObjectId).UserPrincipalName)\n    | summarize min(TimeGenerated), max(TimeGenerated) by UserPrincipalName // Get the first and last failed sign-in time by user\n) on UserPrincipalName\n| where (max_TimeGenerated - min_TimeGenerated) < 10m // Filter by users who have failed sign-in attempts within 10 minutes\n| project UserPrincipalName, count_, min_TimeGenerated, max_TimeGenerated // Select the relevant columns\n"
  },
  {
    "path": "Code-and-Queries/GitEvents.kql",
    "content": "//This rule monitors `GitEvents` for modifications to the repository by users other than the ones specified, potentially highlighting unauthorized changes. Uses a custom table.\n\nGitEvents\n| where OperationName == 'RepoModified'\n| where User notin ('KnownDev1', 'KnownDev2')\n"
  },
  {
    "path": "Code-and-Queries/Last_Signin_Date.kql",
    "content": "//Get the last sign-in date and time for all users\n\nSigninLogs\n| where TimeGenerated > ago(30d)\n| summarize arg_max(TimeGenerated, *) by UserPrincipalName\n| project UserPrincipalName, TimeGenerated\n| join kind=leftouter (\n    externaldata(displayName:string,lastSignInDateTime:datetime)\n    [@\"https://graph.microsoft.com/v1.0/users?$select=displayName,signInActivity\"]\n    with(format=\"json\", ingestionMapping=[{\"column\":\"displayName\",\"path\":\"displayName\"},{\"column\":\"lastSignInDateTime\",\"path\":\"signInActivity/lastSignInDateTime\"}])\n    on $left.UserPrincipalName == $right.displayName\n)\non UserPrincipalName\n| project UserPrincipalName, TimeGenerated, lastSignInDateTime\n"
  },
  {
    "path": "Code-and-Queries/Legacy-auth-IP.kql",
    "content": "//View all legacy authentication events from a specific source IP address\n\nSecurityEvent  \n| where EventID == 4624 and TargetLogonId != 0x0 and IpAddress == \"<source IP address>\"  \n| extend LegacyAuthentication = iif((LogonProcessName =~ \"Advapi\" or LogonProcessName =~ \"Ssp\"), \"True\", \"False\")  \n| where LegacyAuthentication == \"True\"\n"
  },
  {
    "path": "Code-and-Queries/Legacy-auth-timeframe.kql",
    "content": "//View all legacy authentication events within a specific time frame\n\nSecurityEvent  \n| where TimeGenerated > ago(1d) and EventID == 4624 and TargetLogonId != 0x0  \n| extend LegacyAuthentication = iif((LogonProcessName =~ \"Advapi\" or LogonProcessName =~ \"Ssp\"), \"True\", \"False\")  \n| where LegacyAuthentication == \"True\"  \n"
  },
  {
    "path": "Code-and-Queries/Legacy-auth-top10users.kql",
    "content": "//View the top 10 users with the most legacy authentication events\n\nSecurityEvent  \n| where EventID == 4624 and TargetLogonId != 0x0  \n| extend LegacyAuthentication = iif((LogonProcessName =~ \"Advapi\" or LogonProcessName =~ \"Ssp\"), \"True\", \"False\")  \n| where LegacyAuthentication == \"True\"  \n| summarize count() by AccountName  \n| top 10 by count_  \n"
  },
  {
    "path": "Code-and-Queries/Legacy-auth-user.kql",
    "content": "view all legacy authentication events from a specific user:\n\nSecurityEvent  \n| where EventID == 4624 and TargetLogonId != 0x0 and AccountName == \"<username>\"  \n| extend LegacyAuthentication = iif((LogonProcessName =~ \"Advapi\" or LogonProcessName =~ \"Ssp\"), \"True\", \"False\")  \n| where LegacyAuthentication == \"True\"  \n"
  },
  {
    "path": "Code-and-Queries/LegacyAuth30.kql",
    "content": "//This query returns all sign-in attempts using legacy authentication protocols in the last 30 days. \n\nSigninLogs\n| where TimeGenerated > ago(30d)\n| where ClientAppUsed in (\"Browser\", \"Exchange ActiveSync\", \"IMAP4\", \"Mobile Apps and Desktop clients\", \"Other clients\", \"POP3\", \"SMTP\")\n"
  },
  {
    "path": "Code-and-Queries/LegacyAuthGraphAPI.kql",
    "content": "//This query joins the SigninLogs table with an external data source from the Microsoft Graph API, which returns the displayName and lastSignInDateTime properties for all users\n\nSigninLogs\n| where TimeGenerated > ago(30d)\n| where ClientAppUsed in (\"Browser\", \"Exchange ActiveSync\", \"IMAP4\", \"Mobile Apps and Desktop clients\", \"Other clients\", \"POP3\", \"SMTP\")\n| summarize arg_max(TimeGenerated, *) by UserPrincipalName\n| project UserPrincipalName, TimeGenerated\n| join kind=leftouter (\n    externaldata(displayName:string,lastSignInDateTime:datetime)\n    [@\"https://graph.microsoft.com/v1.0/users?$select=displayName,signInActivity\"]\n    with(format=\"json\", ingestionMapping=[{\"column\":\"displayName\",\"path\":\"displayName\"},{\"column\":\"lastSignInDateTime\",\"path\":\"signInActivity/lastSignInDateTime\"}])\n    on $left.UserPrincipalName == $right.displayName\n)\non UserPrincipalName\n| project UserPrincipalName, TimeGenerated, lastSignInDateTime\n| where lastSignInDateTime < ago(90d)\n| extend AccountCustomEntity = UserPrincipalName\n"
  },
  {
    "path": "Code-and-Queries/LegacyAuthTimes.kql",
    "content": "//This query groups and counts the sign-in attempts by user principal name (UPN), which is usually the same as the user’s email address, and orders them by descending order\n\nSigninLogs\n| where TimeGenerated > ago(30d)\n| where ClientAppUsed in (\"Browser\", \"Exchange ActiveSync\", \"IMAP4\", \"Mobile Apps and Desktop clients\", \"Other clients\", \"POP3\", \"SMTP\")\n| summarize count() by UserPrincipalName\n| order by count_ desc\n"
  },
  {
    "path": "Code-and-Queries/MalwareUploaded.kql",
    "content": "//Malware uploaded to SharePoint or OneDrive\n\nOfficeActivity\n| where TimeGenerated > ago(30d)\n| where Operation == \"FileMalwareDetected\"\n| project\n    TimeGenerated,\n    OfficeWorkload,\n    ['File Name']=SourceFileName,\n    ['File Location']=OfficeObjectId,\n    ['Relative File URL']=SourceRelativeUrl,\n    ClientIP\n"
  },
  {
    "path": "Code-and-Queries/MissingUpdates.kql",
    "content": "// Missing updates summary \n// Get a summary of missing updates by category. \nUpdate\n| where TimeGenerated>ago(5h) and OSType==\"Linux\" and SourceComputerId in ((Heartbeat\n| where TimeGenerated>ago(12h) and OSType==\"Linux\" and notempty(Computer)\n| summarize arg_max(TimeGenerated, Solutions) by SourceComputerId\n| where Solutions has \"updates\"\n| distinct SourceComputerId))\n| summarize hint.strategy=partitioned arg_max(TimeGenerated, UpdateState, Classification) by Computer, SourceComputerId, Product, ProductArch\n| where UpdateState=~\"Needed\"\n| summarize by Product, ProductArch, Classification\n| union (Update\n| where TimeGenerated>ago(14h) and OSType!=\"Linux\" and (Optional==false or Classification has \"Critical\" or Classification has \"Security\") and SourceComputerId in ((Heartbeat\n| where TimeGenerated>ago(12h) and OSType=~\"Windows\" and notempty(Computer)\n| summarize arg_max(TimeGenerated, Solutions) by SourceComputerId\n| where Solutions has \"updates\"\n| distinct SourceComputerId))\n| summarize hint.strategy=partitioned arg_max(TimeGenerated, UpdateState, Classification, Approved) by Computer, SourceComputerId, UpdateID\n| where UpdateState=~\"Needed\" and Approved!=false\n| summarize by UpdateID, Classification )\n| summarize allUpdatesCount=count(), criticalUpdatesCount=countif(Classification has \"Critical\"), securityUpdatesCount=countif(Classification has \"Security\"), otherUpdatesCount=countif(Classification !has \"Critical\" and Classification !has \"Security\")\n"
  },
  {
    "path": "Code-and-Queries/No_Signing_Last_90_Days.kql",
    "content": "//Get a list of users who have not signed in for more than 90 days\n\nSigninLogs\n| where TimeGenerated > ago(30d)\n| summarize arg_max(TimeGenerated, *) by UserPrincipalName\n| project UserPrincipalName, TimeGenerated\n| join kind=leftouter (\n    externaldata(displayName:string,lastSignInDateTime:datetime)\n    [@\"https://graph.microsoft.com/v1.0/users?$select=displayName,signInActivity\"]\n    with(format=\"json\", ingestionMapping=[{\"column\":\"displayName\",\"path\":\"displayName\"},{\"column\":\"lastSignInDateTime\",\"path\":\"signInActivity/lastSignInDateTime\"}])\n    on $left.UserPrincipalName == $right.displayName\n)\non UserPrincipalName\n| project UserPrincipalName, TimeGenerated, lastSignInDateTime\n| where lastSignInDateTime < ago(90d)\n"
  },
  {
    "path": "Code-and-Queries/Phishing-campaigns.kql",
    "content": "//This query helps surface phishing campaigns associated with Appspot abuse. These emails frequently contain phishing links that utilize the recipients' own email address as a unique identifier in the URI.\n\nEmailUrlInfo\n// Detect URLs with a subdomain on appspot.com\n| where UrlDomain matches regex @'\\b[\\w\\-]+-dot-[\\w\\-\\.]+\\.appspot\\.com\\b'\n// Enrich results with sender and recipient data\n| join kind=inner EmailEvents on $left.NetworkMessageId==$right.NetworkMessageId\n// Phishing attempts from Appspot related campaigns typically contain the recipient's email address in the URI\n// Example 1: https://example-dot-example.appspot.com/#recipient@domain.com\n// Example 2: https://example-dot-example.appspot.com/index.html?user=recipient@domain.com\n| where Url has RecipientEmailAddress\n    // Some phishing campaigns pass recipient email as a Base64 encoded string in the URI\n    or Url has base64_encode_tostring(RecipientEmailAddress)\n| project-away Timestamp1, NetworkMessageId1, ReportId1\n"
  },
  {
    "path": "Code-and-Queries/Quishing.kql",
    "content": "//Detect QR Codes in emails\n\nlet image_extensions = dynamic([\"jpg\", \"jpeg\", \"png\", \"bmp\", \"gif\"]);\nEmailAttachmentInfo\n| where FileType in (image_extensions)\n| where FileName matches regex \"[A-Z0-9]{9,10}.[A-Za-z0-9]+$\"\n| join EmailUrlInfo on TenantId\n| where UrlLocation == \"Attachment\"\n| distinct FileName, FileType, SenderFromAddress, RecipientEmailAddress, UrlDomain, Url\n"
  },
  {
    "path": "Code-and-Queries/RareDomains.kql",
    "content": "//Rare Domains Seen in Cloud Logs\n\n// Define the time range to look for OfficeActivity events\nlet Lookback = ago(7d);\n// Get the OfficeActivity events and filter by OperationName\nlet OfficeEvents = OfficeActivity\n| where TimeGenerated > Lookback\n| where Operation in (\"FileDownloaded\", \"FileUploaded\")\n| extend Domain = tostring(split(SourceRelativeUrl, \"/\")[2]) // extract the domain name from the file URL\n| project TimeGenerated, UserId, Operation, SourceFileName, Domain;\n// Get the ThreatIntelligenceIndicator records and filter by ThreatType\nlet TIRecords = ThreatIntelligenceIndicator\n| where TimeGenerated > Lookback\n| where ThreatType == \"DomainName\"\n| project Domain = NetworkDestinationAsn, ThreatSeverity;\n// Join the OfficeEvents and TIRecords tables on Domain\nlet JoinedEvents = OfficeEvents\n| join kind=leftouter (\n    TIRecords\n) on Domain;\n// Calculate the rarity score of each domain based on its frequency and threat level\n// The rarity score is defined as log10(Count) * (ThreatLevel + 1), where Count is the number of events for each domain and ThreatLevel is a numeric value from 0 to 3\n// The higher the rarity score, the more rare and potentially malicious the domain is\nlet RarityScore = JoinedEvents\n| summarize Count = count() by Domain, ThreatSeverity // count the number of events for each domain and threat level combination\n| extend RarityScore = log10(Count) * (ThreatSeverity + 1) // calculate the rarity score\n| order by RarityScore desc; // order by rarity score in descending order\n// Display the results\nRarityScore\n"
  },
  {
    "path": "Code-and-Queries/Readme.md",
    "content": "\n"
  },
  {
    "path": "Code-and-Queries/SessionStealing.kql",
    "content": "// Define the time range and the threshold for the number of sessions per user\nlet starttime = 7d;\nlet endtime = now();\nlet session_threshold = 10;\n// Get the sign-in events from Azure Active Directory\nlet signin_events = SigninLogs\n| where TimeGenerated between (starttime .. endtime)\n| where ResultType == 0 // successful sign-ins only\n| project TimeGenerated, UserPrincipalName, IPAddress, SessionId;\n// Get the cloud app events from Microsoft Cloud App Security\nlet cloudapp_events = CloudAppEvents\n| where TimeGenerated between (starttime .. endtime)\n| project TimeGenerated, UserPrincipalName, IPAddress, SessionId;\n// Join the sign-in events and the cloud app events by user principal name and session id\nlet joined_events = signin_events\n| join kind=inner cloudapp_events on UserPrincipalName, SessionId\n| project TimeGenerated, UserPrincipalName, IPAddress, SessionId;\n// Group the events by user principal name and session id, and count the number of distinct IP addresses per session\nlet session_stats = joined_events\n| summarize IPCount = dcount(IPAddress) by UserPrincipalName, SessionId\n| project UserPrincipalName, SessionId, IPCount;\n// Find the sessions that have more than one IP address associated with them\nlet multi_ip_sessions = session_stats\n| where IPCount > 1\n| project UserPrincipalName, SessionId;\n// Find the users that have more than the threshold number of sessions with multiple IP addresses\nlet suspicious_users = multi_ip_sessions\n| summarize SessionCount = count() by UserPrincipalName\n| where SessionCount > session_threshold\n| project UserPrincipalName;\n// Return the suspicious users and their sessions with multiple IP addresses\nsuspicious_users\n| join kind=inner multi_ip_sessions on UserPrincipalName\n| join kind=inner session_stats on UserPrincipalName, SessionId\n| project UserPrincipalName, SessionId, IPCount;\n"
  },
  {
    "path": "Code-and-Queries/Spear_Phishing.kql",
    "content": "//This query looks for email events in the last seven days where the subject contains certain keywords, the sender’s domain is different from the recipients, and the count of such emails exceeds a threshold.\n\nlet lookbackTime = 7d;\nlet threshold = 5;\nEmailEvents\n| where TimeGenerated >= ago(lookbackTime)\n| where Subject has_any (\"urgent\", \"payment\", \"required\", \"request\")\n| where SenderFromDomain != RecipientDomain\n| summarize Count = count() by SenderFromDomain, RecipientEmailAddress\n| where Count > threshold\n| project SenderFromDomain, RecipientEmailAddress, Count\n"
  },
  {
    "path": "Code-and-Queries/TILookupforDNSEvents.kql",
    "content": "//TI Lookup that match DNS events\nlet dt_lookBack = 1h;\nlet ioc_lookBack = 14d;\nThreatIntelligenceIndicator\n| where TimeGenerated >= ago(ioc_lookBack) and ExpirationDateTime > now()\n| where Active == true\n// Picking up only IOC's that contain the entities we want\n| where isnotempty(NetworkIP) or isnotempty(EmailSourceIpAddress) or isnotempty(NetworkDestinationIP) or isnotempty(NetworkSourceIP)\n// As there is potentially more than 1 indicator type for matching IP, taking NetworkIP first, then others if that is empty.\n// Taking the first non-empty value based on potential IOC match availability\n| extend TI_ipEntity = iff(isnotempty(NetworkIP), NetworkIP, NetworkDestinationIP)\n| extend TI_ipEntity = iff(isempty(TI_ipEntity) and isnotempty(NetworkSourceIP), NetworkSourceIP, TI_ipEntity)\n| extend TI_ipEntity = iff(isempty(TI_ipEntity) and isnotempty(EmailSourceIpAddress), EmailSourceIpAddress, TI_ipEntity)\n| join (\n    DnsEvents | where TimeGenerated >= ago(dt_lookBack)\n    | where SubType =~ \"LookupQuery\" and isnotempty(IPAddresses)\n    | extend SingleIP = split(IPAddresses, \",\")  \n    | mvexpand SingleIP\n    | extend SingleIP = tostring(SingleIP)\n    // renaming time column so it is clear the log this came from\n    | extend DNS_TimeGenerated = TimeGenerated\n)\non $left.TI_ipEntity == $right.SingleIP\n| summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by IndicatorId\n| project LatestIndicatorTime, Description, ActivityGroupNames, IndicatorId, ThreatType, Url, ExpirationDateTime, ConfidenceScore, DNS_TimeGenerated, TI_ipEntity, Computer, EventId, SubType, ClientIP, Name, IPAddresses, NetworkIP, NetworkDestinationIP, NetworkSourceIP, EmailSourceIpAddress\n| extend timestamp = DNS_TimeGenerated, IPCustomEntity = ClientIP, HostCustomEntity = Computer, URLCustomEntity = Url\n"
  },
  {
    "path": "Code-and-Queries/TopThreatEmails.kql",
    "content": "//This query determines emails sent by top malicious/bad IP addresses.\n\nlet cutoff = 5;\nEmailEvents\n| where ThreatTypes has \"Malware\" or ThreatTypes has \"Phish\"\n| summarize count() by SenderIPv4\n| where count_ > cutoff // Arbitrary cutoff, increase or decrease as needed\n| join EmailEvents on SenderIPv4  \n| where DeliveryAction =~ \"Delivered\"\n"
  },
  {
    "path": "Code-and-Queries/Unusual-logins.kql",
    "content": "identify unusual login attempts from regions where your suppliers are based, you might use:\n\nSigninLogs\n| where Location in ('SupplierRegion1', 'SupplierRegion2')\n| summarize Count=count() by UserPrincipalName, Location\n| where Count > 5\n"
  },
  {
    "path": "Code-and-Queries/XSS-Attack.kql",
    "content": "Leverage Microsoft Sentinel for XSS attack detection, create an analytics rule with the following KQL query:\n\nAzureDiagnostics\n| where ResourceType == \"APPLICATIONGATEWAYS\"\n| where Category == \"ApplicationGatewayFirewallLog\"\n| where Message contains \"XSS Attack\"\n| project Message, details_message_s, details_data_s, clientIp_s, action_s\n"
  },
  {
    "path": "Images/Readme.md",
    "content": "\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2023 Rod Trent\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# Microsoft Sentinel SOC 101<br>\n## Content and collateral for the Microsoft Sentinel SOC 101 series.\n\nAnnouncing the Microsoft Sentinel 101 series on the <a href=\"https://rodtrent.substack.com/podcast\" target=\"_blank\">After the Blog</a> podcast: <a href=\"https://rodtrent.substack.com/p/episode-5-announcing-the-microsoft#details\" target=\"_blank\">Episode 5: Announcing the Microsoft Sentinel SOC 101 Blog Series</a>\n\nGet the eBook: https://github.com/rod-trent/Sentinel-SOC-101/tree/main/eBook \n\n## TOC\n\n* <a href=\"https://rodtrent.substack.com/p/microsoft-sentinel-soc-101-how-to\" target=\"_blank\">Microsoft Sentinel SOC 101: How to Detect and Mitigate Brute Force Attacks with Microsoft Sentinel</a> - <i>Posted SEP 18, 2023</i>\n* <a href=\"https://rodtrent.substack.com/p/microsoft-sentinel-soc-101-how-to-443\" target=\"_blank\">Microsoft Sentinel SOC 101: How to Detect and Mitigate Phishing Attacks with Microsoft Sentinel</a> - <i>Posted SEP 19, 2023</i>\n* <a href=\"https://rodtrent.substack.com/p/microsoft-sentinel-soc-101-how-to-321\" target=\"_blank\">Microsoft Sentinel SOC 101: How to Detect and Mitigate Malware Attacks with Microsoft Sentinel</a> - <i>Posted SEP 20, 2023</i>\n* <a href=\"https://rodtrent.substack.com/p/microsoft-sentinel-soc-101-how-to-658\" target=\"_blank\">Microsoft Sentinel SOC 101: How to Detect and Mitigate Cross-Site Scripting (XSS) Attacks with Microsoft Sentinel</a> - <i>Posted SEP 21, 2023</i>\n* <a href=\"https://rodtrent.substack.com/p/microsoft-sentinel-soc-101-leveraging\" target=\"_blank\">Microsoft Sentinel SOC 101: Leveraging MITRE ATT&CK Techniques with Microsoft Sentinel</a> - <i>Posted SEP 22, 2023</i>\n* <a href=\"https://rodtrent.substack.com/p/microsoft-sentinel-soc-101-how-to-f83\" target=\"_blank\">Microsoft Sentinel SOC 101: How to Detect and Mitigate Supply Chain Attacks with Microsoft Sentinel</a> - <i>Posted SEP 25, 2023</i>\n* <a href=\"https://rodtrent.substack.com/p/microsoft-sentinel-soc-101-how-to-5ab\" target=\"_blank\">Microsoft Sentinel SOC 101: How to Detect and Mitigate Credential Reuse Attacks with Microsoft Sentinel</a> - <i>Posted SEP 26, 2023</i>\n* <a href=\"https://rodtrent.substack.com/p/microsoft-sentinel-soc-101-how-to-28a\" target=\"_blank\">Microsoft Sentinel SOC 101: How to Detect and Mitigate SQL Injection Attacks with Microsoft Sentinel</a> - <i>Posted SEP 27, 2023</i>\n* <a href=\"https://rodtrent.substack.com/p/microsoft-sentinel-soc-101-how-to-8be\" target=\"_blank\">Microsoft Sentinel SOC 101: How to Detect and Mitigate Denial of Service Attacks with Microsoft Sentinel</a> - <i>Posted SEP 28, 2023</i>\n* <a href=\"https://rodtrent.substack.com/p/microsoft-sentinel-soc-101-how-to-ae5\" target=\"_blank\">Microsoft Sentinel SOC 101: How to Detect and Mitigate Man-in-the-Middle (MitM) Attacks with Microsoft Sentinel</a> - <i>Posted SEP 29, 2023</i>\n* <a href=\"https://rodtrent.substack.com/p/microsoft-sentinel-soc-101-how-to-980\" target=\"_blank\">Microsoft Sentinel SOC 101: How to Detect and Mitigate Keylogger Attacks with Microsoft Sentinel</a> - <i>Posted OCT 2, 2023</i>\n* <a href=\"https://rodtrent.substack.com/p/microsoft-sentinel-soc-101-how-to-8d0\" target=\"_blank\">Microsoft Sentinel SOC 101: How to Detect and Mitigate Cryptojacking Attacks with Microsoft Sentinel</a> - <i>Posted OCT 3, 2023</i>\n* <a href=\"https://rodtrent.substack.com/p/microsoft-sentinel-soc-101-how-to-2a3\" target=\"_blank\">Microsoft Sentinel SOC 101: How to Detect and Mitigate Drive-by Download Attacks with Microsoft Sentinel</a> - <i>Posted OCT 4, 2023</i>\n* <a href=\"https://rodtrent.substack.com/p/microsoft-sentinel-soc-101-how-to-b94\" target=\"_blank\">Microsoft Sentinel SOC 101: How to Detect and Mitigate Quishing Attacks with Microsoft Sentinel</a> - <i>Posted OCT 5, 2023</i>\n* <a href=\"https://rodtrent.substack.com/p/microsoft-sentinel-soc-101-how-to-214\" target=\"_blank\">Microsoft Sentinel SOC 101: How to Detect and Mitigate Session Token Stealing Attacks with Microsoft Sentinel</a> - <i>Posted OCT 6, 2023</i>\n* <a href=\"https://rodtrent.substack.com/p/microsoft-sentinel-soc-101-how-to-15e\" target=\"_blank\">Microsoft Sentinel SOC 101: How to Detect and Mitigate Fileless Malware Attacks with Microsoft Sentinel</a> - <i>Posted OCT 9, 2023</i>\n* <a href=\"https://rodtrent.substack.com/p/microsoft-sentinel-soc-101-how-to-018\" target=\"_blank\">Microsoft Sentinel SOC 101: How to Detect and Mitigate Zero-day Exploits with Microsoft Sentinel</a> - <i>Posted OCT 10, 2023</i>\n* <a href=\"https://rodtrent.substack.com/p/microsoft-sentinel-soc-101-how-to-40b\" target=\"_blank\">Microsoft Sentinel SOC 101: How to Detect and Mitigate a DNS Spoofing Attack with Microsoft Sentinel</a> - <i>Posted OCT 11, 2023</i>\n* <a href=\"https://rodtrent.substack.com/p/microsoft-sentinel-soc-101-how-to-07c\" target=\"_blank\">Microsoft Sentinel SOC 101: How to Detect and Mitigate Advanced Persistent Threats (APTs) with Microsoft Sentinel</a> - <i>Posted OCT 12, 2023</i>\n* <a href=\"https://rodtrent.substack.com/p/microsoft-sentinel-soc-101-how-to-513\" target=\"_blank\">Microsoft Sentinel SOC 101: How to Detect and Mitigate a VIP Account that has Multiple Failed Logons within a Threshold with Microsoft Sentinel</a> - <i>Posted OCT 17, 2023</i>\n* <a href=\"https://rodtrent.substack.com/p/microsoft-sentinel-soc-101-how-to-940\" target=\"_blank\">Microsoft Sentinel SOC 101: How to Detect and Mitigate Rare Domains Seen in Cloud Logs</a> - <i>Posted OCT 19, 2023</i>\n* <a href=\"https://rodtrent.substack.com/p/microsoft-sentinel-soc-101-how-to-448\" target=\"_blank\">Microsoft Sentinel SOC 101: How to Detect and Mitigate Inactive Account Sign-ins with Microsoft Sentinel\nWhere have you been?</a> - <i>Posted FEB 5, 2024</i>\n* <a href=\"https://rodtrent.substack.com/p/microsoft-sentinel-soc-101-how-to-ebc\" target=\"_blank\">Microsoft Sentinel SOC 101: How to Detect and Mitigate Social Engineering Attacks with Microsoft Sentinel</a> - <i>Posted FEB 6, 2024</i>\n* <a href=\"https://rodtrent.substack.com/p/microsoft-sentinel-soc-101-how-to-9b0\" target=\"_blank\">Microsoft Sentinel SOC 101: How to Detect and Mitigate Multiple Microsoft Teams Deleted by a Single User with Microsoft Sentinel</a> - <i>Posted FEB 7, 2024</i>\n\n<p align=\"center\"><img src=\"https://github.com/rod-trent/Sentinel-SOC-101/blob/main/Images/sentinelsocsmall.jpeg?raw=true\" alt=\"Microsoft Sentinel SOC 101\"></center></p>\n"
  },
  {
    "path": "Videos/Readme.md",
    "content": "\n"
  },
  {
    "path": "eBook/Collateral/Readme.md",
    "content": "\n"
  },
  {
    "path": "eBook/Readme.md",
    "content": "# Microsoft Sentinel SOC 101 - the Book\n\nThis is part of an ongoing series to educate about using Microsoft Security products in real world scenario.\n\nThe full series index (including code, queries, and detections) is located here: https://aka.ms/SentinelSOC101 \n\nThe book will be updated when each new part in this series is released.\n\nThis book is updated every time a new part of this series is chaptered. The most current edition of this book will always be located at: https://github.com/rod-trent/Sentinel-SOC-101/tree/main/eBook \n\n*Book release ver. 0.070, February 12, 2024 8:00pm EST*\n\n"
  }
]