Crowdstrike Single IP Allowlisted


Description

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

Query · python

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

Analyst notes

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

Raw source Crowdstrike Single IP Allowlisted · Panther Python
Esc
Published by panther-labs/panther-analysis ↗, licensed under Apache 2.0 ↗. Reproduced here unmodified.
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.
Tests:
  - Name: A Single IP In Created Allowlist
    ExpectedResult: true
    Log:
      {
        "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"
        }
      }
  - Name: Multiple Single IPs In Created Allowlist
    ExpectedResult: true
    Log:
      {
        "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 2.2.2.2 3.3.3.3/32]"
            },
            {
              "Key": "contexts",
              "ValueString": "[API UI OTHER]"
            },
            {
              "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"
        }
      }
  - Name: Single IP Added to existing Allowlist
    ExpectedResult: true
    Log:
      {
        "event": {
          "AuditKeyValues": [
            {
              "Key": "old_group_name",
              "ValueString": "my_allowlist"
            },
            {
              "Key": "old_cidrs",
              "ValueString": "[1.2.3.4/8]"
            },
            {
              "Key": "allowlist_group_id",
              "ValueString": "24821376-7e77-431e-9469-74846978fe64"
            },
            {
              "Key": "group_name",
              "ValueString": "my_allowlist"
            },
            {
              "Key": "description",
              "ValueString": ""
            },
            {
              "Key": "cidrs",
              "ValueString": "[1.2.3.4/8 32.32.32.32]"
            },
            {
              "Key": "contexts",
              "ValueString": "[API]"
            },
            {
              "Key": "active",
              "ValueString": "false"
            },
            {
              "Key": "old_allowlist_group_id",
              "ValueString": "24821376-7e77-431e-9469-74846978fe64"
            },
            {
              "Key": "old_description",
              "ValueString": ""
            },
            {
              "Key": "old_contexts",
              "ValueString": "[API]"
            },
            {
              "Key": "old_active",
              "ValueString": "false"
            }
          ],
          "OperationName": "UpdateAllowlistGroup",
          "ServiceName": "Crowdstrike Allowlist Management",
          "Success": true,
          "UTCTimestamp": "2024-07-26 19:47:16.000000000",
          "UserId": "wormtongue@isengard.org",
          "UserIp": "1.2.3.4"
        },
        "metadata": {
          "customerIDString": "fake_customer_id",
          "eventCreationTime": "2024-07-26 19:47:16.428000000",
          "eventType": "AuthActivityAuditEvent",
          "offset": 366148,
          "version": "1.0"
        }
      }
  - Name: Only CIDR Ranges In Created Allowlist
    ExpectedResult: false
    Log:
      {
        "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/12 2.2.2.2/8 3.3.3.3/4]"
            },
            {
              "Key": "contexts",
              "ValueString": "[API UI OTHER]"
            },
            {
              "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"
        }
      }
  - Name: Unrelated Event
    ExpectedResult: false
    Log:
      {
        "metadata": {
          "customerIDString": "fake_customer_id",
          "offset": 341329,
          "eventType": "AuthActivityAuditEvent",
          "eventCreationTime": "2024-07-22 15:50:16.923000000",
          "version": "1.0"
        },
        "event": {
          "UserId": "sharkey@hobbiton.co",
          "UserIp": "192.0.2.100",
          "OperationName": "deleteUser",
          "ServiceName": "CrowdStrike Authentication",
          "Success": true,
          "UTCTimestamp": "2024-07-22 15:50:16.923000000",
          "AuditKeyValues": [
            {
              "Key": "target_name",
              "ValueString": "frodo.baggins@hobbiton.co"
            }
          ]
        }
      }

# ------ paired body: crowdstrike_single_ip_allowlisted.py ------

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

Detection rules belong to the projects that publish them and remain under their own licenses. This site indexes and links to them; it claims no rights in them.