From a15a6260b4374ae7d4faf5fb2e80f17664155cad Mon Sep 17 00:00:00 2001 From: Ruben Groenewoud <78494512+Aegrah@users.noreply.github.com> Date: Tue, 7 Jan 2025 14:29:17 +0100 Subject: [PATCH] [New Hunts] Adding Several Hunting PRs into this Main PR (#4342) * [New Hunt] Linux PAM Persistence * Fixed notes * [New Hunt] Persistence via Dynamic Linker Hijacking * [New Hunt & Tuning] Persistence via LKMs * [New Hunt] Persistence via Web Shells * Update query * [New Rule] Persistence via DPKG/RPM Package * [New Hunt] Persistence via Container * Update hunting/linux/queries/persistence_via_pluggable_authentication_module.toml * [Hunt Addition] System User Interactive Session * Merge branch 'main' into new-hunts-PAM * Updates * ++ * Match RTA bin executor --------- Co-authored-by: Shashank K S (cherry picked from commit a2b280a6fd00859b12525f255b12e5696b27751d) --- ...sume_role_creation_with_attached_policy.md | 1 + ...ged_policies_attached_to_existing_roles.md | 14 +-- ...rmissions_for_write_actions_to_function.md | 1 + ...tor_console_login_via_federated_session.md | 1 + ...sm_sendcommand_api_used_by_ec2_instance.md | 1 + ..._federated_temporary_credential_request.md | 1 + hunting/index.md | 6 + hunting/index.yml | 30 +++++ ...iver_load_with_low_occurrence_frequency.md | 6 +- ...ersistence_via_dynamic_linker_hijacking.md | 105 ++++++++++++++++++ ...persistence_via_loadable_kernel_modules.md | 89 +++++++++++++++ ...sistence_via_malicious_docker_container.md | 86 ++++++++++++++ ...nce_via_pluggable_authentication_module.md | 92 +++++++++++++++ ...istence_via_rpm_dpkg_installer_packages.md | 90 +++++++++++++++ ...istence_via_ssh_configurations_and_keys.md | 14 ++- .../linux/docs/persistence_via_web_shell.md | 61 ++++++++++ ...er_load_with_low_occurrence_frequency.toml | 6 +- ...sistence_via_dynamic_linker_hijacking.toml | 90 +++++++++++++++ ...rsistence_via_loadable_kernel_modules.toml | 75 +++++++++++++ ...stence_via_malicious_docker_container.toml | 69 ++++++++++++ ...e_via_pluggable_authentication_module.toml | 79 +++++++++++++ ...tence_via_rpm_dpkg_installer_packages.toml | 77 +++++++++++++ ...tence_via_ssh_configurations_and_keys.toml | 13 ++- .../queries/persistence_via_web_shell.toml | 49 ++++++++ ...s_token_retrieval_via_public_client_app.md | 2 + pyproject.toml | 2 +- 26 files changed, 1046 insertions(+), 14 deletions(-) create mode 100644 hunting/linux/docs/persistence_via_dynamic_linker_hijacking.md create mode 100644 hunting/linux/docs/persistence_via_loadable_kernel_modules.md create mode 100644 hunting/linux/docs/persistence_via_malicious_docker_container.md create mode 100644 hunting/linux/docs/persistence_via_pluggable_authentication_module.md create mode 100644 hunting/linux/docs/persistence_via_rpm_dpkg_installer_packages.md create mode 100644 hunting/linux/docs/persistence_via_web_shell.md create mode 100644 hunting/linux/queries/persistence_via_dynamic_linker_hijacking.toml create mode 100644 hunting/linux/queries/persistence_via_loadable_kernel_modules.toml create mode 100644 hunting/linux/queries/persistence_via_malicious_docker_container.toml create mode 100644 hunting/linux/queries/persistence_via_pluggable_authentication_module.toml create mode 100644 hunting/linux/queries/persistence_via_rpm_dpkg_installer_packages.toml create mode 100644 hunting/linux/queries/persistence_via_web_shell.toml diff --git a/hunting/aws/docs/iam_assume_role_creation_with_attached_policy.md b/hunting/aws/docs/iam_assume_role_creation_with_attached_policy.md index a6222151f24..a26ddb52adf 100644 --- a/hunting/aws/docs/iam_assume_role_creation_with_attached_policy.md +++ b/hunting/aws/docs/iam_assume_role_creation_with_attached_policy.md @@ -26,6 +26,7 @@ from logs-aws.cloudtrail-* and aws.cloudtrail.request_parameters RLIKE ".*arn:aws:iam.*" | dissect aws.cloudtrail.request_parameters "%{}AWS\": \"arn:aws:iam::%{target_account_id}:" | where cloud.account.id != target_account_id +| keep @timestamp, event.provider, event.action, aws.cloudtrail.request_parameters, target_account_id, cloud.account.id ``` ## Notes diff --git a/hunting/aws/docs/iam_customer_managed_policies_attached_to_existing_roles.md b/hunting/aws/docs/iam_customer_managed_policies_attached_to_existing_roles.md index da7536e46bd..0b08ad31a14 100644 --- a/hunting/aws/docs/iam_customer_managed_policies_attached_to_existing_roles.md +++ b/hunting/aws/docs/iam_customer_managed_policies_attached_to_existing_roles.md @@ -1,4 +1,4 @@ -# AWS IAM Customer-Managed Policy Attachment for Privilege Escalation +# AWS IAM Customer-Managed Policy Attachment to Existing Roles --- @@ -10,7 +10,7 @@ - **UUID:** `418baaf2-9ae1-11ef-be63-f661ea17fbcd` - **Integration:** [aws.cloudtrail](https://docs.elastic.co/integrations/aws/cloudtrail) - **Language:** `[ES|QL]` -- **Source File:** [AWS IAM Customer-Managed Policy Attachment for Privilege Escalation](../queries/iam_customer_managed_policies_attached_to_existing_roles.toml) +- **Source File:** [AWS IAM Customer-Managed Policy Attachment to Existing Roles](../queries/iam_customer_managed_policies_attached_to_existing_roles.toml) ## Query @@ -29,11 +29,11 @@ from logs-aws.cloudtrail* ## Notes -- Review the `target_account_id` field to verify the AWS account in which the role is being modified, especially if this account is outside of your organization’s typical accounts. -- Examine `aws.cloudtrail.request_parameters` for details on the role and attached policy. Customer-managed policies granting overly permissive access, such as `AdministratorAccess`, may signal unauthorized privilege escalation. -- Cross-reference `event.action` values where `AttachRolePolicy` appears to further investigate attached policies that could enable lateral movement or persistence. -- Evaluate `aws.cloudtrail.user_identity.arn` to confirm if the actor attaching the policy has legitimate permissions for this action. Anomalous or unauthorized actors may indicate privilege abuse. -- Look for patterns of multiple `AttachRolePolicy` actions across roles by the same user or entity. High frequency of these actions could suggest an attempt to establish persistent control across roles within your AWS environment. +- Review the `attached_policy_name` and `target_role_name` fields to identify the customer-managed policy and role involved in the attachment. +- Review the permissions of the attached policy to determine the potential impact of the privilege escalation attempt. +- Review all entities that `target_role_name` may be attached to as these entities may have been compromised or misused. +- Consider reviewing the `aws.cloudtrail.user_identity.arn` field to identify the actor responsible for the privilege escalation attempt. +- Review the user agent of the actor to determine the source of the privilege escalation attempt, such as an AWS CLI or SDK. ## MITRE ATT&CK Techniques diff --git a/hunting/aws/docs/lambda_add_permissions_for_write_actions_to_function.md b/hunting/aws/docs/lambda_add_permissions_for_write_actions_to_function.md index 470d7489f91..5f20d0ca2a3 100644 --- a/hunting/aws/docs/lambda_add_permissions_for_write_actions_to_function.md +++ b/hunting/aws/docs/lambda_add_permissions_for_write_actions_to_function.md @@ -24,6 +24,7 @@ from logs-aws.cloudtrail-* | dissect aws.cloudtrail.request_parameters "{%{?principal_key}=%{principal_id}, %{?function_name_key}=%{function_name}, %{?statement_key}=%{statement_value}, %{?action_key}=lambda:%{action_value}}" | eval write_action = (starts_with(action_value, "Invoke") or starts_with("Update", action_value) or starts_with("Put", action_value)) | where write_action == true +| keep @timestamp, principal_id, event.provider, event.action, aws.cloudtrail.request_parameters, principal_id, function_name, action_value, statement_value, write_action ``` ## Notes diff --git a/hunting/aws/docs/signin_single_factor_console_login_via_federated_session.md b/hunting/aws/docs/signin_single_factor_console_login_via_federated_session.md index ecd2a3302d5..ddc1864d98a 100644 --- a/hunting/aws/docs/signin_single_factor_console_login_via_federated_session.md +++ b/hunting/aws/docs/signin_single_factor_console_login_via_federated_session.md @@ -24,6 +24,7 @@ from logs-aws.cloudtrail-* and aws.cloudtrail.user_identity.type == "FederatedUser" | dissect aws.cloudtrail.additional_eventdata "{%{?mobile_version_key}=%{mobile_version}, %{?mfa_used_key}=%{mfa_used}}" | where mfa_used == "No" +| keep @timestamp, event.provider, event.action, aws.cloudtrail.event_type, aws.cloudtrail.user_identity.type, aws.cloudtrail.additional_eventdata, mobile_version, mfa_used ``` ## Notes diff --git a/hunting/aws/docs/ssm_sendcommand_api_used_by_ec2_instance.md b/hunting/aws/docs/ssm_sendcommand_api_used_by_ec2_instance.md index fdd7a7be660..3f70647239c 100644 --- a/hunting/aws/docs/ssm_sendcommand_api_used_by_ec2_instance.md +++ b/hunting/aws/docs/ssm_sendcommand_api_used_by_ec2_instance.md @@ -22,6 +22,7 @@ from logs-aws.cloudtrail-* and aws.cloudtrail.user_identity.type == "AssumedRole" and event.action == "SendCommand" and user.id like "*:i-*" +| keep @timestamp, event.provider, event.action, aws.cloudtrail.user_identity.type, user.id, aws.cloudtrail.request_parameters ``` ## Notes diff --git a/hunting/aws/docs/sts_suspicious_federated_temporary_credential_request.md b/hunting/aws/docs/sts_suspicious_federated_temporary_credential_request.md index 3b20d7e45bb..469ebb88cd4 100644 --- a/hunting/aws/docs/sts_suspicious_federated_temporary_credential_request.md +++ b/hunting/aws/docs/sts_suspicious_federated_temporary_credential_request.md @@ -26,6 +26,7 @@ from logs-aws.cloudtrail-* | dissect aws.cloudtrail.request_parameters "{%{}policyArns=[%{policies_applied}]" | eval duration_minutes = to_integer(duration_requested) / 60 | where (duration_minutes > 1440) or (policies_applied RLIKE ".*AdministratorAccess.*") +| keep @timestamp, event.dataset, event.provider, event.action, aws.cloudtrail.request_parameters, user_name, duration_requested, duration_minutes, policies_applied ``` ## Notes diff --git a/hunting/index.md b/hunting/index.md index 7b014415d8b..81070ab0372 100644 --- a/hunting/index.md +++ b/hunting/index.md @@ -40,12 +40,18 @@ Here are the queries currently available: - [OSQuery SUID Hunting](./linux/docs/privilege_escalation_via_suid_binaries.md) (ES|QL) - [Persistence Through Reverse/Bind Shells](./linux/docs/persistence_reverse_bind_shells.md) (ES|QL) - [Persistence via Cron](./linux/docs/persistence_via_cron.md) (ES|QL) +- [Persistence via DPKG/RPM Package](./linux/docs/persistence_via_rpm_dpkg_installer_packages.md) (ES|QL) +- [Persistence via Docker Container](./linux/docs/persistence_via_malicious_docker_container.md) (ES|QL) +- [Persistence via Dynamic Linker Hijacking](./linux/docs/persistence_via_dynamic_linker_hijacking.md) (ES|QL) +- [Persistence via Loadable Kernel Modules](./linux/docs/persistence_via_loadable_kernel_modules.md) (ES|QL) - [Persistence via Message-of-the-Day](./linux/docs/persistence_via_message_of_the_day.md) (ES|QL) - [Persistence via Package Manager](./linux/docs/persistence_via_package_manager.md) (ES|QL) +- [Persistence via Pluggable Authentication Modules (PAM)](./linux/docs/persistence_via_pluggable_authentication_module.md) (ES|QL) - [Persistence via SSH Configurations and/or Keys](./linux/docs/persistence_via_ssh_configurations_and_keys.md) (ES|QL) - [Persistence via System V Init](./linux/docs/persistence_via_sysv_init.md) (ES|QL) - [Persistence via Systemd (Timers)](./linux/docs/persistence_via_systemd_timers.md) (ES|QL) - [Persistence via Udev](./linux/docs/persistence_via_udev.md) (ES|QL) +- [Persistence via Web Shell](./linux/docs/persistence_via_web_shell.md) (ES|QL) - [Persistence via rc.local/rc.common](./linux/docs/persistence_via_rc_local.md) (ES|QL) - [Potential Defense Evasion via Multi-Dot Process Execution](./linux/docs/defense_evasion_via_multi_dot_process_execution.md) (ES|QL) - [Privilege Escalation Identification via Existing Sudoers File](./linux/docs/privilege_escalation_via_existing_sudoers.md) (ES|QL) diff --git a/hunting/index.yml b/hunting/index.yml index ba1152c6d7e..053f73f2254 100644 --- a/hunting/index.yml +++ b/hunting/index.yml @@ -220,6 +220,36 @@ linux: mitre: - T1037.004 - T1546.003 + 2a3c46b8-7bd6-4bc4-a4a8-a1af114ea152: + name: Persistence via Pluggable Authentication Modules (PAM) + path: ./linux/queries/persistence_via_pluggable_authentication_module.toml + mitre: + - T1556.003 + 664d65ec-029e-4746-bf97-7bf3a0113e6a: + name: Persistence via Dynamic Linker Hijacking + path: ./linux/queries/persistence_via_dynamic_linker_hijacking.toml + mitre: + - T1574.006 + d667d328-fadc-4a52-9b46-f42b1a83181c: + name: Persistence via Loadable Kernel Modules + path: ./linux/queries/persistence_via_loadable_kernel_modules.toml + mitre: + - T1547.006 + e2e4a1ad-5e03-4968-927c-9ef13c49a3b8: + name: Persistence via Web Shell + path: ./linux/queries/persistence_via_web_shell.toml + mitre: + - T1505.003 + 1d7cae97-2dea-4f01-b04c-85fa4bd991d0: + name: Persistence via DPKG/RPM Package + path: ./linux/queries/persistence_via_rpm_dpkg_installer_packages.toml + mitre: + - T1546.016 + b9b4f11f-1db9-491a-ab43-0e69e3f6d5be: + name: Persistence via Docker Container + path: ./linux/queries/persistence_via_malicious_docker_container.toml + mitre: + - T1610 okta: 0b936024-71d9-11ef-a9be-f661ea17fbcc: name: Failed OAuth Access Token Retrieval via Public Client App diff --git a/hunting/linux/docs/persistence_via_driver_load_with_low_occurrence_frequency.md b/hunting/linux/docs/persistence_via_driver_load_with_low_occurrence_frequency.md index bc09a71d8e3..185d1c99c4e 100644 --- a/hunting/linux/docs/persistence_via_driver_load_with_low_occurrence_frequency.md +++ b/hunting/linux/docs/persistence_via_driver_load_with_low_occurrence_frequency.md @@ -16,11 +16,13 @@ ```sql from logs-auditd_manager.auditd-*, logs-auditd.log-*, auditbeat-* +| keep @timestamp, host.os.type, event.category, event.action, auditd.data.syscall, auditd.data.name, process.executable, process.name, agent.id | where @timestamp > now() - 30 day | where host.os.type == "linux" and event.category == "driver" and event.action == "loaded-kernel-module" and auditd.data.syscall in ("init_module", "finit_module") -| stats host_count = count_distinct(host.id), total_count = count(*) by auditd.data.name, process.executable, process.name +// Process name is different from executable in some cases +| stats agent_count = count_distinct(agent.id), total_count = count(*) by auditd.data.name, process.executable, process.name // Alter this threshold to make sense for your environment -| where host_count == 1 and total_count == 1 +| where agent_count == 1 and total_count <= 3 | limit 100 | sort auditd.data.name asc ``` diff --git a/hunting/linux/docs/persistence_via_dynamic_linker_hijacking.md b/hunting/linux/docs/persistence_via_dynamic_linker_hijacking.md new file mode 100644 index 00000000000..5c6f98f50c7 --- /dev/null +++ b/hunting/linux/docs/persistence_via_dynamic_linker_hijacking.md @@ -0,0 +1,105 @@ +# Persistence via Dynamic Linker Hijacking + +--- + +## Metadata + +- **Author:** Elastic +- **Description:** This hunt identifies potential persistence mechanisms via dynamic linker hijacking on Linux systems. Attackers can manipulate environment variables like LD_PRELOAD and LD_LIBRARY_PATH to execute malicious shared libraries, hijacking the dynamic linker process for persistence or privilege escalation. This hunt monitors for suspicious usage of these environment variables, the creation of shared library files (.so), and access to critical dynamic linker configuration files. + +- **UUID:** `664d65ec-029e-4746-bf97-7bf3a0113e6a` +- **Integration:** [endpoint](https://docs.elastic.co/integrations/endpoint) +- **Language:** `[ES|QL, SQL]` +- **Source File:** [Persistence via Dynamic Linker Hijacking](../queries/persistence_via_dynamic_linker_hijacking.toml) + +## Query + +```sql +from logs-endpoint.events.process-* +| keep @timestamp, host.os.type, event.type, event.action, process.env_vars, agent.id +| where @timestamp > now() - 30 days +| where host.os.type == "linux" and event.type == "start" and event.action == "exec" and +process.env_vars like "LD_PRELOAD=*.so" or +process.env_vars like "LD_LIBRARY_PATH=*" +| stats env_count = count(process.env_vars) by agent.id, process.env_vars +``` + +```sql +from logs-endpoint.events.file-* +| keep @timestamp, host.os.type, event.type, event.action, file.extension, file.path, process.executable, agent.id +| where @timestamp > now() - 30 days +| where host.os.type == "linux" and event.type == "creation" and file.extension == "so" and not ( + // Add your exclusions here + file.path like "/run/initramfs/*" or + file.path like "/var/tmp/mkinitramfs*" +) +| stats cc = count(), agent_count = count_distinct(agent.id) by file.path, process.executable +| where agent_count <= 3 +| sort cc asc +| limit 100 +``` + +```sql +SELECT * FROM process_envs +WHERE key = "LD_PRELOAD" +OR key = "LD_LIBRARY_PATH"; +``` + +```sql +SELECT + f.filename, + f.path, + u.username AS file_owner, + g.groupname AS group_owner, + datetime(f.atime, 'unixepoch') AS file_last_access_time, + datetime(f.mtime, 'unixepoch') AS file_last_modified_time, + datetime(f.ctime, 'unixepoch') AS file_last_status_change_time + datetime(f.btime, 'unixepoch') AS file_created_time, + f.size AS size_bytes +FROM + file f +LEFT JOIN + users u ON f.uid = u.uid +LEFT JOIN + groups g ON f.gid = g.gid +WHERE + f.path = "/etc/ld.so.preload" + OR f.path = "/etc/ld.so.conf" + OR f.path = "/etc/ld.so.cache" + OR f.path LIKE "/etc/ld.so.conf.d/%"; +``` + +```sql +SELECT + p.pid, + p.name AS process_name, + p.path AS process_path, + p.cmdline AS command_line, + pe.key AS env_key, + pe.value AS env_value, + (strftime('%s', 'now') - p.start_time) AS runtime_seconds +FROM + processes p +JOIN + process_envs pe ON p.pid = pe.pid +WHERE + pe.key IN ('LD_PRELOAD', 'LD_LIBRARY_PATH') + AND (strftime('%s', 'now') - p.start_time) > 3600; +``` + +## Notes + +- Identifies processes with suspicious environment variables, specifically LD_PRELOAD and LD_LIBRARY_PATH, which are often used in dynamic linker hijacking attacks. +- Monitors the creation of shared object (.so) files in non-standard or uncommon directories to detect potential malicious libraries. +- Tracks modifications to critical dynamic linker files like /etc/ld.so.preload, /etc/ld.so.conf, and related directories, which are common targets for attackers. +- Uses process environment variables and metadata to detect running processes that rely on suspicious linker configurations, focusing on processes that persist longer than typical short-lived tasks. +- Provides complementary OSQuery queries for detailed file metadata, including file ownership and timestamps, to support forensic investigations. +- This hunt leverages the process.env_vars field, which is a field that must be manually enabled within the Elastic Defend policy advanced settings tab. + +## MITRE ATT&CK Techniques + +- [T1574.006](https://attack.mitre.org/techniques/T1574/006) + +## License + +- `Elastic License v2` diff --git a/hunting/linux/docs/persistence_via_loadable_kernel_modules.md b/hunting/linux/docs/persistence_via_loadable_kernel_modules.md new file mode 100644 index 00000000000..4ef7eb0bebe --- /dev/null +++ b/hunting/linux/docs/persistence_via_loadable_kernel_modules.md @@ -0,0 +1,89 @@ +# Persistence via Loadable Kernel Modules + +--- + +## Metadata + +- **Author:** Elastic +- **Description:** This hunt identifies potential persistence mechanisms leveraging Loadable Kernel Modules (LKMs) on Linux systems. LKMs enable dynamic extension of kernel functionality but can be abused by attackers to load malicious code into the kernel, granting them high privileges or persistence. This hunt monitors suspicious kernel module file creations, LKM-related process executions, and access to kernel module configuration files. + +- **UUID:** `d667d328-fadc-4a52-9b46-f42b1a83181c` +- **Integration:** [endpoint](https://docs.elastic.co/integrations/endpoint) +- **Language:** `[ES|QL, SQL]` +- **Source File:** [Persistence via Loadable Kernel Modules](../queries/persistence_via_loadable_kernel_modules.toml) + +## Query + +```sql +from logs-endpoint.events.file-* +| keep @timestamp, host.os.type, event.type, event.action, file.extension, file.path, process.executable, agent.id +| where @timestamp > now() - 30 day +| where host.os.type == "linux" and event.type == "creation" and file.extension == "ko" and not ( + // Add your exclusions here + file.path like "/run/initramfs/*" or + file.path like "/var/tmp/mkinitramfs*" +) +| stats cc = count(), agent_count = count_distinct(agent.id) by file.path, process.executable +| where agent_count <= 3 +| sort cc asc +| limit 100 +``` + +```sql +from logs-endpoint.events.process-* +| keep @timestamp, host.os.type, event.type, event.action, process.name, agent.id, process.args, process.args_count +| where @timestamp > now() - 30 days +| where host.os.type == "linux" and event.type == "start" and event.action == "exec" and process.name in ("kmod", "modprobe", "insmod", "rmmod") +| stats cc = count(), agent_count = count_distinct(agent.id) by process.args, process.args_count +| where cc == 1 and agent_count == 1 and process.args_count <= 3 +| sort cc asc +| limit 100 +``` + +```sql +SELECT + f.filename, + f.path, + u.username AS file_owner, + g.groupname AS group_owner, + datetime(f.atime, 'unixepoch') AS file_last_access_time, + datetime(f.mtime, 'unixepoch') AS file_last_modified_time, + datetime(f.ctime, 'unixepoch') AS file_last_status_change_time + datetime(f.btime, 'unixepoch') AS file_created_time, + f.size AS size_bytes +FROM + file f +LEFT JOIN + users u ON f.uid = u.uid +LEFT JOIN + groups g ON f.gid = g.gid +WHERE + f.path LIKE '/etc/modprobe.d/%' + OR f.path LIKE '/usr/lib/modprobe.d/%' + OR f.path LIKE '/usr/lib/security/%' + OR f.path LIKE '/etc/modules-load.d/%' + OR f.path LIKE '/run/modules-load.d/%' + OR f.path LIKE '/usr/local/lib/modules-load.d/%' + OR f.path like '/usr/lib/modules-load.d/%' + OR f.path = '/etc/modules' +``` + +```sql +SELECT * FROM kernel_modules; +``` + +## Notes + +- Tracks the creation of loadable kernel module files (.ko) in non-standard directories to identify potential malicious modules. +- Monitors the execution of processes related to kernel module management, such as kmod, modprobe, insmod, and rmmod, to detect suspicious or unusual activity. +- Identifies changes to critical kernel module configuration files, including /etc/modprobe.d/, /etc/modules, and related paths. +- Uses OSQuery queries to gather detailed metadata on kernel modules currently loaded, supporting forensic analysis of potential persistence mechanisms. +- Provides statistics and counts to help identify rare or anomalous kernel module-related events. + +## MITRE ATT&CK Techniques + +- [T1547.006](https://attack.mitre.org/techniques/T1547/006) + +## License + +- `Elastic License v2` diff --git a/hunting/linux/docs/persistence_via_malicious_docker_container.md b/hunting/linux/docs/persistence_via_malicious_docker_container.md new file mode 100644 index 00000000000..d82417ecff7 --- /dev/null +++ b/hunting/linux/docs/persistence_via_malicious_docker_container.md @@ -0,0 +1,86 @@ +# Persistence via Docker Container + +--- + +## Metadata + +- **Author:** Elastic +- **Description:** This hunt identifies potential persistence mechanisms through malicious Docker containers on Linux systems. Attackers can abuse Docker's capabilities, such as privileged containers, host namespace sharing, or mounting sensitive host paths, to maintain persistence or gain unauthorized access to the host. This hunt focuses on detecting suspicious container creations, modifications, and network connections. + +- **UUID:** `b9b4f11f-1db9-491a-ab43-0e69e3f6d5be` +- **Integration:** [endpoint](https://docs.elastic.co/integrations/endpoint) +- **Language:** `[ES|QL, SQL]` +- **Source File:** [Persistence via Docker Container](../queries/persistence_via_malicious_docker_container.toml) + +## Query + +```sql +from logs-endpoint.events.network-* +| keep @timestamp, host.os.type, event.type, event.action, process.executable, destination.ip, agent.id, process.executable, process.command_line +| where @timestamp > now() - 7 days +| where host.os.type == "linux" and event.type == "start" and event.action == "connection_attempted" and +process.executable like "/var/lib/docker/*" and destination.ip IS NOT null and not +CIDR_MATCH( + destination.ip, + // Exclude common destination IP ranges for your environment here + "127.0.0.0/8", "169.254.0.0/16", "224.0.0.0/4", "::1", "172.18.0.0/16" +) +| stats cc = count(), agent_count = count_distinct(agent.id) by process.executable, process.command_line, destination.ip +| where agent_count <= 3 +| sort cc asc +| limit 100 +``` + +```sql +SELECT * FROM docker_containers +``` + +```sql +SELECT * FROM docker_containers +WHERE privileged = 1 +``` + +```sql +SELECT * FROM docker_containers +WHERE created <= strftime('%s', 'now') +AND strftime('%s', 'now') - created <= (7 * 86400); -- Created in the last 7 days +``` + +```sql +SELECT * FROM docker_images +``` + +```sql +SELECT * FROM docker_images +WHERE strftime('%s', 'now') - created <= (7 * 86400); -- Pulled in the last 7 days +``` + +```sql +SELECT + id AS container_id, + name AS container_name, + source AS host_path, + destination AS container_path, + rw AS is_read_write +FROM + docker_container_mounts +WHERE + source IN ('/var/run/docker.sock', '/', '/etc', '/var/lib/docker'); + -- Add your own list of additional sources here +``` + +## Notes + +- Monitors for unusual network connections initiated by Docker containers, focusing on non-local IP addresses to identify potentially malicious activity. +- Detects Docker containers running in privileged mode, which may indicate a risk of host compromise. +- Identifies recently created Docker containers and images to highlight potential unauthorized deployments or suspicious additions. +- Analyzes Docker container mount points to detect access to sensitive host directories, such as /var/run/docker.sock or /etc, which could enable container escape or host-level compromise. +- Provides OSQuery queries to gather additional context about running containers, their configurations, and associated image metadata for forensic analysis. + +## MITRE ATT&CK Techniques + +- [T1610](https://attack.mitre.org/techniques/T1610) + +## License + +- `Elastic License v2` diff --git a/hunting/linux/docs/persistence_via_pluggable_authentication_module.md b/hunting/linux/docs/persistence_via_pluggable_authentication_module.md new file mode 100644 index 00000000000..0818005cfce --- /dev/null +++ b/hunting/linux/docs/persistence_via_pluggable_authentication_module.md @@ -0,0 +1,92 @@ +# Persistence via Pluggable Authentication Modules (PAM) + +--- + +## Metadata + +- **Author:** Elastic +- **Description:** This hunt identifies potential persistence mechanisms leveraging Pluggable Authentication Modules (PAM) on Linux systems. PAM is a powerful framework for managing authentication-related tasks, but its flexibility can be abused by attackers to introduce malicious modules or modify configurations to gain unauthorized access or establish persistence. This hunt monitors for modifications to PAM-related files, directories, and modules. + +- **UUID:** `2a3c46b8-7bd6-4bc4-a4a8-a1af114ea152` +- **Integration:** [endpoint](https://docs.elastic.co/integrations/endpoint) +- **Language:** `[ES|QL, SQL]` +- **Source File:** [Persistence via Pluggable Authentication Modules (PAM)](../queries/persistence_via_pluggable_authentication_module.toml) + +## Query + +```sql +from logs-endpoint.events.file-* +| keep @timestamp, host.os.type, event.type, event.action, file.path, process.executable, agent.id +| where @timestamp > now() - 7 days +| where host.os.type == "linux" and event.action in ("rename", "creation") and ( + file.path like "/lib/security/*" or + file.path like "/lib64/security/*" or + file.path like "/usr/lib64/security/*" or + file.path like "/usr/lib/x86_64-linux-gnu/security/*" or + file.path like "/lib/x86_64-linux-gnu/security/*" or + file.path like "/etc/pam.d/*" or + file.path == "/etc/pam.conf" +) +| stats cc = count(), agent_count = count_distinct(agent.id) by file.path, process.executable +| where agent_count <= 3 +| sort cc asc +| limit 100 +``` + +```sql +SELECT + f.filename, + f.path, + u.username AS file_owner, + g.groupname AS group_owner, + datetime(f.atime, 'unixepoch') AS file_last_access_time, + datetime(f.mtime, 'unixepoch') AS file_last_modified_time, + datetime(f.ctime, 'unixepoch') AS file_last_status_change_time + datetime(f.btime, 'unixepoch') AS file_created_time, + f.size AS size_bytes +FROM + file f +LEFT JOIN + users u ON f.uid = u.uid +LEFT JOIN + groups g ON f.gid = g.gid +WHERE + f.path LIKE '/lib/security/%' + OR f.path LIKE '/lib64/security/%' + OR f.path LIKE '/usr/lib/security/%' + OR f.path LIKE '/usr/lib64/security/%' + OR f.path LIKE '/usr/lib/x86_64-linux-gnu/security/%' + OR f.path LIKE '/lib/x86_64-linux-gnu/security/%' + OR f.path like '/etc/pam.d/%' + OR f.path = '/etc/pam.conf' +``` + +```sql +SELECT * FROM file +WHERE ( + path LIKE '/lib/security/%' + OR path LIKE '/lib64/security/%' + OR path LIKE '/usr/lib/security/%' + OR path LIKE '/usr/lib64/security/%' + OR path LIKE '/usr/lib/x86_64-linux-gnu/security/%' + OR path LIKE '/lib/x86_64-linux-gnu/security/%' + OR path like '/etc/pam.d/%' + OR path = '/etc/pam.conf' + ) +AND (mtime > strftime('%s', 'now') - (7 * 86400)); -- Modified in the last 7 days +``` + +## Notes + +- PAM modules are critical to Linux authentication workflows, but they can be abused to establish persistence or execute malicious actions. +- This hunt identifies suspicious file creation or modification events in PAM directories, such as /etc/pam.d/, /lib/security/, and related paths. +- Uses ES|QL queries to track file events and identify potentially malicious activity based on process activity and file paths. +- Complemented by OSQuery queries to provide detailed file metadata for modified PAM-related files, including timestamps and ownership information. + +## MITRE ATT&CK Techniques + +- [T1556.003](https://attack.mitre.org/techniques/T1556/003) + +## License + +- `Elastic License v2` diff --git a/hunting/linux/docs/persistence_via_rpm_dpkg_installer_packages.md b/hunting/linux/docs/persistence_via_rpm_dpkg_installer_packages.md new file mode 100644 index 00000000000..238898074c4 --- /dev/null +++ b/hunting/linux/docs/persistence_via_rpm_dpkg_installer_packages.md @@ -0,0 +1,90 @@ +# Persistence via DPKG/RPM Package + +--- + +## Metadata + +- **Author:** Elastic +- **Description:** This hunt identifies potential persistence mechanisms leveraging DPKG or RPM package managers on Linux systems. These tools, used for installing and managing software, can be exploited by attackers to execute malicious scripts or establish persistence via lifecycle scripts (preinst, postinst, prerm, postrm). This hunt focuses on detecting suspicious file creations and anomalous process activity related to these package managers. + +- **UUID:** `1d7cae97-2dea-4f01-b04c-85fa4bd991d0` +- **Integration:** [endpoint](https://docs.elastic.co/integrations/endpoint) +- **Language:** `[ES|QL, SQL]` +- **Source File:** [Persistence via DPKG/RPM Package](../queries/persistence_via_rpm_dpkg_installer_packages.toml) + +## Query + +```sql +from logs-endpoint.events.file-* +| keep @timestamp, host.os.type, event.action, file.path, file.name, agent.id, process.executable +| where @timestamp > now() - 7 days +| where host.os.type == "linux" and event.action in ("rename", "creation") and ( + file.path like "/var/lib/dpkg/info/*" or + file.path like "/var/lib/rpm/*" +) and not ( + // Remove these exclusions if you have a high suspicion of this activity + // Add additional exclusions here if necessary based on your environment + file.name like "*-new" or + file.name like "__db*.*" or + file.name like "*.list" or + file.name like "*.md5sums*" +) +| stats cc = count(), agent_count = count_distinct(agent.id) by file.name, process.executable +| where agent_count <= 3 +| sort cc asc +| limit 100 +``` + +```sql +from logs-endpoint.events.process-* +| keep @timestamp, host.os.type, event.type, event.action, process.parent.command_line, process.parent.executable, agent.id, process.executable, process.command_line +| where @timestamp > now() - 7 days +| where host.os.type == "linux" and event.type == "start" and event.action == "exec" and ( + process.parent.command_line like "*/var/tmp/rpm-tmp.*" or + process.parent.executable like "/var/lib/dpkg/info/*" +) +| stats cc = count(), agent_count = count_distinct(agent.id) by process.executable, process.command_line +| where agent_count <= 3 +| sort cc asc +| limit 100 +``` + +```sql +SELECT + f.filename, + f.path, + u.username AS file_owner, + g.groupname AS group_owner, + datetime(f.atime, 'unixepoch') AS file_last_access_time, + datetime(f.mtime, 'unixepoch') AS file_last_modified_time, + datetime(f.ctime, 'unixepoch') AS file_last_status_change_time, + datetime(f.btime, 'unixepoch') AS file_created_time, + f.size AS size_bytes +FROM + file f +LEFT JOIN + users u ON f.uid = u.uid +LEFT JOIN + groups g ON f.gid = g.gid +WHERE ( + f.path LIKE '/var/lib/dpkg/info/%' + OR f.path LIKE '/var/lib/rpm/%' + ) +AND (mtime > strftime('%s', 'now') - (7 * 86400)); -- Modified in the last 7 days +``` + +## Notes + +- Monitors for the creation or renaming of files in directories associated with DPKG and RPM package managers, such as /var/lib/dpkg/info/ and /var/lib/rpm/. +- Excludes common benign file patterns (e.g., temporary files, checksum files, or list files) to reduce noise while detecting unusual modifications. +- Analyzes processes executed from lifecycle scripts or directories associated with package managers, such as /var/tmp/rpm-tmp.* and /var/lib/dpkg/info/*. +- Uses OSQuery queries to gather detailed metadata on files and directories modified by package management activities for forensic analysis. +- Provides counts and statistics to help highlight rare or unusual package management-related activity. + +## MITRE ATT&CK Techniques + +- [T1546.016](https://attack.mitre.org/techniques/T1546/016) + +## License + +- `Elastic License v2` diff --git a/hunting/linux/docs/persistence_via_ssh_configurations_and_keys.md b/hunting/linux/docs/persistence_via_ssh_configurations_and_keys.md index 74ababb2c37..1d53cae90c8 100644 --- a/hunting/linux/docs/persistence_via_ssh_configurations_and_keys.md +++ b/hunting/linux/docs/persistence_via_ssh_configurations_and_keys.md @@ -9,7 +9,7 @@ - **UUID:** `aa759db0-4499-42f2-9f2f-be3e00fdebfa` - **Integration:** [endpoint](https://docs.elastic.co/integrations/endpoint) -- **Language:** `[SQL]` +- **Language:** `[ES|QL, SQL]` - **Source File:** [Persistence via SSH Configurations and/or Keys](../queries/persistence_via_ssh_configurations_and_keys.toml) ## Query @@ -54,9 +54,21 @@ WHERE OR f.path LIKE "/etc/ssh/ssh_config.d/%" ``` +```sql +from logs-endpoint.events.process-* +| where @timestamp > now() - 30 day +| where host.os.type == "linux" and event.type == "start" and event.action == "exec" and process.interactive == "true" +| stats cc = count(), host_count = count_distinct(host.name) by user.name +// Alter this threshold to make sense for your environment +| where cc <= 50 and host_count <= 3 +| sort cc asc +| limit 100 +``` + ## Notes - Monitors SSH keys, authorized_keys files, and SSH configuration files using OSQuery to detect potential unauthorized access or persistence techniques. +- Monitor for interactive processes by unusual users to detect potential unauthorized access or persistence techniques. - Lists detailed information about SSH files, including paths, owners, and permissions. - Requires additional data analysis and investigation into results to identify malicious or unauthorized SSH configurations and keys. diff --git a/hunting/linux/docs/persistence_via_web_shell.md b/hunting/linux/docs/persistence_via_web_shell.md new file mode 100644 index 00000000000..64c52eb77e2 --- /dev/null +++ b/hunting/linux/docs/persistence_via_web_shell.md @@ -0,0 +1,61 @@ +# Persistence via Web Shell + +--- + +## Metadata + +- **Author:** Elastic +- **Description:** This hunt identifies potential persistence mechanisms leveraging web shells on Linux systems. Web shells are malicious scripts or executables that attackers deploy to provide remote access, execute arbitrary commands, or maintain persistence on compromised systems. This hunt focuses on detecting suspicious file creation events and anomalous network activity associated with known web shell behaviors. + +- **UUID:** `e2e4a1ad-5e03-4968-927c-9ef13c49a3b8` +- **Integration:** [endpoint](https://docs.elastic.co/integrations/endpoint) +- **Language:** `[ES|QL]` +- **Source File:** [Persistence via Web Shell](../queries/persistence_via_web_shell.toml) + +## Query + +```sql +from logs-endpoint.events.file-* +| keep @timestamp, host.os.type, event.action, file.extension, process.name, agent.id, file.name, process.executable +| where @timestamp > now() - 30 days +| where host.os.type == "linux" and event.action in ("rename", "creation") and +file.extension in ("php", "py", "pl", "rb", "rs", "lua", "jsp") and not ( + // Add your noisy exclusions here + process.name in ("dnf", "dpkg", "pip3", "pip", "yum", "tar", "code", "vmtoolsd") +) +| stats cc = count(), agent_count = count_distinct(agent.id) by file.name, process.executable +| where agent_count <= 3 +| sort cc asc +| limit 100 +``` + +```sql +from logs-endpoint.events.network-* +| keep @timestamp, host.os.type, event.type, event.action, process.name, source.ip, agent.id, process.executable, process.command_line +| where @timestamp > now() - 30 days +| where host.os.type == "linux" and event.type == "end" and event.action == "disconnect_received" and +( + process.name like "ruby*" or + process.name like "perl*" or + process.name like "python*" or + process.name like "php*" +) and source.ip IS NOT null and not CIDR_MATCH(source.ip, "127.0.0.0/8", "169.254.0.0/16", "224.0.0.0/4", "::1", "172.18.0.0/16") +| stats cc = count(), agent_count = count_distinct(agent.id) by process.executable, process.command_line, source.ip +| where agent_count <= 3 +| sort cc asc +| limit 100 +``` + +## Notes + +- Monitors for the creation or renaming of files with extensions commonly associated with web shells, such as PHP, Python, Perl, Ruby, Lua, and JSP scripts. +- Analyzes network disconnect events to identify anomalous connections initiated by scripting engines, indicating potential use of web shells for remote access. +- Provides statistics and counts to detect rare or unusual activity related to file modifications or network events, helping prioritize investigation efforts. + +## MITRE ATT&CK Techniques + +- [T1505.003](https://attack.mitre.org/techniques/T1505/003) + +## License + +- `Elastic License v2` diff --git a/hunting/linux/queries/persistence_via_driver_load_with_low_occurrence_frequency.toml b/hunting/linux/queries/persistence_via_driver_load_with_low_occurrence_frequency.toml index 7ec92830c66..bf58e7075ef 100644 --- a/hunting/linux/queries/persistence_via_driver_load_with_low_occurrence_frequency.toml +++ b/hunting/linux/queries/persistence_via_driver_load_with_low_occurrence_frequency.toml @@ -18,11 +18,13 @@ mitre = ["T1547.006", "T1069.002"] query = [ ''' from logs-auditd_manager.auditd-*, logs-auditd.log-*, auditbeat-* +| keep @timestamp, host.os.type, event.category, event.action, auditd.data.syscall, auditd.data.name, process.executable, process.name, agent.id | where @timestamp > now() - 30 day | where host.os.type == "linux" and event.category == "driver" and event.action == "loaded-kernel-module" and auditd.data.syscall in ("init_module", "finit_module") -| stats host_count = count_distinct(host.id), total_count = count(*) by auditd.data.name, process.executable, process.name +// Process name is different from executable in some cases +| stats agent_count = count_distinct(agent.id), total_count = count(*) by auditd.data.name, process.executable, process.name // Alter this threshold to make sense for your environment -| where host_count == 1 and total_count == 1 +| where agent_count == 1 and total_count <= 3 | limit 100 | sort auditd.data.name asc ''' diff --git a/hunting/linux/queries/persistence_via_dynamic_linker_hijacking.toml b/hunting/linux/queries/persistence_via_dynamic_linker_hijacking.toml new file mode 100644 index 00000000000..307c920b437 --- /dev/null +++ b/hunting/linux/queries/persistence_via_dynamic_linker_hijacking.toml @@ -0,0 +1,90 @@ +[hunt] +author = "Elastic" +description = """ +This hunt identifies potential persistence mechanisms via dynamic linker hijacking on Linux systems. Attackers can manipulate environment variables like LD_PRELOAD and LD_LIBRARY_PATH to execute malicious shared libraries, hijacking the dynamic linker process for persistence or privilege escalation. This hunt monitors for suspicious usage of these environment variables, the creation of shared library files (.so), and access to critical dynamic linker configuration files. +""" +integration = ["endpoint"] +uuid = "664d65ec-029e-4746-bf97-7bf3a0113e6a" +name = "Persistence via Dynamic Linker Hijacking" +language = ["ES|QL", "SQL"] +license = "Elastic License v2" +notes = [ + "Identifies processes with suspicious environment variables, specifically LD_PRELOAD and LD_LIBRARY_PATH, which are often used in dynamic linker hijacking attacks.", + "Monitors the creation of shared object (.so) files in non-standard or uncommon directories to detect potential malicious libraries.", + "Tracks modifications to critical dynamic linker files like /etc/ld.so.preload, /etc/ld.so.conf, and related directories, which are common targets for attackers.", + "Uses process environment variables and metadata to detect running processes that rely on suspicious linker configurations, focusing on processes that persist longer than typical short-lived tasks.", + "Provides complementary OSQuery queries for detailed file metadata, including file ownership and timestamps, to support forensic investigations.", + "This hunt leverages the process.env_vars field, which is a field that must be manually enabled within the Elastic Defend policy advanced settings tab." +] +mitre = ["T1574.006"] + +query = [ +''' +from logs-endpoint.events.process-* +| keep @timestamp, host.os.type, event.type, event.action, process.env_vars, agent.id +| where @timestamp > now() - 30 days +| where host.os.type == "linux" and event.type == "start" and event.action == "exec" and +process.env_vars like "LD_PRELOAD=*.so" or +process.env_vars like "LD_LIBRARY_PATH=*" +| stats env_count = count(process.env_vars) by agent.id, process.env_vars +''', +''' +from logs-endpoint.events.file-* +| keep @timestamp, host.os.type, event.type, event.action, file.extension, file.path, process.executable, agent.id +| where @timestamp > now() - 30 days +| where host.os.type == "linux" and event.type == "creation" and file.extension == "so" and not ( + // Add your exclusions here + file.path like "/run/initramfs/*" or + file.path like "/var/tmp/mkinitramfs*" +) +| stats cc = count(), agent_count = count_distinct(agent.id) by file.path, process.executable +| where agent_count <= 3 +| sort cc asc +| limit 100 +''', +''' +SELECT * FROM process_envs +WHERE key = "LD_PRELOAD" +OR key = "LD_LIBRARY_PATH"; +''', +''' +SELECT + f.filename, + f.path, + u.username AS file_owner, + g.groupname AS group_owner, + datetime(f.atime, 'unixepoch') AS file_last_access_time, + datetime(f.mtime, 'unixepoch') AS file_last_modified_time, + datetime(f.ctime, 'unixepoch') AS file_last_status_change_time + datetime(f.btime, 'unixepoch') AS file_created_time, + f.size AS size_bytes +FROM + file f +LEFT JOIN + users u ON f.uid = u.uid +LEFT JOIN + groups g ON f.gid = g.gid +WHERE + f.path = "/etc/ld.so.preload" + OR f.path = "/etc/ld.so.conf" + OR f.path = "/etc/ld.so.cache" + OR f.path LIKE "/etc/ld.so.conf.d/%"; +''', +''' +SELECT + p.pid, + p.name AS process_name, + p.path AS process_path, + p.cmdline AS command_line, + pe.key AS env_key, + pe.value AS env_value, + (strftime('%s', 'now') - p.start_time) AS runtime_seconds +FROM + processes p +JOIN + process_envs pe ON p.pid = pe.pid +WHERE + pe.key IN ('LD_PRELOAD', 'LD_LIBRARY_PATH') + AND (strftime('%s', 'now') - p.start_time) > 3600; +''' +] diff --git a/hunting/linux/queries/persistence_via_loadable_kernel_modules.toml b/hunting/linux/queries/persistence_via_loadable_kernel_modules.toml new file mode 100644 index 00000000000..fb62a4c9c92 --- /dev/null +++ b/hunting/linux/queries/persistence_via_loadable_kernel_modules.toml @@ -0,0 +1,75 @@ +[hunt] +author = "Elastic" +description = """ +This hunt identifies potential persistence mechanisms leveraging Loadable Kernel Modules (LKMs) on Linux systems. LKMs enable dynamic extension of kernel functionality but can be abused by attackers to load malicious code into the kernel, granting them high privileges or persistence. This hunt monitors suspicious kernel module file creations, LKM-related process executions, and access to kernel module configuration files. +""" +integration = ["endpoint"] +uuid = "d667d328-fadc-4a52-9b46-f42b1a83181c" +name = "Persistence via Loadable Kernel Modules" +language = ["ES|QL", "SQL"] +license = "Elastic License v2" +notes = [ + "Tracks the creation of loadable kernel module files (.ko) in non-standard directories to identify potential malicious modules.", + "Monitors the execution of processes related to kernel module management, such as kmod, modprobe, insmod, and rmmod, to detect suspicious or unusual activity.", + "Identifies changes to critical kernel module configuration files, including /etc/modprobe.d/, /etc/modules, and related paths.", + "Uses OSQuery queries to gather detailed metadata on kernel modules currently loaded, supporting forensic analysis of potential persistence mechanisms.", + "Provides statistics and counts to help identify rare or anomalous kernel module-related events." +] +mitre = ["T1547.006"] + +query = [ +''' +from logs-endpoint.events.file-* +| keep @timestamp, host.os.type, event.type, event.action, file.extension, file.path, process.executable, agent.id +| where @timestamp > now() - 30 day +| where host.os.type == "linux" and event.type == "creation" and file.extension == "ko" and not ( + // Add your exclusions here + file.path like "/run/initramfs/*" or + file.path like "/var/tmp/mkinitramfs*" +) +| stats cc = count(), agent_count = count_distinct(agent.id) by file.path, process.executable +| where agent_count <= 3 +| sort cc asc +| limit 100 +''', +''' +from logs-endpoint.events.process-* +| keep @timestamp, host.os.type, event.type, event.action, process.name, agent.id, process.args, process.args_count +| where @timestamp > now() - 30 days +| where host.os.type == "linux" and event.type == "start" and event.action == "exec" and process.name in ("kmod", "modprobe", "insmod", "rmmod") +| stats cc = count(), agent_count = count_distinct(agent.id) by process.args, process.args_count +| where cc == 1 and agent_count == 1 and process.args_count <= 3 +| sort cc asc +| limit 100 +''', +''' +SELECT + f.filename, + f.path, + u.username AS file_owner, + g.groupname AS group_owner, + datetime(f.atime, 'unixepoch') AS file_last_access_time, + datetime(f.mtime, 'unixepoch') AS file_last_modified_time, + datetime(f.ctime, 'unixepoch') AS file_last_status_change_time + datetime(f.btime, 'unixepoch') AS file_created_time, + f.size AS size_bytes +FROM + file f +LEFT JOIN + users u ON f.uid = u.uid +LEFT JOIN + groups g ON f.gid = g.gid +WHERE + f.path LIKE '/etc/modprobe.d/%' + OR f.path LIKE '/usr/lib/modprobe.d/%' + OR f.path LIKE '/usr/lib/security/%' + OR f.path LIKE '/etc/modules-load.d/%' + OR f.path LIKE '/run/modules-load.d/%' + OR f.path LIKE '/usr/local/lib/modules-load.d/%' + OR f.path like '/usr/lib/modules-load.d/%' + OR f.path = '/etc/modules' +''', +''' +SELECT * FROM kernel_modules; +''' +] diff --git a/hunting/linux/queries/persistence_via_malicious_docker_container.toml b/hunting/linux/queries/persistence_via_malicious_docker_container.toml new file mode 100644 index 00000000000..0309c756c66 --- /dev/null +++ b/hunting/linux/queries/persistence_via_malicious_docker_container.toml @@ -0,0 +1,69 @@ +[hunt] +author = "Elastic" +description = """ +This hunt identifies potential persistence mechanisms through malicious Docker containers on Linux systems. Attackers can abuse Docker's capabilities, such as privileged containers, host namespace sharing, or mounting sensitive host paths, to maintain persistence or gain unauthorized access to the host. This hunt focuses on detecting suspicious container creations, modifications, and network connections. +""" +integration = ["endpoint"] +uuid = "b9b4f11f-1db9-491a-ab43-0e69e3f6d5be" +name = "Persistence via Docker Container" +language = ["ES|QL", "SQL"] +license = "Elastic License v2" +notes = [ + "Monitors for unusual network connections initiated by Docker containers, focusing on non-local IP addresses to identify potentially malicious activity.", + "Detects Docker containers running in privileged mode, which may indicate a risk of host compromise.", + "Identifies recently created Docker containers and images to highlight potential unauthorized deployments or suspicious additions.", + "Analyzes Docker container mount points to detect access to sensitive host directories, such as /var/run/docker.sock or /etc, which could enable container escape or host-level compromise.", + "Provides OSQuery queries to gather additional context about running containers, their configurations, and associated image metadata for forensic analysis." +] +mitre = ["T1610"] + +query = [ +''' +from logs-endpoint.events.network-* +| keep @timestamp, host.os.type, event.type, event.action, process.executable, destination.ip, agent.id, process.executable, process.command_line +| where @timestamp > now() - 7 days +| where host.os.type == "linux" and event.type == "start" and event.action == "connection_attempted" and +process.executable like "/var/lib/docker/*" and destination.ip IS NOT null and not +CIDR_MATCH( + destination.ip, + // Exclude common destination IP ranges for your environment here + "127.0.0.0/8", "169.254.0.0/16", "224.0.0.0/4", "::1", "172.18.0.0/16" +) +| stats cc = count(), agent_count = count_distinct(agent.id) by process.executable, process.command_line, destination.ip +| where agent_count <= 3 +| sort cc asc +| limit 100 +''', +''' +SELECT * FROM docker_containers +''', +''' +SELECT * FROM docker_containers +WHERE privileged = 1 +''', +''' +SELECT * FROM docker_containers +WHERE created <= strftime('%s', 'now') +AND strftime('%s', 'now') - created <= (7 * 86400); -- Created in the last 7 days +''', +''' +SELECT * FROM docker_images +''', +''' +SELECT * FROM docker_images +WHERE strftime('%s', 'now') - created <= (7 * 86400); -- Pulled in the last 7 days +''', +''' +SELECT + id AS container_id, + name AS container_name, + source AS host_path, + destination AS container_path, + rw AS is_read_write +FROM + docker_container_mounts +WHERE + source IN ('/var/run/docker.sock', '/', '/etc', '/var/lib/docker'); + -- Add your own list of additional sources here +''' +] diff --git a/hunting/linux/queries/persistence_via_pluggable_authentication_module.toml b/hunting/linux/queries/persistence_via_pluggable_authentication_module.toml new file mode 100644 index 00000000000..be3f017201c --- /dev/null +++ b/hunting/linux/queries/persistence_via_pluggable_authentication_module.toml @@ -0,0 +1,79 @@ +[hunt] +author = "Elastic" +description = """ +This hunt identifies potential persistence mechanisms leveraging Pluggable Authentication Modules (PAM) on Linux systems. PAM is a powerful framework for managing authentication-related tasks, but its flexibility can be abused by attackers to introduce malicious modules or modify configurations to gain unauthorized access or establish persistence. This hunt monitors for modifications to PAM-related files, directories, and modules. +""" +integration = ["endpoint"] +uuid = "2a3c46b8-7bd6-4bc4-a4a8-a1af114ea152" +name = "Persistence via Pluggable Authentication Modules (PAM)" +language = ["ES|QL", "SQL"] +license = "Elastic License v2" +notes = [ + "PAM modules are critical to Linux authentication workflows, but they can be abused to establish persistence or execute malicious actions.", + "This hunt identifies suspicious file creation or modification events in PAM directories, such as /etc/pam.d/, /lib/security/, and related paths.", + "Uses ES|QL queries to track file events and identify potentially malicious activity based on process activity and file paths.", + "Complemented by OSQuery queries to provide detailed file metadata for modified PAM-related files, including timestamps and ownership information." +] +mitre = ["T1556.003"] + +query = [ +''' +from logs-endpoint.events.file-* +| keep @timestamp, host.os.type, event.type, event.action, file.path, process.executable, agent.id +| where @timestamp > now() - 7 days +| where host.os.type == "linux" and event.action in ("rename", "creation") and ( + file.path like "/lib/security/*" or + file.path like "/lib64/security/*" or + file.path like "/usr/lib64/security/*" or + file.path like "/usr/lib/x86_64-linux-gnu/security/*" or + file.path like "/lib/x86_64-linux-gnu/security/*" or + file.path like "/etc/pam.d/*" or + file.path == "/etc/pam.conf" +) +| stats cc = count(), agent_count = count_distinct(agent.id) by file.path, process.executable +| where agent_count <= 3 +| sort cc asc +| limit 100 +''', +''' +SELECT + f.filename, + f.path, + u.username AS file_owner, + g.groupname AS group_owner, + datetime(f.atime, 'unixepoch') AS file_last_access_time, + datetime(f.mtime, 'unixepoch') AS file_last_modified_time, + datetime(f.ctime, 'unixepoch') AS file_last_status_change_time + datetime(f.btime, 'unixepoch') AS file_created_time, + f.size AS size_bytes +FROM + file f +LEFT JOIN + users u ON f.uid = u.uid +LEFT JOIN + groups g ON f.gid = g.gid +WHERE + f.path LIKE '/lib/security/%' + OR f.path LIKE '/lib64/security/%' + OR f.path LIKE '/usr/lib/security/%' + OR f.path LIKE '/usr/lib64/security/%' + OR f.path LIKE '/usr/lib/x86_64-linux-gnu/security/%' + OR f.path LIKE '/lib/x86_64-linux-gnu/security/%' + OR f.path like '/etc/pam.d/%' + OR f.path = '/etc/pam.conf' +''', +''' +SELECT * FROM file +WHERE ( + path LIKE '/lib/security/%' + OR path LIKE '/lib64/security/%' + OR path LIKE '/usr/lib/security/%' + OR path LIKE '/usr/lib64/security/%' + OR path LIKE '/usr/lib/x86_64-linux-gnu/security/%' + OR path LIKE '/lib/x86_64-linux-gnu/security/%' + OR path like '/etc/pam.d/%' + OR path = '/etc/pam.conf' + ) +AND (mtime > strftime('%s', 'now') - (7 * 86400)); -- Modified in the last 7 days +''' +] diff --git a/hunting/linux/queries/persistence_via_rpm_dpkg_installer_packages.toml b/hunting/linux/queries/persistence_via_rpm_dpkg_installer_packages.toml new file mode 100644 index 00000000000..7fb9d22d481 --- /dev/null +++ b/hunting/linux/queries/persistence_via_rpm_dpkg_installer_packages.toml @@ -0,0 +1,77 @@ +[hunt] +author = "Elastic" +description = """ +This hunt identifies potential persistence mechanisms leveraging DPKG or RPM package managers on Linux systems. These tools, used for installing and managing software, can be exploited by attackers to execute malicious scripts or establish persistence via lifecycle scripts (preinst, postinst, prerm, postrm). This hunt focuses on detecting suspicious file creations and anomalous process activity related to these package managers. +""" +integration = ["endpoint"] +uuid = "1d7cae97-2dea-4f01-b04c-85fa4bd991d0" +name = "Persistence via DPKG/RPM Package" +language = ["ES|QL", "SQL"] +license = "Elastic License v2" +notes = [ + "Monitors for the creation or renaming of files in directories associated with DPKG and RPM package managers, such as /var/lib/dpkg/info/ and /var/lib/rpm/.", + "Excludes common benign file patterns (e.g., temporary files, checksum files, or list files) to reduce noise while detecting unusual modifications.", + "Analyzes processes executed from lifecycle scripts or directories associated with package managers, such as /var/tmp/rpm-tmp.* and /var/lib/dpkg/info/*.", + "Uses OSQuery queries to gather detailed metadata on files and directories modified by package management activities for forensic analysis.", + "Provides counts and statistics to help highlight rare or unusual package management-related activity." +] +mitre = ["T1546.016"] + +query = [ +''' +from logs-endpoint.events.file-* +| keep @timestamp, host.os.type, event.action, file.path, file.name, agent.id, process.executable +| where @timestamp > now() - 7 days +| where host.os.type == "linux" and event.action in ("rename", "creation") and ( + file.path like "/var/lib/dpkg/info/*" or + file.path like "/var/lib/rpm/*" +) and not ( + // Remove these exclusions if you have a high suspicion of this activity + // Add additional exclusions here if necessary based on your environment + file.name like "*-new" or + file.name like "__db*.*" or + file.name like "*.list" or + file.name like "*.md5sums*" +) +| stats cc = count(), agent_count = count_distinct(agent.id) by file.name, process.executable +| where agent_count <= 3 +| sort cc asc +| limit 100 +''', +''' +from logs-endpoint.events.process-* +| keep @timestamp, host.os.type, event.type, event.action, process.parent.command_line, process.parent.executable, agent.id, process.executable, process.command_line +| where @timestamp > now() - 7 days +| where host.os.type == "linux" and event.type == "start" and event.action == "exec" and ( + process.parent.command_line like "*/var/tmp/rpm-tmp.*" or + process.parent.executable like "/var/lib/dpkg/info/*" +) +| stats cc = count(), agent_count = count_distinct(agent.id) by process.executable, process.command_line +| where agent_count <= 3 +| sort cc asc +| limit 100 +''', +''' +SELECT + f.filename, + f.path, + u.username AS file_owner, + g.groupname AS group_owner, + datetime(f.atime, 'unixepoch') AS file_last_access_time, + datetime(f.mtime, 'unixepoch') AS file_last_modified_time, + datetime(f.ctime, 'unixepoch') AS file_last_status_change_time, + datetime(f.btime, 'unixepoch') AS file_created_time, + f.size AS size_bytes +FROM + file f +LEFT JOIN + users u ON f.uid = u.uid +LEFT JOIN + groups g ON f.gid = g.gid +WHERE ( + f.path LIKE '/var/lib/dpkg/info/%' + OR f.path LIKE '/var/lib/rpm/%' + ) +AND (mtime > strftime('%s', 'now') - (7 * 86400)); -- Modified in the last 7 days +''' +] diff --git a/hunting/linux/queries/persistence_via_ssh_configurations_and_keys.toml b/hunting/linux/queries/persistence_via_ssh_configurations_and_keys.toml index c35bf930be7..1463ea385da 100644 --- a/hunting/linux/queries/persistence_via_ssh_configurations_and_keys.toml +++ b/hunting/linux/queries/persistence_via_ssh_configurations_and_keys.toml @@ -6,10 +6,11 @@ This hunt identifies potential SSH persistence mechanisms on Linux systems using integration = ["endpoint"] uuid = "aa759db0-4499-42f2-9f2f-be3e00fdebfa" name = "Persistence via SSH Configurations and/or Keys" -language = ["SQL"] +language = ["ES|QL", "SQL"] license = "Elastic License v2" notes = [ "Monitors SSH keys, authorized_keys files, and SSH configuration files using OSQuery to detect potential unauthorized access or persistence techniques.", + "Monitor for interactive processes by unusual users to detect potential unauthorized access or persistence techniques.", "Lists detailed information about SSH files, including paths, owners, and permissions.", "Requires additional data analysis and investigation into results to identify malicious or unauthorized SSH configurations and keys." ] @@ -51,5 +52,15 @@ WHERE OR f.path LIKE "/etc/ssh/%" OR f.path LIKE "/etc/ssh/sshd_config.d/%" OR f.path LIKE "/etc/ssh/ssh_config.d/%" +''', +''' +from logs-endpoint.events.process-* +| where @timestamp > now() - 30 day +| where host.os.type == "linux" and event.type == "start" and event.action == "exec" and process.interactive == "true" +| stats cc = count(), host_count = count_distinct(host.name) by user.name +// Alter this threshold to make sense for your environment +| where cc <= 50 and host_count <= 3 +| sort cc asc +| limit 100 ''' ] diff --git a/hunting/linux/queries/persistence_via_web_shell.toml b/hunting/linux/queries/persistence_via_web_shell.toml new file mode 100644 index 00000000000..b2f25fc5e84 --- /dev/null +++ b/hunting/linux/queries/persistence_via_web_shell.toml @@ -0,0 +1,49 @@ +[hunt] +author = "Elastic" +description = """ +This hunt identifies potential persistence mechanisms leveraging web shells on Linux systems. Web shells are malicious scripts or executables that attackers deploy to provide remote access, execute arbitrary commands, or maintain persistence on compromised systems. This hunt focuses on detecting suspicious file creation events and anomalous network activity associated with known web shell behaviors. +""" +integration = ["endpoint"] +uuid = "e2e4a1ad-5e03-4968-927c-9ef13c49a3b8" +name = "Persistence via Web Shell" +language = ["ES|QL"] +license = "Elastic License v2" +notes = [ + "Monitors for the creation or renaming of files with extensions commonly associated with web shells, such as PHP, Python, Perl, Ruby, Lua, and JSP scripts.", + "Analyzes network disconnect events to identify anomalous connections initiated by scripting engines, indicating potential use of web shells for remote access.", + "Provides statistics and counts to detect rare or unusual activity related to file modifications or network events, helping prioritize investigation efforts." +] +mitre = ["T1505.003"] + +query = [ +''' +from logs-endpoint.events.file-* +| keep @timestamp, host.os.type, event.action, file.extension, process.name, agent.id, file.name, process.executable +| where @timestamp > now() - 30 days +| where host.os.type == "linux" and event.action in ("rename", "creation") and +file.extension in ("php", "py", "pl", "rb", "rs", "lua", "jsp") and not ( + // Add your noisy exclusions here + process.name in ("dnf", "dpkg", "pip3", "pip", "yum", "tar", "code", "vmtoolsd") +) +| stats cc = count(), agent_count = count_distinct(agent.id) by file.name, process.executable +| where agent_count <= 3 +| sort cc asc +| limit 100 +''', +''' +from logs-endpoint.events.network-* +| keep @timestamp, host.os.type, event.type, event.action, process.name, source.ip, agent.id, process.executable, process.command_line +| where @timestamp > now() - 30 days +| where host.os.type == "linux" and event.type == "end" and event.action == "disconnect_received" and +( + process.name like "ruby*" or + process.name like "perl*" or + process.name like "python*" or + process.name like "php*" +) and source.ip IS NOT null and not CIDR_MATCH(source.ip, "127.0.0.0/8", "169.254.0.0/16", "224.0.0.0/4", "::1", "172.18.0.0/16") +| stats cc = count(), agent_count = count_distinct(agent.id) by process.executable, process.command_line, source.ip +| where agent_count <= 3 +| sort cc asc +| limit 100 +''' +] diff --git a/hunting/okta/docs/defense_evasion_failed_oauth_access_token_retrieval_via_public_client_app.md b/hunting/okta/docs/defense_evasion_failed_oauth_access_token_retrieval_via_public_client_app.md index cf66d18a3c8..5bc8c3ddeae 100644 --- a/hunting/okta/docs/defense_evasion_failed_oauth_access_token_retrieval_via_public_client_app.md +++ b/hunting/okta/docs/defense_evasion_failed_oauth_access_token_retrieval_via_public_client_app.md @@ -33,6 +33,8 @@ from logs-okta.system* // filter for scopes that are not implicitly granted and okta.outcome.reason == "no_matching_scope" + +| keep @timestamp, event.action, okta.actor.type, okta.outcome.result, okta.outcome.reason, okta.actor.display_name ``` ## Notes diff --git a/pyproject.toml b/pyproject.toml index 6e5a3c4de08..dc8bef21d75 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "detection_rules" -version = "0.3.9" +version = "0.3.10" description = "Detection Rules is the home for rules used by Elastic Security. This repository is used for the development, maintenance, testing, validation, and release of rules for Elastic Security’s Detection Engine." readme = "README.md" requires-python = ">=3.12"