How can I adapt my existing custom CrowdStrike detections and queries so that they work seamlessly with the Crowdstrike.FDREvent log type?
To get the value for a field (regardless of whether it is present as a top-level field, nested under unknown_payload
(Crowdstrike.Unknown
) or nested under event
in Crowdstrike.FDREvent)
the following helper can be used:
from panther_base_helpers import get_crowdstrike_field
The following condition will work seamlessly for both Crowdstrike.ProcessRollup2
and Crowdstrike.FDREvent
with fdr_event_type
→ ProcessRollup2
:
if "curl" in get_crowdstrike_field("CommandLine", ""):
Note that key lookups are case-insensitive: commandline, commandLine and CommandLine will all fetch the same field value.
Detections associated with Crowdstrike.FDREvent
and other log types will need to introduce filtering based on fdr_event_type
field value, when it is present.
For example, a detection associated with both Crowdstrike.DNSRequest
and Crowdstrike.FDREvent
will need to use the following condition, since it will be called for every CrowdStrike event:
def rule(event):
if (
event.get("p_log_type") == "Crowdstrike.FDREvent"
and event.get("fdr_event_type", "") != "DnsRequest"
):
return False
For an application of the above, you can review the Crowdstrike.DNS.Request detection, annotated here with comments explaining the logic step-by-step:
from panther_base_helpers import get_crowdstrike_field
# baddomain.com is present for testing purposes. Add domains you wish to be alerted on to this list
DENYLIST = ["baddomain.com"]
def rule(event):
# If the log type is Crowdstrike.FDREvent but the event type is not DnsRequest,
# the rule should not run thus we return early.
if (
event.get("p_log_type") == "Crowdstrike.FDREvent"
and event.get("fdr_event_type", "") != "DnsRequest"
):
return False
# The following call returns the value for the DomainName field for DnsRequest events, regardless of log type:
# - For log type Crowdstrike.FDREvent -> {"p_log_type": "Crowdstrike.FDREvent", "event": {"DomainName": "example.com"}}
# - For log type Crowdstrike.DNSRequest -> {"p_log_type": "Crowdstrike.DNSRequest", "DomainName": "example.com"}
if get_crowdstrike_field(event, "DomainName") in DENYLIST:
return True
return False
The following list contains CrowdStrike Managed Queries and their counterpart for the Crowdstrike.FDREvent datalake table.
AWS Authentication from CrowdStrike Unmanaged Device
CrowdStrike Large Zip Creation
MacOS Browser Credential Access
Queries on event-type-specific tables such crowdstrike_processrollup2
must now include a condition on the fdr_event_type
field in order to filter records that belong to the given event type:
SELECT DISTINCT aid FROM crowdstrike_processrollup2 WHERE commandline LIKE '%curl%'
SELECT DISTINCT aid FROM crowdstrike_fdrevent WHERE fdr_event_type = 'ProcessRollup2' AND event:CommandLine LIKE '%curl%'
Nested element names are case-sensitive. See Snowflake documentation for accessing semi-structured data.
Queries that were previously referencing fields that are now nested under event
must be duplicated/updated according to the new structure. For example:
SELECT commandline FROM crowdstrike_processrollup2 WHERE commandline LIKE '%curl%'
SELECT event:CommandLine FROM crowdstrike_fdrevent
WHERE fdr_event_type = 'ProcessRollup2' AND event:CommandLine LIKE '%curl%'
SELECT zips.*, pr2.TargetProcessId, pr2.CommandLine
FROM crowdstrike_unknown AS zips
LEFT JOIN crowdstrike_processrollup2 pr2
ON zips.ContextProcessId = pr2.targetprocessid
WHERE
zips.event_simpleName IN (
'GzipFileWritten',
'SevenZipFileWritten',
'ZipFileWritten',
'BZip2FileWritten'
)
AND CAST(unknown_payload:Size as integer) > 10000000
SELECT zips.*, pr2.event:TargetProcessId, pr2.event:CommandLine
FROM crowdstrike_fdrevent AS zips
LEFT JOIN crowdstrike_fdrevent pr2
ON zips.ContextProcessId = pr2.event:TargetProcessId
WHERE
zips.fdr_event_type IN (
'GzipFileWritten',
'SevenZipFileWritten',
'ZipFileWritten',
'BZip2FileWritten'
)
AND CAST(zips.event:Size as integer) > 10000000