From 116a7de890e617c9622ac828f00e908407ea91c7 Mon Sep 17 00:00:00 2001 From: Apoorva Joshi <30438249+ajosh0504@users.noreply.github.com> Date: Wed, 27 Sep 2023 11:53:38 -0700 Subject: [PATCH] [New Rule] Adding Lateral Movement Rules from Advanced Analytic LMD Package (#3119) * Adding Lateral Movement Detection rules * added tags; adjusted tests; updated manifests and schemas * added default value to build_integrations_schema * combined analytic and non-dataset packages for related integrations * adjusted machine learning definitions * adjusted machine learning definitions * removed splat for machine learning list due to 3.8 constraints --------- Co-authored-by: terrancedejesus Co-authored-by: Terrance DeJesus <99630311+terrancedejesus@users.noreply.github.com> (cherry picked from commit 747ee7d593dd638239dadbeb9842cf12a8c40772) --- detection_rules/devtools.py | 13 ++-- .../etc/integration-manifests.json.gz | Bin 7676 -> 7827 bytes .../etc/integration-schemas.json.gz | Bin 2622294 -> 2622437 bytes detection_rules/integrations.py | 20 ++++-- detection_rules/rule.py | 10 ++- detection_rules/schemas/definitions.py | 6 +- ...vement_malicious_remote_file_creation.toml | 45 ++++++++++++++ ...ovement_ml_high_mean_rdp_process_args.toml | 45 ++++++++++++++ ...ent_ml_high_mean_rdp_session_duration.toml | 45 ++++++++++++++ ...ral_movement_ml_high_remote_file_size.toml | 46 ++++++++++++++ ...ml_high_variance_rdp_session_duration.toml | 45 ++++++++++++++ ...ovement_ml_rare_remote_file_directory.toml | 45 ++++++++++++++ ...ovement_ml_rare_remote_file_extension.toml | 44 ++++++++++++++ ...spike_in_connections_from_a_source_ip.toml | 45 ++++++++++++++ ...ke_in_connections_to_a_destination_ip.toml | 45 ++++++++++++++ ...al_movement_ml_spike_in_rdp_processes.toml | 44 ++++++++++++++ ...ent_ml_spike_in_remote_file_transfers.toml | 46 ++++++++++++++ ...nt_ml_unusual_time_for_an_rdp_session.toml | 45 ++++++++++++++ ..._file_creation_in_sensitive_directory.toml | 57 ++++++++++++++++++ tests/test_all_rules.py | 6 +- 20 files changed, 636 insertions(+), 16 deletions(-) create mode 100644 rules/integrations/lmd/lateral_movement_malicious_remote_file_creation.toml create mode 100644 rules/integrations/lmd/lateral_movement_ml_high_mean_rdp_process_args.toml create mode 100644 rules/integrations/lmd/lateral_movement_ml_high_mean_rdp_session_duration.toml create mode 100644 rules/integrations/lmd/lateral_movement_ml_high_remote_file_size.toml create mode 100644 rules/integrations/lmd/lateral_movement_ml_high_variance_rdp_session_duration.toml create mode 100644 rules/integrations/lmd/lateral_movement_ml_rare_remote_file_directory.toml create mode 100644 rules/integrations/lmd/lateral_movement_ml_rare_remote_file_extension.toml create mode 100644 rules/integrations/lmd/lateral_movement_ml_spike_in_connections_from_a_source_ip.toml create mode 100644 rules/integrations/lmd/lateral_movement_ml_spike_in_connections_to_a_destination_ip.toml create mode 100644 rules/integrations/lmd/lateral_movement_ml_spike_in_rdp_processes.toml create mode 100644 rules/integrations/lmd/lateral_movement_ml_spike_in_remote_file_transfers.toml create mode 100644 rules/integrations/lmd/lateral_movement_ml_unusual_time_for_an_rdp_session.toml create mode 100644 rules/integrations/lmd/lateral_movement_remote_file_creation_in_sensitive_directory.toml diff --git a/detection_rules/devtools.py b/detection_rules/devtools.py index 5dfbf37af..f32d6af8c 100644 --- a/detection_rules/devtools.py +++ b/detection_rules/devtools.py @@ -1236,14 +1236,19 @@ def build_integration_manifests(overwrite: bool, integration: str): @integrations_group.command('build-schemas') @click.option('--overwrite', '-o', is_flag=True, help="Overwrite the entire integrations-schema.json.gz file") -def build_integration_schemas(overwrite: bool): +@click.option('--integration', '-i', type=str, + help="Adds a single integration schema to the integrations-schema.json.gz file") +def build_integration_schemas(overwrite: bool, integration: str): """Builds consolidated integrations schemas file.""" click.echo("Building integration schemas...") start_time = time.perf_counter() - build_integrations_schemas(overwrite) - end_time = time.perf_counter() - click.echo(f"Time taken to generate schemas: {(end_time - start_time)/60:.2f} minutes") + if integration: + build_integrations_schemas(overwrite=False, integration=integration) + else: + build_integrations_schemas(overwrite=overwrite) + end_time = time.perf_counter() + click.echo(f"Time taken to generate schemas: {(end_time - start_time)/60:.2f} minutes") @integrations_group.command('show-latest-compatible') diff --git a/detection_rules/etc/integration-manifests.json.gz b/detection_rules/etc/integration-manifests.json.gz index 5303e11f2b397ba4045a1f4f18580e7e841fc010..897bd5e1acb4041631653990037606909e06e1bc 100644 GIT binary patch delta 7498 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 dmu0ykaLXE(+vh>>2eEvtY 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 delta 13802 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 A0ssI2 diff --git a/detection_rules/integrations.py b/detection_rules/integrations.py index 16f6999a2..faa305175 100644 --- a/detection_rules/integrations.py +++ b/detection_rules/integrations.py @@ -47,12 +47,13 @@ class IntegrationManifestSchema(Schema): description = fields.Str(required=True) download = fields.Str(required=True) conditions = fields.Dict(required=True) - policy_templates = fields.List(fields.Dict, required=True) + policy_templates = fields.List(fields.Dict) owner = fields.Dict(required=False) @post_load def transform_policy_template(self, data, **kwargs): - data["policy_templates"] = [policy["name"] for policy in data["policy_templates"]] + if "policy_templates" in data: + data["policy_templates"] = [policy["name"] for policy in data["policy_templates"]] return data @@ -93,21 +94,30 @@ def build_integrations_manifest(overwrite: bool, rule_integrations: list = [], i print(f"final integrations manifests dumped: {MANIFEST_FILE_PATH}") -def build_integrations_schemas(overwrite: bool) -> None: +def build_integrations_schemas(overwrite: bool, integration: str = None) -> None: """Builds a new local copy of integration-schemas.json.gz from EPR integrations.""" - final_integration_schemas = {} saved_integration_schemas = {} # Check if the file already exists and handle accordingly if overwrite and SCHEMA_FILE_PATH.exists(): SCHEMA_FILE_PATH.unlink() + final_integration_schemas = {} elif SCHEMA_FILE_PATH.exists(): - saved_integration_schemas = load_integrations_schemas() + final_integration_schemas = load_integrations_schemas() + else: + final_integration_schemas = {} # Load the integration manifests integration_manifests = load_integrations_manifests() + # if a single integration is specified, only process that integration + if integration: + if integration in integration_manifests: + integration_manifests = {integration: integration_manifests[integration]} + else: + raise ValueError(f"Integration {integration} not found in manifest.") + # Loop through the packages and versions for package, versions in integration_manifests.items(): print(f"processing {package}") diff --git a/detection_rules/rule.py b/detection_rules/rule.py index 61cbf9a20..b7679b9ad 100644 --- a/detection_rules/rule.py +++ b/detection_rules/rule.py @@ -1024,8 +1024,10 @@ class TOMLRuleContents(BaseRuleContents, MarshmallowDataclassMixin): # if integration is not a policy template remove if package["version"]: - policy_templates = packages_manifest[ - package["package"]][package["version"].strip("^")]["policy_templates"] + version_data = packages_manifest.get(package["package"], + {}).get(package["version"].strip("^"), {}) + policy_templates = version_data.get("policy_templates", []) + if package["integration"] not in policy_templates: del package["integration"] @@ -1131,7 +1133,9 @@ class TOMLRuleContents(BaseRuleContents, MarshmallowDataclassMixin): rule_integrations = meta.get("integration", []) if rule_integrations: for integration in rule_integrations: - if integration in definitions.NON_DATASET_PACKAGES or isinstance(data, MachineLearningRuleData): + ineligible_integrations = definitions.NON_DATASET_PACKAGES + \ + [*map(str.lower, definitions.MACHINE_LEARNING_PACKAGES)] + if integration in ineligible_integrations or isinstance(data, MachineLearningRuleData): packaged_integrations.append({"package": integration, "integration": None}) for value in sorted(datasets): diff --git a/detection_rules/schemas/definitions.py b/detection_rules/schemas/definitions.py index cb842b5e1..d43d36aa6 100644 --- a/detection_rules/schemas/definitions.py +++ b/detection_rules/schemas/definitions.py @@ -125,6 +125,7 @@ EXPECTED_RULE_TAGS = [ 'Use Case: Vulnerability' ] +MACHINE_LEARNING_PACKAGES = ['LMD', 'DGA', 'DED', 'ProblemChild', 'Beaconing'] NonEmptyStr = NewType('NonEmptyStr', str, validate=validate.Length(min=1)) TimeUnits = Literal['s', 'm', 'h'] @@ -159,5 +160,6 @@ UUIDString = NewType('UUIDString', str, validate=validate.Regexp(UUID_PATTERN)) BuildingBlockType = Literal['default'] # experimental machine learning features and releases -MachineLearningType = Literal['DGA', 'ProblemChild'] -MachineLearningTypeLower = Literal['dga', 'problemchild'] +MachineLearningType = getattr(Literal, '__getitem__')(tuple(MACHINE_LEARNING_PACKAGES)) # noqa: E999 +MachineLearningTypeLower = getattr(Literal, '__getitem__')( + tuple(map(str.lower, MACHINE_LEARNING_PACKAGES))) # noqa: E999 diff --git a/rules/integrations/lmd/lateral_movement_malicious_remote_file_creation.toml b/rules/integrations/lmd/lateral_movement_malicious_remote_file_creation.toml new file mode 100644 index 000000000..19ea2b676 --- /dev/null +++ b/rules/integrations/lmd/lateral_movement_malicious_remote_file_creation.toml @@ -0,0 +1,45 @@ +[metadata] +creation_date = "2023/09/13" +integration = ["lmd","endpoint"] +maturity = "production" +min_stack_comments = "New fields added: required_fields, related_integrations, setup" +min_stack_version = "8.3.0" +updated_date = "2023/09/21" + +[rule] +author = ["Elastic"] +description = "Malicious remote file creation, which can be an indicator of lateral movement activity." +from = "now-10m" +index = ["logs-endpoint.events.*"] +interval = "5m" +language = "eql" +license = "Elastic License v2" +name = "Malicious Remote File Creation" +references = ["https://www.elastic.co/es/blog/remote-desktop-protocol-connections-elastic-security"] +risk_score = 99 +rule_id = "301571f3-b316-4969-8dd0-7917410030d3" +severity = "critical" +tags = ["Domain: Endpoint", "Use Case: Lateral Movement Detection", "Tactic: Lateral Movement", "Data Source: Elastic Defend"] +type = "eql" + +query = ''' +sequence by host.name +[file where event.action == "creation" and process.name : ("System", "scp", "sshd", "smbd", "vsftpd", "sftp-server")] +[file where event.category == "malware" or event.category == "intrusion_detection" +and process.name:("System", "scp", "sshd", "smbd", "vsftpd", "sftp-server")] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1210" +name = "Exploitation of Remote Services" +reference = "https://attack.mitre.org/techniques/T1210/" + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" + diff --git a/rules/integrations/lmd/lateral_movement_ml_high_mean_rdp_process_args.toml b/rules/integrations/lmd/lateral_movement_ml_high_mean_rdp_process_args.toml new file mode 100644 index 000000000..1258f9bba --- /dev/null +++ b/rules/integrations/lmd/lateral_movement_ml_high_mean_rdp_process_args.toml @@ -0,0 +1,45 @@ +[metadata] +creation_date = "2023/09/13" +integration = ["lmd"] +maturity = "production" +min_stack_comments = "New fields added: required_fields, related_integrations, setup" +min_stack_version = "8.3.0" +updated_date = "2023/09/21" + +[rule] +anomaly_threshold = 70 +author = ["Elastic"] +description = """ +A machine learning job has detected unusually high number of process arguments in an RDP session. Executing +sophisticated attacks such as lateral movement can involve the use of complex commands, obfuscation mechanisms, +redirection and piping, which in turn increases the number of arguments in a command. +""" +from = "now-12h" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "lmd_high_mean_rdp_process_args" +name = "High Mean of Process Arguments in an RDP Session" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "36c48a0c-c63a-4cbc-aee1-8cac87db31a9" +severity = "low" +tags = [ + "Use Case: Lateral Movement Detection", + "Rule Type: ML", + "Rule Type: Machine Learning", + "Tactic: Lateral Movement", +] +type = "machine_learning" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1210" +name = "Exploitation of Remote Services" +reference = "https://attack.mitre.org/techniques/T1210/" + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" + diff --git a/rules/integrations/lmd/lateral_movement_ml_high_mean_rdp_session_duration.toml b/rules/integrations/lmd/lateral_movement_ml_high_mean_rdp_session_duration.toml new file mode 100644 index 000000000..6a3e1989b --- /dev/null +++ b/rules/integrations/lmd/lateral_movement_ml_high_mean_rdp_session_duration.toml @@ -0,0 +1,45 @@ +[metadata] +creation_date = "2023/09/12" +integration = ["lmd"] +maturity = "production" +min_stack_comments = "New fields added: required_fields, related_integrations, setup" +min_stack_version = "8.3.0" +updated_date = "2023/09/21" + +[rule] +anomaly_threshold = 70 +author = ["Elastic"] +description = """ +A machine learning job has detected unusually high mean of RDP session duration. Long RDP sessions can be used to evade +detection mechanisms via session persistence, and might be used to perform tasks such as lateral movement, that might +require uninterrupted access to a compromised machine. +""" +from = "now-12h" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "lmd_high_mean_rdp_session_duration" +name = "High Mean of RDP Session Duration" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "a74c60cb-70ee-4629-a127-608ead14ebf1" +severity = "low" +tags = [ + "Use Case: Lateral Movement Detection", + "Rule Type: ML", + "Rule Type: Machine Learning", + "Tactic: Lateral Movement", +] +type = "machine_learning" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1210" +name = "Exploitation of Remote Services" +reference = "https://attack.mitre.org/techniques/T1210/" + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" + diff --git a/rules/integrations/lmd/lateral_movement_ml_high_remote_file_size.toml b/rules/integrations/lmd/lateral_movement_ml_high_remote_file_size.toml new file mode 100644 index 000000000..2861af3bd --- /dev/null +++ b/rules/integrations/lmd/lateral_movement_ml_high_remote_file_size.toml @@ -0,0 +1,46 @@ +[metadata] +creation_date = "2023/09/13" +integration = ["lmd"] +maturity = "production" +min_stack_comments = "New fields added: required_fields, related_integrations, setup" +min_stack_version = "8.3.0" +updated_date = "2023/09/21" + +[rule] +anomaly_threshold = 70 +author = ["Elastic"] +description = """ +A machine learning job has detected an unusually high file size shared by a remote host indicating potential lateral +movement activity. One of the primary goals of attackers after gaining access to a network is to locate and exfiltrate +valuable information. Instead of multiple small transfers that can raise alarms, attackers might choose to bundle data +into a single large file transfer. +""" +from = "now-90m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "lmd_high_file_size_remote_file_transfer" +name = "Unusual Remote File Size" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "0678bc9c-b71a-433b-87e6-2f664b6b3131" +severity = "low" +tags = [ + "Use Case: Lateral Movement Detection", + "Rule Type: ML", + "Rule Type: Machine Learning", + "Tactic: Lateral Movement", +] +type = "machine_learning" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1210" +name = "Exploitation of Remote Services" +reference = "https://attack.mitre.org/techniques/T1210/" + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" + diff --git a/rules/integrations/lmd/lateral_movement_ml_high_variance_rdp_session_duration.toml b/rules/integrations/lmd/lateral_movement_ml_high_variance_rdp_session_duration.toml new file mode 100644 index 000000000..55a84e1d7 --- /dev/null +++ b/rules/integrations/lmd/lateral_movement_ml_high_variance_rdp_session_duration.toml @@ -0,0 +1,45 @@ +[metadata] +creation_date = "2023/09/13" +integration = ["lmd"] +maturity = "production" +min_stack_comments = "New fields added: required_fields, related_integrations, setup" +min_stack_version = "8.3.0" +updated_date = "2023/09/21" + +[rule] +anomaly_threshold = 70 +author = ["Elastic"] +description = """ +A machine learning job has detected unusually high variance of RDP session duration. Long RDP sessions can be used to +evade detection mechanisms via session persistence, and might be used to perform tasks such as lateral movement, that +might require uninterrupted access to a compromised machine. +""" +from = "now-12h" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "lmd_high_var_rdp_session_duration" +name = "High Variance in RDP Session Duration" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "a8d35ca0-ad8d-48a9-9f6c-553622dca61a" +severity = "low" +tags = [ + "Use Case: Lateral Movement Detection", + "Rule Type: ML", + "Rule Type: Machine Learning", + "Tactic: Lateral Movement", +] +type = "machine_learning" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1210" +name = "Exploitation of Remote Services" +reference = "https://attack.mitre.org/techniques/T1210/" + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" + diff --git a/rules/integrations/lmd/lateral_movement_ml_rare_remote_file_directory.toml b/rules/integrations/lmd/lateral_movement_ml_rare_remote_file_directory.toml new file mode 100644 index 000000000..27da10305 --- /dev/null +++ b/rules/integrations/lmd/lateral_movement_ml_rare_remote_file_directory.toml @@ -0,0 +1,45 @@ +[metadata] +creation_date = "2023/09/12" +integration = ["lmd"] +maturity = "production" +min_stack_comments = "New fields added: required_fields, related_integrations, setup" +min_stack_version = "8.3.0" +updated_date = "2023/09/21" + +[rule] +anomaly_threshold = 70 +author = ["Elastic"] +description = """ +An anomaly detection job has detected a remote file transfer on an unusual directory indicating a potential lateral +movement activity on the host. Many Security solutions monitor well-known directories for suspicious activities, so +attackers might use less common directories to bypass monitoring. +""" +from = "now-90m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "lmd_rare_file_path_remote_transfer" +name = "Unusual Remote File Directory" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "be4c5aed-90f5-4221-8bd5-7ab3a4334751" +severity = "low" +tags = [ + "Use Case: Lateral Movement Detection", + "Rule Type: ML", + "Rule Type: Machine Learning", + "Tactic: Lateral Movement", +] +type = "machine_learning" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1210" +name = "Exploitation of Remote Services" +reference = "https://attack.mitre.org/techniques/T1210/" + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" + diff --git a/rules/integrations/lmd/lateral_movement_ml_rare_remote_file_extension.toml b/rules/integrations/lmd/lateral_movement_ml_rare_remote_file_extension.toml new file mode 100644 index 000000000..6e6949a6c --- /dev/null +++ b/rules/integrations/lmd/lateral_movement_ml_rare_remote_file_extension.toml @@ -0,0 +1,44 @@ +[metadata] +creation_date = "2023/09/13" +integration = ["lmd"] +maturity = "production" +min_stack_comments = "New fields added: required_fields, related_integrations, setup" +min_stack_version = "8.3.0" +updated_date = "2023/09/21" + +[rule] +anomaly_threshold = 70 +author = ["Elastic"] +description = """ +An anomaly detection job has detected a remote file transfer with a rare extension, which could indicate potential +lateral movement activity on the host. +""" +from = "now-90m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "lmd_rare_file_extension_remote_transfer" +name = "Unusual Remote File Extension" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "814d96c7-2068-42aa-ba8e-fe0ddd565e2e" +severity = "low" +tags = [ + "Use Case: Lateral Movement Detection", + "Rule Type: ML", + "Rule Type: Machine Learning", + "Tactic: Lateral Movement", +] +type = "machine_learning" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1210" +name = "Exploitation of Remote Services" +reference = "https://attack.mitre.org/techniques/T1210/" + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" + diff --git a/rules/integrations/lmd/lateral_movement_ml_spike_in_connections_from_a_source_ip.toml b/rules/integrations/lmd/lateral_movement_ml_spike_in_connections_from_a_source_ip.toml new file mode 100644 index 000000000..94fbb3d40 --- /dev/null +++ b/rules/integrations/lmd/lateral_movement_ml_spike_in_connections_from_a_source_ip.toml @@ -0,0 +1,45 @@ +[metadata] +creation_date = "2023/09/13" +integration = ["lmd"] +maturity = "production" +min_stack_comments = "New fields added: required_fields, related_integrations, setup" +min_stack_version = "8.3.0" +updated_date = "2023/09/21" + +[rule] +anomaly_threshold = 70 +author = ["Elastic"] +description = """ +A machine learning job has detected a high count of destination IPs establishing an RDP connection with a single source +IP. Once an attacker has gained access to one system, they might attempt to access more in the network in search of +valuable assets, data, or further access points. +""" +from = "now-12h" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "lmd_high_rdp_distinct_count_destination_ip_for_source" +name = "Spike in Number of Connections Made from a Source IP" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "3e0561b5-3fac-4461-84cc-19163b9aaa61" +severity = "low" +tags = [ + "Use Case: Lateral Movement Detection", + "Rule Type: ML", + "Rule Type: Machine Learning", + "Tactic: Lateral Movement", +] +type = "machine_learning" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1210" +name = "Exploitation of Remote Services" +reference = "https://attack.mitre.org/techniques/T1210/" + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" + diff --git a/rules/integrations/lmd/lateral_movement_ml_spike_in_connections_to_a_destination_ip.toml b/rules/integrations/lmd/lateral_movement_ml_spike_in_connections_to_a_destination_ip.toml new file mode 100644 index 000000000..e0cd42f3e --- /dev/null +++ b/rules/integrations/lmd/lateral_movement_ml_spike_in_connections_to_a_destination_ip.toml @@ -0,0 +1,45 @@ +[metadata] +creation_date = "2023/09/13" +integration = ["lmd"] +maturity = "production" +min_stack_comments = "New fields added: required_fields, related_integrations, setup" +min_stack_version = "8.3.0" +updated_date = "2023/09/21" + +[rule] +anomaly_threshold = 70 +author = ["Elastic"] +description = """ +A machine learning job has detected a high count of source IPs establishing an RDP connection with a single destination +IP. Attackers might use multiple compromised systems to attack a target to ensure redundancy in case a source IP gets +detected and blocked. +""" +from = "now-12h" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "lmd_high_rdp_distinct_count_source_ip_for_destination" +name = "Spike in Number of Connections Made to a Destination IP" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "18a5dd9a-e3fa-4996-99b1-ae533b8f27fc" +severity = "low" +tags = [ + "Use Case: Lateral Movement Detection", + "Rule Type: ML", + "Rule Type: Machine Learning", + "Tactic: Lateral Movement", +] +type = "machine_learning" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1210" +name = "Exploitation of Remote Services" +reference = "https://attack.mitre.org/techniques/T1210/" + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" + diff --git a/rules/integrations/lmd/lateral_movement_ml_spike_in_rdp_processes.toml b/rules/integrations/lmd/lateral_movement_ml_spike_in_rdp_processes.toml new file mode 100644 index 000000000..540ee068b --- /dev/null +++ b/rules/integrations/lmd/lateral_movement_ml_spike_in_rdp_processes.toml @@ -0,0 +1,44 @@ +[metadata] +creation_date = "2023/09/12" +integration = ["lmd"] +maturity = "production" +min_stack_comments = "New fields added: required_fields, related_integrations, setup" +min_stack_version = "8.3.0" +updated_date = "2023/09/21" + +[rule] +anomaly_threshold = 70 +author = ["Elastic"] +description = """ +A machine learning job has detected unusually high number of processes started in a single RDP session. Executing a +large number of processes remotely on other machines can be an indicator of lateral movement activity. +""" +from = "now-12h" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "lmd_high_sum_rdp_number_of_processes" +name = "Spike in Number of Processes in an RDP Session" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "19e9daf3-f5c5-4bc2-a9af-6b1e97098f03" +severity = "low" +tags = [ + "Use Case: Lateral Movement Detection", + "Rule Type: ML", + "Rule Type: Machine Learning", + "Tactic: Lateral Movement", +] +type = "machine_learning" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1210" +name = "Exploitation of Remote Services" +reference = "https://attack.mitre.org/techniques/T1210/" + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" + diff --git a/rules/integrations/lmd/lateral_movement_ml_spike_in_remote_file_transfers.toml b/rules/integrations/lmd/lateral_movement_ml_spike_in_remote_file_transfers.toml new file mode 100644 index 000000000..28b32edd9 --- /dev/null +++ b/rules/integrations/lmd/lateral_movement_ml_spike_in_remote_file_transfers.toml @@ -0,0 +1,46 @@ +[metadata] +creation_date = "2023/09/13" +integration = ["lmd"] +maturity = "production" +min_stack_comments = "New fields added: required_fields, related_integrations, setup" +min_stack_version = "8.3.0" +updated_date = "2023/09/21" + +[rule] +anomaly_threshold = 70 +author = ["Elastic"] +description = """ +A machine learning job has detected an abnormal volume of remote files shared on the host indicating potential lateral +movement activity. One of the primary goals of attackers after gaining access to a network is to locate and exfiltrate +valuable information. Attackers might perform multiple small transfers to match normal egress activity in the network, +to evade detection. +""" +from = "now-90m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "lmd_high_count_remote_file_transfer" +name = "Spike in Remote File Transfers" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "e9b0902b-c515-413b-b80b-a8dcebc81a66" +severity = "low" +tags = [ + "Use Case: Lateral Movement Detection", + "Rule Type: ML", + "Rule Type: Machine Learning", + "Tactic: Lateral Movement", +] +type = "machine_learning" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1210" +name = "Exploitation of Remote Services" +reference = "https://attack.mitre.org/techniques/T1210/" + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" + diff --git a/rules/integrations/lmd/lateral_movement_ml_unusual_time_for_an_rdp_session.toml b/rules/integrations/lmd/lateral_movement_ml_unusual_time_for_an_rdp_session.toml new file mode 100644 index 000000000..db11bb949 --- /dev/null +++ b/rules/integrations/lmd/lateral_movement_ml_unusual_time_for_an_rdp_session.toml @@ -0,0 +1,45 @@ +[metadata] +creation_date = "2023/09/13" +integration = ["lmd"] +maturity = "production" +min_stack_comments = "New fields added: required_fields, related_integrations, setup" +min_stack_version = "8.3.0" +updated_date = "2023/09/21" + +[rule] +anomaly_threshold = 70 +author = ["Elastic"] +description = """ +A machine learning job has detected an RDP session started at an usual time or weekday. An RDP session at an unusual +time could be followed by other suspicious activities, so catching this is a good first step in detecting a larger +attack. +""" +from = "now-12h" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "lmd_unusual_time_weekday_rdp_session_start" +name = "Unusual Time or Day for an RDP Session" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "3f4e2dba-828a-452a-af35-fe29c5e78969" +severity = "low" +tags = [ + "Use Case: Lateral Movement Detection", + "Rule Type: ML", + "Rule Type: Machine Learning", + "Tactic: Lateral Movement", +] +type = "machine_learning" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1210" +name = "Exploitation of Remote Services" +reference = "https://attack.mitre.org/techniques/T1210/" + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" + diff --git a/rules/integrations/lmd/lateral_movement_remote_file_creation_in_sensitive_directory.toml b/rules/integrations/lmd/lateral_movement_remote_file_creation_in_sensitive_directory.toml new file mode 100644 index 000000000..ae7845747 --- /dev/null +++ b/rules/integrations/lmd/lateral_movement_remote_file_creation_in_sensitive_directory.toml @@ -0,0 +1,57 @@ +[metadata] +creation_date = "2023/09/13" +integration = ["lmd","endpoint"] +maturity = "production" +min_stack_comments = "New fields added: required_fields, related_integrations, setup" +min_stack_version = "8.3.0" +updated_date = "2023/09/21" + +[rule] +author = ["Elastic"] +description = """ +Discovery of files created by a remote host on sensitive directories and folders. Remote file creation in these +directories could indicate a malicious binary or script trying to compromise the system. +""" +from = "now-10m" +index = ["logs-endpoint.events.*"] +interval = "5m" +language = "eql" +license = "Elastic License v2" +name = "Remote File Creation on a Sensitive Directory" +references = ["https://www.elastic.co/es/blog/remote-desktop-protocol-connections-elastic-security"] +risk_score = 47 +rule_id = "2377946d-0f01-4957-8812-6878985f515d" +severity = "medium" +tags = ["Domain: Endpoint", "Use Case: Lateral Movement Detection", "Tactic: Lateral Movement", "Data Source: Elastic Defend"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +file where (event.action == "creation" or event.action == "modification") and +process.name:("System", "scp", "sshd", "smbd", "vsftpd", "sftp-server") and not +user.name:("SYSTEM", "root") and +(file.path : ("C*\\Users\\*\\AppData\\Roaming*", "C*\\Program*Files\\*", + "C*\\Windows\\*", "C*\\Windows\\System\\*", + "C*\\Windows\\System32\\*", "/etc/*", "/tmp*", + "/var/tmp*", "/home/*/.*", "/home/.*", "/usr/bin/*", + "/sbin/*", "/bin/*", "/usr/lib/*", "/usr/sbin/*", + "/usr/share/*", "/usr/local/*", "/var/lib/dpkg/*", + "/lib/systemd/*" + ) +) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1210" +name = "Exploitation of Remote Services" +reference = "https://attack.mitre.org/techniques/T1210/" + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" + diff --git a/tests/test_all_rules.py b/tests/test_all_rules.py index eaf7a86c7..458c0be1f 100644 --- a/tests/test_all_rules.py +++ b/tests/test_all_rules.py @@ -632,7 +632,8 @@ class TestRuleMetadata(BaseRuleTest): # checks if an index pattern exists if the package integration tag exists integration_string = "|".join(indices) if not re.search(rule_integration, integration_string): - if rule_integration == "windows" and re.search("winlog", integration_string): + if rule_integration == "windows" and re.search("winlog", integration_string) or \ + rule_integration in [*map(str.lower, definitions.MACHINE_LEARNING_PACKAGES)]: continue err_msg = f'{self.rule_str(rule)} {rule_integration} tag, index pattern missing.' failures.append(err_msg) @@ -658,7 +659,8 @@ class TestRuleMetadata(BaseRuleTest): ] if any([re.search("|".join(non_dataset_packages), i, re.IGNORECASE) for i in rule.contents.data.index]): - if not rule.contents.metadata.integration and rule.id not in ignore_ids: + if not rule.contents.metadata.integration and rule.id not in ignore_ids and \ + rule.contents.data.type not in definitions.MACHINE_LEARNING: err_msg = f'substrings {non_dataset_packages} found in '\ f'{self.rule_str(rule)} rule index patterns are {rule.contents.data.index},' \ f'but no integration tag found'