Skip to content

Commit

Permalink
Introduce detections and rules for Crowdstrike.FDREvent (#648)
Browse files Browse the repository at this point in the history
  • Loading branch information
papanikge authored Feb 3, 2023
1 parent becdd25 commit 7a379a9
Show file tree
Hide file tree
Showing 26 changed files with 783 additions and 45 deletions.
2 changes: 1 addition & 1 deletion Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ click = "~=8.1"
decorator = "~=5.1"
isort = "~=5.10.0"
mypy = "~=0.950"
panther-analysis-tool = "~=0.19.1"
panther-analysis-tool = "~=0.19.3"
pylint = "~=2.15.0"
pylint-print = "~=1.0.0"

Expand Down
24 changes: 12 additions & 12 deletions Pipfile.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 35 additions & 0 deletions global_helpers/global_helpers_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,41 @@ def test_context(self):
self.assertEqual(expected, self.ip_info.context(self.match_field))


class TestGetCrowdstrikeField(unittest.TestCase):
def setUp(self):
self.input = {
"cid": "something",
"aid": "else",
"event": {"foo": "bar"},
"unknown_payload": {"field": "is"},
}

def test_input_key_default_works(self):
response = p_b_h.get_crowdstrike_field(self.input, "zee", default="hello")
self.assertEqual(response, "hello")

def test_input_key_does_not_exist(self):
response = p_b_h.get_crowdstrike_field(self.input, "zee")
self.assertEqual(response, None)

def test_input_key_exists(self):
response = p_b_h.get_crowdstrike_field(self.input, "cid")
self.assertEqual(response, "something")

def test_input_key_can_be_found_in_event(self):
response = p_b_h.get_crowdstrike_field(self.input, "foo")
self.assertEqual(response, "bar")

def test_input_key_can_be_found_in_unknown(self):
response = p_b_h.get_crowdstrike_field(self.input, "field")
self.assertEqual(response, "is")

def test_precedence(self):
self.input["event"]["field"] = "found"
response = p_b_h.get_crowdstrike_field(self.input, "field")
self.assertEqual(response, "found")


class TestGeoInfoFromIP(unittest.TestCase):
def setUp(self):
self.match_field = "clientIp"
Expand Down
29 changes: 19 additions & 10 deletions global_helpers/panther_base_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class PantherUnexpectedAlert(Exception):
# Compliance Helpers #
# # # # # # # # # # # # # #

# Expects a map with the a Key 'Tags' that maps to a map of key/value string pairs, or None if no
# Expects a map with a Key 'Tags' that maps to a map of key/value string pairs, or None if no
# tags are present.
# All Panther defined resources meet this requirement.
CDE_TAG_KEY = "environment"
Expand Down Expand Up @@ -215,19 +215,28 @@ def okta_alert_context(event: dict):


def crowdstrike_detection_alert_context(event: dict):
"""Returns common context for Crowstrike detections"""
"""Returns common context for Crowdstrike detections"""
return {
"user": event.get("UserName", ""),
"console-link": event.get("FalconHostLink", ""),
"commandline": event.get("CommandLine", ""),
"parentcommandline": event.get("ParentCommandLine", ""),
"filename": event.get("FileName", ""),
"filepath": event.get("FilePath", ""),
"description": event.get("DetectDescription", ""),
"action": event.get("PatternDispositionDescription", ""),
"user": get_crowdstrike_field(event, "UserName", default=""),
"console-link": get_crowdstrike_field(event, "FalconHostLink", default=""),
"commandline": get_crowdstrike_field(event, "CommandLine", default=""),
"parentcommandline": get_crowdstrike_field(event, "ParentCommandLine", default=""),
"filename": get_crowdstrike_field(event, "FileName", default=""),
"filepath": get_crowdstrike_field(event, "FilePath", default=""),
"description": get_crowdstrike_field(event, "DetectDescription", default=""),
"action": get_crowdstrike_field(event, "PatternDispositionDescription", default=""),
}


def get_crowdstrike_field(event, field_name, default=None):
return (
deep_get(event, field_name)
or deep_get(event, "event", field_name)
or deep_get(event, "unknown_payload", field_name)
or default
)


def slack_alert_context(event: dict):
return {
"actor-name": deep_get(event, "actor", "user", "name", default="<MISSING_NAME>"),
Expand Down
3 changes: 3 additions & 0 deletions lookup_tables/greynoise/advanced/noise_advanced.yml
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ LogTypeMap:
- "LocalAddressIP6"
- "RemoteAddressIP4"
- "RemoteAddressIP6"
- LogType: Crowdstrike.FDREvent
Selectors:
- 'p_any_ip_addresses'
- LogType: Duo.Authentication
Selectors:
- "$.access_device.ip"
Expand Down
3 changes: 3 additions & 0 deletions lookup_tables/greynoise/advanced/riot_advanced.yml
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ LogTypeMap:
- "LocalAddressIP6"
- "RemoteAddressIP4"
- "RemoteAddressIP6"
- LogType: Crowdstrike.FDREvent
Selectors:
- 'p_any_ip_addresses'
- LogType: Duo.Authentication
Selectors:
- "$.access_device.ip"
Expand Down
3 changes: 3 additions & 0 deletions lookup_tables/greynoise/basic/noise_basic.yml
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ LogTypeMap:
- "LocalAddressIP6"
- "RemoteAddressIP4"
- "RemoteAddressIP6"
- LogType: Crowdstrike.FDREvent
Selectors:
- 'p_any_ip_addresses'
- LogType: Duo.Authentication
Selectors:
- "$.access_device.ip"
Expand Down
3 changes: 3 additions & 0 deletions lookup_tables/greynoise/basic/riot_basic.yml
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ LogTypeMap:
- "LocalAddressIP6"
- "RemoteAddressIP4"
- "RemoteAddressIP6"
- LogType: Crowdstrike.FDREvent
Selectors:
- 'p_any_ip_addresses'
- LogType: Duo.Authentication
Selectors:
- "$.access_device.ip"
Expand Down
3 changes: 3 additions & 0 deletions lookup_tables/ipinfo/ipinfo_asn.yml
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ LogTypeMap:
- LogType: Crowdstrike.UserLogonLogoff
Selectors:
- 'aip'
- LogType: Crowdstrike.FDREvent
Selectors:
- 'p_any_ip_addresses'
- LogType: Dropbox.TeamEvent
Selectors:
- '$.origin.geo_location.ip_address'
Expand Down
3 changes: 3 additions & 0 deletions lookup_tables/ipinfo/ipinfo_asn_datalake.yml
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ LogTypeMap:
- LogType: Crowdstrike.UserLogonLogoff
Selectors:
- 'aip'
- LogType: Crowdstrike.FDREvent
Selectors:
- 'p_any_ip_addresses'
- LogType: Dropbox.TeamEvent
Selectors:
- '$.origin.geo_location.ip_address'
Expand Down
3 changes: 3 additions & 0 deletions lookup_tables/ipinfo/ipinfo_location.yml
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ LogTypeMap:
- LogType: Crowdstrike.UserLogonLogoff
Selectors:
- 'aip'
- LogType: Crowdstrike.FDREvent
Selectors:
- 'p_any_ip_addresses'
- LogType: Dropbox.TeamEvent
Selectors:
- '$.origin.geo_location.ip_address'
Expand Down
3 changes: 3 additions & 0 deletions lookup_tables/ipinfo/ipinfo_location_datalake.yml
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ LogTypeMap:
- LogType: Crowdstrike.UserLogonLogoff
Selectors:
- 'aip'
- LogType: Crowdstrike.FDREvent
Selectors:
- 'p_any_ip_addresses'
- LogType: Dropbox.TeamEvent
Selectors:
- '$.origin.geo_location.ip_address'
Expand Down
3 changes: 3 additions & 0 deletions lookup_tables/tor/tor_exit_nodes.yml
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@ LogTypeMap:
- LogType: Crowdstrike.UserLogonLogoff
Selectors:
- 'aip'
- LogType: Crowdstrike.FDREvent
Selectors:
- 'p_any_ip_addresses'
- LogType: Dropbox.TeamEvent
Selectors:
- '$.origin.geo_location.ip_address'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# 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/aws_queries/AWS_Authentication_from_CrowdStrike_Unmanaged_Device.yml
#
AnalysisType: scheduled_query
Description: Detects AWS Authentication events with IP Addresses not found in CrowdStrike's AIP List
Enabled: false
Query: |
SELECT *
FROM aws_cloudtrail
WHERE p_occurs_since('1 days')
AND eventName IN ('ConsoleLogin', 'SignIn', 'GetSessionToken')
AND eventSource IN ('sts.amazonaws.com', 'signin.amazonaws.com')
AND sourceIPAddress NOT IN
(
SELECT DISTINCT aip
FROM crowdstrike_fdrevent
WHERE p_occurs_since('3 days') AND crowdstrike_fdrevent.fdr_event_type = 'aid_master'
)
QueryName: AWS Authentication from CrowdStrike Unmanaged Device (crowdstrike_fdrevent table)
Schedule:
RateMinutes: 1440
TimeoutMinutes: 3
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# 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
Query: |
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
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 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 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%'
)
)
)
QueryName: CrowdStrike Large Zip Creation (crowdstrike_fdrevent table)
Schedule:
RateMinutes: 1440
TimeoutMinutes: 5
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# 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/MacOS_Browser_Credential_Access.yml
#
AnalysisType: scheduled_query
Description: Detects processes that contain known browser credential files in arguments. (crowdstrike_fdrevent table)
Enabled: false
Query: |
SELECT
*
FROM crowdstrike_fdrevent
WHERE
fdr_event_type = 'ProcessRollup2' AND
event:CommandLine LIKE ANY (
'%/Users/%/Library/Application Support/Google/Chrome/Default/Login Data%',
'%/Users/%/Library/Application Support/Google/Chrome/Default/Cookies%',
'%/Users/%/Library/Application Support/Google/Chrome/Profile%/Cookies%',
'%/Users/%/Library/Cookies%',
'%/Users/%/Library/Application Support/Firefox/Profiles/%.default/cookies.sqlite%',
'%/Users/%/Library/Application Support/Firefox/Profiles/%.default/key%.db%',
'%/Users/%/Library/Application Support/Firefox/Profiles/%.default/logins.json%',
'%Login Data%',
'%Cookies.binarycookies%',
'%key4.db%',
'%key3.db%',
'%logins.json%',
'%cookies.sqlite%'
)
/*
-- allowlist of applications
and event:ImageFileName NOT IN (
'/bin/rm'
)
*/
and p_occurs_since('1 day')
QueryName: MacOS Browser Credential Access (crowdstrike_fdrevent table)
Schedule:
RateMinutes: 1440
TimeoutMinutes: 5
Loading

0 comments on commit 7a379a9

Please sign in to comment.