QUESTION

How can I adapt my existing custom CrowdStrike detections and queries so that they work seamlessly with the Crowdstrike.FDREvent log type?

ANSWER

Detections

Get the value for a field

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_typeProcessRollup2:

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.

Filtering

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

 

Queries

The following list contains CrowdStrike Managed Queries and their counterpart for the Crowdstrike.FDREvent datalake table.

Filter records for a given event type

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.

Fields nested under event

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%'
Joining between tables
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