Detection rules › Kusto
Kusto rules: 25
BloodHound Attack Path Finding - SQL Admin Users on Tier Zero Computers
#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.
BloodHound Attack Path Finding - SQL Admin Users on Tier Zero Computers
Rule Body
id: b3c6f684-5fb3-451d-b1d9-fec8089c2503
name: BloodHound Attack Path Finding - SQL Admin Users on Tier Zero Computers
description: BloodHound Attack Path Finding - SQL Admin Users on Tier Zero Computers
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: BloodHoundEnterprise
dataTypes:
- BHEAttackPathsData_CL
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics: []
relevantTechniques: []
query: BHEAttackPathsData_CL | where Finding == "T0SQLAdmin"
entityMappings:
- entityType: URL
fieldMappings:
- identifier: Url
columnName: domain_name
customDetails:
Description: ShortDescription
Remediation: ShortRemediation
version: 1.0.0
kind: Scheduled
Stages and Predicates
Stage 1: source
BHEAttackPathsData_CL
Stage 2: where
| where Finding == "T0SQLAdmin"
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
Finding | eq |
| field:"Finding" kind:eq value:"T0SQLAdmin" |
Cisco SE - Dropper activity on host
#'Detects possible dropper activity on host.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Execution |
Rule Body
id: b6df3e11-de70-4779-ac9a-276c454a9025
name: Cisco SE - Dropper activity on host
description: |
'Detects possible dropper activity on host.'
severity: High
requiredDataConnectors:
- connectorId: CiscoSecureEndpoint
dataTypes:
- CiscoSecureEndpoint
queryFrequency: 15m
queryPeriod: 15m
triggerOperator: gt
triggerThreshold: 0
status: Available
tactics:
- Execution
relevantTechniques:
- T1204.002
query: |
CiscoSecureEndpoint
| where EventMessage has 'Potential Dropper Infection'
| extend HostCustomEntity = DstHostname, MalwareCustomEntity = ThreatName
entityMappings:
- entityType: Host
fieldMappings:
- identifier: HostName
columnName: HostCustomEntity
- entityType: Malware
fieldMappings:
- identifier: Name
columnName: MalwareCustomEntity
version: 1.0.0
kind: Scheduled
Stages and Predicates
Stage 1: source
CiscoSecureEndpoint
Stage 2: where
| where EventMessage has 'Potential Dropper Infection'
Stage 3: extend
| extend HostCustomEntity = DstHostname, MalwareCustomEntity = ThreatName
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
EventMessage | match |
| field:"EventMessage" kind:match value:"Potential Dropper Infection" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
HostCustomEntity | extend |
MalwareCustomEntity | extend |
Critical Risks
#This query searches for all the exploited risks that RidgeBot identified
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access | |
| Execution | |
| Privilege Escalation |
Rule Body
id: 1eebfaf3-40e1-4bc2-9f42-049b7b8ceb60
name: Critical Risks
description: |
This query searches for all the exploited risks that RidgeBot identified
severity: High
status: Available
requiredDataConnectors:
- connectorId: RidgeBotDataConnector
dataTypes:
- CommonSecurityLog
- connectorId: CefAma
dataTypes:
- CommonSecurityLog
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- Execution
- InitialAccess
- PrivilegeEscalation
relevantTechniques:
- T1189
- T1059
- T1053
- T1548
query: |
CommonSecurityLog
| where DeviceVendor == "RidgeSecurity"
| where DeviceEventClassID == "4001"
| order by TimeGenerated desc
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: DeviceVendor
- entityType: IP
fieldMappings:
- identifier: Address
columnName: Computer
version: 1.0.1
kind: Scheduled
Stages and Predicates
Stage 1: source
CommonSecurityLog
Stage 2: where
| where DeviceVendor == "RidgeSecurity"
Stage 3: where
| where DeviceEventClassID == "4001"
Stage 4: sort
| order by TimeGenerated desc
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
DeviceEventClassID | eq |
| field:"DeviceEventClassID" kind:eq value:"4001" |
DeviceVendor | eq |
| field:"DeviceVendor" kind:eq value:"RidgeSecurity" |
Cyble Vision Alerts OSINT Mention Detected
#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.
'Triggers when Cyble detects an OSINT mention related to monitored keywords, entities, or brand identifiers. OSINT findings may indicate data leaks, expose content, targeting activity, impersonation, or discussions that may require investigation.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Reconnaissance |
Rule Body
id: 9ff985d8-57a8-4302-a8e6-34fa96c3c505
name: Cyble Vision Alerts OSINT Mention Detected
description: |
'Triggers when Cyble detects an OSINT mention related to monitored keywords, entities, or brand identifiers. OSINT findings may indicate data leaks, expose content, targeting activity, impersonation, or discussions that may require investigation.'
severity: Low
status: Available
requiredDataConnectors:
- connectorId: CybleVisionAlerts
dataTypes:
- CybleVisionAlerts_CL
enabled: true
queryfrequency: 30m
queryPeriod: 30m
triggerOperator: GreaterThan
triggerThreshold: 0
eventGroupingSettings:
aggregationKind: AlertPerResult
tactics:
- Reconnaissance
- ResourceDevelopment
relevantTechniques:
- T1592
- T1589
query: |
Alerts_osint
| where Service == "osint"
| extend MappedSeverity = Severity
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: false
reopenClosedIncident: false
lookbackDuration: PT5H
matchingMethod: AllEntities
alertDetailsOverride:
alertDisplayNameFormat: OSINT Mention Identified for Monitored Keyword {{KeywordName}}
alertDescriptionFormat: |
A public OSINT mention referencing monitored keyword/entity {{KeywordName}} has been detected. Source {{OS_Source}}. Mention URL {{OS_MentionURL}}. This may indicate reputational impact, data exposure, or adversarial research targeting the organization.
customDetails:
MappedSeverity: Severity
Status: Status
AlertID: AlertID
Service: Service
AuthorName: OS_AuthorName
AuthorUsername: OS_AuthorUsername
Source: OS_Source
MentionDate: OS_MentionDate
MentionURL: OS_MentionURL
PostSnippet: OS_PostSnippet
entityMappings:
- entityType: DNS
fieldMappings:
- identifier: DomainName
columnName: MA_Domain
- entityType: URL
fieldMappings:
- identifier: Url
columnName: MA_DomainURL
- entityType: Account
fieldMappings:
- identifier: Name
columnName: KeywordName
- entityType: Host
fieldMappings:
- identifier: HostName
columnName: Domain
version: 1.0.0
kind: Scheduled
Stages and Predicates
Stage 1: source
Alerts_osint
Stage 2: where
| where Service == "osint"
Stage 3: extend
| extend MappedSeverity = Severity
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
Service | eq |
| field:"Service" kind:eq value:"osint" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
MappedSeverity | extend |
Detect process drops via Azure Custom Script Extension performing lateral movement
#This detection rule spots processes that where dropped via Azure Custom Script Extension on a machine and are now performing lateral movement. A common procedures for attackers when they compromised one machine is to move laterally to other machines via common protocols such as RDP, SSH, VNC, WMI, RPC, etc. It is not very common in an environment that Custom Script Extensions is being used for this.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Execution | |
| Lateral Movement |
References
Telemetry Coverage
Rule Body
let process_drop_via_arc = (
DeviceFileEvents
| where TimeGenerated > ago(7d)
// Search for file created events by Arc Custom Script Handler
| where ActionType == "FileCreated"
| where InitiatingProcessFileName =~ "customscripthandler.exe"
| where isnotempty(SHA256)
| distinct SHA256
);
DeviceNetworkEvents
| where TimeGenerated > ago(1h)
| join kind=inner process_drop_via_arc on $left.InitiatingProcessSHA256 == $right.SHA256
| where RemotePort in ("5985", "5986", "445", "3389", "22", "5900", "135")
| where ActionType in~ ("ConnectionSuccess", "ConnectionAttempt",
"ConnectionFailed", "ConnectionRequest")
Stages and Predicates
Let Binding: process_drop_via_arc
let process_drop_via_arc = (
DeviceFileEvents
| where TimeGenerated > ago(7d)
| where ActionType == "FileCreated"
| where InitiatingProcessFileName =~ "customscripthandler.exe"
| where isnotempty(SHA256)
| distinct SHA256
);
Stage 1: source
let process_drop_via_arc
Stage 2: source
DeviceNetworkEvents
Stage 3: where
where TimeGenerated > ago(3600s)
Stage 4: join
join kind=inner (process_drop_via_arc) on $left.InitiatingProcessSHA256, $right.SHA256
Stage 5: where
where RemotePort in (135, 22, 3389, 445, 5900, 5985, 5986)
Stage 6: where
where ActionType in~ ("ConnectionAttempt", "ConnectionFailed", "ConnectionRequest", "ConnectionSuccess")
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
ActionType | eq |
| field:"ActionType" kind:eq value:"FileCreated" |
ActionType | in |
| field:"ActionType" kind:in |
InitiatingProcessFileName | eq |
| field:"InitiatingProcessFileName" kind:eq value:"customscripthandler.exe" |
RemotePort | in |
| field:"RemotePort" kind:in |
SHA256 | is_not_null | field:"SHA256" kind:is_not_null |
End-user consent stopped due to risk-based consent
#Detects a user's consent to an OAuth application being blocked due to it being too risky. These events should be investigated to understand why the user attempted to consent to the applicaiton and what other applicaitons they may have consented to. Ref: https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-applications#end-user-stopped-due-to-risk-based-consent
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Persistence | |
| Privilege Escalation |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Azure | any: Entra ID audit event (any operation) |
Rules Detecting the Same Action
These rules filter on the same operation.
- [Entra ID] Application Assigned Administrator Permissions Immediately After Obtaining Role Management Permissions (Kusto)
- [Entra ID] Application Granted Administrative Permission to Assign Microsoft Entra ID Roles (Kusto)
- Added Credentials to Existing Application (Sigma)
- Added Owner To Application (Sigma)
- Admin promotion after Role Management Application Permission Grant (Kusto)
- App Granted Microsoft Permissions (Sigma)
- App Granted Privileged Delegated Or App Permissions (Sigma)
- Application AppID Uri Configuration Changes (Sigma)
Rule Body
id: 009b9bae-23dd-43c4-bcb9-11c4ba7c784a
name: End-user consent stopped due to risk-based consent
description: |
'Detects a user's consent to an OAuth application being blocked due to it being too risky.
These events should be investigated to understand why the user attempted to consent to the applicaiton and what other applicaitons they may have consented to.
Ref: https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-applications#end-user-stopped-due-to-risk-based-consent'
severity: Medium
requiredDataConnectors:
- connectorId: AzureActiveDirectory
dataTypes:
- AuditLogs
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- Persistence
- PrivilegeEscalation
relevantTechniques:
- T1078.004
tags:
- AADSecOpsGuide
query: |
AuditLogs
| where OperationName has "Consent to application"
| where Result =~ "failure"
| extend InitiatingUserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)
| extend InitiatingAadUserId = tostring(InitiatedBy.user.id)
| extend InitiatingIPAddress = tostring(InitiatedBy.user.ipAddress)
| extend userAgent = iif(AdditionalDetails[0].key == "User-Agent", tostring(AdditionalDetails[0].value), tostring(AdditionalDetails[1].value))
| where isnotempty(TargetResources)
| extend TargetAppName = tostring(TargetResources[0].displayName)
| extend TargetAppId = tostring(TargetResources[0].id)
| mv-expand TargetResources[0].modifiedProperties
| extend TargetResources_0_modifiedProperties = columnifexists("TargetResources_0_modifiedProperties", '')
| where isnotempty(TargetResources_0_modifiedProperties)
| where TargetResources_0_modifiedProperties.displayName =~ "MethodExecutionResult."
| extend TargetPropertyDisplayName = tostring(TargetResources_0_modifiedProperties.displayName)
| extend FailureReason = tostring(parse_json(tostring(TargetResources_0_modifiedProperties.newValue)))
| where FailureReason contains "Risky"
| extend InitiatingAccountName = tostring(split(InitiatingUserPrincipalName, "@")[0]), InitiatingAccountUPNSuffix = tostring(split(InitiatingUserPrincipalName, "@")[1])
| project-reorder TimeGenerated, OperationName, Result, TargetAppName, TargetAppId, FailureReason, InitiatingUserPrincipalName, InitiatingAadUserId, InitiatingIPAddress, userAgent
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: InitiatingUserPrincipalName
- identifier: Name
columnName: InitiatingAccountName
- identifier: UPNSuffix
columnName: InitiatingAccountUPNSuffix
- entityType: Account
fieldMappings:
- identifier: AadUserId
columnName: InitiatingAadUserId
- entityType: IP
fieldMappings:
- identifier: Address
columnName: InitiatingIPAddress
- entityType: CloudApplication
fieldMappings:
- identifier: AppId
columnName: TargetAppId
- identifier: Name
columnName: TargetAppName
version: 1.1.1
kind: Scheduled
metadata:
source:
kind: Community
author:
name: Microsoft Security Research
support:
tier: Community
categories:
domains: [ "Security - Others" ]
Stages and Predicates
Stage 1: source
AuditLogs
Stage 2: where
| where OperationName has "Consent to application"
Stage 3: where
| where Result =~ "failure"
Stage 4: extend (4 consecutive steps)
| extend InitiatingUserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)
| extend InitiatingAadUserId = tostring(InitiatedBy.user.id)
| extend InitiatingIPAddress = tostring(InitiatedBy.user.ipAddress)
| extend userAgent = iif(AdditionalDetails[0].key == "User-Agent", tostring(AdditionalDetails[0].value), tostring(AdditionalDetails[1].value))
Stage 5: where
| where isnotempty(TargetResources)
Stage 6: extend
| extend TargetAppName = tostring(TargetResources[0].displayName)
Stage 7: extend
| extend TargetAppId = tostring(TargetResources[0].id)
Stage 8: mv-expand
| mv-expand TargetResources[0].modifiedProperties
Stage 9: extend
| extend TargetResources_0_modifiedProperties = columnifexists("TargetResources_0_modifiedProperties", '')
Stage 10: where
| where isnotempty(TargetResources_0_modifiedProperties)
Stage 11: where
| where TargetResources_0_modifiedProperties.displayName =~ "MethodExecutionResult."
Stage 12: extend
| extend TargetPropertyDisplayName = tostring(TargetResources_0_modifiedProperties.displayName)
Stage 13: extend
| extend FailureReason = tostring(parse_json(tostring(TargetResources_0_modifiedProperties.newValue)))
Stage 14: where
| where FailureReason contains "Risky"
Stage 15: extend
| extend InitiatingAccountName = tostring(split(InitiatingUserPrincipalName, "@")[0]), InitiatingAccountUPNSuffix = tostring(split(InitiatingUserPrincipalName, "@")[1])
Stage 16: project-reorder
| project-reorder TimeGenerated, OperationName, Result, TargetAppName, TargetAppId, FailureReason, InitiatingUserPrincipalName, InitiatingAadUserId, InitiatingIPAddress, userAgent
Indicators
These rows show field, operator, and value matches.
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
InitiatingUserPrincipalName | extend |
InitiatingAadUserId | extend |
InitiatingIPAddress | extend |
userAgent | extend |
TargetAppName | extend |
TargetAppId | extend |
TargetResources_0_modifiedProperties | extend |
TargetPropertyDisplayName | extend |
FailureReason | extend |
InitiatingAccountName | extend |
InitiatingAccountUPNSuffix | extend |
Failover Plan Stopped
#Detects when a failover plan stops. This might indicate disaster recovery activity or issues with primary systems.
Rule Body
id: de4cc05b-2e4e-4104-9559-101b4c41c35e
name: Failover Plan Stopped
description: Detects when a failover plan stops. This might indicate disaster recovery
activity or issues with primary systems.
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: Syslog
dataTypes:
- Syslog
- connectorId: SyslogAma
dataTypes:
- Syslog
queryFrequency: 3h
queryPeriod: 3h
triggerOperator: gt
triggerThreshold: 0
eventGroupingSettings:
aggregationKind: AlertPerResult
tactics: []
relevantTechniques: []
query: "Veeam_GetSecurityEvents\n| where instanceId == 26700\n| project\n Date\
\ = format_datetime(TimeGenerated, 'dd.MM.yyyy HH:mm'),\n DataSource = original_host,\n\
\ EventId = instanceId,\n UserName = user,\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 == 26700
Stage 3: project
| project
Date = format_datetime(TimeGenerated, 'dd.MM.yyyy HH:mm'),
DataSource = original_host,
EventId = instanceId,
UserName = user,
MessageDetails = Description,
Severity = SeverityDescription
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
instanceId | eq |
| field:"instanceId" kind:eq value:"26700" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
DataSource | project |
Date | project |
EventId | project |
MessageDetails | project |
Severity | project |
UserName | project |
GitHub - User was invited to the repository
#Detect activities when a user was invited to the repository. This query runs every day and its severity is Medium.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| GitHub | Audit log action org.invite_member: User invited to join organization |
Rules Detecting the Same Action
These rules filter on the same operation.
Rule Body
id: 0b85a077-8ba5-4cb5-90f7-1e882afe40c9
name: GitHub - User was invited to the repository
description: |
'Detect activities when a user was invited to the repository. This query runs every day and its severity is Medium.'
severity: Medium
status: Available
requiredDataConnectors: []
queryFrequency: 1d
queryPeriod: 7d
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
relevantTechniques:
- T1078
query: |
GitHubAuditData
| where Action == "org.invite_member"
| project Actor, Action
| extend Name = iif(Actor contains "@", split(Actor, "@")[0], Actor)
| extend UPNSuffix = iif(Actor contains "@", split(Actor, "@")[1], "")
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: Actor
- identifier: Name
columnName: Name
- identifier: UPNSuffix
columnName: UPNSuffix
version: 1.0.1
kind: Scheduled
Stages and Predicates
Stage 1: source
GitHubAuditData
Stage 2: where
| where Action == "org.invite_member"
Stage 3: project
| project Actor, Action
Stage 4: extend
| extend Name = iif(Actor contains "@", split(Actor, "@")[0], Actor)
Stage 5: extend
| extend UPNSuffix = iif(Actor contains "@", split(Actor, "@")[1], "")
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
Action | eq |
| field:"Action" kind:eq value:"org.invite_member" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
Action | project |
Actor | project |
Name | extend |
UPNSuffix | extend |
Jira - Global permission added
#'Detects when global permission added.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Privilege Escalation |
Rule Body
id: 5b0cec45-4a91-4f08-bb1b-392427e8f440
name: Jira - Global permission added
description: |
'Detects when global permission added.'
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: JiraAuditAPI
dataTypes:
- JiraAudit
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- PrivilegeEscalation
relevantTechniques:
- T1078
query: |
JiraAudit
| where EventMessage =~ 'Global permission added'
| project EventCreationTime, ObjectItemName, UserName, SrcIpAddr, ChangedValues
| extend AccountCustomEntity = UserName, IPCustomEntity = SrcIpAddr
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: AccountCustomEntity
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity
version: 1.0.0
kind: Scheduled
Stages and Predicates
Stage 1: source
JiraAudit
Stage 2: where
| where EventMessage =~ 'Global permission added'
Stage 3: project
| project EventCreationTime, ObjectItemName, UserName, SrcIpAddr, ChangedValues
Stage 4: extend
| extend AccountCustomEntity = UserName, IPCustomEntity = SrcIpAddr
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
EventMessage | eq |
| field:"EventMessage" kind:eq value:"Global permission added" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
ChangedValues | project |
EventCreationTime | project |
ObjectItemName | project |
SrcIpAddr | project |
UserName | project |
AccountCustomEntity | extend |
IPCustomEntity | extend |
Microsoft Entra ID Hybrid Health AD FS Service Delete
#This detection uses AzureActivity logs (Administrative category) to identify the deletion of an Microsoft Entra ID Hybrid Health AD FS service instance in a tenant. A threat actor can create a new AD Health ADFS service and create a fake server to spoof AD FS signing logs. The health AD FS service can then be deleted after it is no longer needed via HTTP requests to Azure. More information is available in this blog https://o365blog.com/post/hybridhealthagent/
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Defense Impairment |
Telemetry Coverage
Rules Detecting the Same Action
These rules filter on the same operation.
- Azure Active Directory Hybrid Health AD FS New Server (Sigma)
- Azure Active Directory Hybrid Health AD FS Service Delete (Sigma)
- Azure Subscription Permission Elevation Via AuditLogs (Sigma)
- Detect Custom Script or Run Command deployment by risky user (Kusto)
- Microsoft Entra ID Hybrid Health AD FS New Server (Kusto)
- Microsoft Entra ID Hybrid Health AD FS Suspicious Application (Kusto)
- NRT Microsoft Entra ID Hybrid Health AD FS New Server (Kusto)
Rule Body
id: 86a036b2-3686-42eb-b417-909fc0867771
name: Microsoft Entra ID Hybrid Health AD FS Service Delete
description: |
'This detection uses AzureActivity logs (Administrative category) to identify the deletion of an Microsoft Entra ID Hybrid Health AD FS service instance in a tenant.
A threat actor can create a new AD Health ADFS service and create a fake server to spoof AD FS signing logs.
The health AD FS service can then be deleted after it is no longer needed via HTTP requests to Azure.
More information is available in this blog https://o365blog.com/post/hybridhealthagent/'
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: AzureActivity
dataTypes:
- AzureActivity
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- DefenseEvasion
relevantTechniques:
- T1578.003
tags:
- SimuLand
query: |
AzureActivity
| where CategoryValue =~ 'Administrative'
| where ResourceProviderValue =~ 'Microsoft.ADHybridHealthService'
| where _ResourceId has 'AdFederationService'
| where OperationNameValue =~ 'Microsoft.ADHybridHealthService/services/delete'
| extend claimsJson = parse_json(Claims)
| extend AppId = tostring(claimsJson.appid), AccountName = tostring(claimsJson.name), Name = tostring(split(Caller,'@',0)[0]), UPNSuffix = tostring(split(Caller,'@',1)[0])
| project-away claimsJson
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: Caller
- identifier: Name
columnName: Name
- identifier: UPNSuffix
columnName: UPNSuffix
- entityType: IP
fieldMappings:
- identifier: Address
columnName: CallerIpAddress
version: 2.0.3
kind: Scheduled
Stages and Predicates
Stage 1: source
AzureActivity
Stage 2: where
| where CategoryValue =~ 'Administrative'
Stage 3: where
| where ResourceProviderValue =~ 'Microsoft.ADHybridHealthService'
Stage 4: where
| where _ResourceId has 'AdFederationService'
Stage 5: where
| where OperationNameValue =~ 'Microsoft.ADHybridHealthService/services/delete'
Stage 6: extend
| extend claimsJson = parse_json(Claims)
Stage 7: extend
| extend AppId = tostring(claimsJson.appid), AccountName = tostring(claimsJson.name), Name = tostring(split(Caller,'@',0)[0]), UPNSuffix = tostring(split(Caller,'@',1)[0])
Stage 8: project-away
| project-away claimsJson
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
CategoryValue | eq |
| field:"CategoryValue" kind:eq value:"Administrative" |
OperationNameValue | eq |
| field:"azure_ad::operation_name_value" kind:eq value:"Microsoft.ADHybridHealthService/services/delete" |
ResourceProviderValue | eq |
| field:"ResourceProviderValue" kind:eq value:"Microsoft.ADHybridHealthService" |
_ResourceId | match |
| field:"_ResourceId" kind:match value:"AdFederationService" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
AccountName | extend |
AppId | extend |
Name | extend |
UPNSuffix | extend |
Microsoft Recommended Driver Block List
#The query below detects loading or creation of a vulnerable driver that is listed in the Microsoft recommended driver block rules.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Stealth | No specific technique |
References
Telemetry Coverage
Rule Body
// Author: Cyb3rMonk(https://twitter.com/Cyb3rMonk, https://academy.bluraven.io)
//
// Query parameters:
let driver_block_list = externaldata (driver:dynamic) [@"https://raw.githubusercontent.com/Cyb3r-Monk/Microsoft-Vulnerable-Driver-Block-Lists/refs/heads/main/msft_vuln_driver_block_list.json"]
with (format=multijson, ingestionMapping='[{"Column":"driver","Properties":{"Path":"$"}}]')
| evaluate bag_unpack(driver)
;
let driver_hashes = toscalar(
driver_block_list
| where isnotempty(FileHash)
| summarize make_set(tolower(FileHash))
)
;
union
(
DeviceEvents
| where ActionType == "DriverLoad"
| where SHA1 in~ (driver_hashes) or SHA256 in~ (driver_hashes)
),
(
DeviceFileEvents
| where SHA1 in~ (driver_hashes) or SHA256 in~ (driver_hashes)
)
Stages and Predicates
Let Binding: driver_block_list
let driver_block_list = externaldata (driver:dynamic) [@"https://raw.githubusercontent.com/Cyb3r-Monk/Microsoft-Vulnerable-Driver-Block-Lists/refs/heads/main/msft_vuln_driver_block_list.json"]
with (format=multijson, ingestionMapping='[{"Column":"driver","Properties":{"Path":"$"}}]')
| evaluate bag_unpack(driver);
Let Binding: driver_hashes
let driver_hashes = toscalar(
driver_block_list
| where isnotempty(FileHash)
| summarize make_set(tolower(FileHash))
);
Union (2 Sources)
Each leg below queries one source; the rule matches if any leg does. Sources: DeviceEvents, DeviceFileEvents
Leg 1: DeviceEvents
DeviceEvents
| where ActionType == "DriverLoad"
| where SHA1 in~ (driver_hashes) or SHA256 in~ (driver_hashes)
Leg 2: DeviceFileEvents
DeviceFileEvents
| where SHA1 in~ (driver_hashes) or SHA256 in~ (driver_hashes)
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
ActionType | eq |
| field:"ActionType" kind:eq value:"DriverLoad" |
SHA1 | in |
| field:"sha1" kind:in value:"driver_hashes" |
SHA256 | in |
| field:"sha256" kind:in value:"driver_hashes" |
Pathlock TDnR - Authorization Role Changes
#Detects changes to SAP authorization roles (PFCG), forwarded by Pathlock Threat Detection and Response. Unauthorized role modifications are one of the most common SAP privilege escalation vectors and may be used to grant unauthorized access to sensitive transactions or data.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Persistence | |
| Privilege Escalation |
Rule Body
id: 2a3b4c5d-6e7f-4a0b-8c1d-2e3f4a5b6c46
name: Pathlock TDnR - Authorization Role Changes
kind: Scheduled
description: >-
Detects changes to SAP authorization roles (PFCG), forwarded by Pathlock Threat Detection and
Response. Unauthorized role modifications are one of the most common SAP privilege escalation
vectors and may be used to grant unauthorized access to sensitive transactions or data.
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 == "ROLE_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 == "ROLE_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.
| Field | Kind | Values | Search |
|---|---|---|---|
DataSource | eq |
| field:"DataSource" kind:eq value:"ROLE_CHANGES" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
AffectedUser | project |
Area | project |
Bname | project |
CentralTs | project |
DataSource | project |
DestIp | project |
Eventid | project |
Hostname | project |
Instance | project |
LogLine | project |
MessageV1 | project |
MessageV2 | project |
MessageV3 | project |
MessageV4 | project |
MsgId | project |
MsgNo | project |
MsgType | project |
Report | project |
SrcIp | project |
Subid | project |
Sysid | project |
Tcode | project |
TimeGenerated | project |
Samsung Knox - Peripheral Access Detection with Camera Events
#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.
When camera access has been detected on a Knox device, even though such access is disabled through an MDM device policy.
Rule Body
id: cd526f4d-dbe9-4149-8a0a-9ec43c3abb16
name: Samsung Knox - Peripheral Access Detection with Camera Events
version: 1.0.2
kind: NRT
description: When camera access has been detected on a Knox device, even though such access is disabled through an MDM device policy.
severity: High
status: Available
requiredDataConnectors:
- connectorId: SamsungDCDefinition
dataTypes:
- Samsung_Knox_System_CL
tactics: []
relevantTechniques: []
query: |
Samsung_Knox_System_CL
| where Name == "PERIPHERAL_ACCESS_THROUGH_POLICY_DETECTED_CAMERA"
and MitreTtp has "KNOX.2"
suppressionEnabled: false
suppressionDuration: PT5H
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: false
reopenClosedIncident: false
lookbackDuration: PT5H
matchingMethod: AllEntities
eventGroupingSettings:
aggregationKind: SingleAlert
Stages and Predicates
Stage 1: source
Samsung_Knox_System_CL
Stage 2: where
| where Name == "PERIPHERAL_ACCESS_THROUGH_POLICY_DETECTED_CAMERA"
and MitreTtp has "KNOX.2"
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
MitreTtp | match |
| field:"MitreTtp" kind:match value:"KNOX.2" |
Name | eq |
| field:"Name" kind:eq value:"PERIPHERAL_ACCESS_THROUGH_POLICY_DETECTED_CAMERA" |
Sign-ins from IPs that attempt sign-ins to disabled accounts (Uses Authentication Normalization)
#Identifies IPs with failed attempts to sign in to one or more disabled accounts signed in successfully to another account. To use this analytics rule, make sure you have deployed the ASIM normalization parsers
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access | |
| Persistence |
Telemetry Coverage
Rule Body
id: 95002681-4ecb-4da3-9ece-26d7e5feaa33
name: Sign-ins from IPs that attempt sign-ins to disabled accounts (Uses Authentication Normalization)
description: |
'Identifies IPs with failed attempts to sign in to one or more disabled accounts signed in successfully to another account.
To use this analytics rule, make sure you have deployed the [ASIM normalization parsers](https://aka.ms/ASimAuthentication)'
severity: Medium
requiredDataConnectors: []
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
- Persistence
relevantTechniques:
- T1078
- T1098
tags:
- Id: 500c103a-0319-4d56-8e99-3cec8d860757
version: 1.0.0
query: |
imAuthentication
| where EventResult =='Failure'
| where EventResultDetails == 'User disabled'
| summarize StartTime=min(EventStartTime), EndTime=max(EventEndTime), disabledAccountLoginAttempts = count()
, disabledAccountsTargeted = dcount(TargetUsername), disabledAccountSet = make_set(TargetUsername)
, applicationsTargeted = dcount(TargetAppName)
, applicationSet = make_set(TargetAppName)
by SrcDvcIpAddr, Type
| order by disabledAccountLoginAttempts desc
| join kind=leftouter
(
// Consider these IPs suspicious - and alert any related successful sign-ins
imAuthentication
| where EventResult=='Success'
| summarize successfulAccountSigninCount = dcount(TargetUsername), successfulAccountSigninSet = makeset(TargetUsername, 15) by SrcDvcIpAddr, Type
// Assume IPs associated with sign-ins from 100+ distinct user accounts are safe
| where successfulAccountSigninCount < 100
)
on SrcDvcIpAddr
| where isnotempty(successfulAccountSigninCount)
| project StartTime, EndTime, SrcDvcIpAddr, disabledAccountLoginAttempts, disabledAccountsTargeted, disabledAccountSet, applicationSet,
successfulAccountSigninCount, successfulAccountSigninSet, Type
| order by disabledAccountLoginAttempts
entityMappings:
- entityType: IP
fieldMappings:
- identifier: Address
columnName: SrcDvcIpAddr
version: 1.0.3
kind: Scheduled
metadata:
source:
kind: Community
Stages and Predicates
Stage 1: source
imAuthentication
Stage 2: where
| where EventResult =='Failure'
Stage 3: where
| where EventResultDetails == 'User disabled'
Stage 4: summarize
| summarize StartTime=min(EventStartTime), EndTime=max(EventEndTime), disabledAccountLoginAttempts = count()
, disabledAccountsTargeted = dcount(TargetUsername), disabledAccountSet = make_set(TargetUsername)
, applicationsTargeted = dcount(TargetAppName)
, applicationSet = make_set(TargetAppName)
by SrcDvcIpAddr, Type
Stage 5: sort
| order by disabledAccountLoginAttempts desc
Stage 6: join
| join kind=leftouter
(
imAuthentication
| where EventResult=='Success'
| summarize successfulAccountSigninCount = dcount(TargetUsername), successfulAccountSigninSet = makeset(TargetUsername, 15) by SrcDvcIpAddr, Type
| where successfulAccountSigninCount < 100
)
on SrcDvcIpAddr
Stage 7: where
where isnotempty(successfulAccountSigninCount)
Stage 8: project
project EndTime, SrcDvcIpAddr, StartTime, Type, applicationSet, disabledAccountLoginAttempts, disabledAccountSet, disabledAccountsTargeted, successfulAccountSigninCount, successfulAccountSigninSet
Stage 9: sort
sort by disabledAccountLoginAttempts
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
EventResult | eq |
| field:"EventResult" kind:eq |
EventResultDetails | eq |
| field:"Status" kind:eq value:"User disabled" |
successfulAccountSigninCount | is_not_null | field:"successfulAccountSigninCount" kind:is_not_null | |
successfulAccountSigninCount | lt |
| field:"successfulAccountSigninCount" kind:lt value:"100" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
EndTime | project |
SrcDvcIpAddr | project |
StartTime | project |
Type | project |
applicationSet | project |
disabledAccountLoginAttempts | project |
disabledAccountSet | project |
disabledAccountsTargeted | project |
successfulAccountSigninCount | project |
successfulAccountSigninSet | project |
Suspicious parentprocess relationship - Office child processes.
#The attacker sends a spearphishing email to a user. The email contains a link, which points to a website that eventually presents the user a download of an MS Office document. This document contains a malicious macro. The macro spawns a new child process providing initial access. This detection looks for suspicious parent-process chains starting with a browser which spawns an Office application which spawns something else.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Microsoft Defender for Endpoint | DeviceProcessEvents action any: Process activity |
Rule Body
id: 5ee34fa1-64ed-48c7-afa2-794b244f6c60
name: Suspicious parentprocess relationship - Office child processes.
description: |
The attacker sends a spearphishing email to a user. The email contains a link, which points to a website that eventually presents the user a download of an MS Office document. This document contains a malicious macro. The macro spawns a new child process providing initial access. This detection looks for suspicious parent-process chains starting with a browser which spawns an Office application which spawns something else.
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: MicrosoftThreatProtection
dataTypes:
- DeviceProcessEvents
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
relevantTechniques:
- T1566.002
query: |
let browsers = dynamic(["iexplore.exe", "chrome.exe", "firefox.exe", "msedge.exe"]); // Customize this list for your environment.
let officeApps = dynamic(["winword.exe", "excel.exe", "powerpnt.exe"]); // Consider adding other Office applications such as Publisher, Visio and Access.
// This is an allow-list of the most common child processes. This is a quick and dirty solution. Consider allow-listing the full process path instead of file name.
// Also, make this list as short as possible. Remove anything from this list if it doesn't occur in your organization.
let allowList = dynamic(["MSOSYNC.exe", "splwow64.exe", "csc.exe", "outlook.exe", "AcroRd32.exe", "Acrobat.exe", "explorer.exe", "DW20.exe",
"Microsoft.Mashup.Container.Loader.exe", "Microsoft.Mashup.Container.NetFX40.exe", "WerFault.exe", "CLVIEW.exe"]);
DeviceProcessEvents
| where InitiatingProcessParentFileName in~ (browsers) and InitiatingProcessFileName in~ (officeApps) and
FileName !in~ (officeApps) and FileName !in~ (browsers) and FileName !in~ (allowList)
| project-rename ProcessStart_Timestamp = Timestamp
entityMappings:
- entityType: Host
fieldMappings:
- identifier: FullName
columnName: DeviceName
- entityType: Account
fieldMappings:
- identifier: Sid
columnName: AccountSid
- identifier: Name
columnName: AccountName
- identifier: NTDomain
columnName: AccountDomain
- entityType: Process
fieldMappings:
- identifier: CommandLine
columnName: ProcessCommandLine
version: 1.0.1
kind: Scheduled
Stages and Predicates
Parameters
let browsers = dynamic(["iexplore.exe", "chrome.exe", "firefox.exe", "msedge.exe"]);
let officeApps = dynamic(["winword.exe", "excel.exe", "powerpnt.exe"]);
Let Binding: allowList
let allowList = dynamic(["MSOSYNC.exe", "splwow64.exe", "csc.exe", "outlook.exe", "AcroRd32.exe", "Acrobat.exe", "explorer.exe", "DW20.exe",
"Microsoft.Mashup.Container.Loader.exe", "Microsoft.Mashup.Container.NetFX40.exe", "WerFault.exe", "CLVIEW.exe"]);
Stage 1: source
DeviceProcessEvents
Stage 2: where
| where InitiatingProcessParentFileName in~ (browsers) and InitiatingProcessFileName in~ (officeApps) and
FileName !in~ (officeApps) and FileName !in~ (browsers) and FileName !in~ (allowList)
Stage 3: project-rename
| project-rename ProcessStart_Timestamp = Timestamp
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
InitiatingProcessFileName | in |
| field:"parent_process_basename" kind:in |
InitiatingProcessParentFileName | in |
| field:"grandparent_process_basename" kind:in |
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
FileName | in | AcroRd32.exe, Acrobat.exe, CLVIEW.exe, DW20.exe, MSOSYNC.exe, Microsoft.Mashup.Container.Loader.exe, Microsoft.Mashup.Container.NetFX40.exe, WerFault.exe, csc.exe, explorer.exe, outlook.exe, splwow64.exe | excludes:FileName |
FileName | in | chrome.exe, firefox.exe, iexplore.exe, msedge.exe | excludes:FileName |
FileName | in | excel.exe, powerpnt.exe, winword.exe | excludes:FileName field:"FileName" value:"excel.exe" field:"FileName" value:"powerpnt.exe" field:"FileName" value:"winword.exe" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
ProcessStart_Timestamp | project-rename |
Unused IaaS Policy
#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.
The policy detects 'IaaS policies' that no one in the account has been using during the last X days.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access | |
| Privilege Escalation |
Rule Body
id: e0ae5f9e-865b-41f5-98bb-c04113888e85
name: Unused IaaS Policy
kind: Scheduled
description: The policy detects 'IaaS policies' that no one in the account has been using during the last X days.
severity: High
status: Available
queryFrequency: 30m
queryPeriod: 30m
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
- PrivilegeEscalation
relevantTechniques:
- T1078
- T1068
- T1078
query: |-
Authomize_v2_CL
| where ingestion_time() >= ago(30m)
| extend EventID = id_s, Policy = policy_name_s, Severity = severity_s,Description = description_s,Recommendation = recommendation_s,URL = url_s,Tactics = tactics_s
| where Policy has "Unused IaaS Policy"
| project EventID, Policy, Severity, Description, Recommendation, URL, Category, Tactics
entityMappings:
- entityType: URL
fieldMappings:
- identifier: Url
columnName: URL
requiredDataConnectors:
- connectorId: Authomize
dataTypes: [ "Authomize_v2_CL" ]
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: true
reopenClosedIncident: false
lookbackDuration: 5h
matchingMethod: AnyAlert
groupByEntities: []
groupByAlertDetails: []
groupByCustomDetails: []
eventGroupingSettings:
aggregationKind: SingleAlert
alertDetailsOverride:
alertnameFormat: Alert from Authomize - Unused IaaS Policy
alertDescriptionFormat: |
Unused IaaS Policy. The policy detects 'IaaS policies' that no one in the account has been using during the last X days.
alertSeverity: Severity
alertTactics: Tactics
alertDynamicProperties:
- alertProperty: AlertLink
value: URL
customDetails:
AuthomizeEventID: EventID
EventName: Policy
EventDescription: Description
EventRecommendation: Recommendation
ReferencedURL: URL
suppressionDuration: 5h
suppressionEnabled: false
version: 1.0.2
Stages and Predicates
Stage 1: source
Authomize_v2_CL
Stage 2: where
| where ingestion_time() >= ago(30m)
Stage 3: extend
| extend EventID = id_s, Policy = policy_name_s, Severity = severity_s,Description = description_s,Recommendation = recommendation_s,URL = url_s,Tactics = tactics_s
Stage 4: where
| where Policy has "Unused IaaS Policy"
Stage 5: project
| project EventID, Policy, Severity, Description, Recommendation, URL, Category, Tactics
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
Policy | match |
| field:"policy_name_s" kind:match value:"Unused IaaS Policy" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
Category | project |
Description | project |
EventID | project |
Policy | project |
Recommendation | project |
Severity | project |
Tactics | project |
URL | project |