Detection rules › Kusto

Kusto rules: 1b

[AzureSubscription] Suspicious Azure VM Run Command Execution Detected

#
Status
available
Severity
high
Time window
2d
Group by
Authorization, Caller, CorrelationId, OperationNameValue, joinkey
Source
github.com/Azure/Azure-Sentinel

Detects Azure VM Run Command execution correlated with unusual sign-in behavior from UEBA. This can indicate administrative abuse or post-compromise activity.

MITRE ATT&CK Coverage

TacticTechniques
Credential Access
Lateral Movement

Telemetry Coverage

Rule Body

id: 6fa564ac-dfb7-4753-a49b-5fc919866c28
name: "[AzureSubscription] Suspicious Azure VM Run Command Execution Detected"
version: 1.0.0
kind: Scheduled
description: |
  Detects Azure VM Run Command execution correlated with unusual sign-in behavior from UEBA. This can indicate administrative abuse or post-compromise activity.
severity: High
status: Available
requiredDataConnectors:
  - connectorId: AzureActivity
    dataTypes:
      - AzureActivity
queryFrequency: 1d
queryPeriod: 2d
triggerOperator: gt
triggerThreshold: 0
tactics:
  - LateralMovement
  - CredentialAccess
relevantTechniques:
  - T1570
  - T1212
query: |
  AzureActivity
  // Isolate run command actions
  | where OperationNameValue =~ "MICROSOFT.COMPUTE/VIRTUALMACHINES/RUNCOMMAND/ACTION"
  // Confirm that the operation impacted a virtual machine
  | where Authorization has "virtualMachines"
  // Each runcommand operation consists of three events when successful, Started, Accepted (or Rejected), Successful (or Failed).
  | summarize
      StartTime=min(TimeGenerated),
      EndTime=max(TimeGenerated),
      max(CallerIpAddress),
      make_list(ActivityStatusValue)
      by CorrelationId, Authorization, Caller, OperationNameValue
  // Limit to Run Command executions that Succeeded
  | where list_ActivityStatusValue has_any ("Success", "Succeeded")
  // Extract data from the Authorization field
  | extend Authorization_d = parse_json(Authorization)
  | extend Scope = Authorization_d.scope
  | extend Scope_s = split(Scope, "/")
  | extend Subscription = tostring(Scope_s[2])
  | extend VirtualMachineName = tostring(Scope_s[-1])
  | project
      StartTime,
      EndTime,
      Subscription,
      VirtualMachineName,
      CorrelationId,
      Caller,
      CallerIpAddress=max_CallerIpAddress,
      OperationNameValue
  // Create a join key using  the Caller (UPN)
  | extend joinkey = tolower(Caller)
  // Join the Run Command actions to UEBA data
  | join kind = inner (
      BehaviorAnalytics
      // We are specifically interested in unusual logins
      | where EventSource == "Azure AD" and ActivityInsights.ActionUncommonlyPerformedByUser == "True"
      | project
          UEBAEventTime=TimeGenerated,
          UEBAActionType=ActionType,
          UserPrincipalName,
          UEBASourceIPLocation=SourceIPLocation,
          UEBAActivityInsights=ActivityInsights,
          UEBAUsersInsights=UsersInsights
      | where isnotempty(UserPrincipalName) and isnotempty(UEBASourceIPLocation)
      | extend joinkey = tolower(UserPrincipalName)
      )
      on joinkey
  // Create a window around the UEBA event times, check to see if the Run Command action was performed within them
  | extend UEBAWindowStart = UEBAEventTime - 1h, UEBAWindowEnd = UEBAEventTime + 6h
  | where StartTime between (UEBAWindowStart .. UEBAWindowEnd)
  | project
      StartTime,
      EndTime,
      Subscription,
      VirtualMachineName,
      Caller,
      CallerIpAddress,
      UEBAEventTime,
      UEBAActionType,
      UEBASourceIPLocation,
      UEBAActivityInsights,
      UEBAUsersInsights,
      OperationNameValue
  | extend
      AccountName = tostring(split(Caller, "@")[0]),
      AccountUPNSuffix = tostring(split(Caller, "@")[1])
  | extend Source_Network_IPLocation = ""
  | project
          Alert_Category_en = "Azure Subscription",
      Alert_SubCategory_en = "Anomaly User Access Resource",
      Alert_Name_en = "Suspicious Azure VM Run Command Execution Detected",
      Alert_Description_en=
      strcat(
      "At Taiwan time: ",
      format_datetime(datetime_utc_to_local(StartTime, "Asia/Taipei"), "yyyy-MM-dd HH:mm:ss"),
      ", detected user  ",
      iff(isnotempty(Caller), Caller, "<NoCaller>"),
      "  in subscription  ",
      iff(isnotempty(Subscription), Subscription, "<NoSubscription>"),
      "  executed against virtual machine  ",
      iff(isnotempty(VirtualMachineName), VirtualMachineName, "<NoVM>"),
      "  successfully performed Run Command operation: ",
      OperationNameValue,
      ". Source IP: ",
      iff(isnotempty(CallerIpAddress), CallerIpAddress, "<NoIP>"),
      ". The user was also flagged by UEBA detection for uncommon behavior: ",
      iff(isnotempty(UEBAActionType), UEBAActionType, "<NoUEBAType>"),
      ", source location: ",
      iff(isnotempty(UEBASourceIPLocation), UEBASourceIPLocation, "<NoLocation>"),
      ", indicating this administrative operation has potential account abuse risk."
  ),
      Alert_TriageStep_en=
      strcat(
      "1. Confirm whether user  ",
      iff(isnotempty(Caller), Caller, "<NoCaller>"),
      "  is a legitimate operator/maintainer of the VM, and check whether there is a corresponding change or maintenance ticket.",
      "2. Review whether Run Command is an expected command and confirm whether it involves download, account creation, service modification, or persistence behavior.",
      "3. Compare source IP  ",
      iff(isnotempty(CallerIpAddress), CallerIpAddress, "<NoIP>"),
      "  with the location flagged by UEBA ",
      iff(isnotempty(UEBASourceIPLocation), UEBASourceIPLocation, "<NoLocation>"),
      "  to determine whether it is abnormal (VPN, uncommon location, jump server)."
  ),
      Alert_Containment_en=
      strcat(
      "1. If confirmed as an unauthorized operation, immediately revoke user  ",
      iff(isnotempty(Caller), Caller, "<NoCaller>"),
      " 's existing sign-in sessions and access tokens, and force re-authentication or suspend the account.",
      "2. Temporarily remove the account's administrative permissions on the target virtual machine (such as Virtual Machine Contributor / Owner) to prevent Run Command from being executed again.",
      "3. For source IP  ",
      iff(isnotempty(CallerIpAddress), CallerIpAddress, "<NoIP>"),
      "  block it or increase Conditional Access restrictions to prevent continued abuse.",
      "4. Depending on the risk level, isolate the affected VM and perform cybersecurity forensics to prevent lateral movement or malicious persistence."
  ),
      Alert_Remediation_en=
      strcat(
      "1. Apply the least privilege principle to all roles that can execute Run Command, and manage high-privilege accounts through PIM/JIT.",
      "2. Strengthen Conditional Access policies by requiring management operations to pass MFA, device compliance, and named location checks, and block uncommon location sign-ins.",
      "3. Establish real-time alerts and automated response for Run Command-related activity, such as revoking sessions, disabling accounts, and notifying SOC.",
      "4. Ensure Defender for Cloud and EDR are enabled on virtual machines, and regularly audit scheduled tasks, services, and startup items on VMs to avoid malicious command remnants.",
      "5. Reduce the risk of hosts being exploited again through known vulnerabilities by applying regular security patches and vulnerability updates."
  ),
              Alert_Time_TW = datetime_utc_to_local(StartTime, "Asia/Taipei"),
      Alert_Time_UTC0 = StartTime,
      Event_TimeRange_Start_TW = datetime_utc_to_local(StartTime, 'Asia/Taipei'),
      Event_TimeRange_End_TW = datetime_utc_to_local(EndTime, 'Asia/Taipei'),
      Event_TimeRange_Start_UTC0 = StartTime,
      Event_TimeRange_End_UTC0 = EndTime,
      Event_Action = OperationNameValue,
      //Event_Code = score,
      Source_Identity_FullName = Caller,
      //Source_Identity_ID = ActorID,
      Source_Identity_Type = iff(Caller contains '@', "User", "Service"),
      Source_Network_IPAddress = CallerIpAddress,
      Source_Network_IPLocation = Source_Network_IPLocation,
      Target_Device_Name = VirtualMachineName,
      Target_Resource_ID = Subscription,
      Target_Resource_Type = "Azure Subscription"
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: Source_Identity_FullName
  - entityType: Host
    fieldMappings:
      - identifier: HostName
        columnName: Target_Device_Name
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: Source_Network_IPAddress

Stages and Predicates

Stage 1: source

AzureActivity

Stage 2: where

| where OperationNameValue =~ "MICROSOFT.COMPUTE/VIRTUALMACHINES/RUNCOMMAND/ACTION"

Stage 3: where

| where Authorization has "virtualMachines"

Stage 4: summarize

| summarize
    StartTime=min(TimeGenerated),
    EndTime=max(TimeGenerated),
    max(CallerIpAddress),
    make_list(ActivityStatusValue)
    by CorrelationId, Authorization, Caller, OperationNameValue

Stage 5: where

| where list_ActivityStatusValue has_any ("Success", "Succeeded")

Stage 6: extend (5 consecutive steps)

| extend Authorization_d = parse_json(Authorization)
| extend Scope = Authorization_d.scope
| extend Scope_s = split(Scope, "/")
| extend Subscription = tostring(Scope_s[2])
| extend VirtualMachineName = tostring(Scope_s[-1])

Stage 7: project

| project
    StartTime,
    EndTime,
    Subscription,
    VirtualMachineName,
    CorrelationId,
    Caller,
    CallerIpAddress=max_CallerIpAddress,
    OperationNameValue

Stage 8: extend

| extend joinkey = tolower(Caller)

Stage 9: join

| join kind = inner (
    BehaviorAnalytics
    | where EventSource == "Azure AD" and ActivityInsights.ActionUncommonlyPerformedByUser == "True"
    | project
        UEBAEventTime=TimeGenerated,
        UEBAActionType=ActionType,
        UserPrincipalName,
        UEBASourceIPLocation=SourceIPLocation,
        UEBAActivityInsights=ActivityInsights,
        UEBAUsersInsights=UsersInsights
    | where isnotempty(UserPrincipalName) and isnotempty(UEBASourceIPLocation)
    | extend joinkey = tolower(UserPrincipalName)
    )
    on joinkey

Stage 10: extend

extend UEBAWindowEnd, UEBAWindowStart

Stage 11: where

where StartTime >= "UEBAWindowStart" and StartTime <= "UEBAWindowEnd"

Stage 12: project

project Caller, CallerIpAddress, EndTime, OperationNameValue, StartTime, Subscription, UEBAActionType, UEBAActivityInsights, UEBAEventTime, UEBASourceIPLocation, UEBAUsersInsights, VirtualMachineName

Stage 13: extend

extend AccountName, AccountUPNSuffix

Stage 14: extend

extend Source_Network_IPLocation

Stage 15: project

project Alert_Category_en, Alert_Containment_en, Alert_Description_en, Alert_Name_en, Alert_Remediation_en, Alert_SubCategory_en, Alert_Time_TW, Alert_Time_UTC0, Alert_TriageStep_en, Event_Action, Event_TimeRange_End_TW, Event_TimeRange_End_UTC0, Event_TimeRange_Start_TW, Event_TimeRange_Start_UTC0, Source_Identity_FullName, Source_Identity_Type, Source_Network_IPAddress, Source_Network_IPLocation, Target_Device_Name, Target_Resource_ID, Target_Resource_Type

Indicators

These rows show field, operator, and value matches.

Output Fields

These fields are emitted when the rule matches.

FieldSource
Alert_Category_enproject
Alert_Containment_enproject
Alert_Description_enproject
Alert_Name_enproject
Alert_Remediation_enproject
Alert_SubCategory_enproject
Alert_Time_TWproject
Alert_Time_UTC0project
Alert_TriageStep_enproject
Event_Actionproject
Event_TimeRange_End_TWproject
Event_TimeRange_End_UTC0project
Event_TimeRange_Start_TWproject
Event_TimeRange_Start_UTC0project
Source_Identity_FullNameproject
Source_Identity_Typeproject
Source_Network_IPAddressproject
Source_Network_IPLocationproject
Target_Device_Nameproject
Target_Resource_IDproject
Target_Resource_Typeproject

API - JWT validation

#
Status
available
Severity
low
Time window
5m
Source
github.com/Azure/Azure-Sentinel

'42Crunch API protection against JWT validation'

MITRE ATT&CK Coverage

Rule Body

id: bbd163f4-1f56-434f-9c23-b06713c119c2
name: API - JWT validation
description: |
  '42Crunch API protection against JWT validation'
severity: Low
requiredDataConnectors:
  - connectorId: 42CrunchAPIProtection
    dataTypes:
      - FortyTwoCrunchAPIProtection
  - connectorId: FortyTwoCrunchAPIProtection
    dataTypes:
      - FortyTwoCrunchAPIProtection
queryFrequency: 5m
queryPeriod: 5m
triggerOperator: gt
triggerThreshold: 0
eventGroupingSettings:
  aggregationKind: SingleAlert
status: Available
tactics:
  - InitialAccess
  - CredentialAccess
relevantTechniques:
  - T1190
  - T1528
query: |
  FortyTwoCrunchAPIProtection
  | where TimeGenerated >= ago(5m) 
  | where ErrorMessage has "missing [\"x-access-token\"]" 
  | project-away NonBlockingMode, SourcePort, DestinationPort, Query, ApiId, ResponseHeader, RequestHeader, Errors, EventType, Uuid 
  | sort by TimeGenerated desc 
customDetails:
entityMappings:
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: SourceIp
  - entityType: Host
    fieldMappings:
      - identifier: HostName
        columnName: Hostname
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: InstanceName
version: 3.0.1
kind: Scheduled

Stages and Predicates

Stage 1: source

FortyTwoCrunchAPIProtection

Stage 2: where

| where TimeGenerated >= ago(5m)

Stage 3: where

| where ErrorMessage has "missing [\"x-access-token\"]"

Stage 4: project-away

| project-away NonBlockingMode, SourcePort, DestinationPort, Query, ApiId, ResponseHeader, RequestHeader, Errors, EventType, Uuid

Stage 5: sort

| sort by TimeGenerated desc

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
ErrorMessagematch
  • missing ["x-access-token"] transforms: term
field:"aws::errorMessage" kind:match

AWSCloudTrail - Privilege escalation via CloudFormation policy

#
Status
available
Severity
medium
Time window
1d
Source
github.com/Azure/Azure-Sentinel

Detects creation of inline IAM policies with CloudFormation and IAM permissions associated with privilege escalation pathways, including iam:PassRole plus stack creation capabilities. This pattern can enable indirect elevation and should be investigated for unauthorized policy changes.

MITRE ATT&CK Coverage

TacticTechniques
Privilege Escalation

Telemetry Coverage

Rules Detecting the Same Action

These rules filter on the same operation.

Rule Body

id: 719d5204-10ab-4b1f-aee1-da7326750260
name: AWSCloudTrail - Privilege escalation via CloudFormation policy
description: |
  Detects creation of inline IAM policies with CloudFormation and IAM permissions associated with privilege
  escalation pathways, including iam:PassRole plus stack creation capabilities. This pattern can enable indirect
  elevation and should be investigated for unauthorized policy changes.
severity: Medium
status: Available
requiredDataConnectors:
  - connectorId: AWS
    dataTypes:
      - AWSCloudTrail
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
  - PrivilegeEscalation
relevantTechniques:
  - T1098.003
query: |
    AWSCloudTrail
      | where EventName in ("PutUserPolicy","PutRolePolicy","PutGroupPolicy") and isempty(ErrorCode) and isempty(ErrorMessage)
      | extend PolicyName = tostring(parse_json(RequestParameters).policyName)
      | extend Statement = parse_json(tostring((parse_json(RequestParameters).policyDocument))).Statement
      | mvexpand Statement
      | extend Action = parse_json(Statement).Action , Effect = tostring(parse_json(Statement).Effect), Resource = tostring(parse_json(Statement).Resource), Condition = tostring(parse_json(Statement).Condition)
      | extend Action = tostring(Action)
      | where Effect =~ "Allow" and (((Action has "iam:*" or Action has "iam:PassRole") and Action has "cloudformation:*") or ((Action has "iam:*" or Action has "iam:PassRole") and Action contains "cloudformation:DescribeStacks" and Action contains "cloudformation:CreateStack") or ((Action contains "iam:*" or Action contains "iam:PassRole") and Action contains "cloudformation:Describe*" and Action contains "cloudformation:Create*")) and Resource == "*" and Condition == ""
      | extend UserIdentityArn = iif(isempty(UserIdentityArn), tostring(parse_json(Resources)[0].ARN), UserIdentityArn)
      | extend UserName = tostring(split(UserIdentityArn, '/')[-1])
      | extend AccountName = case( UserIdentityPrincipalid == "Anonymous", "Anonymous", isempty(UserIdentityUserName), UserName, UserIdentityUserName)
      | extend AccountName = iif(AccountName contains "@", tostring(split(AccountName, '@', 0)[0]), AccountName),
        AccountUPNSuffix = iif(AccountName contains "@", tostring(split(AccountName, '@', 1)[0]), "")
      | distinct TimeGenerated, EventName, PolicyName, SourceIpAddress, RecipientAccountId, AccountName, AccountUPNSuffix, UserIdentityArn, UserIdentityUserName
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: Name
        columnName: AccountName
      - identifier: UPNSuffix
        columnName: AccountUPNSuffix
      - identifier: CloudAppAccountId
        columnName: RecipientAccountId
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: SourceIpAddress
customDetails:
  PolicyName: PolicyName
  EventName: EventName
  UserIdentityArn: UserIdentityArn
  RecipientAccountId: RecipientAccountId
alertDetailsOverride:
  alertDisplayNameFormat: 'AWS CloudFormation privilege escalation policy update by {{AccountName}}'
  alertDescriptionFormat: 'Detected {{EventName}} Event, updating inline CloudFormation escalation policy {{PolicyName}} in account {{RecipientAccountId}}.'
version: 1.0.2
kind: Scheduled

Stages and Predicates

Stage 1: source

AWSCloudTrail

Stage 2: where

| where EventName in ("PutUserPolicy","PutRolePolicy","PutGroupPolicy") and isempty(ErrorCode) and isempty(ErrorMessage)

Stage 3: extend

| extend PolicyName = tostring(parse_json(RequestParameters).policyName)

Stage 4: extend

| extend Statement = parse_json(tostring((parse_json(RequestParameters).policyDocument))).Statement

Stage 5: mv-expand

| mvexpand Statement

Stage 6: extend

| extend Action = parse_json(Statement).Action , Effect = tostring(parse_json(Statement).Effect), Resource = tostring(parse_json(Statement).Resource), Condition = tostring(parse_json(Statement).Condition)

Stage 7: extend

| extend Action = tostring(Action)

Stage 8: where

| where Effect =~ "Allow" and (((Action has "iam:*" or Action has "iam:PassRole") and Action has "cloudformation:*") or ((Action has "iam:*" or Action has "iam:PassRole") and Action contains "cloudformation:DescribeStacks" and Action contains "cloudformation:CreateStack") or ((Action contains "iam:*" or Action contains "iam:PassRole") and Action contains "cloudformation:Describe*" and Action contains "cloudformation:Create*")) and Resource == "*" and Condition == ""

Stage 9: extend (4 consecutive steps)

| extend UserIdentityArn = iif(isempty(UserIdentityArn), tostring(parse_json(Resources)[0].ARN), UserIdentityArn)
| extend UserName = tostring(split(UserIdentityArn, '/')[-1])
| extend AccountName = case( UserIdentityPrincipalid == "Anonymous", "Anonymous", isempty(UserIdentityUserName), UserName, UserIdentityUserName)
| extend AccountName = iif(AccountName contains "@", tostring(split(AccountName, '@', 0)[0]), AccountName),
    AccountUPNSuffix = iif(AccountName contains "@", tostring(split(AccountName, '@', 1)[0]), "")

Stage 10: distinct

| distinct TimeGenerated, EventName, PolicyName, SourceIpAddress, RecipientAccountId, AccountName, AccountUPNSuffix, UserIdentityArn, UserIdentityUserName

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
Actioncontains
  • cloudformation:Create*
  • cloudformation:CreateStack
  • cloudformation:Describe*
  • cloudformation:DescribeStacks
  • iam:*
  • iam:PassRole
field:"Action" kind:contains
Actionmatch
  • cloudformation:* transforms: term
  • iam:* transforms: term
  • iam:PassRole transforms: term
field:"Action" kind:match
Effecteq
  • Allow
field:"Effect" kind:eq value:"Allow"
ErrorCodeis_null
  • (no value, null check)
field:"aws::errorCode" kind:is_null
ErrorMessageis_null
  • (no value, null check)
field:"aws::errorMessage" kind:is_null
EventNamein
  • PutGroupPolicy corpus 12 (kusto 11, panther 1)
  • PutRolePolicy corpus 12 (kusto 11, panther 1)
  • PutUserPolicy corpus 12 (kusto 11, panther 1)
field:"aws::eventName" kind:in
Resourceeq
  • *
field:"Resource" kind:eq value:"*"

Output Fields

These fields are emitted when the rule matches.

FieldSource
PolicyNameextend
Statementextend
Actionextend
Conditionextend
Effectextend
Resourceextend
UserIdentityArnextend
UserNameextend
AccountNameextend
AccountUPNSuffixextend

Cisco Cloud Security - Empty User Agent Detected

#
Status
available
Severity
medium
Time window
15m
Source
github.com/Azure/Azure-Sentinel

'Rule helps to detect empty and unusual user agent indicating web browsing activity by an unusual process other than a web browser.'

MITRE ATT&CK Coverage

Rule Body

id: 2b328487-162d-4034-b472-59f1d53684a1
name: Cisco Cloud Security - Empty User Agent Detected
description: |
  'Rule helps to detect empty and unusual user agent indicating web browsing activity by an unusual process other than a web browser.'
severity: Medium
status: Available
requiredDataConnectors:
  - connectorId: CiscoUmbrellaDataConnector
    dataTypes:
      - Cisco_Umbrella_proxy_CL
queryFrequency: 15m
queryPeriod: 15m
triggerOperator: gt
triggerThreshold: 0
tactics:
  - CommandAndControl
relevantTechniques:
  - T1001.003
query: |
  Cisco_Umbrella
  | where EventType == "proxylogs"
  | where HttpUserAgentOriginal == ''
  | extend Message = "Empty User Agent"
  | project TimeGenerated, Message, SrcIpAddr, DstIpAddr, UrlOriginal 
entityMappings:
  - entityType: URL
    fieldMappings:
      - identifier: Url
        columnName: UrlOriginal
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: SrcIpAddr
version: 1.1.3
kind: Scheduled

Stages and Predicates

Stage 1: source

Cisco_Umbrella

Stage 2: where

| where EventType == "proxylogs"

Stage 3: where

| where HttpUserAgentOriginal == ''

Stage 4: extend

| extend Message = "Empty User Agent"

Stage 5: project

| project TimeGenerated, Message, SrcIpAddr, DstIpAddr, UrlOriginal

Indicators

These rows show field, operator, and value matches.

Output Fields

These fields are emitted when the rule matches.

FieldSource
DstIpAddrproject
Messageproject
SrcIpAddrproject
TimeGeneratedproject
UrlOriginalproject

CiscoISE - Log collector was suspended

#
Status
available
Severity
medium
Time window
10m
Source
github.com/Azure/Azure-Sentinel

'Detects when log collector was suspended.'

MITRE ATT&CK Coverage

Rule Body

id: ce171782-1643-4f21-bbb7-fa954b1e6897
name: CiscoISE - Log collector was suspended
description: |
  'Detects when log collector was suspended.'
severity: Medium
status: Available
requiredDataConnectors:
  - connectorId: SyslogAma
    datatypes:
      - Syslog
queryFrequency: 10m
queryPeriod: 10m
triggerOperator: gt
triggerThreshold: 0
tactics:
  - DefenseEvasion
relevantTechniques:
  - T1562.002
query: |
  let lbtime = 10m;
  CiscoISEEvent
  | where TimeGenerated > ago(lbtime)
  | where EventId == '59207'
  | project TimeGenerated, SrcIpAddr, DstIpAddr
  | extend IPCustomEntity = DstIpAddr
entityMappings:
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: IPCustomEntity
version: 1.0.3
kind: Scheduled

Stages and Predicates

Parameters

let lbtime = 10m;

Stage 1: source

CiscoISEEvent

Stage 2: where

| where TimeGenerated > ago(lbtime)

Stage 3: where

| where EventId == '59207'

Stage 4: project

| project TimeGenerated, SrcIpAddr, DstIpAddr

Stage 5: extend

| extend IPCustomEntity = DstIpAddr

Indicators

These rows show field, operator, and value matches.

Output Fields

These fields are emitted when the rule matches.

FieldSource
DstIpAddrproject
SrcIpAddrproject
TimeGeneratedproject
IPCustomEntityextend

CTE - Admin Login Detected

#
Severity
informational
Time window
30m
Source
github.com/Azure/Azure-Sentinel

An administrator logged into the Cybereinforce console.

MITRE ATT&CK Coverage

TacticTechniques
Initial Access

Rule Body

id: 65bc5f1d-d29d-4729-a5a6-d9614b0900e0
name: CTE - Admin Login Detected
description: |
  An administrator logged into the Cybereinforce console.
severity: Informational
requiredDataConnectors:
  - connectorId: cybereinforce_cte
    dataTypes:
      - CybereinforceCTE_CL
queryFrequency: 30m
queryPeriod: 30m
triggerOperator: gt
triggerThreshold: 0
tactics:
  - InitialAccess
relevantTechniques:
  - T1078
query: |
  CybereinforceCTE_CL
  | where EventType == "auth.login"
  | extend AccountName = tostring(split(Actor, "@")[0]), UPNSuffix = tostring(split(Actor, "@")[1])
  | project TimeGenerated, TenantId, Actor, AccountName, UPNSuffix, Severity, Category, Source
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: Name
        columnName: AccountName
      - identifier: UPNSuffix
        columnName: UPNSuffix
version: 1.0.0
kind: Scheduled

Stages and Predicates

Stage 1: source

CybereinforceCTE_CL

Stage 2: where

| where EventType == "auth.login"

Stage 3: extend

| extend AccountName = tostring(split(Actor, "@")[0]), UPNSuffix = tostring(split(Actor, "@")[1])

Stage 4: project

| project TimeGenerated, TenantId, Actor, AccountName, UPNSuffix, Severity, Category, Source

Indicators

These rows show field, operator, and value matches.

Output Fields

These fields are emitted when the rule matches.

FieldSource
AccountNameproject
Actorproject
Categoryproject
Severityproject
Sourceproject
TenantIdproject
TimeGeneratedproject
UPNSuffixproject

DNS events related to mining pools (ASIM DNS Schema)

#
Severity
low
Time window
1d
Author
Microsoft Security Research
Source
github.com/Azure/Azure-Sentinel

Identifies IP addresses that may be performing DNS lookups associated with common currency mining pools. This analytic rule uses ASIM and supports any built-in or custom source that supports the ASIM DNS schema

MITRE ATT&CK Coverage

TacticTechniques
Impact

Telemetry Coverage

ProviderRecord / event type
SysmonEvent ID 22: DNSEvent (DNS query)

Rule Body

id: c094384d-7ea7-4091-83be-18706ecca981
name: DNS events related to mining pools (ASIM DNS Schema)
description: |
  'Identifies IP addresses that may be performing DNS lookups associated with common currency mining pools.
  This analytic rule uses [ASIM](https://aka.ms/AboutASIM) and supports any built-in or custom source that supports the ASIM DNS schema'
severity: Low
requiredDataConnectors:
  - connectorId: WindowsForwardedEvents
    dataTypes:
      - WindowsEvent
  - connectorId: DNS
    dataTypes:
      - DnsEvents
  - connectorId: AzureFirewall
    dataTypes: 
      - AzureDiagnostics
  - connectorId: Zscaler
    dataTypes:
      - CommonSecurityLog
  - connectorId: InfobloxNIOS
    dataTypes: 
      - Syslog
  - connectorId: GCPDNSDataConnector
    dataTypes: 
      - GCP_DNS_CL
  - connectorId: NXLogDnsLogs
    dataTypes: 
      - NXLog_DNS_Server_CL
  - connectorId: CiscoUmbrellaDataConnector
    dataTypes: 
      - Cisco_Umbrella_dns_CL
  - connectorId: Corelight
    dataTypes: 
      - Corelight_CL

queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
  - Impact
relevantTechniques:
  - T1496
tags:
  - ParentAlert: https://github.com/Azure/Azure-Sentinel/blob/master/Detections/DnsEvents/DNS_Miners.yaml
    version: 1.0.0
  - Schema: ASIMDns
    SchemaVersion: 0.1.1
query: |
  let minersDomains=dynamic(["monerohash.com", "do-dear.com", "xmrminerpro.com", "secumine.net", "xmrpool.com", "minexmr.org", "hashanywhere.com", 
  "xmrget.com", "mininglottery.eu", "minergate.com", "moriaxmr.com", "multipooler.com", "moneropools.com", "xmrpool.eu", "coolmining.club", 
  "supportxmr.com", "minexmr.com", "hashvault.pro", "xmrpool.net", "crypto-pool.fr", "xmr.pt", "miner.rocks", "walpool.com", "herominers.com", 
  "gntl.co.uk", "semipool.com", "coinfoundry.org", "cryptoknight.cc", "fairhash.org", "baikalmine.com", "tubepool.xyz", "fairpool.xyz", "asiapool.io", 
  "coinpoolit.webhop.me", "nanopool.org", "moneropool.com", "miner.center", "prohash.net", "poolto.be", "cryptoescrow.eu", "monerominers.net", "cryptonotepool.org", 
  "extrmepool.org", "webcoin.me", "kippo.eu", "hashinvest.ws", "monero.farm", "supportxmr.com", "xmrpool.eu", "linux-repository-updates.com", "1gh.com", 
  "dwarfpool.com", "hash-to-coins.com", "hashvault.pro", "pool-proxy.com", "hashfor.cash", "fairpool.cloud", "litecoinpool.org", "mineshaft.ml", "abcxyz.stream", 
  "moneropool.ru", "cryptonotepool.org.uk", "extremepool.org", "extremehash.com", "hashinvest.net", "unipool.pro", "crypto-pools.org", "monero.net", 
  "backup-pool.com", "mooo.com", "freeyy.me", "cryptonight.net", "shscrypto.net"]);
  _Im_Dns(domain_has_any=minersDomains)
  | extend HostName = tostring(split(Dvc, ".")[0]), DomainIndex = toint(indexof(Dvc, '.'))
  | extend HostNameDomain = iff(DomainIndex != -1, substring(Dvc, DomainIndex + 1), Dvc)
  | project-away DomainIndex
entityMappings:
  - entityType: Host
    fieldMappings:
      - identifier: FullName
        columnName: Dvc
      - identifier: HostName
        columnName: HostName
      - identifier: DnsDomain
        columnName: HostNameDomain
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: SrcIpAddr
  - entityType: AzureResource
    fieldMappings:
      - identifier: ResourceId
        columnName: _ResourceId
version: 1.3.5
kind: Scheduled
metadata:
    source:
        kind: Community
    author:
        name: Microsoft Security Research
    support:
        tier: Community
    categories:
        domains: [ "Security - Network" ]

Stages and Predicates

Let Binding: minersDomains used in Stage 1

let minersDomains = dynamic(["monerohash.com", "do-dear.com", "xmrminerpro.com", "secumine.net", "xmrpool.com", "minexmr.org", "hashanywhere.com", 
"xmrget.com", "mininglottery.eu", "minergate.com", "moriaxmr.com", "multipooler.com", "moneropools.com", "xmrpool.eu", "coolmining.club", 
"supportxmr.com", "minexmr.com", "hashvault.pro", "xmrpool.net", "crypto-pool.fr", "xmr.pt", "miner.rocks", "walpool.com", "herominers.com", 
"gntl.co.uk", "semipool.com", "coinfoundry.org", "cryptoknight.cc", "fairhash.org", "baikalmine.com", "tubepool.xyz", "fairpool.xyz", "asiapool.io", 
"coinpoolit.webhop.me", "nanopool.org", "moneropool.com", "miner.center", "prohash.net", "poolto.be", "cryptoescrow.eu", "monerominers.net", "cryptonotepool.org", 
"extrmepool.org", "webcoin.me", "kippo.eu", "hashinvest.ws", "monero.farm", "supportxmr.com", "xmrpool.eu", "linux-repository-updates.com", "1gh.com", 
"dwarfpool.com", "hash-to-coins.com", "hashvault.pro", "pool-proxy.com", "hashfor.cash", "fairpool.cloud", "litecoinpool.org", "mineshaft.ml", "abcxyz.stream", 
"moneropool.ru", "cryptonotepool.org.uk", "extremepool.org", "extremehash.com", "hashinvest.net", "unipool.pro", "crypto-pools.org", "monero.net", 
"backup-pool.com", "mooo.com", "freeyy.me", "cryptonight.net", "shscrypto.net"]);

Stage 1: source

_Im_Dns(domain_has_any=minersDomains)

Stage 2: extend

| extend HostName = tostring(split(Dvc, ".")[0]), DomainIndex = toint(indexof(Dvc, '.'))

Stage 3: extend

| extend HostNameDomain = iff(DomainIndex != -1, substring(Dvc, DomainIndex + 1), Dvc)
HostNameDomain =
ifDomainIndex != -1substring(Dvc, (DomainIndex + 1))
elseDvc

Stage 4: project-away

| project-away DomainIndex

Output Fields

These fields are emitted when the rule matches.

FieldSource
HostNameextend
HostNameDomainextend

Flare source code results

#

This is a third-party alert feed, not a detection over modeled telemetry. The vendor product raised the finding; this rule forwards it into the SIEM. It is searchable for reference but is excluded from the detection-rule browse and the ATT&CK coverage matrix.

Status
available
Severity
medium
Time window
1h
Source
github.com/Azure/Azure-Sentinel

'This query searches for events found on code sharing platforms.'

MITRE ATT&CK Coverage

TacticTechniques
Reconnaissance

Rule Body

id: 9cb7c337-f178-4af6-b0e8-b6b7552d762d
name: Flare source code results
description: |
    'This query searches for events found on code sharing platforms.'
severity: Medium
status: Available
requiredDataConnectors:
  - connectorId: Flare
    dataTypes:
      - FireworkV2_CL
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
  - Reconnaissance
relevantTechniques:
  - T1593
query: |
  FireworkV2_CL
  | where notempty(uid) and RiskScore >= 3
  | extend index_name = split(uid, "/")[0]
  | extend category_name = split(uid, "/")[1]
  | where index_name == "driller" and category_name contains "github"
version: 3.0.0
kind: Scheduled

Stages and Predicates

Stage 1: source

FireworkV2_CL

Stage 2: where

| where notempty(uid) and RiskScore >= 3

Stage 3: extend

| extend index_name = split(uid, "/")[0]

Stage 4: extend

| extend category_name = split(uid, "/")[1]

Stage 5: where

| where index_name == "driller" and category_name contains "github"

Indicators

These rows show field, operator, and value matches.

Output Fields

These fields are emitted when the rule matches.

FieldSource
index_nameextend
category_nameextend

Four-Eyes Authorization Request Rejected

#
Status
available
Severity
informational
Time window
1d
Source
github.com/Azure/Azure-Sentinel

Detects when a four-eyes authorization request is rejected.

Rule Body

id: dfd1d756-623d-4951-84a5-ce51f726d322
name: Four-Eyes Authorization Request Rejected
description: Detects when a four-eyes authorization request is rejected.
severity: Informational
status: Available
requiredDataConnectors:
- connectorId: Syslog
  dataTypes:
  - Syslog
- connectorId: SyslogAma
  dataTypes:
  - Syslog
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
eventGroupingSettings:
  aggregationKind: AlertPerResult
tactics: []
relevantTechniques: []
query: "Veeam_GetSecurityEvents\n| where instanceId == 42404\n| extend Operation =\
  \ extract(\"Operation=\\\"([^\\\"]*)\\\"\", 1, SyslogMessage)\n| project\n    Date\
  \ = format_datetime(TimeGenerated, 'dd.MM.yyyy HH:mm'),\n    DataSource = original_host,\n\
  \    EventId = instanceId,\n    [\"User Name\"] = user,\n    [\"Operation Name\"\
  ] = Operation,\n    MessageDetails = Description,\n   Severity = SeverityDescription"
version: 1.0.1
kind: Scheduled
customDetails:
  Date: Date
  VbrHostName: DataSource
  EventId: EventId
  MessageDetails: MessageDetails
  Severity: Severity

Stages and Predicates

Stage 1: source

Veeam_GetSecurityEvents

Stage 2: where

| where instanceId == 42404

Stage 3: extend

| extend Operation = extract("Operation=\"([^\"]*)\"", 1, SyslogMessage)

Stage 4: project

| project
    Date = format_datetime(TimeGenerated, 'dd.MM.yyyy HH:mm'),
    DataSource = original_host,
    EventId = instanceId,
    ["User Name"] = user,
    ["Operation Name"] = Operation,
    MessageDetails = Description,
   Severity = SeverityDescription

Indicators

These rows show field, operator, and value matches.

Output Fields

These fields are emitted when the rule matches.

FieldSource
DataSourceproject
Dateproject
EventIdproject
MessageDetailsproject
Operation Nameproject
Severityproject
User Nameproject

GCP IAM - High privileged role added to service account

#
Status
available
Severity
high
Time window
15m
Source
github.com/Azure/Azure-Sentinel

'Detects when high privileged role was added to service account.'

MITRE ATT&CK Coverage

TacticTechniques
Privilege Escalation

Rules Detecting the Same Action

These rules filter on the same operation.

Rule Body

id: 86112c4b-2535-4178-aa0e-ed9e32e3f054
name: GCP IAM - High privileged role added to service account
description: |
  'Detects when high privileged role was added to service account.'
severity: High
status: Available
requiredDataConnectors:
  - connectorId: GCPIAMDataConnector
    dataTypes:
      - GCP_IAM
queryFrequency: 15m
queryPeriod: 15m
triggerOperator: gt
triggerThreshold: 0
tactics:
  - PrivilegeEscalation
relevantTechniques:
  - T1078
query: |
  let privileged_roles = dynamic(['roles/iam.securityAdmin', 'roles/secretmanager.admin', 'roles/secretmanager.secretAccessor', 'roles/apigateway.admin', 'roles/logging.admin', 'roles/iam.organizationRoleAdmin', 'roles/iam.roleAdmin', 'roles/iam.serviceAccountAdmin', 'roles/iam.serviceAccountCreator', 'roles/iam.serviceAccountKeyAdmin']);
  GCP_IAM
  | where PayloadMethodname =~ 'SetIamPolicy'
  | extend action = parse_json(todynamic(PayloadServicedataPolicydeltaBindingdeltas))[0]['action']
  | where action =~ 'ADD'
  | extend role = parse_json(todynamic(PayloadServicedataPolicydeltaBindingdeltas))[0]['role']
  | where role in~ (privileged_roles)
  | project-away action
  | extend AccountName = tostring(split(PayloadAuthenticationinfoPrincipalemail, "@")[0]), AccountUPNSuffix = tostring(split(PayloadAuthenticationinfoPrincipalemail, "@")[1])
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: PayloadAuthenticationinfoPrincipalemail
      - identifier: Name
        columnName: AccountName
      - identifier: UPNSuffix
        columnName: AccountUPNSuffix
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: SrcIpAddr
version: 1.0.1
kind: Scheduled

Stages and Predicates

Let Binding: privileged_roles used in Stage 6

let privileged_roles = dynamic(['roles/iam.securityAdmin', 'roles/secretmanager.admin', 'roles/secretmanager.secretAccessor', 'roles/apigateway.admin', 'roles/logging.admin', 'roles/iam.organizationRoleAdmin', 'roles/iam.roleAdmin', 'roles/iam.serviceAccountAdmin', 'roles/iam.serviceAccountCreator', 'roles/iam.serviceAccountKeyAdmin']);

Stage 1: source

GCP_IAM

Stage 2: where

| where PayloadMethodname =~ 'SetIamPolicy'

Stage 3: extend

| extend action = parse_json(todynamic(PayloadServicedataPolicydeltaBindingdeltas))[0]['action']

Stage 4: where

| where action =~ 'ADD'

Stage 5: extend

| extend role = parse_json(todynamic(PayloadServicedataPolicydeltaBindingdeltas))[0]['role']

Stage 6: where

| where role in~ (privileged_roles)

Stage 7: project-away

| project-away action

Stage 8: extend

| extend AccountName = tostring(split(PayloadAuthenticationinfoPrincipalemail, "@")[0]), AccountUPNSuffix = tostring(split(PayloadAuthenticationinfoPrincipalemail, "@")[1])

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
PayloadMethodnameeq
  • SetIamPolicy
field:"gcp::method_name" kind:eq value:"SetIamPolicy"
actioneq
  • ADD
field:"action" kind:eq value:"ADD"
rolein
  • roles/apigateway.admin
  • roles/iam.organizationRoleAdmin
  • roles/iam.roleAdmin
  • roles/iam.securityAdmin
  • roles/iam.serviceAccountAdmin
  • roles/iam.serviceAccountCreator
  • roles/iam.serviceAccountKeyAdmin
  • roles/logging.admin
  • roles/secretmanager.admin
  • roles/secretmanager.secretAccessor
field:"role" kind:in

Output Fields

These fields are emitted when the rule matches.

FieldSource
roleextend
AccountNameextend
AccountUPNSuffixextend

PaloAlto - Forbidden countries

#
Status
available
Severity
medium
Time window
1h
Group by
DstUsername, SrcIpAddr
Source
github.com/Azure/Azure-Sentinel

'Detects suspicious connections from forbidden countries.'

MITRE ATT&CK Coverage

Rule Body

id: 9fcc7734-4d1b-11ec-81d3-0242ac130003
name: PaloAlto - Forbidden countries
description: |
  'Detects suspicious connections from forbidden countries.'
severity: Medium
status: Available
requiredDataConnectors:
  - connectorId: CefAma
    dataTypes:
      - CommonSecurityLog
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
  - InitialAccess
relevantTechniques:
  - T1190
  - T1133
query: |
  let bl_countries = dynamic(['CH', 'RU']);
  PaloAltoCDLEvent 
  | where EventResourceId =~ 'TRAFFIC'
  | where MaliciousIPCountry  in (bl_countries)
  | summarize count() by DstUsername, SrcIpAddr 
  | extend IPCustomEntity = SrcIpAddr, AccountCustomEntity = DstUsername
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: Name
        columnName: AccountCustomEntity
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: IPCustomEntity
version: 1.0.4
kind: Scheduled

Stages and Predicates

Parameters

let bl_countries = dynamic(['CH', 'RU']);

Stage 1: source

PaloAltoCDLEvent

Stage 2: where

| where EventResourceId =~ 'TRAFFIC'

Stage 3: where

| where MaliciousIPCountry  in (bl_countries)

Stage 4: summarize

| summarize count() by DstUsername, SrcIpAddr

Stage 5: extend

| extend IPCustomEntity = SrcIpAddr, AccountCustomEntity = DstUsername

Indicators

These rows show field, operator, and value matches.

Output Fields

These fields are emitted when the rule matches.

FieldSource
DstUsernamesummarize
SrcIpAddrsummarize
AccountCustomEntityextend
IPCustomEntityextend

Pathlock TDnR - SAP Authorization Changes

#
Status
available
Severity
high
Time window
1h
Source
github.com/Azure/Azure-Sentinel

Detects changes to SAP authorization objects, forwarded by Pathlock Threat Detection and Response. Unauthorized authorization changes may be used to escalate privileges, bypass access controls, or create persistent privileged access in SAP systems.

MITRE ATT&CK Coverage

Rule Body

id: 2a3b4c5d-6e7f-4a0b-8c1d-2e3f4a5b6c03
name: Pathlock TDnR - SAP Authorization Changes
kind: Scheduled
description: >-
  Detects changes to SAP authorization objects, forwarded by Pathlock Threat Detection and Response.
  Unauthorized authorization changes may be used to escalate privileges, bypass access controls,
  or create persistent privileged access in SAP systems.
severity: High
status: Available
requiredDataConnectors:
  - connectorId: Pathlock_TDnR
    dataTypes:
      - Pathlock_TDnR_CL
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
  - PrivilegeEscalation
  - Persistence
relevantTechniques:
  - T1548
  - T1098
query: |
  Pathlock_TDnR_CL
  | where DataSource == "AUTH_CHANGES"
  | project TimeGenerated, Sysid, DataSource, Eventid, Instance, Hostname, Bname,
            Tcode, Report, Area, Subid, SrcIp, DestIp, AffectedUser, LogLine,
            MsgType, MsgId, MsgNo, MessageV1, MessageV2, MessageV3, MessageV4, CentralTs
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: Name
        columnName: Bname
  - entityType: Host
    fieldMappings:
      - identifier: HostName
        columnName: Hostname
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: SrcIp
eventGroupingSettings:
  aggregationKind: SingleAlert
incidentConfiguration:
  createIncident: true
  groupingConfiguration:
    enabled: true
    reopenClosedIncident: false
    lookbackDuration: 5h
    matchingMethod: AnyAlert
    groupByEntities: []
    groupByAlertDetails: []
    groupByCustomDetails: []
suppressionDuration: 5h
suppressionEnabled: false
version: 1.0.0

Stages and Predicates

Stage 1: source

Pathlock_TDnR_CL

Stage 2: where

| where DataSource == "AUTH_CHANGES"

Stage 3: project

| project TimeGenerated, Sysid, DataSource, Eventid, Instance, Hostname, Bname,
          Tcode, Report, Area, Subid, SrcIp, DestIp, AffectedUser, LogLine,
          MsgType, MsgId, MsgNo, MessageV1, MessageV2, MessageV3, MessageV4, CentralTs

Indicators

These rows show field, operator, and value matches.

Output Fields

These fields are emitted when the rule matches.

FieldSource
AffectedUserproject
Areaproject
Bnameproject
CentralTsproject
DataSourceproject
DestIpproject
Eventidproject
Hostnameproject
Instanceproject
LogLineproject
MessageV1project
MessageV2project
MessageV3project
MessageV4project
MsgIdproject
MsgNoproject
MsgTypeproject
Reportproject
SrcIpproject
Subidproject
Sysidproject
Tcodeproject
TimeGeneratedproject

Potential beaconing activity (ASIM Network Session schema)

#
Status
available
Severity
low
Time window
1h
Group by
DstIpAddr, DstPortNumber, SrcIpAddr, TimeDeltainSeconds
Source
github.com/Azure/Azure-Sentinel

This rule identifies beaconing patterns from Network traffic logs based on recurrent frequency patterns. Such potential outbound beaconing patterns to untrusted public networks should be investigated for any malware callbacks or data exfiltration attempts as discussed in this Blog. This analytic rule uses ASIM and supports any built-in or custom source that supports the ASIM NetworkSession schema'

MITRE ATT&CK Coverage

Telemetry Coverage

Rule Body

id: fcb9d75c-c3c1-4910-8697-f136bfef2363
name: Potential beaconing activity (ASIM Network Session schema)
description: |
  This rule identifies beaconing patterns from Network traffic logs based on recurrent frequency patterns. 
  Such potential outbound beaconing patterns to untrusted public networks should be investigated for any malware callbacks or data exfiltration attempts as discussed in this [Blog](https://medium.com/@HuntOperator/detect-beaconing-with-flare-elastic-stack-and-intrusion-detection-systems-110dc74e0c56).
  This analytic rule uses [ASIM](https://aka.ms/AboutASIM) and supports any built-in or custom source that supports the ASIM NetworkSession schema'
severity: Low
status: Available
requiredDataConnectors:
  - connectorId: AWSS3
    dataTypes:
      - AWSVPCFlow
  - connectorId: MicrosoftThreatProtection
    dataTypes:
      - DeviceNetworkEvents
  - connectorId: SecurityEvents
    dataTypes:
      - SecurityEvent
  - connectorId: WindowsSecurityEvents
    dataTypes:
      - SecurityEvent
  - connectorId: WindowsForwardedEvents
    dataTypes:
      - WindowsEvent
  - connectorId: Zscaler
    dataTypes:
      - CommonSecurityLog
  - connectorId: MicrosoftSysmonForLinux
    dataTypes:
      - Syslog
  - connectorId: PaloAltoNetworks
    dataTypes:
      - CommonSecurityLog
  - connectorId: AzureMonitor(VMInsights)
    dataTypes:
      - VMConnection
  - connectorId: AzureFirewall
    dataTypes:
      - AzureDiagnostics
  - connectorId: AzureNSG
    dataTypes:
      - AzureDiagnostics
  - connectorId: CiscoASA
    dataTypes:
      - CommonSecurityLog
  - connectorId: CiscoAsaAma
    dataTypes:
      - CommonSecurityLog
  - connectorId: Corelight
    dataTypes:
      - Corelight_CL
  - connectorId: AIVectraStream
    dataTypes:
      - VectraStream
  - connectorId: CheckPoint
    dataTypes:
      - CommonSecurityLog
  - connectorId: Fortinet
    dataTypes:
      - CommonSecurityLog
  - connectorId: CiscoMeraki
    dataTypes:
      - Syslog
      - CiscoMerakiNativePoller

queryFrequency: 1d
queryPeriod: 2d
triggerOperator: gt
triggerThreshold: 0
tactics:
  - CommandAndControl
relevantTechniques:
  - T1071
  - T1571
tags:
  - ParentAlert: https://github.com/Azure/Azure-Sentinel/blob/master/Detections/CommonSecurityLog/PaloAlto-NetworkBeaconing.yaml
    ParentVersion: 1.0.0
  - Schema: ASIMNetworkSession
    SchemaVersion: 0.2.4

query: |
  let querystarttime = 2d;
  let queryendtime = 1d;
  let TimeDeltaThreshold = 10;
  let TotalEventsThreshold = 15;
  let PercentBeaconThreshold = 80;
  let LocalNetworks=dynamic(["169.254.0.0/16","127.0.0.0/8"]);
  _Im_NetworkSession(starttime=ago(querystarttime), endtime=ago(queryendtime))
  | where not(ipv4_is_private(DstIpAddr))
  | where not (ipv4_is_in_any_range(DstIpAddr, LocalNetworks))
  | project 
      TimeGenerated
      , SrcIpAddr
      , SrcPortNumber
      , DstIpAddr
      , DstPortNumber
      , DstBytes
      , SrcBytes
  | sort by 
      SrcIpAddr asc
      , TimeGenerated asc
      , DstIpAddr asc
      , DstPortNumber asc
  | serialize
  | extend 
      nextTimeGenerated = next(TimeGenerated, 1)
      , nextSrcIpAddr = next(SrcIpAddr, 1)
  | extend 
      TimeDeltainSeconds = datetime_diff('second', nextTimeGenerated, TimeGenerated)
  | where SrcIpAddr == nextSrcIpAddr
  //Whitelisting criteria/ threshold criteria
  | where TimeDeltainSeconds > TimeDeltaThreshold 
  | project
      TimeGenerated
      , TimeDeltainSeconds
      , SrcIpAddr
      , SrcPortNumber
      , DstIpAddr
      , DstPortNumber
      , DstBytes
      , SrcBytes
  | summarize
      count()
      , sum(DstBytes)
      , sum(SrcBytes)
      , make_list(TimeDeltainSeconds) 
      by TimeDeltainSeconds
          , bin(TimeGenerated, 1h)
          , SrcIpAddr
          , DstIpAddr
          , DstPortNumber
  | summarize
      (MostFrequentTimeDeltaCount, MostFrequentTimeDeltainSeconds) = arg_max(count_, TimeDeltainSeconds)
      , TotalEvents=sum(count_)
      , TotalSrcBytes = sum(sum_SrcBytes)
      , TotalDstBytes = sum(sum_DstBytes)
      by bin(TimeGenerated, 1h)
          , SrcIpAddr
          , DstIpAddr
          , DstPortNumber
  | where TotalEvents > TotalEventsThreshold 
  | extend BeaconPercent = MostFrequentTimeDeltaCount/toreal(TotalEvents) * 100
  | where BeaconPercent > PercentBeaconThreshold
entityMappings:
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: SrcIpAddr
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: DstIpAddr

alertDetailsOverride:
  alertDisplayNameFormat: Potential beaconing from {{SrcIpAddr}} to {{DstIpAddr}}
  alertDescriptionFormat: Potential beaconing pattern from a client at address {{SrcIpAddr}} to a server at address {{DstIpAddr}} over port {{DstPortNumber}} identified. Such potential outbound beaconing pattern to untrusted public networks should be investigated for any malware callbacks or data exfiltration attempts as discussed in this [Blog](http://www.austintaylor.io/detect/beaconing/intrusion/detection/system/command/control/flare/elastic/stack/2017/06/10/detect-beaconing-with-flare-elasticsearch-and-intrusion-detection-systems/). The recurring frequency, reported as FrequencyTime in the custom details, and the total transferred volume reported as TotalDstBytes in the custom details, can help to determine the significance of this incident.

customDetails:
  DstPortNumber: DstPortNumber
  FrequencyCount: TotalSrcBytes
  FrequencyTime: MostFrequentTimeDeltaCount
  TotalDstBytes: TotalDstBytes

version: 1.1.6
kind: Scheduled

Stages and Predicates

Parameters

let querystarttime = 2d;
let queryendtime = 1d;
let TimeDeltaThreshold = 10;
let TotalEventsThreshold = 15;
let PercentBeaconThreshold = 80;
let LocalNetworks = dynamic(["169.254.0.0/16","127.0.0.0/8"]);

Stage 1: source

_Im_NetworkSession(starttime=ago(querystarttime), endtime=ago(queryendtime))

Stage 2: where

| where not(ipv4_is_private(DstIpAddr))

Stage 3: where

| where not (ipv4_is_in_any_range(DstIpAddr, LocalNetworks))

Stage 4: project

| project 
    TimeGenerated
    , SrcIpAddr
    , SrcPortNumber
    , DstIpAddr
    , DstPortNumber
    , DstBytes
    , SrcBytes

Stage 5: sort

| sort by 
    SrcIpAddr asc
    , TimeGenerated asc
    , DstIpAddr asc
    , DstPortNumber asc

Stage 6: kusto:serialize

| serialize

Stage 7: extend

| extend 
    nextTimeGenerated = next(TimeGenerated, 1)
    , nextSrcIpAddr = next(SrcIpAddr, 1)

Stage 8: extend

| extend 
    TimeDeltainSeconds = datetime_diff('second', nextTimeGenerated, TimeGenerated)

Stage 9: where

| where SrcIpAddr == nextSrcIpAddr

Stage 10: where

| where TimeDeltainSeconds > TimeDeltaThreshold

Stage 11: project

| project
    TimeGenerated
    , TimeDeltainSeconds
    , SrcIpAddr
    , SrcPortNumber
    , DstIpAddr
    , DstPortNumber
    , DstBytes
    , SrcBytes

Stage 12: summarize

| summarize
    count()
    , sum(DstBytes)
    , sum(SrcBytes)
    , make_list(TimeDeltainSeconds) 
    by TimeDeltainSeconds
        , bin(TimeGenerated, 1h)
        , SrcIpAddr
        , DstIpAddr
        , DstPortNumber

Stage 13: summarize

| summarize
    (MostFrequentTimeDeltaCount, MostFrequentTimeDeltainSeconds) = arg_max(count_, TimeDeltainSeconds)
    , TotalEvents=sum(count_)
    , TotalSrcBytes = sum(sum_SrcBytes)
    , TotalDstBytes = sum(sum_DstBytes)
    by bin(TimeGenerated, 1h)
        , SrcIpAddr
        , DstIpAddr
        , DstPortNumber

Stage 14: where

| where TotalEvents > TotalEventsThreshold

Stage 15: extend

| extend BeaconPercent = MostFrequentTimeDeltaCount/toreal(TotalEvents) * 100

Stage 16: where

| where BeaconPercent > PercentBeaconThreshold

Indicators

These rows show field, operator, and value matches.

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
DstIpAddrcidr_match10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16, 127.0.0.0/8excludes:DstIpAddr
DstIpAddrcidr_match169.254.0.0/16, 127.0.0.0/8excludes:DstIpAddr field:"DstIpAddr" value:"169.254.0.0/16" field:"DstIpAddr" value:"127.0.0.0/8"

Output Fields

These fields are emitted when the rule matches.

FieldSource
DstIpAddrsummarize
DstPortNumbersummarize
MostFrequentTimeDeltaCountsummarize
MostFrequentTimeDeltainSecondssummarize
SrcIpAddrsummarize
TotalDstBytessummarize
TotalEventssummarize
TotalSrcBytessummarize
BeaconPercentextend

Registries Alerts for Prancer

#
Status
available
Severity
high
Time window
5h
Source
github.com/Azure/Azure-Sentinel

'High severity registry alerts found by Prancer.'

MITRE ATT&CK Coverage

TacticTechniques
Reconnaissance

Rule Body

id: 08706063-c15e-4d96-beae-9e8d92ccefbb
name: Registries Alerts for Prancer
description: |
  'High severity registry alerts found by Prancer.'
severity: High
requiredDataConnectors:
- connectorId: PrancerLogData
  dataTypes:
    - prancer_CL
queryFrequency: 5h
queryPeriod: 5h
triggerOperator: gt
triggerThreshold: 0
eventGroupingSettings:
  aggregationKind: SingleAlert
status: Available
tactics:
  - Reconnaissance
relevantTechniques:
  - T1595
query: |
  union prancer_CL
  | where deviceProduct_s == 'azure'
  | where parse_json(data_data_snapshots_s)[0].type == 'Microsoft.ContainerRegistry/registries'
  | where data_data_severity_s == 'High' and data_data_result_s == 'failed'
  | extend snapshot = parse_json(data_data_snapshots_s)
  | mv-expand snapshot 
  | extend
      id = tostring(snapshot.id),
      structure = tostring(snapshot.structure),
      reference = tostring(snapshot.reference),
      source = tostring(snapshot.source),
      collection = tostring(snapshot.collection),
      type = tostring(snapshot.type),
      region = tostring(snapshot.region),
      resourceTypes = tostring(snapshot.resourceTypes),
      path = tostring(snapshot.path)

customDetails:
entityMappings:
  - entityType: AzureResource
    fieldMappings:
      - identifier: ResourceId
        columnName: path
alertDetailsOverride:
  alertDisplayNameFormat: "{{data_data_message_s}}"  
  alertDescriptionFormat: "{{data_data_description_s}}"
  alertSeverityColumnName: "{{data_data_severity_s}}"
  alertDynamicProperties:
    - alertProperty: RemediationSteps
      value: data_data_remediation_description_s
version: 1.0.2
kind: Scheduled


Stages and Predicates

Stage 1: union

union of 1 branches

Stage 2: source

prancer_CL

Stage 3: where

where deviceProduct_s == "azure"

Stage 4: where

where parse_json(data_data_snapshots_s)[0].type == "Microsoft.ContainerRegistry/registries"

Stage 5: where

where data_data_result_s == "failed" and data_data_severity_s == "High"

Stage 6: extend

extend snapshot

Stage 7: mv-expand

mv-expand snapshot

Stage 8: extend

extend collection, id, path, reference, region, resourceTypes, source, structure, type

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
data_data_result_seq
  • failed
field:"data_data_result_s" kind:eq value:"failed"
data_data_severity_seq
  • High
field:"data_data_severity_s" kind:eq value:"High"
data_data_snapshots_s[0].typeeq
  • Microsoft.ContainerRegistry/registries transforms: kusto_accessor_expr:{"expression":"parse_json(data_data_snapshots_s)[0].type","field":"data_data_snapshots_s[0].type"}, kusto_dynamic_path
field:"data_data_snapshots_s[0].type" kind:eq value:"Microsoft.ContainerRegistry/registries"
deviceProduct_seq
  • azure
field:"deviceProduct_s" kind:eq value:"azure"

Output Fields

These fields are emitted when the rule matches.

FieldSource
snapshotextend
collectionextend
idextend
pathextend
referenceextend
regionextend
resourceTypesextend
sourceextend
structureextend
typeextend

Sentinel One - Multiple alerts on host

#
Status
available
Severity
high
Time window
15m
Group by
DstHostname
Source
github.com/Azure/Azure-Sentinel

'Detects when multiple alerts received from same host.'

MITRE ATT&CK Coverage

TacticTechniques
Initial Access

Rule Body

id: 47e427e6-61bc-4e24-8d16-a12871b9f939
name: Sentinel One - Multiple alerts on host
description: |
  'Detects when multiple alerts received from same host.'
severity: High
status: Available
requiredDataConnectors:
  - connectorId: SentinelOne
    dataTypes:
      - SentinelOne
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
  - InitialAccess
relevantTechniques:
  - T1190
query: | 
  SentinelOne
  | where ActivityType == 3608
  | extend RuleName = extract(@'Custom Rule:\s(.*?)\sin Group', 1, EventOriginalMessage)
  | extend DstHostname = extract(@'detected on\s(\S+)\.', 1, EventOriginalMessage)
  | summarize count() by DstHostname, bin(TimeGenerated, 15m)
  | where count_ > 1
  | extend HostCustomEntity = DstHostname
entityMappings:
  - entityType: Host
    fieldMappings:
      - identifier: HostName
        columnName: HostCustomEntity
version: 1.0.2
kind: Scheduled

Stages and Predicates

Stage 1: source

SentinelOne

Stage 2: where

| where ActivityType == 3608

Stage 3: extend

| extend RuleName = extract(@'Custom Rule:\s(.*?)\sin Group', 1, EventOriginalMessage)

Stage 4: extend

| extend DstHostname = extract(@'detected on\s(\S+)\.', 1, EventOriginalMessage)

Stage 5: summarize

| summarize count() by DstHostname, bin(TimeGenerated, 15m)

Stage 6: where

| where count_ > 1

Stage 7: extend

| extend HostCustomEntity = DstHostname

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
ActivityTypeeq
  • 3608 corpus 3 (kusto 3)
field:"ActivityType" kind:eq value:"3608"
count_gt
  • 1 transforms: number
field:"count_" kind:gt value:"1"

Output Fields

These fields are emitted when the rule matches.

FieldSource
DstHostnamesummarize
HostCustomEntityextend

Sentinel One - User viewed agent's passphrase

#
Status
available
Severity
medium
Time window
1h
Source
github.com/Azure/Azure-Sentinel

'Detects when a user viewed agent's passphrase.'

MITRE ATT&CK Coverage

TacticTechniques
Credential Access

Rule Body

id: 51999097-60f4-42c0-bee8-fa28160e5583
name: Sentinel One - User viewed agent's passphrase
description: |
  'Detects when a user viewed agent's passphrase.'
severity: Medium
status: Available
requiredDataConnectors:
  - connectorId: SentinelOne
    dataTypes:
      - SentinelOne
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
  - CredentialAccess
relevantTechniques:
  - T1555
query: | 
  SentinelOne
  | where ActivityType == 64
  | extend AccountCustomEntity = SrcUserName, HostCustomEntity = DataComputerName
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: Name
        columnName: AccountCustomEntity
  - entityType: Host
    fieldMappings:
      - identifier: HostName
        columnName: HostCustomEntity
version: 1.0.0
kind: Scheduled

Stages and Predicates

Stage 1: source

SentinelOne

Stage 2: where

| where ActivityType == 64

Stage 3: extend

| extend AccountCustomEntity = SrcUserName, HostCustomEntity = DataComputerName

Indicators

These rows show field, operator, and value matches.

Output Fields

These fields are emitted when the rule matches.

FieldSource
AccountCustomEntityextend
HostCustomEntityextend

SOCRadar Unsynced Closed Incident

#
Status
available
Severity
low
Time window
1d
Source
github.com/Azure/Azure-Sentinel

'Detects Microsoft Sentinel incidents tagged as SOCRadar that were closed more than 30 minutes ago but do not have the Synced tag. This may indicate the SOCRadar-Alarm-Sync playbook has failed to update the SOCRadar platform with the closure status.'

MITRE ATT&CK Coverage

TacticTechniques
Discovery

Rule Body

id: 6e2f8d4b-5a71-4c9e-b3f6-8a1c9d4e7b2a
name: SOCRadar Unsynced Closed Incident
description: |
  'Detects Microsoft Sentinel incidents tagged as SOCRadar that were closed more than 30 minutes ago but do not have the Synced tag. This may indicate the SOCRadar-Alarm-Sync playbook has failed to update the SOCRadar platform with the closure status.'
severity: Low
status: Available
requiredDataConnectors: []
queryFrequency: 1h
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
  - Discovery
relevantTechniques:
  - T1526
query: |
    SecurityIncident
    | where Labels has "SOCRadar"
    | where Status == "Closed"
    | where LastModifiedTime < ago(30m)
    | where not(Labels has "Synced")
    | extend AlarmId = extract(@"#(\d+)", 1, Title)
    | extend AccountName = AlarmId
    | project TimeGenerated, IncidentName, Title, Status, Classification, LastModifiedTime, AlarmId, AccountName
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: Name
        columnName: AccountName
version: 1.0.0
kind: Scheduled

Stages and Predicates

Stage 1: source

SecurityIncident

Stage 2: where

| where Labels has "SOCRadar"

Stage 3: where

| where Status == "Closed"

Stage 4: where

| where LastModifiedTime < ago(30m)

Stage 5: where

| where not(Labels has "Synced")

Stage 6: extend

| extend AlarmId = extract(@"#(\d+)", 1, Title)

Stage 7: extend

| extend AccountName = AlarmId

Stage 8: project

| project TimeGenerated, IncidentName, Title, Status, Classification, LastModifiedTime, AlarmId, AccountName

Indicators

These rows show field, operator, and value matches.

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
LabelsmatchSyncedexcludes:Labels field:"Labels" value:"Synced"

Output Fields

These fields are emitted when the rule matches.

FieldSource
AccountNameproject
AlarmIdproject
Classificationproject
IncidentNameproject
LastModifiedTimeproject
Statusproject
TimeGeneratedproject
Titleproject

SpyCloud plaintext credential exposure detected

#
Severity
high
Time window
2d
Source
github.com/Azure/Azure-Sentinel

'Identifies user accounts exposed with a plaintext password in a third-party data breach. Unremediated exposures of this kind can lead directly to account takeover.'

MITRE ATT&CK Coverage

TacticTechniques
Credential Access

Rule Body

id: a25eba0e-ff42-4c97-a379-d76bdb2aa1e3
name: SpyCloud plaintext credential exposure detected
description: |
  'Identifies user accounts exposed with a plaintext password in a third-party data breach.
  Unremediated exposures of this kind can lead directly to account takeover.'
severity: High
requiredDataConnectors:
  - connectorId: SpyCloudEnterpriseProtectionCCF
    dataTypes:
      - SpyCloudBreachWatchlistV2_CL
queryFrequency: 1h
queryPeriod: 2d
triggerOperator: gt
triggerThreshold: 0
tactics:
  - CredentialAccess
relevantTechniques:
  - T1555
query: |
  // Human-readable constant for the severity threshold used below
  let severityThreshold = 20;
  SpyCloudBreachWatchlistV2_CL
  | where Severity == severityThreshold
  | mv-expand IPAddress = IPAddresses to typeof(string)
  | extend AccountName = Username, AccountEmail = Email
  | project TimeGenerated, DocumentId, SourceId, SpyCloudPublishDate, AccountEmail,
      TargetDomain, PasswordPlaintext, AccountName, IPAddress
eventGroupingSettings:
  aggregationKind: SingleAlert
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: Name
        columnName: AccountName
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: IPAddress
  - entityType: Mailbox
    fieldMappings:
      - identifier: MailboxPrimaryAddress
        columnName: AccountEmail
version: 1.0.0
kind: scheduled

Stages and Predicates

Parameters

let severityThreshold = 20;

Stage 1: source

SpyCloudBreachWatchlistV2_CL

Stage 2: where

| where Severity == severityThreshold

Stage 3: mv-expand

| mv-expand IPAddress = IPAddresses to typeof(string)

Stage 4: extend

| extend AccountName = Username, AccountEmail = Email

Stage 5: project

| project TimeGenerated, DocumentId, SourceId, SpyCloudPublishDate, AccountEmail,
    TargetDomain, PasswordPlaintext, AccountName, IPAddress

Indicators

These rows show field, operator, and value matches.

Output Fields

These fields are emitted when the rule matches.

FieldSource
AccountEmailproject
AccountNameproject
DocumentIdproject
IPAddressproject
PasswordPlaintextproject
SourceIdproject
SpyCloudPublishDateproject
TargetDomainproject
TimeGeneratedproject

Trend Micro CAS - Infected user

#
Status
available
Severity
high
Time window
10m
Source
github.com/Azure/Azure-Sentinel

'Detects when malware was detected for user account.'

MITRE ATT&CK Coverage

TacticTechniques
Initial Access

Rule Body

id: 3649dfb8-a5ca-47dd-8965-cd2f633ca533
name: Trend Micro CAS - Infected user
description: |
  'Detects when malware was detected for user account.'
severity: High
status: Available
requiredDataConnectors:
  - connectorId: TrendMicroCAS
    dataTypes:
      - TrendMicroCAS
queryFrequency: 10m
queryPeriod: 10m
triggerOperator: gt
triggerThreshold: 0
tactics:
  - InitialAccess
relevantTechniques:
  - T1566
query: |
  TrendMicroCAS
  | where EventType has_all ('virtual', 'analyzer')
  | where isnotempty(VirusName)
  | extend AccountCustomEntity = DstUserName, MalwareCustomEntity = VirusName
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: Name
        columnName: AccountCustomEntity
  - entityType: Malware
    fieldMappings:
      - identifier: Name
        columnName: MalwareCustomEntity
version: 1.0.1
kind: Scheduled

Stages and Predicates

Stage 1: source

TrendMicroCAS

Stage 2: where

| where EventType has_all ('virtual', 'analyzer')

Stage 3: where

| where isnotempty(VirusName)

Stage 4: extend

| extend AccountCustomEntity = DstUserName, MalwareCustomEntity = VirusName

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
EventTypematch
  • analyzer transforms: term corpus 2 (kusto 2)
  • virtual transforms: term corpus 2 (kusto 2)
field:"EventType" kind:match
VirusNameis_not_null
  • (no value, null check)
field:"VirusName" kind:is_not_null

Output Fields

These fields are emitted when the rule matches.

FieldSource
AccountCustomEntityextend
MalwareCustomEntityextend

Trend Micro CAS - Suspicious filename

#
Status
available
Severity
medium
Time window
1h
Source
github.com/Azure/Azure-Sentinel

'Detects unexpected filename.'

MITRE ATT&CK Coverage

TacticTechniques
Initial Access

Rule Body

id: 52c4640a-1e2b-4155-b69e-e1869c9a57c9
name: Trend Micro CAS - Suspicious filename
description: |
  'Detects unexpected filename.'
severity: Medium
status: Available
requiredDataConnectors:
  - connectorId: TrendMicroCAS
    dataTypes:
      - TrendMicroCAS
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
  - InitialAccess
relevantTechniques:
  - T1566
query: |
  TrendMicroCAS
  | where isnotempty(SrcFileName)
  | where SrcFileName matches regex @'\A[a-zA-Z0-9_\-.]{1,3}\.\w+$'
  | extend AccountCustomEntity = DstUserName
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: Name
        columnName: AccountCustomEntity
version: 1.0.0
kind: Scheduled

Stages and Predicates

Stage 1: source

TrendMicroCAS

Stage 2: where

| where isnotempty(SrcFileName)

Stage 3: where

| where SrcFileName matches regex @'\A[a-zA-Z0-9_\-.]{1,3}\.\w+$'

Stage 4: extend

| extend AccountCustomEntity = DstUserName

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
SrcFileNameis_not_null
  • (no value, null check)
field:"SrcFileName" kind:is_not_null
SrcFileNameregex_match
  • \A[a-zA-Z0-9_\-.]{1,3}.\w+$
field:"SrcFileName" kind:regex_match value:"\A[a-zA-Z0-9_\-.]{1,3}.\w+$"

Output Fields

These fields are emitted when the rule matches.

FieldSource
AccountCustomEntityextend

Back to all Kusto rules