From 7529897c6d7f300bdc78c7d1de7530a0b252691c Mon Sep 17 00:00:00 2001 From: Jonhnathan <26856693+w0rk3r@users.noreply.github.com> Date: Fri, 8 Dec 2023 15:54:40 -0300 Subject: [PATCH] [Security Content] Introduce Investigate Plugin in Investigation Guides (#3080) * [Security Content] Introduce Investigate Plugin in Investigation Guides * Add compatibility note * Update Transform format * update transform unit tests for investigate * updated docs with transform --------- Co-authored-by: brokensound77 Co-authored-by: Justin Ibarra <16747370+brokensound77@users.noreply.github.com> (cherry picked from commit aeb1f91320d372ec9d88e9b5bfdba8ca3ffa5123) --- detection_rules/rule.py | 28 ++++++------- detection_rules/schemas/definitions.py | 3 ++ docs/developing.md | 38 +++++++++++++++++ ...ommand_and_control_common_webservices.toml | 41 +++++++++++++++++-- ...ol_remote_file_copy_desktopimgdownldr.toml | 37 ++++++++++++++++- ...and_control_remote_file_copy_mpcmdrun.toml | 37 ++++++++++++++++- ...d_control_remote_file_copy_powershell.toml | 37 ++++++++++++++++- ...d_control_certutil_network_connection.toml | 40 ++++++++++++++++-- tests/test_all_rules.py | 12 +++++- 9 files changed, 247 insertions(+), 26 deletions(-) create mode 100644 docs/developing.md diff --git a/detection_rules/rule.py b/detection_rules/rule.py index 730d9f45ca6..d63619a2e4d 100644 --- a/detection_rules/rule.py +++ b/detection_rules/rule.py @@ -91,34 +91,30 @@ class OsQuery: ecs_mapping: Optional[Dict[str, Dict[Literal['field', 'value'], str]]] @dataclass(frozen=True) - class Insight: + class Investigate: @dataclass(frozen=True) class Provider: + excluded: bool field: str + queryType: definitions.InvestigateProviderQueryType value: str - type: str + valueType: definitions.InvestigateProviderValueType label: str + description: Optional[str] providers: List[List[Provider]] + relativeFrom: Optional[str] + relativeTo: Optional[str] # these must be lists in order to have more than one. Their index in the list is how they will be referenced in the # note string templates osquery: Optional[List[OsQuery]] - insight: Optional[List[Insight]] + investigate: Optional[List[Investigate]] - @validates_schema - def validate_transforms(self, value: dict, **kwargs): - """Validate transform fields.""" - # temporarily invalidate insights until schema stabilizes - insight = value.get('insight') - if insight is not None: - raise NotImplementedError('Insights are not stable yet.') - return - - def render_insight_osquery_to_string(self) -> Dict[Literal['osquery', 'insight'], List[str]]: + def render_investigate_osquery_to_string(self) -> Dict[definitions.TransformTypes, List[str]]: obj = self.to_dict() - rendered: Dict[Literal['osquery', 'insight'], List[str]] = {'osquery': [], 'insight': []} + rendered: Dict[definitions.TransformTypes, List[str]] = {'osquery': [], 'investigate': []} for plugin, entries in obj.items(): for entry in entries: rendered[plugin].append(f'!{{{plugin}{json.dumps(entry, sort_keys=True, separators=(",", ":"))}}}') @@ -343,12 +339,12 @@ def process_transforms(cls, transform: RuleTransform, obj: dict) -> dict: # only create functions that CAREFULLY mutate the obj dict def process_note_plugins(): - """Format the note field with osquery and insight plugin strings.""" + """Format the note field with osquery and investigate plugin strings.""" note = obj.get('note') if not note: return - rendered = transform.render_insight_osquery_to_string() + rendered = transform.render_investigate_osquery_to_string() rendered_patterns = {} for plugin, entries in rendered.items(): rendered_patterns.update(**{f'{plugin}_{i}': e for i, e in enumerate(entries)}) diff --git a/detection_rules/schemas/definitions.py b/detection_rules/schemas/definitions.py index 240d3f8bda8..e1b1c5273a3 100644 --- a/detection_rules/schemas/definitions.py +++ b/detection_rules/schemas/definitions.py @@ -140,6 +140,8 @@ Date = NewType('Date', str, validate=validate.Regexp(DATE_PATTERN)) FilterLanguages = Literal["kuery", "lucene", "eql", "esql"] Interval = NewType('Interval', str, validate=validate.Regexp(INTERVAL_PATTERN)) +InvestigateProviderQueryType = Literal["phrase", "range"] +InvestigateProviderValueType = Literal["string", "boolean"] Markdown = NewType("MarkdownField", CodeString) Maturity = Literal['development', 'experimental', 'beta', 'production', 'deprecated'] MaxSignals = NewType("MaxSignals", int, validate=validate.Range(min=1)) @@ -160,6 +162,7 @@ ThresholdValue = NewType("ThresholdValue", int, validate=validate.Range(min=1)) TimelineTemplateId = NewType('TimelineTemplateId', str, validate=validate.OneOf(list(TIMELINE_TEMPLATES))) TimelineTemplateTitle = NewType('TimelineTemplateTitle', str, validate=validate.OneOf(TIMELINE_TEMPLATES.values())) +TransformTypes = Literal["osquery", "investigate"] UUIDString = NewType('UUIDString', str, validate=validate.Regexp(UUID_PATTERN)) BuildingBlockType = Literal['default'] diff --git a/docs/developing.md b/docs/developing.md new file mode 100644 index 00000000000..b7b57ba9c8b --- /dev/null +++ b/docs/developing.md @@ -0,0 +1,38 @@ +# Developing + +Notes for managing and internal development + +## Transforms + +Transforms are data structures within rules which will be integrated into other fields at build +time for rules, meaning they are not directly converted. + +### CLI + +There are some helper commands to assist with converting transforms into the excpected rule TOML format + +- create transform in Kibana +- export it (or copy it) +- run the following commmand and paste them (multiple) +- copy and paste into rule, with minor format changes if needed + +```console +(detection_dev) ➜ detection-rules git:(initial_inv_queries) python -m detection_rules dev transforms guide-plugin-convert + +█▀▀▄ ▄▄▄ ▄▄▄ ▄▄▄ ▄▄▄ ▄▄▄ ▄▄▄ ▄▄▄ ▄ ▄ █▀▀▄ ▄ ▄ ▄ ▄▄▄ ▄▄▄ +█ █ █▄▄ █ █▄▄ █ █ █ █ █ █▀▄ █ █▄▄▀ █ █ █ █▄▄ █▄▄ +█▄▄▀ █▄▄ █ █▄▄ █▄▄ █ ▄█▄ █▄█ █ ▀▄█ █ ▀▄ █▄▄█ █▄▄ █▄▄ ▄▄█ + +Enter plugin contents []: !{investigate{"label":"Alerts associated with the host in the last 48h","providers":[[{"field":"event.kind","excluded":false,"queryType":"phrase","value":"signal","valueType":"string"},{"field":"host.name","excluded":false,"queryType":"phrase","value":"{{host.name}}","valueType":"string"}]],"relativeFrom":"now-48h/h","relativeTo":"now"}} +[transform] + +[[transform.investigate]] +label = "Alerts associated with the host in the last 48h" +providers = [[{field = "event.kind", excluded = false, queryType = "phrase", value = "signal", valueType = "string"}, {field = "host.name", excluded = false, queryType = "phrase", value = "{{host.name}}", valueType = "string"}]] +relativeFrom = "now-48h/h" +relativeTo = "now" +``` + +Other transform suppoprt can be found under + +`python -m detection-rules dev transforms -h` diff --git a/rules/windows/command_and_control_common_webservices.toml b/rules/windows/command_and_control_common_webservices.toml index 2e6a01b5963..4c3bd0d90a0 100644 --- a/rules/windows/command_and_control_common_webservices.toml +++ b/rules/windows/command_and_control_common_webservices.toml @@ -4,7 +4,7 @@ integration = ["endpoint"] maturity = "production" min_stack_comments = "New fields added: required_fields, related_integrations, setup" min_stack_version = "8.3.0" -updated_date = "2023/10/16" +updated_date = "2023/12/07" [transform] [[transform.osquery]] @@ -31,6 +31,38 @@ services.path FROM services JOIN authenticode ON services.path = authenticode.pa authenticode.path JOIN hash ON services.path = hash.path WHERE authenticode.result != 'trusted' """ +[[transform.investigate]] +label = "Alerts associated with the user in the last 48h" +relativeFrom = "now-48h/h" +relativeTo = "now" +providers = [ + [ + {field = "event.kind", excluded = false, queryType = "phrase", value = "signal", valueType = "string"}, + {field = "user.id", excluded = false, queryType = "phrase", value = "{{user.id}}", valueType = "string"} + ] +] + + +[[transform.investigate]] +label = "Alerts associated with the host in the last 48h" +relativeFrom = "now-48h/h" +relativeTo = "now" +providers = [ + [ + {field = "event.kind", excluded = false, queryType = "phrase", value = "signal", valueType = "string"}, + {field = "host.name", excluded = false, queryType = "phrase", value = "{{host.name}}", valueType = "string"} + ] +] + +[[transform.investigate]] +label = "Investigate the Subject Process Network Events" +providers = [ + [ + {field = "process.entity_id", excluded = false, queryType = "phrase", value = "{{process.entity_id}}", valueType = "string"}, + {field = "event.category", excluded = false, queryType = "phrase", value = "network", valueType = "string"} + ] +] + [rule] author = ["Elastic"] @@ -55,11 +87,14 @@ This rule looks for processes outside known legitimate program locations communi > **Note**: > This investigation guide uses the [Osquery Markdown Plugin](https://www.elastic.co/guide/en/security/master/invest-guide-run-osquery.html) introduced in Elastic Stack version 8.5.0. Older Elastic Stack versions will display unrendered Markdown in this guide. +> This investigation guide uses the [Investigate Markdown Plugin](https://www.elastic.co/guide/en/security/master/interactive-investigation-guides.html) introduced in Elastic Stack version 8.8.0. Older Elastic Stack versions will display unrendered Markdown in this guide. #### Possible investigation steps -- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures. +- Investigate the process execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures. - Investigate other alerts associated with the user/host during the past 48 hours. + - $investigate_0 + - $investigate_1 - Verify whether the digital signature exists in the executable. - Identify the operation type (upload, download, tunneling, etc.). - Examine the host for derived artifacts that indicate suspicious activities: @@ -67,6 +102,7 @@ This rule looks for processes outside known legitimate program locations communi - Observe and collect information about the following activities in both the sandbox and the alert subject host: - Attempts to contact external domains and addresses. - Use the Elastic Defend network events to determine domains and addresses contacted by the subject process by filtering by the process' `process.entity_id`. + - $investigate_2 - Examine the DNS cache for suspicious or anomalous entries. - $osquery_0 - Use the Elastic Defend registry events to examine registry keys accessed, modified, or created by the related processes in the process tree. @@ -75,7 +111,6 @@ This rule looks for processes outside known legitimate program locations communi - $osquery_2 - $osquery_3 - Retrieve the files' SHA-256 hash values using the PowerShell `Get-FileHash` cmdlet and search for the existence and reputation of the hashes in resources like VirusTotal, Hybrid-Analysis, CISCO Talos, Any.run, etc. -- Investigate potentially compromised accounts. Analysts can do this by searching for login events (for example, 4624) to the target host after the registry modification. ### False positive analysis diff --git a/rules/windows/command_and_control_remote_file_copy_desktopimgdownldr.toml b/rules/windows/command_and_control_remote_file_copy_desktopimgdownldr.toml index ad5c2304bf3..c71d69c29b5 100644 --- a/rules/windows/command_and_control_remote_file_copy_desktopimgdownldr.toml +++ b/rules/windows/command_and_control_remote_file_copy_desktopimgdownldr.toml @@ -2,7 +2,7 @@ creation_date = "2020/09/03" integration = ["endpoint", "windows"] maturity = "production" -updated_date = "2023/10/23" +updated_date = "2023/12/07" min_stack_comments = "New fields added: required_fields, related_integrations, setup" min_stack_version = "8.3.0" @@ -31,6 +31,37 @@ services.path FROM services JOIN authenticode ON services.path = authenticode.pa authenticode.path JOIN hash ON services.path = hash.path WHERE authenticode.result != 'trusted' """ +[[transform.investigate]] +label = "Alerts associated with the user in the last 48h" +relativeFrom = "now-48h/h" +relativeTo = "now" +providers = [ + [ + {field = "event.kind", excluded = false, queryType = "phrase", value = "signal", valueType = "string"}, + {field = "user.id", excluded = false, queryType = "phrase", value = "{{user.id}}", valueType = "string"} + ] +] + +[[transform.investigate]] +label = "Alerts associated with the host in the last 48h" +relativeFrom = "now-48h/h" +relativeTo = "now" +providers = [ + [ + {field = "event.kind", excluded = false, queryType = "phrase", value = "signal", valueType = "string"}, + {field = "host.name", excluded = false, queryType = "phrase", value = "{{host.name}}", valueType = "string"}, + ] +] + +[[transform.investigate]] +label = "Investigate the Subject Process Network Events" +providers = [ + [ + {field = "process.entity_id", excluded = false, queryType = "phrase", value = "{{process.entity_id}}", valueType = "string"}, + {field = "event.category", excluded = false, queryType = "phrase", value = "network", valueType = "string"} + ] +] + [rule] author = ["Elastic"] @@ -53,6 +84,7 @@ The `Desktopimgdownldr.exe` utility is used to to configure lockscreen/desktop i > **Note**: > This investigation guide uses the [Osquery Markdown Plugin](https://www.elastic.co/guide/en/security/master/invest-guide-run-osquery.html) introduced in Elastic Stack version 8.5.0. Older Elastic Stack versions will display unrendered Markdown in this guide. +> This investigation guide uses the [Investigate Markdown Plugin](https://www.elastic.co/guide/en/security/master/interactive-investigation-guides.html) introduced in Elastic Stack version 8.8.0. Older Elastic Stack versions will display unrendered Markdown in this guide. #### Possible investigation steps @@ -60,6 +92,8 @@ The `Desktopimgdownldr.exe` utility is used to to configure lockscreen/desktop i - Identify the user account that performed the action and whether it should perform this kind of action. - Contact the account owner and confirm whether they are aware of this activity. - Investigate other alerts associated with the user/host during the past 48 hours. + - $investigate_0 + - $investigate_1 - Assess whether this behavior is prevalent in the environment by looking for similar occurrences across hosts. - Check the reputation of the domain or IP address used to host the downloaded file or if the user downloaded the file from an internal system. - Examine the host for derived artifacts that indicate suspicious activities: @@ -67,6 +101,7 @@ The `Desktopimgdownldr.exe` utility is used to to configure lockscreen/desktop i - Observe and collect information about the following activities in both the sandbox and the alert subject host: - Attempts to contact external domains and addresses. - Use the Elastic Defend network events to determine domains and addresses contacted by the subject process by filtering by the process' `process.entity_id`. + - $investigate_2 - Examine the DNS cache for suspicious or anomalous entries. - $osquery_0 - Use the Elastic Defend registry events to examine registry keys accessed, modified, or created by the related processes in the process tree. diff --git a/rules/windows/command_and_control_remote_file_copy_mpcmdrun.toml b/rules/windows/command_and_control_remote_file_copy_mpcmdrun.toml index 0689cc5a180..9315508f798 100644 --- a/rules/windows/command_and_control_remote_file_copy_mpcmdrun.toml +++ b/rules/windows/command_and_control_remote_file_copy_mpcmdrun.toml @@ -2,7 +2,7 @@ creation_date = "2020/09/03" integration = ["endpoint", "windows"] maturity = "production" -updated_date = "2023/10/23" +updated_date = "2023/12/07" min_stack_comments = "New fields added: required_fields, related_integrations, setup" min_stack_version = "8.3.0" @@ -31,6 +31,37 @@ services.path FROM services JOIN authenticode ON services.path = authenticode.pa authenticode.path JOIN hash ON services.path = hash.path WHERE authenticode.result != 'trusted' """ +[[transform.investigate]] +label = "Alerts associated with the user in the last 48h" +relativeFrom = "now-48h/h" +relativeTo = "now" +providers = [ + [ + {field = "event.kind", excluded = false, queryType = "phrase", value = "signal", valueType = "string"}, + {field = "user.id", excluded = false, queryType = "phrase", value = "{{user.id}}", valueType = "string"} + ] +] + +[[transform.investigate]] +label = "Alerts associated with the host in the last 48h" +relativeFrom = "now-48h/h" +relativeTo = "now" +providers = [ + [ + {field = "event.kind", excluded = false, queryType = "phrase", value = "signal", valueType = "string"}, + {field = "host.name", excluded = false, queryType = "phrase", value = "{{host.name}}", valueType = "string"} + ] +] + +[[transform.investigate]] +label = "Investigate the Subject Process Network Events" +providers = [ + [ + {field = "process.entity_id", excluded = false, queryType = "phrase", value = "{{process.entity_id}}", valueType = "string"}, + {field = "event.category", excluded = false, queryType = "phrase", value = "network", valueType = "string"} + ] +] + [rule] author = ["Elastic"] @@ -50,6 +81,7 @@ The `MpCmdRun.exe` is a command-line tool part of Windows Defender and is used t > **Note**: > This investigation guide uses the [Osquery Markdown Plugin](https://www.elastic.co/guide/en/security/master/invest-guide-run-osquery.html) introduced in Elastic Stack version 8.5.0. Older Elastic Stack versions will display unrendered Markdown in this guide. +> This investigation guide uses the [Investigate Markdown Plugin](https://www.elastic.co/guide/en/security/master/interactive-investigation-guides.html) introduced in Elastic Stack version 8.8.0. Older Elastic Stack versions will display unrendered Markdown in this guide. #### Possible investigation steps @@ -57,12 +89,15 @@ The `MpCmdRun.exe` is a command-line tool part of Windows Defender and is used t - Identify the user account that performed the action and whether it should perform this kind of action. - Contact the account owner and confirm whether they are aware of this activity. - Investigate other alerts associated with the user/host during the past 48 hours. + - $investigate_0 + - $investigate_1 - Check the reputation of the domain or IP address used to host the downloaded file. - Examine the host for derived artifacts that indicate suspicious activities: - Analyze the file using a private sandboxed analysis system. - Observe and collect information about the following activities in both the sandbox and the alert subject host: - Attempts to contact external domains and addresses. - Use the Elastic Defend network events to determine domains and addresses contacted by the subject process by filtering by the process' `process.entity_id`. + - $investigate_2 - Examine the DNS cache for suspicious or anomalous entries. - $osquery_0 - Use the Elastic Defend registry events to examine registry keys accessed, modified, or created by the related processes in the process tree. diff --git a/rules/windows/command_and_control_remote_file_copy_powershell.toml b/rules/windows/command_and_control_remote_file_copy_powershell.toml index 19b82fd0775..7d6f6074295 100644 --- a/rules/windows/command_and_control_remote_file_copy_powershell.toml +++ b/rules/windows/command_and_control_remote_file_copy_powershell.toml @@ -2,7 +2,7 @@ creation_date = "2020/11/30" integration = ["endpoint"] maturity = "production" -updated_date = "2023/10/22" +updated_date = "2023/12/07" min_stack_comments = "New fields added: required_fields, related_integrations, setup" min_stack_version = "8.3.0" @@ -31,6 +31,37 @@ services.path FROM services JOIN authenticode ON services.path = authenticode.pa authenticode.path JOIN hash ON services.path = hash.path WHERE authenticode.result != 'trusted' """ +[[transform.investigate]] +label = "Alerts associated with the user in the last 48h" +relativeFrom = "now-48h/h" +relativeTo = "now" +providers = [ + [ + {field = "event.kind", excluded = false, queryType = "phrase", value = "signal", valueType = "string"}, + {field = "user.id", excluded = false, queryType = "phrase", value = "{{user.id}}", valueType = "string"} + ] +] + +[[transform.investigate]] +label = "Alerts associated with the host in the last 48h" +relativeFrom = "now-48h/h" +relativeTo = "now" +providers = [ + [ + {field = "event.kind", excluded = false, queryType = "phrase", value = "signal", valueType = "string"}, + {field = "host.name", excluded = false, queryType = "phrase", value = "{{host.name}}", valueType = "string"} + ] +] + +[[transform.investigate]] +label = "Investigate the Subject Process Network Events" +providers = [ + [ + {field = "process.entity_id", excluded = false, queryType = "phrase", value = "{{process.entity_id}}", valueType = "string"}, + {field = "event.category", excluded = false, queryType = "phrase", value = "network", valueType = "string"} + ] +] + [rule] author = ["Elastic"] @@ -50,6 +81,7 @@ PowerShell is one of system administrators' main tools for automation, report ro > **Note**: > This investigation guide uses the [Osquery Markdown Plugin](https://www.elastic.co/guide/en/security/master/invest-guide-run-osquery.html) introduced in Elastic Stack version 8.5.0. Older Elastic Stack versions will display unrendered Markdown in this guide. +> This investigation guide uses the [Investigate Markdown Plugin](https://www.elastic.co/guide/en/security/master/interactive-investigation-guides.html) introduced in Elastic Stack version 8.8.0. Older Elastic Stack versions will display unrendered Markdown in this guide. #### Possible investigation steps @@ -57,12 +89,15 @@ PowerShell is one of system administrators' main tools for automation, report ro - Identify the user account that performed the action and whether it should perform this kind of action. - Evaluate whether the user needs to use PowerShell to complete tasks. - Investigate other alerts associated with the user/host during the past 48 hours. + - $investigate_0 + - $investigate_1 - Check the reputation of the domain or IP address used to host the downloaded file. - Examine the host for derived artifacts that indicate suspicious activities: - Analyze the file using a private sandboxed analysis system. - Observe and collect information about the following activities in both the sandbox and the alert subject host: - Attempts to contact external domains and addresses. - Use the Elastic Defend network events to determine domains and addresses contacted by the subject process by filtering by the process' `process.entity_id`. + - $investigate_2 - Examine the DNS cache for suspicious or anomalous entries. - $osquery_0 - Use the Elastic Defend registry events to examine registry keys accessed, modified, or created by the related processes in the process tree. diff --git a/rules_building_block/command_and_control_certutil_network_connection.toml b/rules_building_block/command_and_control_certutil_network_connection.toml index 35d06368aeb..4ef4afc104f 100644 --- a/rules_building_block/command_and_control_certutil_network_connection.toml +++ b/rules_building_block/command_and_control_certutil_network_connection.toml @@ -4,7 +4,7 @@ integration = ["endpoint", "windows"] maturity = "production" min_stack_comments = "New fields added: required_fields, related_integrations, setup" min_stack_version = "8.3.0" -updated_date = "2023/10/16" +updated_date = "2023/12/07" bypass_bbr_timing = true [transform] @@ -32,6 +32,37 @@ services.path FROM services JOIN authenticode ON services.path = authenticode.pa authenticode.path JOIN hash ON services.path = hash.path WHERE authenticode.result != 'trusted' """ +[[transform.investigate]] +label = "Alerts associated with the user in the last 48h" +relativeFrom = "now-48h/h" +relativeTo = "now" +providers = [ + [ + {field = "event.kind", excluded = false, queryType = "phrase", value = "signal", valueType = "string"}, + {field = "user.id", excluded = false, queryType = "phrase", value = "{{user.id}}", valueType = "string"} + ] +] + +[[transform.investigate]] +label = "Alerts associated with the host in the last 48h" +relativeFrom = "now-48h/h" +relativeTo = "now" +providers = [ + [ + {field = "event.kind", excluded = false, queryType = "phrase", value = "signal", valueType = "string"}, + {field = "host.name", excluded = false, queryType = "phrase", value = "{{host.name}}", valueType = "string"} + ] +] + +[[transform.investigate]] +label = "Investigate the Subject Process Network Events" +providers = [ + [ + {field = "process.entity_id", excluded = false, queryType = "phrase", value = "{{process.entity_id}}", valueType = "string"}, + {field = "event.category", excluded = false, queryType = "phrase", value = "network", valueType = "string"} + ] +] + [rule] author = ["Elastic"] @@ -55,11 +86,14 @@ This rule looks for network events where `certutil.exe` contacts IP ranges other > **Note**: > This investigation guide uses the [Osquery Markdown Plugin](https://www.elastic.co/guide/en/security/master/invest-guide-run-osquery.html) introduced in Elastic Stack version 8.5.0. Older Elastic Stack versions will display unrendered Markdown in this guide. +> This investigation guide uses the [Investigate Markdown Plugin](https://www.elastic.co/guide/en/security/master/interactive-investigation-guides.html) introduced in Elastic Stack version 8.8.0. Older Elastic Stack versions will display unrendered Markdown in this guide. #### Possible investigation steps -- Investigate the script execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures. +- Investigate the process execution chain (parent process tree) for unknown processes. Examine their executable files for prevalence, whether they are located in expected locations, and if they are signed with valid digital signatures. - Investigate other alerts associated with the user/host during the past 48 hours. + - $investigate_0 + - $investigate_1 - Investigate if the downloaded file was executed. - Determine the context in which `certutil.exe` and the file were run. - Examine the host for derived artifacts that indicate suspicious activities: @@ -67,6 +101,7 @@ This rule looks for network events where `certutil.exe` contacts IP ranges other - Observe and collect information about the following activities in both the sandbox and the alert subject host: - Attempts to contact external domains and addresses. - Use the Elastic Defend network events to determine domains and addresses contacted by the subject process by filtering by the process' `process.entity_id`. + - $investigate_2 - Examine the DNS cache for suspicious or anomalous entries. - $osquery_0 - Use the Elastic Defend registry events to examine registry keys accessed, modified, or created by the related processes in the process tree. @@ -75,7 +110,6 @@ This rule looks for network events where `certutil.exe` contacts IP ranges other - $osquery_2 - $osquery_3 - Retrieve the files' SHA-256 hash values using the PowerShell `Get-FileHash` cmdlet and search for the existence and reputation of the hashes in resources like VirusTotal, Hybrid-Analysis, CISCO Talos, Any.run, etc. -- Investigate potentially compromised accounts. Analysts can do this by searching for login events (for example, 4624) to the target host after the registry modification. ### False positive analysis diff --git a/tests/test_all_rules.py b/tests/test_all_rules.py index fda4aa0e422..50d1d1af82d 100644 --- a/tests/test_all_rules.py +++ b/tests/test_all_rules.py @@ -1220,15 +1220,25 @@ def test_note_has_osquery_warning(self): '(https://www.elastic.co/guide/en/security/master/invest-guide-run-osquery.html) ' 'introduced in Elastic Stack version 8.5.0. Older Elastic Stack versions will display ' 'unrendered Markdown in this guide.') + invest_note_pattern = ('> This investigation guide uses the [Investigate Markdown Plugin]' + '(https://www.elastic.co/guide/en/security/master/interactive-investigation-guides.html)' + ' introduced in Elastic Stack version 8.8.0. Older Elastic Stack versions will display ' + 'unrendered Markdown in this guide.') for rule in self.production_rules.rules: if not rule.contents.get('transform'): continue + osquery = rule.contents.transform.get('osquery') if osquery and osquery_note_pattern not in rule.contents.data.note: self.fail(f'{self.rule_str(rule)} Investigation guides using the Osquery Markdown must contain ' f'the following note:\n{osquery_note_pattern}') + investigate = rule.contents.transform.get('investigate') + if investigate and invest_note_pattern not in rule.contents.data.note: + self.fail(f'{self.rule_str(rule)} Investigation guides using the Investigate Markdown must contain ' + f'the following note:\n{invest_note_pattern}') + def test_plugin_placeholders_match_entries(self): """Test that the number of plugin entries match their respective placeholders in note.""" for rule in self.production_rules.rules: @@ -1276,7 +1286,7 @@ def test_if_plugins_explicitly_defined(self): for rule in self.production_rules.rules: note = rule.contents.data.get('note') if note is not None: - results = re.search(r'(!{osquery|!{insight)', note, re.I | re.M) + results = re.search(r'(!{osquery|!{investigate)', note, re.I | re.M) err_msg = f'{self.rule_str(rule)} investigation guide plugin pattern detected! Use Transform' self.assertIsNone(results, err_msg)