Descriptor:
  Name: MicrosoftDefenderExpertsPlugin
  DisplayName: Microsoft Defender Experts Security Copilot Plugin
  Description: Leverage detections built by the Microsoft Defender Experts team in identifying threat actor activity. For more information on Microsoft Defender Experts, go here https://www.microsoft.com/en-us/security/business/services/microsoft-defender-experts-hunting?msockid=3eb9717c7a346743120665a77b05660a
  Icon: https://raw.githubusercontent.com/KwachSean/SecurityCopilot/main/DEXlogo_resized_icon.png

SkillGroups:
  - Format: KQL
    Skills:
      - Name: DEX-SuspiciousUseOfAzureHound
        DisplayName: Suspicious Use of AzureHound
        Description: Detects potential suspicious usage of AzureHound on devices.
        Inputs:
          - Name: days
            Description: Look back x amount of days, for example 10, 20, 30.
            Required: true
        Settings:
          Target: Defender
          Template: |-
            DeviceProcessEvents
            | where TimeGenerated > ago({{days}}d)
            | where FileName has "azurehound.exe"
            | where ProcessCommandLine has "azurehound" and ProcessCommandLine has_any ("az-rm", "az-ad", "list", "Invoke-azurehound")

      - Name: DEX-ReconnaissanceActivityUsingNetworkLogs
        DisplayName: Reconnaissance Activity Using Network Logs
        Description: Detects reconnaissance activity leveraging network logs and specific URLs.
        Inputs:
          - Name: days
            Description: Look back x amount of days, for example 10, 20, 30.
            Required: true
        Settings:
          Target: Defender
          Template: |-
            DeviceNetworkEvents
            | where TimeGenerated > ago({{days}}d)
            | where RemoteUrl in ("login.microsoftonline.com", "graph.microsoft.com")
            | where InitiatingProcessCommandLine has_any ("list", "-u", "-p", "--u", "--p", "--app", "--secret", "-app", "-secret", "--cert", "-cert", "-j", "--j")
            | where InitiatingProcessFolderPath !contains "Microsoft"
            | summarize dcount(RemoteUrl) by bin(Timestamp, 1m), InitiatingProcessFileName, DeviceId
            | where dcount_RemoteUrl == 2

      - Name: DEX-RoadreconAndRoadtxActivity
        DisplayName: ROADrecon and ROADtx Activity
        Description: Detects known filenames and command line activity associated with ROADrecon and ROADtx tools.
        Inputs:
          - Name: days
            Description: Look back x amount of days, for example 10, 20, 30.
            Required: true
        Settings:
          Target: Defender
          Template: |-
            DeviceProcessEvents
            | where TimeGenerated > ago({{days}}d)
            | where InitiatingProcessFileName has_any ("powershell", "cmd.exe", "pwsh.exe")
            | where FileName has_any ("roadrecon.exe", "roadtx.exe")
            | where ProcessCommandLine has_any ("auth", "gather", "plugin", "dump", "gettokens", "interactiveauth", "listaliases", "findscope", "device", "prt", "prtauth", "keepassauth", "browserprtauth", "browserprtinject")
            | project-reorder Timestamp, ReportId, DeviceId, InitiatingProcessCommandLine, FileName, InitiatingProcessFileName, ProcessCommandLine, InitiatingProcessParentFileName, ProcessVersionInfoOriginalFileName, ProcessVersionInfoInternalFileName, InitiatingProcessVersionInfoOriginalFileName, InitiatingProcessFileName

      - Name: DEX-FederatedIdPAdditionActivity
        DisplayName: Federated IdP Addition Activity
        Description: Detects possible roadoidc activity related to federated identity provider addition.
        Inputs:
          - Name: days
            Description: Look back x amount of days, for example 10, 20, 30.
            Required: true
        Settings:
          Target: Defender
          Template: |-
            DeviceNetworkEvents
            | where TimeGenerated > ago({{days}}d)
            | where InitiatingProcessFileName == "python.exe"
            | where InitiatingProcessParentFileName == "roadtx.exe"
            | where InitiatingProcessCommandLine has_any ("federatedappauth", "azurewebsites", "--key-pem", "--cert-pem")
            | extend RemoteUrl = replace_regex(RemoteUrl, @'http(s)?://', '')
            | where ActionType == "ConnectionSuccess"
            | project DeviceId, Timestamp, ReportId, InitiatingProcessFileName, InitiatingProcessId, InitiatingProcessAccountSid, RemoteIP, RemoteUrl, ActionType

      - Name: DEX-RecentEntraIDJoinedDevices
        DisplayName: Recent Entra ID-Joined Devices
        Description: Identifies devices recently joined to Entra ID, potentially by threat actors to maintain access.
        Inputs:
          - Name: days
            Description: Look back x amount of days, for example 10, 20, 30.
            Required: true
        Settings:
          Target: Defender
          Template: |-
            AuditLogs
            | where TimeGenerated > ago({{days}}d)
            | extend userPrincipalName_ = tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName)
            | extend DeviceRegInfo = tostring(AdditionalDetails[0].value)
            | extend TrustType = tostring(AdditionalDetails[2].value)
            | extend DeviceID = tostring(AdditionalDetails[4].value)
            | where userPrincipalName_ contains " "         //add user entity here
            | project TimeGenerated, OperationName, Category, DeviceRegInfo, DeviceID, TrustType, userPrincipalName_

      - Name: DEX-FakeGlobalProtectTool
        DisplayName: Fake Global Protect Tool
        Description: Detects possible use of a fake Global Protect tool by looking for known file and folder patterns.
        Inputs:
          - Name: days
            Description: Look back x amount of days, for example 10, 20, 30.
            Required: true
        Settings:
          Target: Defender
          Template: |-
            DeviceNetworkEvents
            | where TimeGenerated > ago({{days}}d)
            | where InitiatingProcessFileName has_any ("GlobalProtect.exe", "GlobalProtectPortal.exe")
            | where InitiatingProcessParentFileName endswith ".tmp"
            | where InitiatingProcessFolderPath has_all ("appdata", "paloalto")

      - Name: DEX-FakeAuthenticatorExecutable
        DisplayName: Fake Authenticator Executable
        Description: Detects use of a fake authenticator executable for information stealing, requiring Microsoft Defender XDR.
        Inputs:
          - Name: days
            Description: Look back x amount of days, for example 10, 20, 30.
            Required: true
        Settings:
          Target: Defender
          Template: |-
            DeviceProcessEvents
            | where TimeGenerated > ago({{days}}d)
            | where InitiatingProcessFileName has "msedge.exe"
            | where InitiatingProcessCommandLine has_all ("msedge.exe", "--no-startup-window")
            | where FileName has "Authenticator.exe"
            | join kind=inner
              (DeviceNetworkEvents
              | where InitiatingProcessFileName has "Authenticator.exe"
              | where RemoteUrl has "paradiso4.fun"
              | where ActionType == "ConnectionSuccess")
              on DeviceId

      - Name: DEX-EmailBombingActivity
        DisplayName: Email Bombing Activity Detection
        Description: Detects possible email bombing activity using anomaly detection on inbound emails.
        Inputs:
          - Name: days
            Description: Look back x amount of days, for example 10, 20, 30.
            Required: true
        Settings:
          Target: Defender
          Template: |-
            EmailEvents
            | where EmailDirection == "Inbound"
            | where Timestamp > ago({{days}}d)
            | make-series Emailcount = count() on Timestamp step 1h by RecipientObjectId
            | extend (Anomalies, AnomalyScore, ExpectedEmails) = series_decompose_anomalies(Emailcount)
            | mv-expand Emailcount, Anomalies, AnomalyScore, ExpectedEmails to typeof(double), Timestamp
            | where Anomalies != 0
            | where AnomalyScore >= 10

      - Name: DEX-TeamsPhishingActivity
        DisplayName: Teams Phishing Activity Detection
        Description: Detects possible Teams phishing activity by identifying suspicious chat creations.
        Inputs:
          - Name: alertedMachine
            Description: DeviceId of the alerted machine.
            Required: true
        Settings:
          Target: Defender
          Template: |-
            let suspiciousUpns = DeviceProcessEvents
            | where DeviceId == "{{alertedMachine}}"
            | where isnotempty(InitiatingProcessAccountUpn)
            | project InitiatingProcessAccountUpn;
            CloudAppEvents
            | where Application == "Microsoft Teams"
            | where ActionType == "ChatCreated"
            | where isempty(AccountObjectId)
            | where RawEventData.ParticipantInfo.HasForeignTenantUsers == true
            | where RawEventData.CommunicationType == "OneonOne"
            | where RawEventData.ParticipantInfo.HasGuestUsers == false
            | where RawEventData.ParticipantInfo.HasOtherGuestUsers == false
            | where RawEventData.Members[0].DisplayName in ("Microsoft  Security", "Help Desk", "Help Desk Team", "Help Desk IT", "Microsoft Security", "office")
            | where AccountId has "@"
            | extend TargetUPN = tolower(tostring(RawEventData.Members[1].UPN))
            | where TargetUPN in (suspiciousUpns)

      - Name: DEX-CobaltStrikeDNSBeaconing
        DisplayName: Cobalt Strike DNS Beaconing Detection
        Description: Detects suspicious DNS queries associated with Cobalt Strike beacons.
        Inputs:
          - Name: days
            Description: Look back x amount of days, for example 10, 20, 30.
            Required: true
        Settings:
          Target: Defender
          Template: |-
            let badNames = dynamic(["aaa.stage.", "post.1"]);
            (union isfuzzy=true
            (DnsEvents
            | where TimeGenerated > ago({{days}}d)
            | where Name has_any (badNames)
            | extend Domain = Name, SourceIp = ClientIP, RemoteIP = todynamic(IPAddresses)
            | mv-expand RemoteIP
            | extend RemoteIP = tostring(RemoteIP)),
            (VMConnection
            | where TimeGenerated > ago({{days}}d)
            | where isnotempty(RemoteDnsCanonicalNames)
            | parse RemoteDnsCanonicalNames with * '["' DNSName '"]' *
            | where DNSName has_any (badNames)
            | extend Domain = DNSName, RemoteIP = RemoteIp
            ))
            | summarize StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated) by Domain, SourceIp, RemoteIP, Computer
            | extend timestamp = StartTimeUtc, HostName = split(Computer, '.', 0)[0], DnsDomain = strcat_array(array_slice(split(Computer, '.'), 1, -1), '.')
            | extend Host_0_HostName = HostName
            | extend Host_0_DnsDomain = DnsDomain
            | extend IP_0_Address = RemoteIP

      - Name: DEX-ExcelLaunchingAnomalousProcesses
        DisplayName: Excel Launching Anomalous Processes
        Description: Detects Excel launching anomalous processes congruent with Qakbot payloads, indicating potential malicious activity.
        Inputs:
          - Name: days
            Description: Look back x amount of days, for example 10, 20, 30.
            Required: true
        Settings:
          Target: Defender
          Template: |-
            DeviceProcessEvents
            | where TimeGenerated > ago({{days}}d)
            | where InitiatingProcessParentFileName has "excel.exe" or InitiatingProcessFileName =~ "excel.exe"
            | where InitiatingProcessFileName in~ ("excel.exe", "regsvr32.exe")
            | where FileName in~ ("regsvr32.exe", "rundll32.exe")
            | where ProcessCommandLine has @"..\"

      - Name: DEX-GeneralAttemptsToAccessLocalEmailStore
        DisplayName: General Attempts to Access Local Email Store
        Description: Detects attempts to access files in the local path containing Outlook emails.
        Inputs:
          - Name: days
            Description: Look back x amount of days, for example 10, 20, 30.
            Required: true
        Settings:
          Target: Defender
          Template: |-
            DeviceFileEvents
            | where TimeGenerated > ago({{days}}d)
            | where FolderPath hasprefix "EmailStorage"
            | where FolderPath has "Outlook"
            | project FileName, FolderPath, InitiatingProcessFileName, InitiatingProcessCommandLine, DeviceId, Timestamp

      - Name: DEX-QakbotCraigslistDomains
        DisplayName: Qakbot Craigslist Domains Detection
        Description: Detects malicious domains impersonating Craigslist used by Qakbot operators.
        Inputs:
          - Name: days
            Description: Look back x amount of days, for example 10, 20, 30.
            Required: true
        Settings:
          Target: Defender
          Template: |-
            DeviceNetworkEvents
            | where TimeGenerated > ago({{days}}d)
            | where RemoteUrl matches regex @"abuse\.[a-zA-Z]\d{2}-craigslist\.org"

      - Name: DEX-QakbotEmailTheft
        DisplayName: Qakbot Email Theft Detection
        Description: Detects email stealing activities by Qakbot using specific patterns.
        Inputs:
          - Name: days
            Description: Look back x amount of days, for example 10, 20, 30.
            Required: true
        Settings:
          Target: Defender
          Template: |-
            DeviceFileEvents
            | where TimeGenerated > ago({{days}}d)
            | where InitiatingProcessFileName =~ 'ping.exe' and InitiatingProcessCommandLine == 'ping.exe -t 127.0.0.1'
            and InitiatingProcessParentFileName in~('msra.exe', 'mobsync.exe') and FolderPath endswith ".eml"

      - Name: DEX-QakbotReconnaissanceActivities
        DisplayName: Qakbot Reconnaissance Activities Detection
        Description: Detects reconnaissance and beaconing activities after code injection by Qakbot.
        Inputs:
          - Name: days
            Description: Look back x amount of days, for example 7, 14, 21.
            Required: true
        Settings:
          Target: Defender
          Template: |-
            DeviceProcessEvents
            | where TimeGenerated > ago({{days}}d)
            | where InitiatingProcessFileName == InitiatingProcessCommandLine
            | where ProcessCommandLine has_any (
            "whoami /all","cmd /c set","arp -a","ipconfig /all","net view /all","nslookup -querytype=ALL -timeout=10",
            "net share","route print","netstat -nao","net localgroup")
            | summarize dcount(FileName), make_set(ProcessCommandLine) by DeviceId, bin(Timestamp, 1d), InitiatingProcessFileName, InitiatingProcessCommandLine
            | where dcount_FileName >= 8

      - Name: DEX-SuspiciousNamedPipes
        DisplayName: Suspicious Named Pipes Detection
        Description: Detects named pipe events that may be linked to Cobalt Strike usage.
        Inputs:
          - Name: hours
            Description: Look back x amount of hours, for example 1, 2, 3.
            Required: true
        Settings:
          Target: Defender
          Template: |-
            let timeframe = {{hours}}h;
            let CobaltStrikeDefaults = dynamic([@"msagent_", @"MSSE-", @"postex_", @"status_", @"mypipe-f", @"mypipe-h", @"ntsvcs_", @"scerpc_", @"mojo.5688.8052."]);
            let CobaltStrikeMallable = dynamic([@"win_svc", @"ntsvcs", @"scerpc", @"status_", @"SearchTextHarvester", @"DserNamePipe", @"wkssvc_", @"scerpc_", @"spoolss_", @"CatalogChangeListener", @"fullduplex_", @"demoagent_", @"PGMessagePipe", @"MsFteWds", @"postex_ssh_", @"windows.update.manager", @"\f4c3", @"\f53f", @"halfduplex_"]);
            DeviceEvents
            | where Timestamp >= ago(timeframe)
            | where ActionType == "NamedPipeEvent"
            | extend AdditionalFields = parse_json(AdditionalFields)
            | extend ThreadId = tostring(AdditionalFields.ThreadId)
            | extend PipeName = tostring(AdditionalFields.PipeName)
            | extend InitiatingPID = tostring(InitiatingProcessId)
            | extend InitiatingParentPID = tostring(InitiatingProcessParentId)
            | where PipeName has_any (CobaltStrikeDefaults) or
              (PipeName matches regex @"\\mojo\.\d+\.\d+\." and not(PipeName matches regex @"\\mojo\.\d+\.\d+\.\d+$" or PipeName has InitiatingPID or PipeName has InitiatingParentPID or PipeName has ThreadId)) or
              (PipeName matches regex @"\\(edge|chrome)\.sync\.\d+\.\d+\." and not(PipeName matches regex @"\\(edge|chrome|edge\.sync|chrome\.sync)\.\d+\.\d+\.\d+$" or PipeName has InitiatingPID or PipeName has InitiatingParentPID or PipeName has ThreadId)) or
              (PipeName matches regex @"\\PSHost\.\d+\." and not(PipeName matches regex @"\\PSHost\.\d+\.\d+\." or PipeName has InitiatingPID or PipeName has InitiatingParentPID)) or
              (PipeName matches regex @"\\crashpad_" and not(PipeName matches regex @"\\crashpad_\d+_[A-Z]+" or PipeName has InitiatingPID or PipeName has InitiatingParentPID)) or
              (PipeName matches regex @"\\cubeb-pipe-" and not(PipeName matches regex @"\\cubeb-pipe-\d+_[0-9]{1,3}+" or PipeName has InitiatingPID)) or
              (PipeName has_any (CobaltStrikeMallable) and PipeName matches regex @"[a-fA-F0-9]{2,10}$") or
              (PipeName matches regex @"\\pipe\\[0-9a-f]{7,10}" or PipeName matches regex @"\\pipe\\[0-9a-f]{8}")

      - Name: DEX-CobaltStrikeInvokedWithWMI
        DisplayName: Cobalt Strike Invoked with WMI Detection
        Description: Detects possible invocation of Cobalt Strike using Windows Management Instrumentation (WMI).
        Inputs:
          - Name: days
            Description: Look back x amount of days, for example 7, 14, 21.
            Required: true
        Settings:
          Target: Defender
          Template: |-
            DeviceProcessEvents
            | where TimeGenerated > ago({{days}}d)
            | where InitiatingProcessFileName =~ 'wmiprvse.exe'
            | where FileName =~ 'powershell.exe'
            and (ProcessCommandLine hasprefix '-e' or ProcessCommandLine contains 'frombase64')
            | where ProcessCommandLine matches regex '[A-Za-z0-9+/]{50,}[=]{0,2}'
            | where ProcessCommandLine !has 'Windows\\CCM\\'
            | project DeviceId, Timestamp, InitiatingProcessId, InitiatingProcessFileName, ProcessId, FileName, ProcessCommandLine

      - Name: DEX-AutomatedEmailNotificationsAndSuspiciousSignInActivity
        DisplayName: Automated Email Notifications and Suspicious Sign-In Activity Detection
        Description: Correlates automated email notifications with suspicious sign-in activity to identify potential compromises.
        Inputs:
          - Name: days
            Description: Look back x amount of days, for example 1, 2, 3.
            Required: true
        Settings:
          Target: Defender
          Template: |-
            let usersWithSuspiciousEmails = EmailEvents
                | where TimeGenerated > ago({{days}}d)
                | where SenderFromAddress in ("no-reply@notify.microsoft.com", "no-reply@dropbox.com") or InternetMessageId startswith "<OneTimePasscode"
                | where isnotempty(RecipientObjectId)
                | distinct RecipientObjectId;
            AADSignInEventsBeta
            | where TimeGenerated > ago({{days}}d)
            | where AccountObjectId in (usersWithSuspiciousEmails)
            | where RiskLevelDuringSignIn == 100

      - Name: DEX-FileShareContentsAndSuspiciousSignInActivity
        DisplayName: File Share Contents and Suspicious Sign-In Activity Detection
        Description: Correlates file share emails with suspicious sign-ins to detect potential compromises.
        Inputs:
          - Name: days
            Description: Look back x amount of days, for example 1, 2, 3.
            Required: true
        Settings:
          Target: Defender
          Template: |-
            let usersWithSuspiciousEmails = EmailEvents
                | where TimeGenerated > ago({{days}}d)
                | where Subject has_all ("shared", "with you")
                | where Subject has_any ("payment", "invoice", "urgent", "mandatory", "Payoff", "Wire", "Confirmation", "password")
                | where isnotempty(RecipientObjectId)
                | summarize RecipientCount = dcount(RecipientObjectId), RecipientList = make_set(RecipientObjectId) by Subject
                | where RecipientCount >= 10
                | mv-expand RecipientList to typeof(string)
                | distinct RecipientList;
            AADSignInEventsBeta
            | where TimeGenerated > ago({{days}}d)
            | where AccountObjectId in (usersWithSuspiciousEmails)
            | where RiskLevelDuringSignIn == 100

      - Name: DEX-OneDriveOrSharePointMassFileSharingDetection
        DisplayName: OneDrive or SharePoint Mass File Sharing Detection
        Description: Detects files shared with multiple participants in OneDrive or SharePoint, indicating potential lateral movements or BEC attacks.
        Inputs:
          - Name: days
            Description: Look back x amount of days, for example 1, 2, 3.
            Required: true
        Settings:
          Target: Defender
          Template: |-
            let securelinkCreated = CloudAppEvents
                | where TimeGenerated > ago({{days}}d)
                | where ActionType == "SecureLinkCreated"
                | project FileCreatedTime = Timestamp, AccountObjectId, ObjectName;
            let filesCreated = securelinkCreated
                | where isnotempty(ObjectName)
                | distinct tostring(ObjectName);
            CloudAppEvents
            | where TimeGenerated > ago({{days}}d)
            | where ActionType == "AddedToSecureLink"
            | where Application in ("Microsoft SharePoint Online", "Microsoft OneDrive for Business")
            | extend FileShared = tostring(RawEventData.ObjectId)
            | where FileShared in (filesCreated)
            | extend UserSharedWith = tostring(RawEventData.TargetUserOrGroupName)
            | extend TypeofUserSharedWith = RawEventData.TargetUserOrGroupType
            | where TypeofUserSharedWith == "Guest"
            | where isnotempty(FileShared) and isnotempty(UserSharedWith)
            | join kind=inner securelinkCreated on $left.FileShared == $right.ObjectName
            | summarize NumofUsersSharedWith = dcount(UserSharedWith) by FileShared
            | where NumofUsersSharedWith >= 20

      - Name: DEX-DropboxMassFileSharingDetection
        DisplayName: Dropbox Mass File Sharing Detection
        Description: Detects files hosted on Dropbox that have been shared with multiple participants.
        Inputs:
          - Name: days
            Description: Look back x amount of days, for example 1, 2, 3.
            Required: true
        Settings:
          Target: Defender
          Template: |-
            CloudAppEvents
            | where TimeGenerated > ago({{days}}d)
            | where ActionType in ("Added users and/or groups to shared file/folder", "Invited user to Dropbox and added them to shared file/folder")
            | where Application == "Dropbox"
            | where ObjectType == "File"
            | extend FileShared = tostring(ObjectName)
            | where isnotempty(FileShared)
            | mv-expand ActivityObjects
            | where ActivityObjects.Type == "Account" and ActivityObjects.Role == "To"
            | extend SharedBy = AccountId
            | extend UserSharedWith = tostring(ActivityObjects.Name)
            | summarize dcount(UserSharedWith) by FileShared, AccountObjectId
            | where dcount_UserSharedWith >= 20

      - Name: DEX-PossibleAiTMPhishingAttemptAgainstEntraID
        DisplayName: Possible AiTM Phishing Attempt Against Entra ID
        Description: |
          Threat actors may attempt to phish users to hijack sign-in sessions, even if MFA is enabled, by stealing and replaying credentials and session cookies. This detection looks for successful Entra ID sign-ins with a high-risk profile and then checks for network connections to the same IP address immediately before the sign-in, indicating possible phishing activity.
        Inputs:
          - Name: days
            Description: Look back x amount of days, for example 1, 2, 3.
            Required: true
        Settings:
          Target: Defender
          Template: |-
            let time_threshold = 10m;
            let RiskySignins = materialize (SigninLogs
            | where TimeGenerated > ago({{days}}d)
            | where ResultType == 0
            | where RiskLevelDuringSignIn =~ "high" or RiskLevelAggregated =~ "high"
            | extend SignInTime = TimeGenerated, Name = split(UserPrincipalName, "@")[0], UPNSuffix = split(UserPrincipalName, "@")[1]);
            let ips = todynamic(toscalar(RiskySignins | summarize make_list(IPAddress)));
            RiskySignins
            | join kind=inner (_Im_WebSession(starttime=ago({{days}}d), ipaddr_has_any_prefix=ips, eventresult="Success", pack=True))
            on $left.IPAddress == $right.DstIpAddr
            | where EventStartTime < TimeGenerated
            | extend TimeDelta = TimeGenerated - EventStartTime
            | where TimeDelta <= time_threshold
            | extend NetworkEventStartTime = EventStartTime, NetworkEventEndTime = EventEndTime
            | extend SrcUsername = column_ifexists("SrcUsername", "Unknown")
            | project-reorder SignInTime, UserPrincipalName, IPAddress, AppDisplayName, ClientAppUsed, DeviceDetail, LocationDetails, NetworkLocationDetails, RiskEventTypes, UserAgent, NetworkEventStartTime, NetworkEventEndTime, SrcIpAddr, DstIpAddr, DstPortNumber, Dvc, DvcHostname, SrcBytes, NetworkProtocol, SrcUsername

      - Name: DEX-SigninsFromVPSProviders
        DisplayName: Sign-ins From VPS Providers
        Description: Detects successful logons from known VPS providers with suspicious token patterns.
        Inputs:
          - Name: riskScoreCutoff
            Description: Adjust this based on the volume of results; default is 20.
            Required: false
            DefaultValue: 20
        Settings:
          Target: Defender
          Template: |-
            let riskScoreCutoff = {{riskScoreCutoff}};
            let IP_Data = (externaldata(network:string)
            [@"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Sample%20Data/Feeds/VPS_Networks.csv"] with (format="csv"));
            SigninLogs
            | where ResultType == 0
            | extend additionalDetails = tostring(Status.additionalDetails)
            | evaluate ipv4_lookup(IP_Data, IPAddress, network, return_unmatched = false)
            | summarize make_set(additionalDetails), StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by IPAddress, UserPrincipalName
            | extend timestamp = StartTime, UserPrincipalName = tolower(UserPrincipalName), AccountCustomEntity = UserPrincipalName, IPCustomEntity = IPAddress
            | join kind=leftouter (
                IdentityInfo
                | summarize LatestReportTime = arg_max(TimeGenerated, *) by AccountUPN
                | extend UserPrincipalName = tolower(AccountUPN)
            ) on UserPrincipalName
            | join kind=leftouter (
                BehaviorAnalytics
                | where ActivityType in ("FailedLogOn", "LogOn")
                | where isnotempty(SourceIPAddress)
                | where ActivityInsights["ISPUncommonlyUsedInTenant"] == True
                | summarize IPInvestigationPriority = sum(InvestigationPriority) by IPAddress = SourceIPAddress
            ) on IPAddress
            | extend UEBARiskScore = IPInvestigationPriority
            | where UEBARiskScore > riskScoreCutoff
            | sort by UEBARiskScore desc

      - Name: DEX-SigninsFromNordVPNProviders
        DisplayName: Sign-ins from Nord VPN Providers
        Description: Tracks sign-ins via Nord VPN using a daily-updated API to detect unusual activity.
        Inputs:
          - Name: hours
            Description: Look back x amount of hours, for example 4, 8, 12.
            Required: true
        Settings:
          Target: Defender
          Template: |-
            let nord_vpn_feed = (externaldata(id:int, ip_address:string, search_keywords:dynamic, categories:dynamic, name:string, domain:string, price:int, flag:string, country:string, location:dynamic, load:int, features:dynamic)
              [@"https://raw.githubusercontent.com/microsoft/mstic/master/nordvpn-servers.csv"] with (format="csv", ignoreFirstRecord=True));
            SigninLogs
            | where TimeGenerated > ago({{hours}}h)
            | where ResultType == 0
            | summarize TotalEvents = count(), AppList = make_set(AppDisplayName), StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by IPAddress, UserPrincipalName, ClientAppUsed, ConditionalAccessStatus, AuthenticationRequirement, RiskDetail
            | join kind=inner nord_vpn_feed on $left.IPAddress == $right.ip_address
            | extend timestamp = StartTime, UserPrincipalName = tolower(UserPrincipalName), AccountCustomEntity = UserPrincipalName, IPCustomEntity = IPAddress
            | join kind=leftouter (
                IdentityInfo
                | summarize LatestReportTime = arg_max(TimeGenerated, *) by AccountUPN
                | extend UserPrincipalName = tolower(AccountUPN)
            ) on UserPrincipalName
            | join kind=leftouter (
                BehaviorAnalytics
                | where ActivityType in ("FailedLogOn", "LogOn")
                | where isnotempty(SourceIPAddress)
                | where ActivityInsights["ISPUncommonlyUsedInTenant"] == True
                | summarize IPInvestigationPriority = sum(InvestigationPriority) by IPAddress = SourceIPAddress
            ) on IPAddress
            | extend UEBARiskScore = IPInvestigationPriority
            | sort by UEBARiskScore desc

      - Name: DEX-SuccessfulSigninFromNonCompliantDevice
        DisplayName: Successful Sign-in From Non-Compliant Device
        Description: Detects successful sign-ins from devices marked non-compliant.
        Inputs:
          - Name: riskScoreCutoff
            Description: Adjust this based on the volume of results; default is 0.
            Required: false
            DefaultValue: 0
        Settings:
          Target: Defender
          Template: |-
            SigninLogs
            | where ResultType == 0
            | where tostring(DeviceDetail.isCompliant) == "false"
            | extend Account_0_Name = tolower(UserPrincipalName)
            | extend IP_0_Address = IPAddress
            | join kind=leftouter (
                IdentityInfo
                | summarize LatestReportTime = arg_max(TimeGenerated, *) by AccountUPN
                | extend Account_0_Name = tolower(AccountUPN)
            ) on Account_0_Name
            | join kind=leftouter (
                BehaviorAnalytics
                | where ActivityType in ("FailedLogOn", "LogOn")
                | where isnotempty(SourceIPAddress)
                | summarize IPInvestigationPriority = sum(InvestigationPriority) by IP_0_Address = SourceIPAddress
            ) on IP_0_Address
            | extend UEBARiskScore = IPInvestigationPriority
            | where UEBARiskScore > {{riskScoreCutoff}}
            | sort by UEBARiskScore desc
