Detection rules › Kusto
Kusto rules: 2g
Brute force attack against Azure Portal
#Detects Azure Portal brute force attacks by monitoring for multiple authentication failures and a successful login within a 20-minute window. Default settings: 10 failures, 25 deviations. Ref: https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-sign-ins-error-codes.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Credential Access |
Telemetry Coverage
Rule Body
id: 28b42356-45af-40a6-a0b4-a554cdfd5d8a
name: Brute force attack against Azure Portal
description: |
Detects Azure Portal brute force attacks by monitoring for multiple authentication failures and a successful login within a 20-minute window. Default settings: 10 failures, 25 deviations.
Ref: https://docs.microsoft.com/azure/active-directory/reports-monitoring/reference-sign-ins-error-codes.
severity: Medium
requiredDataConnectors:
- connectorId: AzureActiveDirectory
dataTypes:
- SigninLogs
- connectorId: AzureActiveDirectory
dataTypes:
- AADNonInteractiveUserSignInLogs
queryFrequency: 1d
queryPeriod: 7d
triggerOperator: gt
triggerThreshold: 0
status: Available
tactics:
- CredentialAccess
relevantTechniques:
- T1110
query: |
// Set threshold value for deviation
let threshold = 25;
// Set the time range for the query
let timeRange = 24h;
// Set the authentication window duration
let authenticationWindow = 20m;
// Define a reusable function 'aadFunc' that takes a table name as input
let aadFunc = (tableName: string) {
// Query the specified table
table(tableName)
// Filter data within the last 24 hours
| where TimeGenerated > ago(1d)
// Filter records related to "Azure Portal" applications
| where AppDisplayName has "Azure Portal"
// Extract and transform some fields
| extend
DeviceDetail = todynamic(DeviceDetail),
LocationDetails = todynamic(LocationDetails)
| extend
OS = tostring(DeviceDetail.operatingSystem),
Browser = tostring(DeviceDetail.browser),
State = tostring(LocationDetails.state),
City = tostring(LocationDetails.city),
Region = tostring(LocationDetails.countryOrRegion)
// Categorize records as Success or Failure based on ResultType
| extend FailureOrSuccess = iff(ResultType in ("0", "50125", "50140", "70043", "70044"), "Success", "Failure")
// Sort and identify sessions
| sort by UserPrincipalName asc, TimeGenerated asc
| extend SessionStartedUtc = row_window_session(TimeGenerated, timeRange, authenticationWindow, UserPrincipalName != prev(UserPrincipalName) or prev(FailureOrSuccess) == "Success")
// Summarize data
| summarize FailureOrSuccessCount = count() by FailureOrSuccess, UserId, UserDisplayName, AppDisplayName, IPAddress, Browser, OS, State, City, Region, Type, CorrelationId, bin(TimeGenerated, authenticationWindow), ResultType, UserPrincipalName, SessionStartedUtc
| summarize FailureCountBeforeSuccess = sumif(FailureOrSuccessCount, FailureOrSuccess == "Failure"), StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), makelist(FailureOrSuccess), IPAddress = make_set(IPAddress, 15), make_set(Browser, 15), make_set(City, 15), make_set(State, 15), make_set(Region, 15), make_set(ResultType, 15) by SessionStartedUtc, UserPrincipalName, CorrelationId, AppDisplayName, UserId, Type
// Filter records where "Success" occurs in the middle of a session
| where array_index_of(list_FailureOrSuccess, "Success") != 0
| where array_index_of(list_FailureOrSuccess, "Success") == array_length(list_FailureOrSuccess) - 1
// Remove unnecessary columns from the output
| project-away SessionStartedUtc, list_FailureOrSuccess
// Join with another table and calculate deviation
| join kind=inner (
table(tableName)
| where TimeGenerated > ago(7d)
| where AppDisplayName has "Azure Portal"
| extend FailureOrSuccess = iff(ResultType in ("0", "50125", "50140", "70043", "70044"), "Success", "Failure")
| summarize avgFailures = avg(todouble(FailureOrSuccess == "Failure")) by UserPrincipalName
) on UserPrincipalName
| extend Deviation = abs(FailureCountBeforeSuccess - avgFailures) / avgFailures
// Filter records based on deviation and failure count criteria
| where Deviation > threshold and FailureCountBeforeSuccess >= 10
// Expand the IPAddress array
| mv-expand IPAddress
| extend IPAddress = tostring(IPAddress)
| extend timestamp = StartTime
};
// Call 'aadFunc' with different table names and union the results
let aadSignin = aadFunc("SigninLogs");
let aadNonInt = aadFunc("AADNonInteractiveUserSignInLogs");
union isfuzzy=true aadSignin, aadNonInt
// Additional transformation - Split UserPrincipalName
| extend Name = tostring(split(UserPrincipalName,'@',0)[0]), UPNSuffix = tostring(split(UserPrincipalName,'@',1)[0])
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: UserPrincipalName
- identifier: Name
columnName: Name
- identifier: UPNSuffix
columnName: UPNSuffix
- entityType: Account
fieldMappings:
- identifier: AadUserId
columnName: UserId
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPAddress
version: 2.1.4
kind: Scheduled
Stages and Predicates
Parameters
let threshold = 25;
let timeRange = 24h;
let authenticationWindow = 20m;
let aadSignin = aadFunc("SigninLogs");
let aadNonInt = aadFunc("AADNonInteractiveUserSignInLogs");
Let Binding: aadFunc
let aadFunc = (tableName: string) {
table(tableName)
| where TimeGenerated > ago(1d)
| where AppDisplayName has "Azure Portal"
| extend
DeviceDetail = todynamic(DeviceDetail),
LocationDetails = todynamic(LocationDetails)
| extend
OS = tostring(DeviceDetail.operatingSystem),
Browser = tostring(DeviceDetail.browser),
State = tostring(LocationDetails.state),
City = tostring(LocationDetails.city),
Region = tostring(LocationDetails.countryOrRegion)
| extend FailureOrSuccess = iff(ResultType in ("0", "50125", "50140", "70043", "70044"), "Success", "Failure")
| sort by UserPrincipalName asc, TimeGenerated asc
| extend SessionStartedUtc = row_window_session(TimeGenerated, timeRange, authenticationWindow, UserPrincipalName != prev(UserPrincipalName) or prev(FailureOrSuccess) == "Success")
| summarize FailureOrSuccessCount = count() by FailureOrSuccess, UserId, UserDisplayName, AppDisplayName, IPAddress, Browser, OS, State, City, Region, Type, CorrelationId, bin(TimeGenerated, authenticationWindow), ResultType, UserPrincipalName, SessionStartedUtc
| summarize FailureCountBeforeSuccess = sumif(FailureOrSuccessCount, FailureOrSuccess == "Failure"), StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), makelist(FailureOrSuccess), IPAddress = make_set(IPAddress, 15), make_set(Browser, 15), make_set(City, 15), make_set(State, 15), make_set(Region, 15), make_set(ResultType, 15) by SessionStartedUtc, UserPrincipalName, CorrelationId, AppDisplayName, UserId, Type
| where array_index_of(list_FailureOrSuccess, "Success") != 0
| where array_index_of(list_FailureOrSuccess, "Success") == array_length(list_FailureOrSuccess) - 1
| project-away SessionStartedUtc, list_FailureOrSuccess
| join kind=inner (
table(tableName)
| where TimeGenerated > ago(7d)
| where AppDisplayName has "Azure Portal"
| extend FailureOrSuccess = iff(ResultType in ("0", "50125", "50140", "70043", "70044"), "Success", "Failure")
| summarize avgFailures = avg(todouble(FailureOrSuccess == "Failure")) by UserPrincipalName
) on UserPrincipalName
| extend Deviation = abs(FailureCountBeforeSuccess - avgFailures) / avgFailures
| where Deviation > threshold and FailureCountBeforeSuccess >= 10
| mv-expand IPAddress
| extend IPAddress = tostring(IPAddress)
| extend timestamp = StartTime
};
Union isfuzzy=true (2 Sources)
Each leg below queries one source; the rule matches if any leg does. Sources: aadSignin, aadNonInt
Leg 1: aadSignin
Leg 2: aadNonInt
Applied to the Combined Result
| extend Name = tostring(split(UserPrincipalName,'@',0)[0]), UPNSuffix = tostring(split(UserPrincipalName,'@',1)[0])
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
Name | extend |
UPNSuffix | extend |
CTE - Rule Capacity Critical (95%)
#Tenant-wide blocking-rule/IOC capacity has reached 95% - new rules or IOCs may soon fail to be added. Emitted by the daily tenant health-check job (api/src/functions/tenantHealthChecks.js) when usage newly crosses this threshold, and re-emitted at most once per ~30 days while it remains above threshold.
Rule Body
id: bd06aa7c-8aef-40f3-bf32-a70b5d48f79e
name: CTE - Rule Capacity Critical (95%)
description: |
Tenant-wide blocking-rule/IOC capacity has reached 95% - new rules or IOCs may soon fail to be added. Emitted by the daily tenant health-check job (api/src/functions/tenantHealthChecks.js) when usage newly crosses this threshold, and re-emitted at most once per ~30 days while it remains above threshold.
severity: High
requiredDataConnectors:
- connectorId: cybereinforce_cte
dataTypes:
- CybereinforceCTE_CL
queryFrequency: 24h
queryPeriod: 2d
triggerOperator: gt
triggerThreshold: 0
tactics:
[]
relevantTechniques: []
query: |
CybereinforceCTE_CL
| where EventType == "rule.capacity_critical"
| extend d = parse_json(Details)
| extend AppName = "Cybereinforce", RuleCount = toint(d.ruleCount), RuleLimit = toint(d.ruleLimit), UsedPct = todouble(d.usedPct)
| project TimeGenerated, TenantId, AppName, RuleCount, RuleLimit, UsedPct, Severity, Category, Source
entityMappings:
- entityType: CloudApplication
fieldMappings:
- identifier: Name
columnName: AppName
- identifier: InstanceName
columnName: TenantId
version: 1.0.0
kind: Scheduled
Stages and Predicates
Stage 1: source
CybereinforceCTE_CL
Stage 2: where
| where EventType == "rule.capacity_critical"
Stage 3: extend
| extend d = parse_json(Details)
Stage 4: extend
| extend AppName = "Cybereinforce", RuleCount = toint(d.ruleCount), RuleLimit = toint(d.ruleLimit), UsedPct = todouble(d.usedPct)
Stage 5: project
| project TimeGenerated, TenantId, AppName, RuleCount, RuleLimit, UsedPct, Severity, Category, Source
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
EventType | eq |
| field:"EventType" kind:eq value:"rule.capacity_critical" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
AppName | project |
Category | project |
RuleCount | project |
RuleLimit | project |
Severity | project |
Source | project |
TenantId | project |
TimeGenerated | project |
UsedPct | project |
CYFIRMA - Attack Surface - Cloud Weakness Medium Rule
#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.
"This rule detects cloud storage buckets (e.g., AWS S3) that are publicly accessible without authentication. Such misconfigurations can lead to data exfiltration, compliance violations, and reputational damage. The detection is based on Cyfirma's Attack Surface Intelligence."
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Discovery |
Rule Body
id: b8a3c5e2-04d5-4b61-9b62-b4f53a417f74
name: CYFIRMA - Attack Surface - Cloud Weakness Medium Rule
description: |
"This rule detects cloud storage buckets (e.g., AWS S3) that are publicly accessible without authentication.
Such misconfigurations can lead to data exfiltration, compliance violations, and reputational damage.
The detection is based on Cyfirma's Attack Surface Intelligence."
version: 1.0.1
kind: Scheduled
severity: Medium
requiredDataConnectors:
- connectorId: CyfirmaAttackSurfaceAlertsConnector
dataTypes:
- CyfirmaASCloudWeaknessAlerts_CL
queryFrequency: 5m
queryPeriod: 5m
triggerOperator: gt
triggerThreshold: 0
status: Available
tactics:
- InitialAccess
- Collection
- Discovery
- Exfiltration
relevantTechniques:
- T1087
- T1087.004
query: |
// Medium Severity - Attack Surface - Cloud Weakness - Unauthorized Public Cloud Storage Exposure Detected
let timeFrame = 5m;
CyfirmaASCloudWeaknessAlerts_CL
| where severity == 'High' and TimeGenerated between (ago(timeFrame) .. now())
| extend
Description=description,
FirstSeen=first_seen,
LastSeen=last_seen,
RiskScore=risk_score,
Domain=asset_name,
AlertUID=alert_uid,
UID=uid,
Source=source,
SourceType=source_type,
CreatedDate=created_date,
Impact=impact,
ProviderName='CYFIRMA',
ProductName='DeCYFIR/DeTCT'
| project
TimeGenerated,
Description,
Domain,
RiskScore,
FirstSeen,
LastSeen,
AlertUID,
UID,
Source,
SourceType,
CreatedDate,
Impact,
ProviderName,
ProductName
entityMappings:
- entityType: DNS
fieldMappings:
- identifier: DomainName
columnName: Domain
customDetails:
TimeGenerated: TimeGenerated
RiskScore: RiskScore
FirstSeen: FirstSeen
LastSeen: LastSeen
AlertUID: AlertUID
UID: UID
Source: Source
SourceType: SourceType
CreatedDate: CreatedDate
Impact: Impact
alertDetailsOverride:
alertDisplayNameFormat: "CYFIRMA - Medium Severity Alert - Unauthorized Public Cloud Storage Exposure Detected - Domain: {{Domain}}"
alertDescriptionFormat: "CYFIRMA - Medium Severity Alert - Unauthorized Public Cloud Storage Exposure Detected - {{Description}}"
alertDynamicProperties:
- alertProperty: ProductName
value: ProductName
- alertProperty: ProviderName
value: ProviderName
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: false
reopenClosedIncident: false
lookbackDuration: PT5H
matchingMethod: AllEntities
eventGroupingSettings:
aggregationKind: AlertPerResult
Stages and Predicates
Parameters
let timeFrame = 5m;
Stage 1: source
CyfirmaASCloudWeaknessAlerts_CL
Stage 2: where
| where severity == 'High' and TimeGenerated between (ago(timeFrame) .. now())
Stage 3: extend
| extend
Description=description,
FirstSeen=first_seen,
LastSeen=last_seen,
RiskScore=risk_score,
Domain=asset_name,
AlertUID=alert_uid,
UID=uid,
Source=source,
SourceType=source_type,
CreatedDate=created_date,
Impact=impact,
ProviderName='CYFIRMA',
ProductName='DeCYFIR/DeTCT'
Stage 4: project
| project
TimeGenerated,
Description,
Domain,
RiskScore,
FirstSeen,
LastSeen,
AlertUID,
UID,
Source,
SourceType,
CreatedDate,
Impact,
ProviderName,
ProductName
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
severity | eq |
| field:"severity" kind:eq value:"High" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
AlertUID | project |
CreatedDate | project |
Description | project |
Domain | project |
FirstSeen | project |
Impact | project |
LastSeen | project |
ProductName | project |
ProviderName | project |
RiskScore | project |
Source | project |
SourceType | project |
TimeGenerated | project |
UID | project |
CYFIRMA - High severity Command & Control Network Indicators with Block Recommendation Rule
#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.
"This analytics rule detects network-based indicators identified by CYFIRMA threat intelligence as associated with Command & Control (C2) infrastructure. These may represent attacker-controlled endpoints used to maintain persistence, exfiltrate data, or receive commands from malware-infected hosts."
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access | |
| Command & Control | |
| Exfiltration |
Rule Body
id: 6b61b716-afd9-4f6c-ad00-965d5987cafd
name: CYFIRMA - High severity Command & Control Network Indicators with Block Recommendation Rule
description: |
"This analytics rule detects network-based indicators identified by CYFIRMA threat intelligence as associated with Command & Control (C2) infrastructure.
These may represent attacker-controlled endpoints used to maintain persistence, exfiltrate data, or receive commands from malware-infected hosts."
version: 1.0.1
kind: Scheduled
severity: High
enabled: false
requiredDataConnectors:
- connectorId: CyfirmaCyberIntelligenceDC
dataTypes:
- CyfirmaIndicators_CL
query: |
// Network Indicators query with Block Recommended Action and C2 Roles
let timeFrame= 5m;
CyfirmaIndicators_CL
| where ConfidenceScore >= 80
and TimeGenerated between (ago(timeFrame) .. now())
and pattern !contains 'file:hashes' and RecommendedActions has 'Block' and (Roles contains 'c2' or Roles contains 'Command & Control')
| extend IPv4 = extract(@"ipv4-addr:value\s*=\s*'([^']+)'", 1, pattern)
| extend IPv6 = extract(@"ipv6-addr:value\s*=\s*'([^']+)'", 1, pattern)
| extend URL = extract(@"url:value\s*=\s*'([^']+)'", 1, pattern)
| extend Domain = extract(@"domain-name:value\s*=\s*'([^']+)'", 1, pattern)
| extend parsed = parse_json(extensions)
| extend extensionKeys = bag_keys(parsed)
| mv-expand extensionKeys
| extend extensionKeyStr = tostring(extensionKeys)
| extend ext = parsed[extensionKeyStr]
| extend props = ext.properties
| extend
extension_id = extensionKeyStr,
ASN_Owner = props.asn_owner,
ASN = props.asn,
ProviderName = 'CYFIRMA',
ProductName = 'DeCYFIR/DeTCT'
| project
IPv4,
IPv6,
URL,
Domain,
ThreatActors,
RecommendedActions,
Sources,
Roles,
Country,
IPAbuse,
name,
Description,
ConfidenceScore,
IndicatorID,
created,
modified,
valid_from,
Tags,
ThreatType,
TimeGenerated,
SecurityVendors,
ProductName,
ProviderName
queryFrequency: 5m
queryPeriod: 5m
triggerOperator: gt
triggerThreshold: 0
suppressionDuration: 5m
suppressionEnabled: true
tactics:
- CommandAndControl
- InitialAccess
- Exfiltration
relevantTechniques:
- T1071
- T1090
- T1573
- T1105
- T1568
- T1566
- T1041
- T1071.001
- T1573.001
- T1568.002
- T1566.002
alertDetailsOverride:
alertDisplayNameFormat: "High-Confidence Command & Control Network Indicators with Block Recommendation Rule - {{name}} "
alertDescriptionFormat: "{{Description}} - {{name}} "
alertDynamicProperties:
- alertProperty: ProductName
value: ProductName
- alertProperty: ProviderName
value: ProviderName
customDetails:
ThreatActors: ThreatActors
Sources: Sources
RecommendedActions: RecommendedActions
Roles: Roles
Country: Country
Description: Description
ConfidenceScore: ConfidenceScore
SecurityVendors: SecurityVendors
IndicatorID: IndicatorID
Created: created
Modified: modified
ValidFrom: valid_from
Tags: Tags
ThreatType: ThreatType
TimeGenerated: TimeGenerated
IPAbuse: IPAbuse
entityMappings:
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPv4
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPv6
- entityType: DNS
fieldMappings:
- identifier: DomainName
columnName: Domain
- entityType: URL
fieldMappings:
- identifier: Url
columnName: URL
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: false
reopenClosedIncident: false
lookbackDuration: PT5H
matchingMethod: AllEntities
eventGroupingSettings:
aggregationKind: AlertPerResult
Stages and Predicates
Parameters
let timeFrame = 5m;
Stage 1: source
CyfirmaIndicators_CL
Stage 2: where
| where ConfidenceScore >= 80
and TimeGenerated between (ago(timeFrame) .. now())
and pattern !contains 'file:hashes' and RecommendedActions has 'Block' and (Roles contains 'c2' or Roles contains 'Command & Control')
Stage 3: extend (6 consecutive steps)
| extend IPv4 = extract(@"ipv4-addr:value\s*=\s*'([^']+)'", 1, pattern)
| extend IPv6 = extract(@"ipv6-addr:value\s*=\s*'([^']+)'", 1, pattern)
| extend URL = extract(@"url:value\s*=\s*'([^']+)'", 1, pattern)
| extend Domain = extract(@"domain-name:value\s*=\s*'([^']+)'", 1, pattern)
| extend parsed = parse_json(extensions)
| extend extensionKeys = bag_keys(parsed)
Stage 4: mv-expand
| mv-expand extensionKeys
Stage 5: extend (4 consecutive steps)
| extend extensionKeyStr = tostring(extensionKeys)
| extend ext = parsed[extensionKeyStr]
| extend props = ext.properties
| extend
extension_id = extensionKeyStr,
ASN_Owner = props.asn_owner,
ASN = props.asn,
ProviderName = 'CYFIRMA',
ProductName = 'DeCYFIR/DeTCT'
Stage 6: project
| project
IPv4,
IPv6,
URL,
Domain,
ThreatActors,
RecommendedActions,
Sources,
Roles,
Country,
IPAbuse,
name,
Description,
ConfidenceScore,
IndicatorID,
created,
modified,
valid_from,
Tags,
ThreatType,
TimeGenerated,
SecurityVendors,
ProductName,
ProviderName
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
ConfidenceScore | ge |
| field:"ConfidenceScore" kind:ge value:"80" |
RecommendedActions | match |
| field:"RecommendedActions" kind:match value:"Block" |
Roles | contains |
| field:"Roles" kind:contains |
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
pattern | contains | file:hashes | excludes:pattern field:"pattern" value:"file:hashes" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
ConfidenceScore | project |
Country | project |
Description | project |
Domain | project |
IPAbuse | project |
IPv4 | project |
IPv6 | project |
IndicatorID | project |
ProductName | project |
ProviderName | project |
RecommendedActions | project |
Roles | project |
SecurityVendors | project |
Sources | project |
Tags | project |
ThreatActors | project |
ThreatType | project |
TimeGenerated | project |
URL | project |
created | project |
modified | project |
name | project |
valid_from | project |
Detect threat information in web requests (ASIM Web Session)
#'This rule would generate an alert if EvenSeverity is 'High' or 'ThreatRiskLevel' or 'ThreatOriginalConfidence' value is greater than 90.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access |
Rule Body
id: 7d2ed1c7-da26-45fd-b4ea-b6f2bbeccea7
name: Detect threat information in web requests (ASIM Web Session)
description: |
'This rule would generate an alert if EvenSeverity is 'High' or 'ThreatRiskLevel' or 'ThreatOriginalConfidence' value is greater than 90.
severity: High
status: Available
tags:
- Schema: WebSession
SchemaVersion: 0.2.6
requiredDataConnectors: []
queryFrequency: 5m
queryPeriod: 5m
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
relevantTechniques:
- T1190
- T1133
query: |
let lookback= 5m;
_Im_WebSession(starttime=ago(lookback))
| project
EventSeverity,
ThreatName,
ThreatCategory,
ThreatRiskLevel,
ThreatOriginalConfidence,
ThreatField,
TimeGenerated,
SrcIpAddr,
SrcUsername,
SrcHostname,
Url,
DstIpAddr
| where ThreatRiskLevel >= 90
or toint(ThreatOriginalConfidence) >= 90
or EventSeverity =~ "High"
| summarize
EventCount = count(),
EventStartTime=min(TimeGenerated),
EvenEndTime=max(TimeGenerated)
by
SrcIpAddr,
SrcUsername,
SrcHostname,
Url,
DstIpAddr,
ThreatName,
ThreatCategory,
ThreatRiskLevel,
ThreatOriginalConfidence,
ThreatField
| extend
Name = iif(SrcUsername contains "@", tostring(split(SrcUsername, '@', 0)[0]), SrcUsername),
UPNSuffix = iif(SrcUsername contains "@", tostring(split(SrcUsername, '@', 1)[0]), "")
entityMappings:
- entityType: Host
fieldMappings:
- identifier: HostName
columnName: SrcHostname
- entityType: IP
fieldMappings:
- identifier: Address
columnName: SrcIpAddr
- entityType: IP
fieldMappings:
- identifier: Address
columnName: DstIpAddr
- entityType: Account
fieldMappings:
- identifier: Name
columnName: Name
- identifier: UPNSuffix
columnName: UPNSuffix
- entityType: URL
fieldMappings:
- identifier: Url
columnName: Url
eventGroupingSettings:
aggregationKind: AlertPerResult
customDetails:
ThreatCategory: ThreatCategory
ThreatConfidence: ThreatOriginalConfidence
ThreatName: ThreatName
EventStartTime: EventStartTime
EvenEndTime: EvenEndTime
EventCount: EventCount
alertDetailsOverride:
alertDisplayNameFormat: "User '{{SrcUsername}}' with IP address '{{SrcIpAddr}}' has been identified as being associated with a threat named '{{ThreatName}}'"
version: 1.0.0
kind: Scheduled
Stages and Predicates
Parameters
let lookback = 5m;
Stage 1: source
_Im_WebSession(starttime=ago(lookback))
Stage 2: project
| project
EventSeverity,
ThreatName,
ThreatCategory,
ThreatRiskLevel,
ThreatOriginalConfidence,
ThreatField,
TimeGenerated,
SrcIpAddr,
SrcUsername,
SrcHostname,
Url,
DstIpAddr
Stage 3: where
| where ThreatRiskLevel >= 90
or toint(ThreatOriginalConfidence) >= 90
or EventSeverity =~ "High"
Stage 4: summarize
| summarize
EventCount = count(),
EventStartTime=min(TimeGenerated),
EvenEndTime=max(TimeGenerated)
by
SrcIpAddr,
SrcUsername,
SrcHostname,
Url,
DstIpAddr,
ThreatName,
ThreatCategory,
ThreatRiskLevel,
ThreatOriginalConfidence,
ThreatField
Stage 5: extend
| extend
Name = iif(SrcUsername contains "@", tostring(split(SrcUsername, '@', 0)[0]), SrcUsername),
UPNSuffix = iif(SrcUsername contains "@", tostring(split(SrcUsername, '@', 1)[0]), "")
Indicators
These rows show field, operator, and value matches.
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
DstIpAddr | summarize |
EvenEndTime | summarize |
EventCount | summarize |
EventStartTime | summarize |
SrcHostname | summarize |
SrcIpAddr | summarize |
SrcUsername | summarize |
ThreatCategory | summarize |
ThreatField | summarize |
ThreatName | summarize |
ThreatOriginalConfidence | summarize |
ThreatRiskLevel | summarize |
Url | summarize |
Name | extend |
UPNSuffix | extend |
Excessive number of HTTP authentication failures from a source (ASIM Web Session schema)
#This rule identifies a source that repeatedly fails to authenticate to a web service (HTTP response code 403). This may indicate a brute force or credential stuffing attack. This rule uses the Advanced Security Information Model (ASIM) and supports any web session source that complies with ASIM.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Persistence | |
| Credential Access |
Rule Body
id: a1bddaf8-982b-4089-ba9e-6590dfcf80ea
name: Excessive number of HTTP authentication failures from a source (ASIM Web Session schema)
description: |
This rule identifies a source that repeatedly fails to authenticate to a web service (HTTP response code 403). This may indicate a [brute force](https://en.wikipedia.org/wiki/Brute-force_attack) or [credential stuffing](https://en.wikipedia.org/wiki/Credential_stuffing) attack.
This rule uses the [Advanced Security Information Model (ASIM)](https://aka.ms/AboutASIM) and supports any web session source that complies with ASIM.
severity: Low
requiredDataConnectors:
- connectorId: SquidProxy
dataTypes:
- SquidProxy_CL
- connectorId: Zscaler
dataTypes:
- CommonSecurityLog
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- Persistence
- CredentialAccess
relevantTechniques:
- T1110
- T1556
tags:
- ParentAlert: https://github.com/Azure/Azure-Sentinel/blob/master/Detections/CommonSecurityLog/Wazuh-Large%20Number%20of%20Web%20errors%20from%20an%20IP.yaml
ParentVersion: 1.1.0
- Schema: ASIMWebSession
SchemaVersion: 0.2.1
query: |
let error403_count_threshold=200;
_Im_WebSession(eventresultdetails_in=dynamic(["403"]))
| extend ParsedUrl=parse_url(Url)
| extend UrlHost=tostring(ParsedUrl["Host"]), UrlSchema=tostring(ParsedUrl["Schema"])
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), NumberOfErrors = count(), Urls=makeset(Url) by UrlHost, SrcIpAddr
| where NumberOfErrors > error403_count_threshold
| sort by NumberOfErrors desc
| extend Url=tostring(Urls[0])
entityMappings:
- entityType: URL
fieldMappings:
- identifier: Url
columnName: Url
- entityType: IP
fieldMappings:
- identifier: Address
columnName: SrcIpAddr
customDetails:
NumberOfErrors: NumberOfErrors
alertDetailsOverride:
alertDisplayNameFormat: Excessive number of HTTP authentication failures from {{SrcIpAddr}
alertDescriptionFormat: A client with address {{SrcIpAddr}} generated a large number of failed authentication HTTP requests. This may indicate a [brute force](https://en.wikipedia.org/wiki/Brute-force_attack) or [credential stuffing](https://en.wikipedia.org/wiki/Credential_stuffing) attack.
version: 1.0.6
kind: Scheduled
metadata:
source:
kind: Community
author:
name: Yaron
support:
tier: Community
categories:
domains: [ "Security - Others" ]
Stages and Predicates
Parameters
let error403_count_threshold = 200;
Stage 1: source
_Im_WebSession(eventresultdetails_in=dynamic(["403"]))
Stage 2: extend
| extend ParsedUrl=parse_url(Url)
Stage 3: extend
| extend UrlHost=tostring(ParsedUrl["Host"]), UrlSchema=tostring(ParsedUrl["Schema"])
Stage 4: summarize
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), NumberOfErrors = count(), Urls=makeset(Url) by UrlHost, SrcIpAddr
Stage 5: where
| where NumberOfErrors > error403_count_threshold
Stage 6: sort
| sort by NumberOfErrors desc
Stage 7: extend
| extend Url=tostring(Urls[0])
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
NumberOfErrors | gt |
| field:"NumberOfErrors" kind:gt value:"200" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
EndTime | summarize |
NumberOfErrors | summarize |
SrcIpAddr | summarize |
StartTime | summarize |
UrlHost | summarize |
Urls | summarize |
Url | extend |
Malicious BEC Inbox Rule
#'Often times after the initial compromise in a BEC attack the attackers create inbox rules to delete emails that contain certain keywords related to their BEC attack. This is done so as to limit ability to warn compromised users that they've been compromised.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Persistence | |
| Stealth |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Microsoft 365 | Exchange audit operation New-InboxRule: Federated domain added |
Rules Detecting the Same Action
These rules filter on the same operation.
- High risk Office operation conducted by IP Address that recently attempted to log into a disabled account (Kusto)
- Inbox Rules Creation Or Update Activity in O365 (Sigma)
- M365 Exchange Inbox Phishing Evasion Rule Created (Elastic)
- Mail Forwarding/Redirecting Activity In O365 (Sigma)
- O365 New Email Forwarding Rule Created (Splunk)
- Rare and potentially high-risk Office operations (Kusto)
Rule Body
id: 8ac77493-3cae-4840-8634-15fb23f8fb68
name: Malicious BEC Inbox Rule
description: |
'Often times after the initial compromise in a BEC attack the attackers create inbox rules to delete emails that contain certain keywords related to their BEC attack.
This is done so as to limit ability to warn compromised users that they've been compromised.
severity: Medium
requiredDataConnectors:
- connectorId: Office365
dataTypes:
- OfficeActivity
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- Persistence
- DefenseEvasion
relevantTechniques:
- T1098
- T1078
tags:
- BEC
query: |
let BEC_Keywords = dynamic([ 'invoice','payment','paycheck','transfer','bank statement','bank details','closing','funds','bank account','account details','remittance','purchase','deposit',"PO#","Zahlung","Rechnung","Paiement", "virement bancaire","Bankuberweisung",'hacked','phishing']);
OfficeActivity
| where Operation =~ "New-InboxRule"
| where Parameters has "Deleted Items" or Parameters has "Junk Email" or Parameters has "DeleteMessage"
| extend Events=todynamic(Parameters)
| parse Events with * "SubjectContainsWords" SubjectContainsWords '}'*
| parse Events with * "BodyContainsWords" BodyContainsWords '}'*
| parse Events with * "SubjectOrBodyContainsWords" SubjectOrBodyContainsWords '}'*
| where SubjectContainsWords has_any (BEC_Keywords)
or BodyContainsWords has_any (BEC_Keywords)
or SubjectOrBodyContainsWords has_any (BEC_Keywords)
| extend ClientIPAddress = case( ClientIP has ".", tostring(split(ClientIP,":")[0]), ClientIP has "[", tostring(trim_start(@'[[]',tostring(split(ClientIP,"]")[0]))), ClientIP )
| extend Keyword = iff(isnotempty(SubjectContainsWords), SubjectContainsWords, (iff(isnotempty(BodyContainsWords),BodyContainsWords,SubjectOrBodyContainsWords )))
| extend RuleDetail = case(OfficeObjectId contains '/' , tostring(split(OfficeObjectId, '/')[-1]) , tostring(split(OfficeObjectId, '\\')[-1]))
| summarize count(), StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated) by Operation, UserId, ClientIPAddress, ResultStatus, Keyword, OriginatingServer, OfficeObjectId, RuleDetail
| extend UserName = split(UserId, '@')[0], DomainName = split(UserId, '@')[1]
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: UserId
- identifier: Name
columnName: UserName
- identifier: UPNSuffix
columnName: DomainName
- entityType: IP
fieldMappings:
- identifier: Address
columnName: ClientIPAddress
version: 1.0.2
kind: Scheduled
Stages and Predicates
Let Binding: BEC_Keywords
let BEC_Keywords = dynamic([ 'invoice','payment','paycheck','transfer','bank statement','bank details','closing','funds','bank account','account details','remittance','purchase','deposit',"PO#","Zahlung","Rechnung","Paiement", "virement bancaire","Bankuberweisung",'hacked','phishing']);
Stage 1: source
OfficeActivity
Stage 2: where
| where Operation =~ "New-InboxRule"
Stage 3: where
| where Parameters has "Deleted Items" or Parameters has "Junk Email" or Parameters has "DeleteMessage"
Stage 4: extend
| extend Events=todynamic(Parameters)
Stage 5: parse
| parse Events with * "SubjectContainsWords" SubjectContainsWords '}'*
Stage 6: parse
| parse Events with * "BodyContainsWords" BodyContainsWords '}'*
Stage 7: parse
| parse Events with * "SubjectOrBodyContainsWords" SubjectOrBodyContainsWords '}'*
Stage 8: where
| where SubjectContainsWords has_any (BEC_Keywords)
or BodyContainsWords has_any (BEC_Keywords)
or SubjectOrBodyContainsWords has_any (BEC_Keywords)
Stage 9: extend (3 consecutive steps)
| extend ClientIPAddress = case( ClientIP has ".", tostring(split(ClientIP,":")[0]), ClientIP has "[", tostring(trim_start(@'[[]',tostring(split(ClientIP,"]")[0]))), ClientIP )
| extend Keyword = iff(isnotempty(SubjectContainsWords), SubjectContainsWords, (iff(isnotempty(BodyContainsWords),BodyContainsWords,SubjectOrBodyContainsWords )))
| extend RuleDetail = case(OfficeObjectId contains '/' , tostring(split(OfficeObjectId, '/')[-1]) , tostring(split(OfficeObjectId, '\\')[-1]))
ClientIPAddress =ClientIP has "."tostring(split(ClientIP, ":")[0])ClientIP has "["tostring(trim_start(@'[[]', tostring(split(ClientIP, "]")[0])))ClientIPStage 10: summarize
| summarize count(), StartTimeUtc = min(TimeGenerated), EndTimeUtc = max(TimeGenerated) by Operation, UserId, ClientIPAddress, ResultStatus, Keyword, OriginatingServer, OfficeObjectId, RuleDetail
Stage 11: extend
| extend UserName = split(UserId, '@')[0], DomainName = split(UserId, '@')[1]
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
BodyContainsWords | match |
| field:"BodyContainsWords" kind:match |
Operation | eq |
| field:"Operation" kind:eq value:"New-InboxRule" |
Parameters | match |
| field:"m365::Parameters" kind:match |
SubjectContainsWords | match |
| field:"SubjectContainsWords" kind:match |
SubjectOrBodyContainsWords | match |
| field:"SubjectOrBodyContainsWords" kind:match |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
ClientIPAddress | summarize |
EndTimeUtc | summarize |
Keyword | summarize |
OfficeObjectId | summarize |
Operation | summarize |
OriginatingServer | summarize |
ResultStatus | summarize |
RuleDetail | summarize |
StartTimeUtc | summarize |
UserId | summarize |
DomainName | extend |
UserName | extend |
NRT Authentication Methods Changed for VIP Users
#Identifies authentication methods being changed for a list of VIP users watchlist. This could be an indication of an attacker adding an auth method to the account so they can have continued access.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Persistence |
Telemetry Coverage
Rules Detecting the Same Action
These rules filter on the same operation.
- [Entra ID] Authentication Method Changed for Privileged Account (Kusto)
- Account Created and Deleted in Short Timeframe (Kusto)
- Account Created And Deleted Within A Close Time Frame (Sigma)
- Account created from non-approved sources (Kusto)
- Account created or deleted by non-approved user (Kusto)
- Addition of a Temporary Access Pass to a Privileged Account (Kusto)
- Authentication Method Changed for Privileged Account (Kusto)
- Authentication Methods Changed for Privileged Account (Kusto)
Rule Body
id: 29e99017-e28d-47be-8b9a-c8c711f8a903
name: NRT Authentication Methods Changed for VIP Users
description: |
'Identifies authentication methods being changed for a list of VIP users watchlist. This could be an indication of an attacker adding an auth method to the account so they can have continued access.'
severity: Medium
requiredDataConnectors:
- connectorId: AzureActiveDirectory
dataTypes:
- AuditLogs
tactics:
- Persistence
relevantTechniques:
- T1098
tags:
- AADSecOpsGuide
query: |
let security_info_actions = dynamic(["User registered security info", "User changed default security info", "User deleted security info", "Admin updated security info", "User reviewed security info", "Admin deleted security info", "Admin registered security info"]);
let VIPUsers = _GetWatchlist('VIPUsers')
| extend ["User Principal Name"] = column_ifexists("User Principal Name","")
| distinct ["User Principal Name"];
AuditLogs
| where Category =~ "UserManagement"
| where ActivityDisplayName in (security_info_actions)
| extend InitiatingAppName = tostring(InitiatedBy.app.displayName)
| extend InitiatingAppServicePrincipalId = tostring(InitiatedBy.app.servicePrincipalId)
| extend InitiatingUserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)
| extend InitiatingAadUserId = tostring(InitiatedBy.user.id)
| extend InitiatingIpAddress = tostring(iff(isnotempty(InitiatedBy.user.ipAddress), InitiatedBy.user.ipAddress, InitiatedBy.app.ipAddress))
| mv-apply TargetResource = TargetResources on
(
where TargetResource.type =~ "User"
| extend Target = trim(@'"',tolower(tostring(TargetResource.userPrincipalName)))
)
| where Target in~ (VIPUsers)
| summarize Start=min(TimeGenerated), End=max(TimeGenerated), Actions = make_set(ResultReason) by InitiatingUserPrincipalName, InitiatingAadUserId, InitiatingAppName, InitiatingAppServicePrincipalId, InitiatingIpAddress, Result, Target
| extend TargetName = tostring(split(Target,'@',0)[0]), TargetUPNSuffix = tostring(split(Target,'@',1)[0])
| extend InitiatedByName = tostring(split(InitiatingUserPrincipalName,'@',0)[0]), InitiatedByUPNSuffix = tostring(split(InitiatingUserPrincipalName,'@',1)[0])
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: Target
- identifier: Name
columnName: TargetName
- identifier: UPNSuffix
columnName: TargetUPNSuffix
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: InitiatingUserPrincipalName
- identifier: Name
columnName: InitiatedByName
- identifier: UPNSuffix
columnName: InitiatedByUPNSuffix
- entityType: Account
fieldMappings:
- identifier: AadUserId
columnName: InitiatingAadUserId
- entityType: Account
fieldMappings:
- identifier: AadUserId
columnName: InitiatingAppServicePrincipalId
- entityType: IP
fieldMappings:
- identifier: Address
columnName: InitiatingIpAddress
version: 1.0.6
kind: NRT
Stages and Predicates
Let Binding: security_info_actions
let security_info_actions = dynamic(["User registered security info", "User changed default security info", "User deleted security info", "Admin updated security info", "User reviewed security info", "Admin deleted security info", "Admin registered security info"]);
Let Binding: VIPUsers
let VIPUsers = _GetWatchlist('VIPUsers')
| extend ["User Principal Name"] = column_ifexists("User Principal Name","")
| distinct ["User Principal Name"];
Stage 1: source
AuditLogs
Stage 2: where
| where Category =~ "UserManagement"
Stage 3: where
| where ActivityDisplayName in (security_info_actions)
Stage 4: extend (5 consecutive steps)
| extend InitiatingAppName = tostring(InitiatedBy.app.displayName)
| extend InitiatingAppServicePrincipalId = tostring(InitiatedBy.app.servicePrincipalId)
| extend InitiatingUserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)
| extend InitiatingAadUserId = tostring(InitiatedBy.user.id)
| extend InitiatingIpAddress = tostring(iff(isnotempty(InitiatedBy.user.ipAddress), InitiatedBy.user.ipAddress, InitiatedBy.app.ipAddress))
Stage 5: kusto:mv-apply
| mv-apply TargetResource = TargetResources on
(
where TargetResource.type =~ "User"
| extend Target = trim(@'"',tolower(tostring(TargetResource.userPrincipalName)))
)
Stage 6: where
| where Target in~ (VIPUsers)
Stage 7: summarize
| summarize Start=min(TimeGenerated), End=max(TimeGenerated), Actions = make_set(ResultReason) by InitiatingUserPrincipalName, InitiatingAadUserId, InitiatingAppName, InitiatingAppServicePrincipalId, InitiatingIpAddress, Result, Target
Stage 8: extend
| extend TargetName = tostring(split(Target,'@',0)[0]), TargetUPNSuffix = tostring(split(Target,'@',1)[0])
Stage 9: extend
| extend InitiatedByName = tostring(split(InitiatingUserPrincipalName,'@',0)[0]), InitiatedByUPNSuffix = tostring(split(InitiatingUserPrincipalName,'@',1)[0])
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
ActivityDisplayName | in |
| field:"azure_ad::activity_display_name" kind:in |
Category | eq |
| field:"Category" kind:eq value:"UserManagement" |
Target | in |
| field:"Target" kind:in value:"VIPUsers" |
TargetResource.type | eq |
| field:"TargetResource.type" kind:eq value:"User" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
Actions | summarize |
End | summarize |
InitiatingAadUserId | summarize |
InitiatingAppName | summarize |
InitiatingAppServicePrincipalId | summarize |
InitiatingIpAddress | summarize |
InitiatingUserPrincipalName | summarize |
Result | summarize |
Start | summarize |
Target | summarize |
TargetName | extend |
TargetUPNSuffix | extend |
InitiatedByName | extend |
InitiatedByUPNSuffix | extend |
Okta Fast Pass phishing Detection
#This query detects cases in which Okta FastPass effectively prevented access to a known phishing website.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access |
Telemetry Coverage
| Platform | Record / event type |
|---|---|
| Okta | System Log event type user.authentication.auth_via_mfa: User authenticated via MFA |
Rules Detecting the Same Action
These rules filter on the same operation.
- First Occurrence of Okta User Session Started via Proxy (Elastic)
- MFA Fatigue (OKTA) (Kusto)
- Okta AiTM Phishing Attempt Blocked by FastPass (Panther)
- Okta Authentication Failed During MFA Challenge (Splunk)
- Okta FastPass Phishing Detection (Sigma)
- Okta FastPass Phishing Detection (Elastic)
- Okta MFA Bruteforce Attack (YARA-L)
- Okta Mismatch Between Source And Response For Verify Push Request (YARA-L)
Rule Body
id: 78d2b06c-8dc0-40e1-91c8-66d916c186f3
name: Okta Fast Pass phishing Detection
description: |
This query detects cases in which Okta FastPass effectively prevented access to a known phishing website.
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: OktaSSO
dataTypes:
- Okta_CL
- connectorId: OktaSSOv2
dataTypes:
- OktaSSO
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
relevantTechniques:
- T1566.002
tags:
- Okta
query: |
// Add any known good IPs to this list to reduce noise
let AllowedIPList = dynamic([]);
OktaSSO
| where isnotempty(client_ipAddress_s) and client_ipAddress_s !in (AllowedIPList)
| where eventType_s == 'user.authentication.auth_via_mfa'
| where outcome_result_s == 'FAILURE'
| where outcome_reason_s == 'FastPass declined phishing attempt'
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by actor_alternateId_s, actor_displayName_s, client_userAgent_os_s, client_ipAddress_s, client_geographicalContext_state_s,displayMessage_s, outcome_result_s,
outcome_reason_s, column_ifexists('debugContext_debugData_logOnlySecurityData_s', ""), column_ifexists('debugContext_debugData_threatSuspected_s', ""), client_userAgent_rawUserAgent_s,client_userAgent_browser_s, severity_s, client_geographicalContext_city_s, client_geographicalContext_country_s
| extend Location = strcat(client_geographicalContext_city_s, "-", client_geographicalContext_country_s), AccountName = tostring(split(actor_alternateId_s, "@")[0]), AccountUPNSuffix = tostring(split(actor_alternateId_s, "@")[1])
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: AccountName
- identifier: UPNSuffix
columnName: AccountUPNSuffix
- entityType: IP
fieldMappings:
- identifier: Address
columnName: client_ipAddress_s
customDetails:
UserAgent: client_userAgent_rawUserAgent_s
UserAgentOS: client_userAgent_os_s
UserAgentBrowser: client_userAgent_browser_s
Location: Location
alertDetailsOverride:
alertDisplayNameFormat: 'Okta FastPass phishing attempt declined for {{actor_alternateId_s}}'
alertDescriptionFormat: 'Okta FastPass declined a phishing attempt for {{actor_alternateId_s}} from {{client_ipAddress_s}} using {{client_userAgent_browser_s}}.'
version: 1.1.2
kind: Scheduled
Stages and Predicates
Parameters
let AllowedIPList = dynamic([]);
Stage 1: source
OktaSSO
Stage 2: where
| where isnotempty(client_ipAddress_s) and client_ipAddress_s !in (AllowedIPList)
Stage 3: where
| where eventType_s == 'user.authentication.auth_via_mfa'
Stage 4: where
| where outcome_result_s == 'FAILURE'
Stage 5: where
| where outcome_reason_s == 'FastPass declined phishing attempt'
Stage 6: summarize
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by actor_alternateId_s, actor_displayName_s, client_userAgent_os_s, client_ipAddress_s, client_geographicalContext_state_s,displayMessage_s, outcome_result_s,
outcome_reason_s, column_ifexists('debugContext_debugData_logOnlySecurityData_s', ""), column_ifexists('debugContext_debugData_threatSuspected_s', ""), client_userAgent_rawUserAgent_s,client_userAgent_browser_s, severity_s, client_geographicalContext_city_s, client_geographicalContext_country_s
Stage 7: extend
| extend Location = strcat(client_geographicalContext_city_s, "-", client_geographicalContext_country_s), AccountName = tostring(split(actor_alternateId_s, "@")[0]), AccountUPNSuffix = tostring(split(actor_alternateId_s, "@")[1])
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
client_ipAddress_s | is_not_null | field:"okta::client.ipAddress" kind:is_not_null | |
eventType_s | eq |
| field:"okta::eventType" kind:eq value:"user.authentication.auth_via_mfa" |
outcome_reason_s | eq |
| field:"okta::outcome.reason" kind:eq value:"FastPass declined phishing attempt" |
outcome_result_s | eq |
| field:"okta::outcome.result" kind:eq value:"FAILURE" |
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
client_ipAddress_s | eq | [] | excludes:client_ipAddress_s field:"client_ipAddress_s" value:"[]" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
EndTime | summarize |
StartTime | summarize |
actor_alternateId_s | summarize |
actor_displayName_s | summarize |
client_geographicalContext_city_s | summarize |
client_geographicalContext_country_s | summarize |
client_geographicalContext_state_s | summarize |
client_ipAddress_s | summarize |
client_userAgent_browser_s | summarize |
client_userAgent_os_s | summarize |
client_userAgent_rawUserAgent_s | summarize |
displayMessage_s | summarize |
outcome_reason_s | summarize |
outcome_result_s | summarize |
severity_s | summarize |
AccountName | extend |
AccountUPNSuffix | extend |
Location | extend |
Spearphishing Attachment: ISO Images (Microsoft Sentinel)
#ISO images are often meant to be used offline and they are often used by IT Admins and/or used on Servers.
Installation from an iso file don't require network connection most of the time. Activities deviating from these situations can be considered as highly suspicious. Below queries detects opening a mounted image, process creation under a mounted image, and network connection from a process created under a mounted image.
All detections can be used seperately or combined together to generate a higher fidelity alert. WARNING: Check your Sysmon parsing functions and verify you have the logs. Using "Rendered Description" field for parsing causes parsing issues for registry events. Detect opening of a mounted image:
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access | No specific technique |
Telemetry Coverage
Rule Body
// Author: Cyb3rMonk(https://twitter.com/Cyb3rMonk, https://mergene.medium.com)
// Link to original post:
// Part-1: https://mergene.medium.com/detecting-initial-access-html-smuggling-and-iso-images-part-1-c4f953edd13f?source=friends_link&sk=e685d7d44928edd142972a4041463f10
// Part-2: https://mergene.medium.com/detecting-initial-access-html-smuggling-and-iso-images-part-2-f8dd600430e2?source=friends_link&sk=38b7cd310a4929c25d3eefc545683d5f
//
//
let parse_sysmon_events = (T:(TimeGenerated:datetime,EventID:int, Source:string, EventData:string))
{
T
| where Source == "Microsoft-Windows-Sysmon"
| extend EventData = parse_xml(EventData).DataItem.EventData.Data
| mv-expand bagexpansion=array EventData
| evaluate bag_unpack(EventData)
| extend Key=tostring(['@Name']), Value=['#text']
| evaluate pivot(Key, any(Value), TimeGenerated, Source, EventLog, Computer, EventLevel, EventLevelName, EventID, UserName, RenderedDescription, MG, ManagementGroupName, Type, _ResourceId)
};
// Query Parameters
let lookback = 2h;
Event
| where TimeGenerated > ago(lookback)
| where EventID == 11
| invoke parse_sysmon_events()
| where tostring(TargetFilename) endswith ".iso.lnk" or tostring(TargetFilename) endswith ".img.lnk"
// Exclude servers and workstation used by IT admins if needed.
// Author: Cyb3rMonk(https://twitter.com/Cyb3rMonk, https://mergene.medium.com)
// Link to original post:
// Part-1: https://mergene.medium.com/detecting-initial-access-html-smuggling-and-iso-images-part-1-c4f953edd13f?source=friends_link&sk=e685d7d44928edd142972a4041463f10
// Part-2: https://mergene.medium.com/detecting-initial-access-html-smuggling-and-iso-images-part-2-f8dd600430e2?source=friends_link&sk=38b7cd310a4929c25d3eefc545683d5f
//
//
let parse_sysmon_events = (T:(TimeGenerated:datetime,EventID:int, Source:string, EventData:string))
{
T
| where Source == "Microsoft-Windows-Sysmon"
| extend EventData = parse_xml(EventData).DataItem.EventData.Data
| mv-expand bagexpansion=array EventData
| evaluate bag_unpack(EventData)
| extend Key=tostring(['@Name']), Value=['#text']
| evaluate pivot(Key, any(Value), TimeGenerated, Source, EventLog, Computer, EventLevel, EventLevelName, EventID, UserName, RenderedDescription, MG, ManagementGroupName, Type, _ResourceId)
};
// Query Parameters
let lookback = 2h;
Event
| where TimeGenerated > ago(lookback)
| where EventID == 13
| invoke parse_sysmon_events()
| where TargetObject startswith @"HKLM\SYSTEM\MountedDevices\\DosDevices"
| extend Folder = replace(@'.*\\([A-Z]:)',@'\1\\',tostring(TargetObject))
| join kind = inner
(
Event
| where TimeGenerated > ago(lookback)
| where EventID == 1
| invoke parse_sysmon_events()
| extend Folder = tostring(CurrentDirectory)
) on Computer, Folder
// If needed, exclude servers from the results.
// Author: Cyb3rMonk(https://twitter.com/Cyb3rMonk, https://mergene.medium.com)
// Link to original post:
// Part-1: https://mergene.medium.com/detecting-initial-access-html-smuggling-and-iso-images-part-1-c4f953edd13f?source=friends_link&sk=e685d7d44928edd142972a4041463f10
// Part-2: https://mergene.medium.com/detecting-initial-access-html-smuggling-and-iso-images-part-2-f8dd600430e2?source=friends_link&sk=38b7cd310a4929c25d3eefc545683d5f
//
//
let parse_sysmon_events = (T:(TimeGenerated:datetime,EventID:int, Source:string, EventData:string))
{
T
| where Source == "Microsoft-Windows-Sysmon"
| extend EventData = parse_xml(EventData).DataItem.EventData.Data
| mv-expand bagexpansion=array EventData
| evaluate bag_unpack(EventData)
| extend Key=tostring(['@Name']), Value=['#text']
| evaluate pivot(Key, any(Value), TimeGenerated, Source, EventLog, Computer, EventLevel, EventLevelName, EventID, UserName, RenderedDescription, MG, ManagementGroupName, Type, _ResourceId)
};
// Query Parameters
let lookback = 30h;
Event
| where TimeGenerated > ago(lookback)
| where EventID == 13
| invoke parse_sysmon_events()
| where TargetObject startswith @"HKLM\SYSTEM\MountedDevices\\DosDevices"
| extend Folder = replace(@'.*\\([A-Z]:)',@'\1\\',tostring(TargetObject))
| join kind = inner
(
Event
| where TimeGenerated > ago(lookback)
| where EventID == 3
| invoke parse_sysmon_events()
| extend Folder = replace(@'^([A-Z]:\\).*',@'\1',tostring(Image))
) on Computer, Folder
// If needed, exclude the legitimate activity and servers
Stages and Predicates
Parameters
let lookback = 2h;
Let Binding: parse_sysmon_events
let parse_sysmon_events = (T:(TimeGenerated:datetime,EventID:int, Source:string, EventData:string))
{
T
| where Source == "Microsoft-Windows-Sysmon"
| extend EventData = parse_xml(EventData).DataItem.EventData.Data
| mv-expand bagexpansion=array EventData
| evaluate bag_unpack(EventData)
| extend Key=tostring(['@Name']), Value=['#text']
| evaluate pivot(Key, any(Value), TimeGenerated, Source, EventLog, Computer, EventLevel, EventLevelName, EventID, UserName, RenderedDescription, MG, ManagementGroupName, Type, _ResourceId)
};
Stage 1: source
Event
Stage 2: where
where TimeGenerated > ago(7200s)
Stage 3: where
where EventID == 11
Stage 4: where
where Source == "Microsoft-Windows-Sysmon"
Stage 5: extend
extend EventData
Stage 6: mv-expand
mv-expand EventData
Stage 7: evaluate
evaluate
Stage 8: extend
extend Key, Value
Stage 9: evaluate
evaluate
Stage 10: where
where (TargetFilename endswith ".img.lnk" or TargetFilename endswith ".iso.lnk")
Stage 11: source
Event
Stage 12: where
where TimeGenerated > ago(7200s)
Stage 13: where
where EventID == 13
Stage 14: where
where Source == "Microsoft-Windows-Sysmon"
Stage 15: extend
extend EventData
Stage 16: mv-expand
mv-expand EventData
Stage 17: evaluate
evaluate
Stage 18: extend
extend Key, Value
Stage 19: evaluate
evaluate
Stage 20: where
where TargetObject startswith @"HKLM\SYSTEM\MountedDevices\\DosDevices"
Stage 21: extend
extend Folder
Stage 22: join
join kind=inner (Event) on Computer, Folder
Stage 23: source
Event
Stage 24: where
where TimeGenerated > ago(108000s)
Stage 25: where
where EventID == 13
Stage 26: where
where Source == "Microsoft-Windows-Sysmon"
Stage 27: extend
extend EventData
Stage 28: mv-expand
mv-expand EventData
Stage 29: evaluate
evaluate
Stage 30: extend
extend Key, Value
Stage 31: evaluate
evaluate
Stage 32: where
where TargetObject startswith @"HKLM\SYSTEM\MountedDevices\\DosDevices"
Stage 33: extend
extend Folder
Stage 34: join
join kind=inner (Event) on Computer, Folder
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
EventID | eq |
| field:"EventID" kind:eq |
Source | eq |
| field:"Source" kind:eq value:"Microsoft-Windows-Sysmon" |
TargetFilename | ends_with |
| field:"TargetFilename" kind:ends_with |
TargetObject | starts_with |
| field:"TargetObject" kind:starts_with value:"HKLM\SYSTEM\MountedDevices\\DosDevices" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
EventData | extend |
Key | extend |
Value | extend |
Suspicious named pipes
#This query looks for Named Pipe events that either contain one of the known IOCs or make use of patterns that can be linked to CobaltStrike usage.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Execution | |
| Stealth |
Telemetry Coverage
Rule Body
id: ddf7c669-db26-4215-acaf-11e2953a04e6
name: Suspicious named pipes
description: |
This query looks for Named Pipe events that either contain one of the known IOCs or make use of patterns that can be linked to CobaltStrike usage.
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: MicrosoftThreatProtection
dataTypes:
- DeviceEvents
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- Execution
- DefenseEvasion
relevantTechniques:
- T1559
- T1055
query: |
let timeframe=1h;
let CobaltStrikeDefaults= dynamic([@"msagent_", @"MSSE-", @"postex_", @"status_", @"mypipe-f", @"mypipe-h",@"ntsvcs_",@"scerpc_", @"mojo.5688.8052."]);
let CobaltStrikeMallable= dynamic([@"win_svc", @"ntsvcs", @"scerpc", @"status_", @"SearchTextHarvester", @"DserNamePipe",@"wkssvc_",@"scerpc_", @"spoolss_",@"CatalogChangeListener",@"fullduplex_",@"demoagent_",@"PGMessagePipe",@"MsFteWds",@"postex_ssh_",@"windows.update.manager",@"\f4c3",@"\f53f",@"halfduplex_"]);
DeviceEvents
| where Timestamp >= ago(timeframe)
| where ActionType == "NamedPipeEvent"
| extend AdditionalFields=parse_json(AdditionalFields)
| extend ThreadId=tostring(AdditionalFields.ThreadId)
| extend PipeName=tostring(AdditionalFields.PipeName)
// creating string based variants of the processIDs for matching several times later
| extend InitiatingPID=tostring(InitiatingProcessId)
| extend InitiatingParentPID=tostring(InitiatingProcessParentId)
// Begin allow-list.
// End allow-list.
| where PipeName has_any (CobaltStrikeDefaults) or
// Mojo is generated by Chrome(ium) browsers and teams and have distinct pattern including the (parent)ProcessId and ThreadId plus a random character string, CobaltStrike generates hex.
(PipeName matches regex @"\\mojo\.\d+\.\d+\." and not(PipeName matches regex @"\\mojo\.\d+\.\d+\.\d+$" or PipeName has InitiatingPID or PipeName has InitiatingParentPID or PipeName has ThreadId)) or
// Chrome(ium) browsers sync processes have distinct pattern including the (parent)ProcessId and ThreadId plus a random character string, CobaltStrike generates hex.
(PipeName matches regex @"\\(edge|chrome)\.sync\.\d+\.\d+\." and not(PipeName matches regex @"\\(edge|chrome|edge\.sync|chrome\.sync)\.\d+\.\d+\.\d+$" or PipeName has InitiatingPID or PipeName has InitiatingParentPID or PipeName has ThreadId)) or
// PSHost is generated by PowerShell and has a distinct pattern including the (parent)ProcessId.
(PipeName matches regex @"\\PSHost\.\d+\." and not(PipeName matches regex @"\\PSHost\.\d+\.\d+\." or PipeName has InitiatingPID or PipeName has InitiatingParentPID)) or
// Crashpad pipes have a distinct pattern including the ProcessId and a string of upper case characters.
(PipeName matches regex @"\\crashpad_" and not(PipeName matches regex @"\\crashpad_\d+_[A-Z]+" or PipeName has InitiatingPID or PipeName has InitiatingParentPID)) or
// Firefox pipes have a distinct pattern including the ProcessId and 1-3 digits which are sequential for each new pipe.
(PipeName matches regex @"\\cubeb-pipe-" and not(PipeName matches regex @"\\cubeb-pipe-\d+_[0-9]{1-3}+" or PipeName has InitiatingPID)) or
// Based on a list of public mallable profiles and a suffix that is a random HEX string.
(PipeName has_any (CobaltStrikeMallable) and PipeName matches regex @"[a-fA-F0-9]{2,10}$") or
(PipeName matches regex @"\\pipe\\[0-9a-f]{7,10}" or PipeName matches regex @"\\pipe\\[0-9a-f]{8}")
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Sid
columnName: AccountSid
- identifier: Name
columnName: AccountName
- identifier: NTDomain
columnName: AccountDomain
- entityType: Host
fieldMappings:
- identifier: FullName
columnName: DeviceName
- entityType: Process
fieldMappings:
- identifier: CommandLine
columnName: ProcessCommandLine
version: 1.0.0
kind: Scheduled
Stages and Predicates
Parameters
let timeframe = 1h;
let CobaltStrikeDefaults = dynamic([@"msagent_", @"MSSE-", @"postex_", @"status_", @"mypipe-f", @"mypipe-h",@"ntsvcs_",@"scerpc_", @"mojo.5688.8052."]);
Let Binding: CobaltStrikeMallable
let CobaltStrikeMallable = dynamic([@"win_svc", @"ntsvcs", @"scerpc", @"status_", @"SearchTextHarvester", @"DserNamePipe",@"wkssvc_",@"scerpc_", @"spoolss_",@"CatalogChangeListener",@"fullduplex_",@"demoagent_",@"PGMessagePipe",@"MsFteWds",@"postex_ssh_",@"windows.update.manager",@"\f4c3",@"\f53f",@"halfduplex_"]);
Stage 1: source
DeviceEvents
Stage 2: where
| where Timestamp >= ago(timeframe)
Stage 3: where
| where ActionType == "NamedPipeEvent"
Stage 4: extend (5 consecutive steps)
| extend AdditionalFields=parse_json(AdditionalFields)
| extend ThreadId=tostring(AdditionalFields.ThreadId)
| extend PipeName=tostring(AdditionalFields.PipeName)
| extend InitiatingPID=tostring(InitiatingProcessId)
| extend InitiatingParentPID=tostring(InitiatingProcessParentId)
Stage 5: where
| where PipeName has_any (CobaltStrikeDefaults) or
(PipeName matches regex @"\\mojo\.\d+\.\d+\." and not(PipeName matches regex @"\\mojo\.\d+\.\d+\.\d+$" or PipeName has InitiatingPID or PipeName has InitiatingParentPID or PipeName has ThreadId)) or
(PipeName matches regex @"\\(edge|chrome)\.sync\.\d+\.\d+\." and not(PipeName matches regex @"\\(edge|chrome|edge\.sync|chrome\.sync)\.\d+\.\d+\.\d+$" or PipeName has InitiatingPID or PipeName has InitiatingParentPID or PipeName has ThreadId)) or
(PipeName matches regex @"\\PSHost\.\d+\." and not(PipeName matches regex @"\\PSHost\.\d+\.\d+\." or PipeName has InitiatingPID or PipeName has InitiatingParentPID)) or
(PipeName matches regex @"\\crashpad_" and not(PipeName matches regex @"\\crashpad_\d+_[A-Z]+" or PipeName has InitiatingPID or PipeName has InitiatingParentPID)) or
(PipeName matches regex @"\\cubeb-pipe-" and not(PipeName matches regex @"\\cubeb-pipe-\d+_[0-9]{1-3}+" or PipeName has InitiatingPID)) or
(PipeName has_any (CobaltStrikeMallable) and PipeName matches regex @"[a-fA-F0-9]{2,10}$") or
(PipeName matches regex @"\\pipe\\[0-9a-f]{7,10}" or PipeName matches regex @"\\pipe\\[0-9a-f]{8}")
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
ActionType | eq |
| field:"ActionType" kind:eq value:"NamedPipeEvent" |
PipeName | match |
| field:"PipeName" kind:match |
PipeName | regex_match |
| field:"PipeName" kind:regex_match |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
AdditionalFields | extend |
ThreadId | extend |
PipeName | extend |
InitiatingPID | extend |
InitiatingParentPID | extend |
Suspicious Sign In by Entra ID Connect Sync Account
#'This query looks for sign ins by the Microsoft Entra ID Connect Sync account to Azure where properties about the logon are anomalous. This query uses Microsoft Sentinel's UEBA features to detect these suspicious properties. A threat actor may attempt to steal the Sync account credentials and use them to access Azure resources. This alert should be reviewed to ensure that the log in came was from a legitimate source.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access |
Rule Body
id: 2cd8b3d5-c9e0-4be3-80f7-0469d511c3f6
name: Suspicious Sign In by Entra ID Connect Sync Account
description: |
'This query looks for sign ins by the Microsoft Entra ID Connect Sync account to Azure where properties about the logon are anomalous.
This query uses Microsoft Sentinel's UEBA features to detect these suspicious properties.
A threat actor may attempt to steal the Sync account credentials and use them to access Azure resources. This alert should be
reviewed to ensure that the log in came was from a legitimate source.'
severity: Medium
requiredDataConnectors:
- connectorId: BehaviorAnalytics
dataTypes:
- BehaviorAnalytics
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
status: Available
tactics:
- InitialAccess
relevantTechniques:
- T1078.004
query: |
BehaviorAnalytics
// User modification is expected from this account so focus on logons
| where ActivityType =~ "LogOn"
| where UserName startswith "Sync_" and UsersInsights.AccountDisplayName =~ "On-Premises Directory Synchronization Service Account"
// Filter out this expected activity
| where ActivityInsights.App !~ "Microsoft Azure Active Directory Connect"
| where InvestigationPriority > 0
| extend Name = split(UserPrincipalName, "@")[0], UPNSuffix = split(UserPrincipalName, "@")[1]
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: UserPrincipalName
- identifier: Name
columnName: Name
- identifier: UPNSuffix
columnName: UPNSuffix
- entityType: IP
fieldMappings:
- identifier: Address
columnName: SourceIPAddress
- entityType: Host
fieldMappings:
- identifier: HostName
columnName: DestinationDevice
alertDetailsOverride:
alertDisplayNameFormat: Suspicious Sign In by AAD Connect Sync Account {{UserPrincipalName}} from {{SourceIPAddress}}
alertDescriptionFormat: |
This query looks for sign ins by the Azure AD Connect Sync account to Azure where properties about the logon are anomalous.
This query uses Microsoft Sentinel's UEBA features to detect these suspicious properties.
A threat actor may attempt to steal the Sync account credentials and use them to access Azure resources. This alert should be
reviewed to ensure that the log in came was from a legitimate source.
In this case {{UserPrincipalName}} logged in from {{SourceIPAddress}}.
version: 1.0.3
kind: Scheduled
metadata:
source:
kind: Community
author:
name: Microsoft Security Community
support:
tier: Community
categories:
domains: [ "Identity", "Security - Threat Protection" ]
Stages and Predicates
Stage 1: source
BehaviorAnalytics
Stage 2: where
| where ActivityType =~ "LogOn"
Stage 3: where
| where UserName startswith "Sync_" and UsersInsights.AccountDisplayName =~ "On-Premises Directory Synchronization Service Account"
Stage 4: where
| where ActivityInsights.App !~ "Microsoft Azure Active Directory Connect"
Stage 5: where
| where InvestigationPriority > 0
Stage 6: extend
| extend Name = split(UserPrincipalName, "@")[0], UPNSuffix = split(UserPrincipalName, "@")[1]
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
ActivityInsights.App | ne |
| field:"ActivityInsights.App" kind:ne value:"Microsoft Azure Active Directory Connect" |
ActivityType | eq |
| field:"ActivityType" kind:eq value:"LogOn" |
InvestigationPriority | gt |
| field:"InvestigationPriority" kind:gt value:"0" |
UserName | starts_with |
| field:"user" kind:starts_with value:"Sync_" |
UsersInsights.AccountDisplayName | eq |
| field:"UsersInsights.AccountDisplayName" kind:eq value:"On-Premises Directory Synchronization Service Account" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
Name | extend |
UPNSuffix | extend |
Tailscale Premium: Large outbound transfer over tailnet
#Identifies when a single src-dst pair transfers more than 100 MB over the tailnet within a 1-hour window. Large bursts can indicate data staging, exfiltration, or a misconfigured backup. Requires Tailscale Premium or Enterprise.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Exfiltration |
Rule Body
id: d2e3f4a5-2b3c-4d5e-6f7a-8b9c0d1e2f3a
name: "Tailscale Premium: Large outbound transfer over tailnet"
description: |
Identifies when a single src-dst pair transfers more than 100 MB over the tailnet within a 1-hour window. Large bursts can indicate data staging, exfiltration, or a misconfigured backup. Requires Tailscale Premium or Enterprise.
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: TailscalePremiumCCF
dataTypes:
- Tailscale_Network_CL
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- Exfiltration
- Collection
relevantTechniques:
- T1041
- T1020
query: |
let bytesThreshold = 100 * 1024 * 1024;
Tailscale_Network_CL
| where TimeGenerated > ago(1h)
| where HasVirtualTraffic
| mv-expand t = VirtualTraffic
| extend Src = tostring(t.src), Dst = tostring(t.dst), Proto = toint(t.proto), Bytes = tolong(t.txBytes) + tolong(t.rxBytes), Pkts = tolong(t.txPkts) + tolong(t.rxPkts)
| summarize TotalBytes = sum(Bytes), TotalPackets = sum(Pkts) by NodeId, SrcNodeName, SrcUser, DstNodeName, DstUser, Src, Dst, Proto
| where TotalBytes > bytesThreshold
| extend TotalMB = round(TotalBytes / 1024.0 / 1024.0, 2)
| order by TotalBytes desc
entityMappings:
- entityType: Host
fieldMappings:
- identifier: HostName
columnName: SrcNodeName
- entityType: Host
fieldMappings:
- identifier: HostName
columnName: DstNodeName
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: SrcUser
- entityType: IP
fieldMappings:
- identifier: Address
columnName: Src
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: true
reopenClosedIncident: false
lookbackDuration: PT5H
matchingMethod: AllEntities
kind: Scheduled
version: 1.0.0
Stages and Predicates
Parameters
let bytesThreshold = 100 * 1024 * 1024;
Stage 1: source
Tailscale_Network_CL
Stage 2: where
| where TimeGenerated > ago(1h)
Stage 3: where
| where HasVirtualTraffic
Stage 4: mv-expand
| mv-expand t = VirtualTraffic
Stage 5: extend
| extend Src = tostring(t.src), Dst = tostring(t.dst), Proto = toint(t.proto), Bytes = tolong(t.txBytes) + tolong(t.rxBytes), Pkts = tolong(t.txPkts) + tolong(t.rxPkts)
Stage 6: summarize
| summarize TotalBytes = sum(Bytes), TotalPackets = sum(Pkts) by NodeId, SrcNodeName, SrcUser, DstNodeName, DstUser, Src, Dst, Proto
Stage 7: where
| where TotalBytes > bytesThreshold
Stage 8: extend
| extend TotalMB = round(TotalBytes / 1024.0 / 1024.0, 2)
Stage 9: sort
| order by TotalBytes desc
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
HasVirtualTraffic | eq |
| field:"HasVirtualTraffic" kind:eq value:"true" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
Dst | summarize |
DstNodeName | summarize |
DstUser | summarize |
NodeId | summarize |
Proto | summarize |
Src | summarize |
SrcNodeName | summarize |
SrcUser | summarize |
TotalBytes | summarize |
TotalPackets | summarize |
TotalMB | extend |
TI Map URL Entity to SecurityAlert Data
#'This query identifies any URL indicators of compromise (IOCs) from threat intelligence (TI) by searching for matches in SecurityAlert data.'
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Command & Control |
Rule Body
id: f30a47c1-65fb-42b1-a7f4-00941c12550b
name: TI Map URL Entity to SecurityAlert Data
description: |
'This query identifies any URL indicators of compromise (IOCs) from threat intelligence (TI) by searching for matches in SecurityAlert data.'
severity: Medium
requiredDataConnectors:
- connectorId: MicrosoftCloudAppSecurity
dataTypes:
- SecurityAlert
- connectorId: AzureSecurityCenter
dataTypes:
- SecurityAlert
- connectorId: ThreatIntelligence
dataTypes:
- ThreatIntelligenceIndicator
- connectorId: ThreatIntelligenceTaxii
dataTypes:
- ThreatIntelligenceIndicator
- connectorId: MicrosoftDefenderThreatIntelligence
dataTypes:
- ThreatIntelligenceIndicator
queryFrequency: 1h
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
tactics:
- CommandAndControl
relevantTechniques:
- T1071
query: |
let dt_lookBack = 1h;
let ioc_lookBack = 14d;
let URLRegex = "((https?|ftp|ldap|wss?|file):\\/\\/(([\\:\\%\\w\\_\\-]+(\\.|@))*((xn--)?[a-zA-Z0-9\\-]+\\.)+(xn--[a-z0-9]+|[A-Za-z]+)|\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{0,3})[.,:\\w@?^=%&\\/~+#-]*[\\w@?^=%&\\/~+#-])";
let SecurityEvents = materialize(SecurityAlert
| where TimeGenerated >= ago(dt_lookBack)
| extend MSTI = case(AlertName has "TI map" and VendorName == "Microsoft" and ProductName == 'Azure Sentinel', true, false)
| where MSTI == false
// Extract URL from JSON data
| mv-expand parse_json(Entities)
| where isnotempty(Entities.Url) or isnotempty(Entities.Urls)
| extend Url = coalesce(Entities.Url, Entities.Urls)
| mv-expand Url
| extend Url = tolower(Url)
// Extract hostname from JSON data for entity mapping
| extend Compromised_Host = tostring(parse_json(ExtendedProperties).["Compromised Host"])
| extend Alert_TimeGenerated = TimeGenerated);
let EventUrls = materialize(SecurityEvents | distinct Url | summarize make_list(Url));
ThreatIntelligenceIndicator
| where isnotempty(Url)
| where TimeGenerated >= ago(ioc_lookBack)
| extend Url = tolower(Url)
| where tolower(Url) in (EventUrls)
| summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by IndicatorId
| where Active == true and ExpirationDateTime > now()
| where Description !contains_cs "State: inactive;" and Description !contains_cs "State: falsepos;"
// using innerunique to keep perf fast and result set low, we only need one match to indicate potential malicious activity that needs to be investigated
| join kind=innerunique (SecurityEvents) on Url
| where Alert_TimeGenerated < ExpirationDateTime
| summarize Alert_TimeGenerated = arg_max(Alert_TimeGenerated, *) by IndicatorId, AlertName
| project timestamp = Alert_TimeGenerated, ActivityGroupNames, IndicatorId, ThreatType, ExpirationDateTime, ConfidenceScore, AlertName, AlertSeverity, Description, Url, Compromised_Host
entityMappings:
- entityType: Host
fieldMappings:
- identifier: HostName
columnName: Compromised_Host
- entityType: URL
fieldMappings:
- identifier: Url
columnName: Url
version: 1.2.8
kind: Scheduled
Stages and Predicates
Parameters
let dt_lookBack = 1h;
let ioc_lookBack = 14d;
Let Binding: URLRegex
let URLRegex = "((https?|ftp|ldap|wss?|file):\\/\\/(([\\:\\%\\w\\_\\-]+(\\.|@))*((xn--)?[a-zA-Z0-9\\-]+\\.)+(xn--[a-z0-9]+|[A-Za-z]+)|\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{0,3})[.,:\\w@?^=%&\\/~+#-]*[\\w@?^=%&\\/~+#-])";
Let Binding: SecurityEvents
let SecurityEvents = materialize(SecurityAlert
| where TimeGenerated >= ago(dt_lookBack)
| extend MSTI = case(AlertName has "TI map" and VendorName == "Microsoft" and ProductName == 'Azure Sentinel', true, false)
| where MSTI == false
| mv-expand parse_json(Entities)
| where isnotempty(Entities.Url) or isnotempty(Entities.Urls)
| extend Url = coalesce(Entities.Url, Entities.Urls)
| mv-expand Url
| extend Url = tolower(Url)
| extend Compromised_Host = tostring(parse_json(ExtendedProperties).["Compromised Host"])
| extend Alert_TimeGenerated = TimeGenerated);
Let Binding: EventUrls
let EventUrls = materialize(SecurityEvents | distinct Url | summarize make_list(Url));
Stage 1: source
ThreatIntelligenceIndicator
Stage 2: where
| where isnotempty(Url)
Stage 3: where
| where TimeGenerated >= ago(ioc_lookBack)
Stage 4: extend
| extend Url = tolower(Url)
Stage 5: where
| where tolower(Url) in (EventUrls)
Stage 6: summarize
| summarize LatestIndicatorTime = arg_max(TimeGenerated, *) by IndicatorId
Stage 7: where
| where Active == true and ExpirationDateTime > now()
Stage 8: where
| where Description !contains_cs "State: inactive;" and Description !contains_cs "State: falsepos;"
Stage 9: join
| join kind=innerunique (SecurityEvents) on Url
Stage 10: where
where Alert_TimeGenerated < ExpirationDateTime
Stage 11: summarize
summarize Alert_TimeGenerated by IndicatorId, AlertName
Stage 12: project
project ActivityGroupNames, AlertName, AlertSeverity, Compromised_Host, ConfidenceScore, Description, ExpirationDateTime, IndicatorId, ThreatType, Url, timestamp
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
Active | eq |
| field:"Active" kind:eq value:"true" |
Entities.Url | is_not_null | field:"Entities.Url" kind:is_not_null | |
Entities.Urls | is_not_null | field:"Entities.Urls" kind:is_not_null | |
MSTI | eq |
| field:"MSTI" kind:eq value:"false" |
Url | in |
| field:"Url" kind:in value:"EventUrls" |
Url | is_not_null | field:"Url" kind:is_not_null |
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
Description | contains | State: falsepos; | excludes:Description field:"Description" value:"State: falsepos;" |
Description | contains | State: inactive; | excludes:Description field:"Description" value:"State: inactive;" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
ActivityGroupNames | project |
AlertName | project |
AlertSeverity | project |
Compromised_Host | project |
ConfidenceScore | project |
Description | project |
ExpirationDateTime | project |
IndicatorId | project |
ThreatType | project |
Url | project |
timestamp | project |
Vaikora - High severity AI agent action
#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.
Identifies high or critical severity AI agent actions ingested from Vaikora in the last 6 hours.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Initial Access | No specific technique |
| Execution | No specific technique |
| Persistence | No specific technique |
| Stealth | No specific technique |
| Credential Access | No specific technique |
| Discovery | No specific technique |
| Lateral Movement | No specific technique |
| Collection | No specific technique |
| Command & Control | No specific technique |
| Exfiltration | No specific technique |
| Impact | No specific technique |
Rule Body
id: ac3ec787-fd49-4e93-88cc-aaa9b31061ac
name: Vaikora - High severity AI agent action
description: |
Identifies high or critical severity AI agent actions ingested from Vaikora in the last 6 hours.
severity: High
requiredDataConnectors:
- connectorId: VaikoraSecurityCenter
dataTypes:
- Vaikora_AgentSignals_CL
queryFrequency: 6h
queryPeriod: 6h
triggerOperator: gt
triggerThreshold: 0
status: Available
tactics:
- InitialAccess
- Execution
- Persistence
- DefenseEvasion
- CredentialAccess
- Discovery
- LateralMovement
- Collection
- CommandAndControl
- Exfiltration
- Impact
relevantTechniques: []
query: |
Vaikora_AgentSignals_CL
| where TimeGenerated >= ago(6h)
| where severity_s in ("high", "critical")
| extend
ActionId = action_id_s,
AgentId = agent_id_s,
ActionType = action_type_s,
Severity = severity_s,
Status = status_s,
IsAnomaly = is_anomaly_b,
AnomalyScore = anomaly_score_d
| project TimeGenerated, ActionId, AgentId, ActionType, Severity, Status, IsAnomaly, AnomalyScore
| order by TimeGenerated desc
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: AgentId
alertDetailsOverride:
alertDisplayNameFormat: "Vaikora {{severity_s}} agent action: {{action_type_s}}"
alertDescriptionFormat: "Vaikora detected a {{severity_s}} severity action on agent {{agent_id_s}}."
alertSeverityColumnName: severity_s
version: 1.0.1
kind: Scheduled
Stages and Predicates
Stage 1: source
Vaikora_AgentSignals_CL
Stage 2: where
| where TimeGenerated >= ago(6h)
Stage 3: where
| where severity_s in ("high", "critical")
Stage 4: extend
| extend
ActionId = action_id_s,
AgentId = agent_id_s,
ActionType = action_type_s,
Severity = severity_s,
Status = status_s,
IsAnomaly = is_anomaly_b,
AnomalyScore = anomaly_score_d
Stage 5: project
| project TimeGenerated, ActionId, AgentId, ActionType, Severity, Status, IsAnomaly, AnomalyScore
Stage 6: sort
| order by TimeGenerated desc
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
severity_s | in |
| field:"okta::severity" kind:in |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
ActionId | project |
ActionType | project |
AgentId | project |
AnomalyScore | project |
IsAnomaly | project |
Severity | project |
Status | project |
TimeGenerated | project |
Valimail Enforce - Email Authentication Key Deleted
#This query searches for deletion of SPF delegations or DKIM keys, which are medium-severity events that could degrade email authentication posture for a domain.
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Defense Impairment |
Rule Body
id: 483078c6-d029-40f3-931a-30af0032008b
name: Valimail Enforce - Email Authentication Key Deleted
description: |
This query searches for deletion of SPF delegations or DKIM keys, which are medium-severity events
that could degrade email authentication posture for a domain.
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: ValimailEnforce
dataTypes:
- ValimailEnforceEvents_CL
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- DefenseEvasion
relevantTechniques:
- T1562
query: |
ValimailEnforceEvents_CL
| where EventSeverity == "Medium"
| where EventCategory in ("SPFConfiguration", "DKIMConfiguration")
| where IsHighValueEvent == true
| summarize
EventCount = count(),
FirstSeen = min(PerformedAt),
LastSeen = max(PerformedAt),
AffectedDomains = make_set(Subject),
Actions = make_set(EventType)
by User, EventCategory
| extend
AccountName = tostring(split(User, "@")[0]),
AccountDomain = tostring(split(User, "@")[1]),
DomainName = tostring(AffectedDomains[0])
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: AccountName
- identifier: UPNSuffix
columnName: AccountDomain
- entityType: DNS
fieldMappings:
- identifier: DomainName
columnName: DomainName
alertDetailsOverride:
alertDisplayNameFormat: "{{EventCategory}} key deleted on {{EventCount}} domain(s) by {{User}}"
alertDescriptionFormat: |
User '{{User}}' deleted one or more {{EventCategory}} records affecting
domains: {{AffectedDomains}}. This may weaken email authentication posture.
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: true
reopenClosedIncident: false
lookbackDuration: 1d
matchingMethod: Selected
groupByEntities:
- Account
version: 1.0.0
kind: Scheduled
Stages and Predicates
Stage 1: source
ValimailEnforceEvents_CL
Stage 2: where
| where EventSeverity == "Medium"
Stage 3: where
| where EventCategory in ("SPFConfiguration", "DKIMConfiguration")
Stage 4: where
| where IsHighValueEvent == true
Stage 5: summarize
| summarize
EventCount = count(),
FirstSeen = min(PerformedAt),
LastSeen = max(PerformedAt),
AffectedDomains = make_set(Subject),
Actions = make_set(EventType)
by User, EventCategory
Stage 6: extend
| extend
AccountName = tostring(split(User, "@")[0]),
AccountDomain = tostring(split(User, "@")[1]),
DomainName = tostring(AffectedDomains[0])
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
EventCategory | in |
| field:"EventCategory" kind:in |
EventSeverity | eq |
| field:"EventSeverity" kind:eq value:"Medium" |
IsHighValueEvent | eq |
| field:"IsHighValueEvent" kind:eq value:"true" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
Actions | summarize |
AffectedDomains | summarize |
EventCategory | summarize |
EventCount | summarize |
FirstSeen | summarize |
LastSeen | summarize |
User | summarize |
AccountDomain | extend |
AccountName | extend |
DomainName | extend |
VMware Edge Cloud Orchestrator - New LAN-Side Client Device Detected
#This analytics rule creates notifications of newly connected devices. These clients are connected to the LAN interface of the Edge.
Rule Body
id: 69c0644f-4ad5-41b6-9e09-a94c072ab80e
name: VMware Edge Cloud Orchestrator - New LAN-Side Client Device Detected
version: 1.0.0
kind: Scheduled
description: This analytics rule creates notifications of newly connected devices. These clients are connected to the LAN interface of the Edge.
severity: Informational
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
requiredDataConnectors:
- connectorId: VMwareSDWAN
dataTypes:
- SDWAN
query: |+
VMware_VECO_EventLogs_CL
| extend details = todynamic(detail)
| evaluate bag_unpack(details)
| where event == "EDGE_NEW_DEVICE"
suppressionEnabled: false
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: true
reopenClosedIncident: false
lookbackDuration: 1h
matchingMethod: AllEntities
groupByEntities: []
groupByAlertDetails: []
groupByCustomDetails: []
eventGroupingSettings:
aggregationKind: AlertPerResult
alertDetailsOverride:
alertDynamicProperties: []
customDetails:
Client_MAC_Address: client_mac
DHCP_Parameter_List: dhcp_param_list
entityMappings:
- entityType: Host
fieldMappings:
- identifier: HostName
columnName: hostname
- identifier: OSFamily
columnName: os_description
- identifier: OSVersion
columnName: os_version
- entityType: IP
fieldMappings:
- identifier: Address
columnName: client_ipv4addr
suppressionDuration: 5h
Stages and Predicates
Stage 1: source
VMware_VECO_EventLogs_CL
Stage 2: extend
| extend details = todynamic(detail)
Stage 3: evaluate
| evaluate bag_unpack(details)
Stage 4: where
| where event == "EDGE_NEW_DEVICE"
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
event | eq |
| field:"event" kind:eq value:"EDGE_NEW_DEVICE" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
details | extend |
Windows Binaries Executed from Non-Default Directory
#The query detects Windows binaries, that can be executed from a non-default directory (e.g. C:\Windows, C:\Windows\System32 etc.). Ref: https://lolbas-project.github.io/
MITRE ATT&CK Coverage
| Tactic | Techniques |
|---|---|
| Execution |
Telemetry Coverage
| Provider | Record / event type |
|---|---|
| Security-Auditing | Event ID 4688: A new process has been created. |
Rule Body
id: 15049017-527f-4d3b-b011-b0e99e68ef45
name: Windows Binaries Executed from Non-Default Directory
description: |
'The query detects Windows binaries, that can be executed from a non-default directory (e.g. C:\Windows\, C:\Windows\System32 etc.).
Ref: https://lolbas-project.github.io/'
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: SecurityEvents
dataTypes:
- SecurityEvent
- connectorId: WindowsSecurityEvents
dataTypes:
- SecurityEvent
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- Execution
relevantTechniques:
- T1059
query: |
let procList = externaldata(Process:string) [@"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Sample%20Data/Microsoft_Lolbas_Execution_Binaries.csv"] with (format="csv", ignoreFirstRecord=True);
SecurityEvent
| where EventID == 4688 and Process has_any (procList) and not (NewProcessName has ("C:\\Windows\\"))
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by EventID, Computer, SubjectUserName, NewProcessName, Process, CommandLine
| extend Name=tostring(split(SubjectUserName, "@")[0]), UPNSuffix=tostring(split(SubjectUserName, "@")[1])
| extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'')
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: Name
- identifier: UPNSuffix
columnName: UPNSuffix
- entityType: Host
fieldMappings:
- identifier: FullName
columnName: Computer
- identifier: HostName
columnName: HostName
- identifier: DnsDomain
columnName: DnsDomain
- entityType: Process
fieldMappings:
- identifier: CommandLine
columnName: CommandLine
version: 1.0.4
kind: Scheduled
Stages and Predicates
Let Binding: procList
let procList = externaldata(Process:string) [@"https://raw.githubusercontent.com/Azure/Azure-Sentinel/master/Sample%20Data/Microsoft_Lolbas_Execution_Binaries.csv"] with (format="csv", ignoreFirstRecord=True);
Stage 1: source
SecurityEvent
Stage 2: where
| where EventID == 4688 and Process has_any (procList) and not (NewProcessName has ("C:\\Windows\\"))
Stage 3: summarize
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by EventID, Computer, SubjectUserName, NewProcessName, Process, CommandLine
Stage 4: extend
| extend Name=tostring(split(SubjectUserName, "@")[0]), UPNSuffix=tostring(split(SubjectUserName, "@")[1])
Stage 5: extend
| extend HostName = iif(Computer has '.',substring(Computer,0,indexof(Computer,'.')),Computer) , DnsDomain = iif(Computer has '.',substring(Computer,indexof(Computer,'.')+1),'')
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
EventID | eq |
| field:"EventID" kind:eq value:"4688" |
Process | match |
| field:"Process" kind:match value:"procList" |
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
NewProcessName | match | C:\Windows\ | excludes:NewProcessName field:"NewProcessName" value:"C:\Windows\" |
Output Fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
CommandLine | summarize |
Computer | summarize |
EndTime | summarize |
EventID | summarize |
NewProcessName | summarize |
Process | summarize |
StartTime | summarize |
SubjectUserName | summarize |
Name | extend |
UPNSuffix | extend |
DnsDomain | extend |
HostName | extend |