From add7ce9508fa7866089553b2718310c71123c536 Mon Sep 17 00:00:00 2001 From: eric-forte-elastic <119343520+eric-forte-elastic@users.noreply.github.com> Date: Thu, 28 Sep 2023 16:32:55 -0400 Subject: [PATCH] [Bug] Updated os.path calls to pathlib (#3110) * Updated os.path calls to pathlib * fixed typo * os.join replacement typo * additional join typo * updated os directory functions * exist_ok typo * cleanup * Updated for cleanliness --------- Co-authored-by: Mika Ayenson (cherry picked from commit 16550b7144f065fa12200fd880c9cc90d9de2de4) --- rta/adobe_hijack.py | 19 ++++++------- rta/bitsadmin_download.py | 10 +++---- rta/c2_dns_from_iso.py | 8 +++--- rta/certutil_file_obfuscation.py | 10 +++---- rta/clr_logs_creation.py | 7 ++--- rta/common.py | 39 +++++++++++++------------- rta/delete_bootconf.py | 8 ++---- rta/disable_windows_fw.py | 8 ++---- rta/evasion_loadlib_via_callback.py | 8 +++--- rta/evasion_ntdll_from_unusual_path.py | 11 +++++--- rta/evasion_oversized_dll_load.py | 14 +++++---- rta/evasion_unhook_ldrloaddll.py | 8 +++--- rta/exec_dll_file_compressed.py | 8 +++--- rta/exec_java_via_scripting.py | 9 +++--- rta/exec_persistence_from_iso.py | 8 +++--- rta/execution_iso_dll_rundll32.py | 8 +++--- rta/execution_iso_dll_sideload.py | 8 +++--- rta/file_create_exchange_um.py | 8 +++--- rta/file_create_ms_addins.py | 8 +++--- rta/file_create_mstsc_startup.py | 4 +-- rta/file_create_outlook_vba.py | 8 +++--- rta/file_create_powershell_profile.py | 8 +++--- rta/file_create_scripting_startup.py | 8 +++--- rta/file_create_vbs_startup.py | 8 +++--- rta/file_delete_vbk.py | 7 ++--- rta/file_ms_template_macros.py | 8 +++--- rta/file_script_startup_folder.py | 8 +++--- rta/file_susp_browser_extension.py | 8 +++--- rta/git_creds_access.py | 7 ++--- rta/hosts_file_modify.py | 8 ++---- rta/installutil_network.py | 12 ++++---- rta/iqy_file_writes.py | 22 +++++++-------- rta/mac_office_descendant.py | 8 ++---- rta/modify_bootconf.py | 8 ++---- rta/ms_office_drop_exe.py | 9 +++--- rta/msoffice_addins_file.py | 8 +++--- rta/persistent_scripts.py | 7 ++--- rta/powershell_args.py | 8 ++---- rta/powershell_from_script.py | 8 ++---- rta/process_name_masquerade.py | 8 ++---- rta/recycle_bin_process.py | 10 +++---- rta/registry_hive_export.py | 8 ++---- rta/schtask_escalation.py | 8 ++---- rta/secure_file_deletion.py | 7 ++--- rta/sevenzip_encrypted.py | 14 ++++----- rta/sticky_keys_write_execute.py | 12 ++++---- rta/suspicious_office_descendant_fp.py | 6 ++-- rta/suspicious_powershell_download.py | 8 ++---- rta/suspicious_wscript_parent.py | 8 ++---- rta/system_restore_process.py | 8 ++---- rta/uac_cdssync.py | 10 +++---- rta/uac_mmc_deserialization.py | 14 ++++----- rta/unusual_ms_tool_network.py | 7 ++--- rta/unusual_parent_child.py | 10 +++---- rta/user_dir_escalation.py | 11 ++++---- rta/winrar_encrypted.py | 16 +++++------ rta/winrar_startup_folder.py | 9 +++--- 57 files changed, 253 insertions(+), 300 deletions(-) diff --git a/rta/adobe_hijack.py b/rta/adobe_hijack.py index 3499f58f8..3d0f91607 100644 --- a/rta/adobe_hijack.py +++ b/rta/adobe_hijack.py @@ -9,10 +9,9 @@ # Description: Replaces PE file that will run on Adobe Reader start. import os +from pathlib import Path -from . import common -from . import RtaMetadata - +from . import RtaMetadata, common metadata = RtaMetadata( uuid="2df08481-31db-44a8-b01d-1c0df827bddb", @@ -25,20 +24,20 @@ metadata = RtaMetadata( @common.requires_os(metadata.platforms) def main(): - rdr_cef_dir = "C:\\Program Files (x86)\\Adobe\\Acrobat Reader DC\\Reader\\AcroCEF" - rdrcef_exe = os.path.join(rdr_cef_dir, "RdrCEF.exe") + 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" - backup = os.path.abspath("xxxxxx") + backup = Path("xxxxxx").resolve() backedup = False # backup original if it exists - if os.path.isfile(rdrcef_exe): + if rdrcef_exe.is_file(): common.log("{} already exists, backing up file.".format(rdrcef_exe)) common.copy_file(rdrcef_exe, backup) backedup = True else: common.log("{} doesn't exist. Creating path.".format(rdrcef_exe)) - os.makedirs(rdr_cef_dir) + rdr_cef_dir.mkdir(parents=True) # overwrite original common.copy_file(cmd_path, rdrcef_exe) @@ -47,10 +46,10 @@ def main(): if backedup: common.log("Putting back backup copy.") common.copy_file(backup, rdrcef_exe) - os.remove(backup) + backup.unlink() else: common.remove_file(rdrcef_exe) - os.removedirs(rdr_cef_dir) + rdr_cef_dir.rmdir() if __name__ == "__main__": diff --git a/rta/bitsadmin_download.py b/rta/bitsadmin_download.py index 38e8bd7fb..648278dc4 100644 --- a/rta/bitsadmin_download.py +++ b/rta/bitsadmin_download.py @@ -9,12 +9,10 @@ # Description: Runs BitsAdmin to download file via command line. -import os import subprocess +from pathlib import Path -from . import common -from . import RtaMetadata - +from . import RtaMetadata, common metadata = RtaMetadata( uuid="aee48793-01ec-428f-9890-c5db9df07830", @@ -30,8 +28,8 @@ def main(): common.log("Running Windows BitsAdmin to Download") server, ip, port = common.serve_web() url = "http://" + ip + ":" + str(port) + "/bin/myapp.exe" - dest_path = os.path.abspath("myapp-test.exe") - fake_word = os.path.abspath("winword.exe") + dest_path = Path("myapp-test.exe").resolve() + fake_word = Path("winword.exe").resolve() common.log("Emulating parent process: {parent}".format(parent=fake_word)) common.copy_file("C:\\Windows\\System32\\cmd.exe", fake_word) diff --git a/rta/c2_dns_from_iso.py b/rta/c2_dns_from_iso.py index 38de43412..0545f6f40 100644 --- a/rta/c2_dns_from_iso.py +++ b/rta/c2_dns_from_iso.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 os +from pathlib import Path + +from . import RtaMetadata, common metadata = RtaMetadata( uuid="ba802fb2-f183-420e-947m-da5ce0235d123", @@ -27,7 +27,7 @@ PS_SCRIPT = common.get_path("bin", "ExecFromISOFile.ps1") @common.requires_os(metadata.platforms) def main(): - if os.path.exists(ISO) and os.path.exists(PS_SCRIPT): + if Path(ISO).is_file() and Path(PS_SCRIPT).is_file(): print(f'[+] - ISO File {ISO} will be mounted and executed via powershell') # 3 unique domains to trigger 3 unique rules looking for dns events via a process running from a mounted ISO file diff --git a/rta/certutil_file_obfuscation.py b/rta/certutil_file_obfuscation.py index 706473488..d2063e34a 100644 --- a/rta/certutil_file_obfuscation.py +++ b/rta/certutil_file_obfuscation.py @@ -9,11 +9,9 @@ # signal.rule.name: Encoding or Decoding Files via CertUtil # Description: Uses certutil to create an encoded copy of cmd.exe. Then uses certutil to decode that copy. -import os - -from . import common -from . import RtaMetadata +from pathlib import Path +from . import RtaMetadata, common metadata = RtaMetadata( uuid="7b2c1b3e-2097-4e2f-bf5c-e157a91b8001", @@ -27,8 +25,8 @@ metadata = RtaMetadata( @common.requires_os(metadata.platforms) def main(): common.log("Encoding target") - encoded_file = os.path.abspath("encoded.txt") - decoded_file = os.path.abspath("decoded.exe") + encoded_file = Path("encoded.txt").resolve() + decoded_file = Path("decoded.exe").resolve() common.execute( [ "c:\\Windows\\System32\\certutil.exe", diff --git a/rta/clr_logs_creation.py b/rta/clr_logs_creation.py index c216b25a4..a06288517 100644 --- a/rta/clr_logs_creation.py +++ b/rta/clr_logs_creation.py @@ -3,10 +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 os +from pathlib import Path +from . import RtaMetadata, common metadata = RtaMetadata( uuid="9bf3622b-dd76-4156-a89c-6845dca46b1f", @@ -32,7 +31,7 @@ def main(): fake_clr_logs = fake_clr_path + "\\msxsl.exe.log" common.copy_file(EXE_FILE, msxsl) - os.makedirs(fake_clr_path, exist_ok=True) + Path(fake_clr_path).mkdir(parents=True, exist_ok=True) common.log("Creating a fake clr log file") common.execute([msxsl, "-c", f"echo RTA > {fake_clr_logs}"], timeout=10) common.remove_files(msxsl, fake_clr_logs) diff --git a/rta/common.py b/rta/common.py index fc1458257..47858425a 100644 --- a/rta/common.py +++ b/rta/common.py @@ -127,7 +127,7 @@ else: CMD_PATH = "/bin/sh" POWERSHELL_PATH = None -BASE_DIR = os.path.dirname(os.path.abspath(__file__)) +BASE_DIR = Path(__file__).resolve().parent ALL_IP = "0.0.0.0" IP_REGEX = r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}" CALLBACK_REGEX = r"https?://" + IP_REGEX + r":\d+" @@ -176,6 +176,7 @@ def requires_os(*os_list: str): @functools.wraps(f) def decorated(*args, **kwargs): if CURRENT_OS not in os_list: + # NOTE os.path.relpath supports Path objects and does not exist in pathlib filename = os.path.relpath(inspect.getsourcefile(f)) func_name = f.__name__ @@ -191,7 +192,7 @@ def requires_os(*os_list: str): def check_dependencies(*paths: str) -> bool: missing = [] for path in paths: - if not os.path.exists(path): + if not Path(path).exists(): log("Missing dependency %s" % path, "!") missing.append(path) return len(missing) == 0 @@ -200,7 +201,7 @@ def check_dependencies(*paths: str) -> bool: def dependencies(*paths: str): missing = [] for path in paths: - if not os.path.exists(path): + if not Path(path).exists(): missing.append(path) def decorator(f): @@ -209,6 +210,7 @@ def dependencies(*paths: str): if len(missing): log("Missing dependencies for %s:%s()" % (f.func_code.co_filename, f.func_code.co_name), "!") for dep in missing: + # NOTE os.path.relpath supports Path objects and does not exist in pathlib print(" - %s" % os.path.relpath(dep, BASE_DIR)) return MISSING_DEPENDENCIES return f(*args, **kwargs) @@ -237,8 +239,8 @@ def temporary_file(contents, file_name=None): def temporary_file_helper(contents, file_name=None): - if not (file_name and os.path.isabs(file_name)): - file_name = os.path.join(tempfile.gettempdir(), file_name or f"temp{hash(contents):d}") + if not (file_name and Path(file_name).is_absolute()): + file_name = Path(tempfile.gettempdir()) / file_name or f"temp{hash(contents):d}" with open(file_name, "wb" if isinstance(contents, bytes) else "w") as f: f.write(contents) @@ -373,14 +375,13 @@ def link_file(source, target): log("Linking %s -> %s" % (source, target)) execute(["ln", "-s", source, target]) - -def remove_file(path): - if os.path.exists(path): +def remove_file(path: str): + if Path(path).is_file(): log("Removing %s" % path, log_type="-") # Try three times to remove the file for _ in range(3): try: - os.remove(path) + Path(path).unlink() except OSError: time.sleep(0.25) else: @@ -388,12 +389,11 @@ def remove_file(path): def remove_directory(path): - if os.path.exists(path): - if os.path.isdir(path): - log(f"Removing directory {path:s}", log_type="-") - shutil.rmtree(path) - else: - remove_file(path) + if Path(path).is_dir(): + log(f"Removing directory {path:s}", log_type="-") + shutil.rmtree(path) + else: + remove_file(path) def is_64bit(): @@ -534,9 +534,9 @@ def get_ipv4_address(hostname): def find_writeable_directory(base_dir): for root, dirs, files in os.walk(base_dir): for d in dirs: - subdir = os.path.join(base_dir, d) + subdir = Path(base_dir) / d try: - test_file = os.path.join(subdir, "test_file") + test_file = Path(subdir) / "test_file" f = open(test_file, "w") f.close() os.remove(test_file) @@ -557,10 +557,11 @@ def run_system(arguments=None): return None if arguments is None: + # NOTE os.path.relpath supports Path objects and does not exist in pathlib arguments = [sys.executable, os.path.abspath(sys.argv[0])] + sys.argv[1:] log("Attempting to elevate to SYSTEM using PsExec") - if not os.path.exists(PS_EXEC): + if not Path(PS_EXEC).is_file(): log("PsExec not found", log_type="-") return MISSING_PSEXEC @@ -717,7 +718,7 @@ def enable_logon_auditing(host="localhost", verbose=True, sleep=2): def print_file(path): print(path) - if not os.path.exists(path): + if not Path(path).is_file(): print("--- NOT FOUND ----") else: print("-" * 16) diff --git a/rta/delete_bootconf.py b/rta/delete_bootconf.py index e3d86d4fe..31270f3c4 100644 --- a/rta/delete_bootconf.py +++ b/rta/delete_bootconf.py @@ -10,11 +10,9 @@ # Description: Uses bcdedit.exe to backup the current boot configuration, and then to delete the current boot # configuration, finally restoring the original. -import os - -from . import common -from . import RtaMetadata +from pathlib import Path +from . import RtaMetadata, common metadata = RtaMetadata( uuid="eaf71384-2e38-4970-b170-9645ccde1d2b", @@ -30,7 +28,7 @@ def main(): # Messing with the boot configuration is probably not a great idea so create a backup: common.log("Exporting the boot configuration....") bcdedit = "bcdedit.exe" - backup_file = os.path.abspath("boot.cfg") + backup_file = Path("boot.cfg").resolve() common.execute(["bcdedit.exe", "/export", backup_file]) # WARNING: this is a destructive command which might be super bad to run diff --git a/rta/disable_windows_fw.py b/rta/disable_windows_fw.py index ceb612b6d..35323c3af 100644 --- a/rta/disable_windows_fw.py +++ b/rta/disable_windows_fw.py @@ -9,11 +9,9 @@ # signal.rule.name: Disable Windows Firewall Rules via Netsh # Description: Uses netsh.exe to backup, disable and restore firewall rules. -import os - -from . import common -from . import RtaMetadata +from pathlib import Path +from . import RtaMetadata, common metadata = RtaMetadata( uuid="75e14e5a-1188-47ea-9b96-2cf6e9443fc2", @@ -29,7 +27,7 @@ def main(): common.log("NetSH Advanced Firewall Configuration", log_type="~") netsh = "netsh.exe" - rules_file = os.path.abspath("fw.rules") + rules_file = Path("fw.rules").resolve() # Check to be sure that fw.rules does not already exist from previously running this script common.remove_file(rules_file) diff --git a/rta/evasion_loadlib_via_callback.py b/rta/evasion_loadlib_via_callback.py index 9e0f98345..381461014 100644 --- a/rta/evasion_loadlib_via_callback.py +++ b/rta/evasion_loadlib_via_callback.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 os +from pathlib import Path + +from . import RtaMetadata, common metadata = RtaMetadata( uuid="ae4b2807-3a16-485e-bb69-5d36bbe9b7d1", @@ -22,7 +22,7 @@ BIN = common.get_path("bin", "LoadLib-Callback64.exe") @common.requires_os(metadata.platforms) def main(): - if os.path.exists(BIN) : + if Path(BIN).is_file(): print(f'[+] - File {BIN} will be executed') common.execute(BIN) # cleanup diff --git a/rta/evasion_ntdll_from_unusual_path.py b/rta/evasion_ntdll_from_unusual_path.py index f1c54dae3..e447052fb 100644 --- a/rta/evasion_ntdll_from_unusual_path.py +++ b/rta/evasion_ntdll_from_unusual_path.py @@ -4,9 +4,9 @@ # 2.0. -from . import common -from . import RtaMetadata +from pathlib import Path +from . import RtaMetadata, common metadata = RtaMetadata( uuid="e6d5315f-4c70-4788-8564-e7c23786a4d0", @@ -20,10 +20,13 @@ metadata = RtaMetadata( @common.requires_os(metadata.platforms) def main(): - import win32file, win32api, os, time + import time from os import path + + import win32api + import win32file win32file.CopyFile(path.expandvars("%systemroot%\\system32\\ntdll.dll"), path.expandvars("%localappdata%\\Temp\\notntdll.dll"), 0) - if os.path.exists(path.expandvars("%localappdata%\\Temp\\notntdll.dll")): + if Path(path.expandvars("%localappdata%\\Temp\\notntdll.dll")).is_file(): print(f"[+] - NTDLL copied") r = win32api.LoadLibrary(path.expandvars("%localappdata%\\Temp\\notntdll.dll")) if r > 0 : diff --git a/rta/evasion_oversized_dll_load.py b/rta/evasion_oversized_dll_load.py index a09192410..1622d8b23 100644 --- a/rta/evasion_oversized_dll_load.py +++ b/rta/evasion_oversized_dll_load.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 +from pathlib import Path +from . import RtaMetadata, common metadata = RtaMetadata( uuid="ec52377c-b2a8-4c44-8eb4-465376f2189a", @@ -30,16 +30,18 @@ WER = "c:\\windows\\system32\\werfault.exe" @common.requires_os(metadata.platforms) def main(): - import os, win32file + import os from os import path - if os.path.exists(DLL) : + + import win32file + if Path(DLL).is_file(): tempc = path.expandvars("%localappdata%\\Temp\\oversized.dll") rta_dll = path.expandvars("%localappdata%\\Temp\\faultrep.dll") rta_pe = path.expandvars("%localappdata%\\Temp\\wer.exe") # copy files to temp win32file.CopyFile(DLL,tempc, 0) win32file.CopyFile(WER, rta_pe, 0) - if os.path.exists(tempc): + if Path(tempc).is_file(): print(f"[+] - {DLL} copied to {tempc}") print(f"[+] - File {tempc} will be appended with null bytes to reach 90MB in size.") # append null bytes to makde the DLL oversized 90+MB in size @@ -49,7 +51,7 @@ def main(): # copied via cmd to trigger the rule - python is signed and won't trigger the file mod part of the rule common.execute(["cmd.exe", "/c", "copy", tempc, rta_dll]) - if os.path.exists(rta_dll) and os.path.exists(rta_pe): + if Path(rta_dll).is_file() and Path(rta_pe).is_file(): # should trigger rundll32 rules common.execute(["rundll32.exe", rta_dll, "DllMain"]) # should trigger dll sideload from current dir diff --git a/rta/evasion_unhook_ldrloaddll.py b/rta/evasion_unhook_ldrloaddll.py index decbaf052..971059e8d 100644 --- a/rta/evasion_unhook_ldrloaddll.py +++ b/rta/evasion_unhook_ldrloaddll.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 os +from pathlib import Path + +from . import RtaMetadata, common metadata = RtaMetadata( uuid="7fcf2f31-b510-45f8-9de4-7dc8f5ecb68b", @@ -24,7 +24,7 @@ BIN = common.get_path("bin", "rta_unhook_ldrload.exe") @common.requires_os(metadata.platforms) def main(): - if os.path.exists(BIN) : + if Path(BIN).is_file(): print(f'[+] - File {BIN} will be executed') common.execute(BIN) # cleanup diff --git a/rta/exec_dll_file_compressed.py b/rta/exec_dll_file_compressed.py index cc8da48fc..628a90bf4 100644 --- a/rta/exec_dll_file_compressed.py +++ b/rta/exec_dll_file_compressed.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 os +from pathlib import Path + +from . import RtaMetadata, common metadata = RtaMetadata( uuid="bbad34f5-3542-4484-9b23-5ef05af94c0f", @@ -22,7 +22,7 @@ RENAMER = common.get_path("bin", "rcedit-x64.exe") @common.requires_os(metadata.platforms) def main(): path = "C:\\Users\\Public\\Temp\\7z\\" - os.makedirs(path, exist_ok=True) + Path(path).mkdir(parents=True, exist_ok=True) file = "C:\\Users\\Public\\Temp\\7z\\file.exe" user32 = "C:\\Windows\\System32\\user32.dll" dll = "C:\\Users\\Public\\Temp\\7z\\unsigned.dll" diff --git a/rta/exec_java_via_scripting.py b/rta/exec_java_via_scripting.py index a53899926..518abee61 100644 --- a/rta/exec_java_via_scripting.py +++ b/rta/exec_java_via_scripting.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 +from pathlib import Path + +from . import RtaMetadata, common metadata = RtaMetadata( uuid="a3b26c9e-6910-43f7-93b2-84cc777e54f4", @@ -32,8 +33,8 @@ def main(): cscript = "C:\\Users\\Public\\cscript.exe" executable = path + "Javafake.exe" - if not os.path.exists(path): - os.makedirs(path) + if not Path(path).is_dir(): + Path(path).mkdir(parents=True) else: pass common.copy_file(EXE_FILE, cscript) diff --git a/rta/exec_persistence_from_iso.py b/rta/exec_persistence_from_iso.py index 39cbd9500..74dea60e4 100644 --- a/rta/exec_persistence_from_iso.py +++ b/rta/exec_persistence_from_iso.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 os +from pathlib import Path + +from . import RtaMetadata, common metadata = RtaMetadata( uuid="a4355bfc-aa15-43f6-a36d-523aa637127b", @@ -26,7 +26,7 @@ PS_SCRIPT = common.get_path("bin", "ExecFromISOFile.ps1") @common.requires_os(metadata.platforms) def main(): - if os.path.exists(ISO) and os.path.exists(PS_SCRIPT): + if Path(ISO).is_file() and Path(PS_SCRIPT).is_file(): print(f'[+] - ISO File {ISO} will be mounted and executed via powershell') # commands to trigger two unique rules looking for persistence from a mounted ISO file diff --git a/rta/execution_iso_dll_rundll32.py b/rta/execution_iso_dll_rundll32.py index d9151e82d..66db61faa 100644 --- a/rta/execution_iso_dll_rundll32.py +++ b/rta/execution_iso_dll_rundll32.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 os +from pathlib import Path + +from . import RtaMetadata, common metadata = RtaMetadata( uuid="8bd17f51-3fc0-46a8-9e1a-662723314ad4", @@ -27,7 +27,7 @@ PS_SCRIPT = common.get_path("bin", "ExecFromISOFile.ps1") @common.requires_os(metadata.platforms) def main(): - if os.path.exists(ISO) and os.path.exists(PS_SCRIPT): + if Path(ISO).is_file() and Path(PS_SCRIPT).is_file(): print(f'[+] - ISO File {ISO} will be mounted and executed via powershell') # import ExecFromISO function that takes two args -ISOFIle pointing to ISO file path and -procname pointing to the filename to execute diff --git a/rta/execution_iso_dll_sideload.py b/rta/execution_iso_dll_sideload.py index 228ddafc9..1aa167ac1 100644 --- a/rta/execution_iso_dll_sideload.py +++ b/rta/execution_iso_dll_sideload.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 os +from pathlib import Path + +from . import RtaMetadata, common metadata = RtaMetadata( uuid="ba802fb2-f183-420e-947b-da5ce0c74d123", @@ -25,7 +25,7 @@ PS_SCRIPT = common.get_path("bin", "ExecFromISOFile.ps1") @common.requires_os(metadata.platforms) def main(): - if os.path.exists(ISO) and os.path.exists(PS_SCRIPT): + if Path(ISO).is_file() and Path(PS_SCRIPT).is_file(): print(f'[+] - ISO File {ISO} will be mounted and executed via powershell') # import ExecFromISO function that takes two args -ISOFIle pointing to ISO file path and -procname pointing to the filename to execute diff --git a/rta/file_create_exchange_um.py b/rta/file_create_exchange_um.py index 64ec87067..92a498449 100644 --- a/rta/file_create_exchange_um.py +++ b/rta/file_create_exchange_um.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 os +from pathlib import Path + +from . import RtaMetadata, common metadata = RtaMetadata( uuid="29eb99a6-14cc-4d37-81dd-c2e78cda8c74", @@ -26,7 +26,7 @@ def main(): path = "C:\\Users\\Public\\Microsoft\\Exchange Server Test\\FrontEnd\\HttpProxy\\owa\\auth\\" argpath = "C:\\Users\\Public\\Microsoft\\'Exchange Server Test'\\FrontEnd\\HttpProxy\\owa\\auth\\" common.copy_file(EXE_FILE, proc) - os.makedirs(path, exist_ok=True) + Path(path).mkdir(parents=True, exist_ok=True) file = argpath + "\\shell.php" common.execute([proc, "/c", f"echo AAAAAAAA | Out-File {file}"], timeout=10, kill=True) diff --git a/rta/file_create_ms_addins.py b/rta/file_create_ms_addins.py index 44c37b531..0870275e1 100644 --- a/rta/file_create_ms_addins.py +++ b/rta/file_create_ms_addins.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 os +from pathlib import Path + +from . import RtaMetadata, common metadata = RtaMetadata( uuid="5432792c-d31a-42cc-a82f-0884ea230493", @@ -20,7 +20,7 @@ EXE_FILE = common.get_path("bin", "renamed_posh.exe") @common.requires_os(metadata.platforms) def main(): path = "C:\\Users\\Public\\\\AppData\\Roaming\\Microsoft\\Word\\Startup" - os.makedirs(path, exist_ok=True) + Path(path).mkdir(parents=True, exist_ok=True) file = path + "\\file.xll" common.copy_file(EXE_FILE, file) diff --git a/rta/file_create_mstsc_startup.py b/rta/file_create_mstsc_startup.py index d9dd0d5e8..bebe6a7b7 100644 --- a/rta/file_create_mstsc_startup.py +++ b/rta/file_create_mstsc_startup.py @@ -5,7 +5,7 @@ from . import common from . import RtaMetadata -import os +from pathlib import Path metadata = RtaMetadata( uuid="55750f93-0545-4222-a1fe-8b25a1c736f0", @@ -23,7 +23,7 @@ def main(): path = "C:\\Users\\Public\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Startup" argpath = "C:\\Users\\Public\\AppData\\Roaming\\Microsoft\\Windows\\'Start Menu'\\Programs\\Startup" common.copy_file(EXE_FILE, mstsc) - os.makedirs(path, exist_ok=True) + Path(path).mkdir(parents=True, exist_ok=True) file = argpath + "\\file.exe" common.execute([mstsc, "/c", f"echo AAAAAAAA | Out-File {file}"], timeout=10, kill=True) diff --git a/rta/file_create_outlook_vba.py b/rta/file_create_outlook_vba.py index 07effea29..4797cec9b 100644 --- a/rta/file_create_outlook_vba.py +++ b/rta/file_create_outlook_vba.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 os +from pathlib import Path + +from . import RtaMetadata, common metadata = RtaMetadata( uuid="3c40b5fd-afd0-4794-8af3-f7af249edf84", @@ -20,7 +20,7 @@ EXE_FILE = common.get_path("bin", "renamed_posh.exe") @common.requires_os(metadata.platforms) def main(): path = "C:\\Users\\Public\\AppData\\Roaming\\Microsoft\\Outlook" - os.makedirs(path, exist_ok=True) + Path(path).mkdir(parents=True, exist_ok=True) file = path + "\\VbaProject.OTM" common.copy_file(EXE_FILE, file) diff --git a/rta/file_create_powershell_profile.py b/rta/file_create_powershell_profile.py index 0f4ee9a25..d82fccd06 100644 --- a/rta/file_create_powershell_profile.py +++ b/rta/file_create_powershell_profile.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 os +from pathlib import Path + +from . import RtaMetadata, common metadata = RtaMetadata( uuid="1bc32d6d-c5c9-43c6-bada-6d26469b5dac", @@ -20,7 +20,7 @@ EXE_FILE = common.get_path("bin", "renamed_posh.exe") @common.requires_os(metadata.platforms) def main(): path = "C:\\Users\\Public\\Documents\\WindowsPowerShell" - os.makedirs(path, exist_ok=True) + Path(path).mkdir(parents=True, exist_ok=True) file = path + "\\profile.ps1" common.copy_file(EXE_FILE, file) diff --git a/rta/file_create_scripting_startup.py b/rta/file_create_scripting_startup.py index 05fb8b5c2..5f8caa28e 100644 --- a/rta/file_create_scripting_startup.py +++ b/rta/file_create_scripting_startup.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 os +from pathlib import Path + +from . import RtaMetadata, common metadata = RtaMetadata( uuid="e56f77bc-d9a7-4e02-97e2-b3056f3d4171", @@ -25,7 +25,7 @@ def main(): powershell = "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe" path = "C:\\Users\\Public\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Startup" argpath = "C:\\Users\\Public\\AppData\\Roaming\\Microsoft\\Windows\\'Start Menu'\\Programs\\Startup" - os.makedirs(path, exist_ok=True) + Path(path).mkdir(parents=True, exist_ok=True) file = argpath + "\\file.exe" common.execute([powershell, "/c", f"echo AAAAAAAA | Out-File {file}"], timeout=10, kill=True) diff --git a/rta/file_create_vbs_startup.py b/rta/file_create_vbs_startup.py index 4349550fd..d1586236a 100644 --- a/rta/file_create_vbs_startup.py +++ b/rta/file_create_vbs_startup.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 os +from pathlib import Path + +from . import RtaMetadata, common metadata = RtaMetadata( uuid="7cee9313-5e55-472b-9d61-a95b0c9725d6", @@ -23,7 +23,7 @@ EXE_FILE = common.get_path("bin", "renamed_posh.exe") @common.requires_os(metadata.platforms) def main(): path = "C:\\Users\\Programs\\Startup" - os.makedirs(path, exist_ok=True) + Path(path).mkdir(parents=True, exist_ok=True) file = path + "\\a.vbs" common.copy_file(EXE_FILE, file) diff --git a/rta/file_delete_vbk.py b/rta/file_delete_vbk.py index 905d4dfc1..686a9631c 100644 --- a/rta/file_delete_vbk.py +++ b/rta/file_delete_vbk.py @@ -3,10 +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 os +from pathlib import Path +from . import RtaMetadata, common metadata = RtaMetadata( uuid="a6c80b08-ca72-4c3e-93c7-ac3421e4235e", @@ -22,7 +21,7 @@ metadata = RtaMetadata( @common.requires_os(metadata.platforms) def main(): - fakebkp = os.path.abspath("fake.vbk") + fakebkp = Path("fake.vbk").resolve() with open(fakebkp, 'w'): pass common.remove_file(fakebkp) diff --git a/rta/file_ms_template_macros.py b/rta/file_ms_template_macros.py index 6362b7c9f..a92c79720 100644 --- a/rta/file_ms_template_macros.py +++ b/rta/file_ms_template_macros.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 os +from pathlib import Path + +from . import RtaMetadata, common metadata = RtaMetadata( uuid="858475a2-78a6-40f8-8691-7ce0c631cc0c", @@ -22,7 +22,7 @@ metadata = RtaMetadata( @common.requires_os(metadata.platforms) def main(): path = "C:\\Users\\Public\\AppData\\Roaming\\Microsoft\\Templates\\" - os.makedirs(path, exist_ok=True) + Path(path).mkdir(parents=True, exist_ok=True) file = path + "\\Normal.dotm" common.temporary_file_helper("testing", file_name=file) diff --git a/rta/file_script_startup_folder.py b/rta/file_script_startup_folder.py index 3ed6cc4e3..1d180bc79 100644 --- a/rta/file_script_startup_folder.py +++ b/rta/file_script_startup_folder.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 os +from pathlib import Path + +from . import RtaMetadata, common metadata = RtaMetadata( uuid="b8dcb997-e099-472e-8f2f-15a80c8dfe1a", @@ -32,7 +32,7 @@ def main(): path = "C:\\Users\\Public\\AppData\\Roaming\\Microsoft\\Windows\\'Start Menu'\\Programs\\Startup\\" file = path + "\\a.js" common.copy_file(EXE_FILE, proc) - os.makedirs(path, exist_ok=True) + Path(path).mkdir(parents=True, exist_ok=True) common.execute([proc, "/c", f"Copy-Item {EXE_FILE} {file}"], timeout=10) common.remove_files(proc, file) diff --git a/rta/file_susp_browser_extension.py b/rta/file_susp_browser_extension.py index 4eefa1d49..03aafdb19 100644 --- a/rta/file_susp_browser_extension.py +++ b/rta/file_susp_browser_extension.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 os +from pathlib import Path + +from . import RtaMetadata, common metadata = RtaMetadata( uuid="edb804d6-85df-4dca-a521-1b6dfee9f354", @@ -26,7 +26,7 @@ def main(): path = "C:\\Users\\Public\\AppData\\Roaming\\Mozilla\\Test\\Profiles\\AdefaultA" file = path + "\\extensions.json" common.copy_file(EXE_FILE, proc) - os.makedirs(path, exist_ok=True) + Path(path).mkdir(parents=True, exist_ok=True) common.execute([proc, "/c", f"Copy-Item {EXE_FILE} {file}"], timeout=10) common.remove_files(proc, file) diff --git a/rta/git_creds_access.py b/rta/git_creds_access.py index 8ebd6fb53..ec5808078 100644 --- a/rta/git_creds_access.py +++ b/rta/git_creds_access.py @@ -3,10 +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 os +from pathlib import Path +from . import RtaMetadata, common metadata = RtaMetadata( uuid="e15ea2ec-c8a9-4203-8d01-d18d1c27fd58", @@ -25,7 +24,7 @@ def main(): gitpath = "C:\\Users\\Public\\.config\\git" try: - os.makedirs(gitpath) + Path(gitpath).mkdir(parents=True) except Exception: pass gitcreds = gitpath + "\\credentials" diff --git a/rta/hosts_file_modify.py b/rta/hosts_file_modify.py index 9505a0c42..d7122e4d7 100644 --- a/rta/hosts_file_modify.py +++ b/rta/hosts_file_modify.py @@ -11,12 +11,10 @@ import os import random import time - +from pathlib import Path from string import ascii_letters -from . import common -from . import RtaMetadata - +from . import RtaMetadata, common metadata = RtaMetadata( uuid="f24491d0-720b-4150-a2a1-45b5b07238aa", @@ -35,7 +33,7 @@ def main(): } hosts_file = hosts_files[common.CURRENT_OS] - backup = os.path.abspath(hosts_file + "_backup") + backup = Path(hosts_file + "_backup").resolve() common.log("Backing up original 'hosts' file.") common.copy_file(hosts_file, backup) diff --git a/rta/installutil_network.py b/rta/installutil_network.py index b964a166c..ac0c41cdf 100644 --- a/rta/installutil_network.py +++ b/rta/installutil_network.py @@ -10,12 +10,10 @@ # Elastic detection: Unusual Network Activity from a Windows System Binary # Description: Uses mock .NET malware and InstallUtil to create network activity from InstallUtil. -import os import sys +from pathlib import Path -from . import common -from . import RtaMetadata - +from . import RtaMetadata, common metadata = RtaMetadata( uuid="6dfa88c9-9fb2-4fb0-8bea-0bc45222b498", @@ -56,9 +54,9 @@ def main(): install_util86 = "C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\InstallUtil.exe" fallback = False - if os.path.exists(install_util64): + if Path(install_util64).is_file(): install_util = install_util64 - elif os.path.exists(install_util86): + elif Path(install_util86).is_file(): install_util = install_util86 else: install_util = None @@ -70,7 +68,7 @@ def main(): else: common.log("Unable to find InstallUtil, creating temp file") - install_util = os.path.abspath("InstallUtil.exe") + install_util = Path("InstallUtil.exe").resolve() common.copy_file(sys.executable, install_util) common.execute( [ diff --git a/rta/iqy_file_writes.py b/rta/iqy_file_writes.py index 9afd0bff8..e93b5f2b0 100644 --- a/rta/iqy_file_writes.py +++ b/rta/iqy_file_writes.py @@ -8,11 +8,9 @@ # ATT&CK: T1140, T1192, T1193 # Description: Generates four file writes related to file extensions (PUB, IQY) -import os - -from . import common -from . import RtaMetadata +from pathlib import Path +from . import RtaMetadata, common metadata = RtaMetadata( uuid="71f67037-1df3-4d5f-b8cb-eaf295ad16ed", @@ -26,9 +24,9 @@ metadata = RtaMetadata( @common.requires_os(metadata.platforms) def main(): common.log("Suspicious File Writes (IQY, PUB)") - adobe_path = os.path.abspath("AcroRd32.exe") - msoffice_path = os.path.abspath("winword.exe") - browser_path = os.path.abspath("iexplore.exe") + adobe_path = Path("AcroRd32.exe").resolve() + msoffice_path = Path("winword.exe").resolve() + browser_path = Path("iexplore.exe").resolve() common.copy_file(common.CMD_PATH, adobe_path) common.copy_file(common.CMD_PATH, msoffice_path) common.copy_file(common.CMD_PATH, browser_path) @@ -36,22 +34,22 @@ def main(): # write file as adobe, then run it common.log("Creating a 'suspicious' executable") - bad_path = os.path.abspath("bad.exe") + bad_path = Path("bad.exe").resolve() # PDF writing IQY file - fake_iqy = os.path.abspath("test.iqy") + fake_iqy = Path("test.iqy").resolve() common.execute([adobe_path, "/c", "echo", "test", ">", fake_iqy]) # PDF writing PUB file - fake_pub = os.path.abspath("test.pub") + fake_pub = Path("test.pub").resolve() common.execute([adobe_path, "/c", "echo", "test", ">", fake_pub]) # Winword writing IQY file - fake_doc_iqy = os.path.abspath("test_word.iqy") + fake_doc_iqy = Path("test_word.iqy").resolve() common.execute([msoffice_path, "/c", "echo", "test", ">", fake_doc_iqy]) # Browser writing IQY file - fake_browser_iqy = os.path.abspath("test_browser.iqy") + fake_browser_iqy = Path("test_browser.iqy").resolve() common.execute([browser_path, "/c", "echo", "test", ">", fake_browser_iqy]) # cleanup diff --git a/rta/mac_office_descendant.py b/rta/mac_office_descendant.py index 47dafc0dd..60f411632 100644 --- a/rta/mac_office_descendant.py +++ b/rta/mac_office_descendant.py @@ -7,11 +7,9 @@ # RTA: mac_office_descendant.py # Description: Creates a suspicious process spawned from "Microsoft Word" -import os - -from . import common -from . import RtaMetadata +from pathlib import Path +from . import RtaMetadata, common metadata = RtaMetadata( uuid="bb523eb1-db67-4ae6-9369-af1a93322817", @@ -25,7 +23,7 @@ metadata = RtaMetadata( @common.requires_os(metadata.platforms) def main(): common.log("Emulating Microsoft Word running enumeration commands") - office_path = os.path.abspath("Microsoft Word") + office_path = Path("Microsoft Word").resolve() common.copy_file("/bin/sh", office_path) common.execute([office_path], stdin="whoami") diff --git a/rta/modify_bootconf.py b/rta/modify_bootconf.py index c832fec4e..ead87d16d 100644 --- a/rta/modify_bootconf.py +++ b/rta/modify_bootconf.py @@ -3,11 +3,9 @@ # 2.0; you may not use this file except in compliance with the Elastic License # 2.0. -import os - -from . import common -from . import RtaMetadata +from pathlib import Path +from . import RtaMetadata, common metadata = RtaMetadata( uuid="672cd0e6-fa5a-468f-80c8-04f92bead469", @@ -27,7 +25,7 @@ def main(): # Messing with the boot configuration is not a great idea so create a backup: common.log("Exporting the boot configuration....") - backup_file = os.path.abspath("boot.cfg") + backup_file = Path("boot.cfg").resolve() common.execute([bcdedit, "/export", backup_file]) # WARNING: this sets up computer to boot into Safe Mode upon reboot diff --git a/rta/ms_office_drop_exe.py b/rta/ms_office_drop_exe.py index 7d0e1a438..13e4cb1e8 100644 --- a/rta/ms_office_drop_exe.py +++ b/rta/ms_office_drop_exe.py @@ -10,10 +10,9 @@ import os import time +from pathlib import Path -from . import common -from . import RtaMetadata - +from . import RtaMetadata, common metadata = RtaMetadata( uuid="ce85674f-fb6c-44d5-b880-4ce9062e1028", @@ -35,10 +34,10 @@ def main(): for office_app in ["winword.exe", "excel.exe", "powerpnt.exe", "outlook.exe"]: common.log("Emulating office application %s" % office_app) - office_path = os.path.abspath(office_app) + office_path = Path(office_app).resolve() common.copy_file(cmd_path, office_path) - bad_path = os.path.abspath("bad-{}-{}.exe".format(hash(office_app), os.getpid())) + bad_path = Path("bad-{}-{}.exe".format(hash(office_app), os.getpid())).resolve() common.execute([office_path, "/c", "copy", cmd_path, bad_path]) time.sleep(1) diff --git a/rta/msoffice_addins_file.py b/rta/msoffice_addins_file.py index 99a0239f6..30ceb12cc 100644 --- a/rta/msoffice_addins_file.py +++ b/rta/msoffice_addins_file.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 os +from pathlib import Path + +from . import RtaMetadata, common metadata = RtaMetadata( uuid="97979b30-908d-4c57-a33a-f3b78e55a84a", @@ -23,7 +23,7 @@ EXE_FILE = common.get_path("bin", "renamed_posh.exe") @common.requires_os(metadata.platforms) def main(): path = "C:\\Users\\Public\\AppData\\Roaming\\Microsoft\\Word\\Startup" - os.makedirs(path, exist_ok=True) + Path(path).mkdir(parents=True, exist_ok=True) file = path + "\\file.exe" common.copy_file(EXE_FILE, file) diff --git a/rta/persistent_scripts.py b/rta/persistent_scripts.py index ac7fc765a..da2e4a743 100644 --- a/rta/persistent_scripts.py +++ b/rta/persistent_scripts.py @@ -9,10 +9,9 @@ import os import time +from pathlib import Path -from . import common -from . import RtaMetadata - +from . import RtaMetadata, common metadata = RtaMetadata( uuid="2ab62c28-1abb-4ac5-a16d-2f4f75d01d02", @@ -38,7 +37,7 @@ def main(): # Remove any existing profiles user_profile = os.environ["USERPROFILE"] - log_file = os.path.join(user_profile, NAME + ".log") + log_file = Path(user_profile) / NAME / ".log" # Remove log file if exists common.remove_file(log_file) diff --git a/rta/powershell_args.py b/rta/powershell_args.py index c2f5ce327..b10c86fd2 100644 --- a/rta/powershell_args.py +++ b/rta/powershell_args.py @@ -9,11 +9,9 @@ # Description: Calls PowerShell with suspicious command line arguments. import base64 -import os - -from . import common -from . import RtaMetadata +from pathlib import Path +from . import RtaMetadata, common metadata = RtaMetadata( uuid="5efc844c-0c11-4f84-a904-ada611315298", @@ -31,7 +29,7 @@ def encode(command): @common.requires_os(metadata.platforms) def main(): common.log("PowerShell Suspicious Commands") - temp_script = os.path.abspath("tmp.ps1") + temp_script = Path("tmp.ps1").resolve() # Create an empty script with open(temp_script, "w") as f: diff --git a/rta/powershell_from_script.py b/rta/powershell_from_script.py index 5693f97cb..b5410c938 100644 --- a/rta/powershell_from_script.py +++ b/rta/powershell_from_script.py @@ -9,12 +9,10 @@ # ATT&CK: T1064, T1192, T1193 # Description: Creates a javascript file that will launch powershell. -import os import time +from pathlib import Path -from . import common -from . import RtaMetadata - +from . import RtaMetadata, common metadata = RtaMetadata( uuid="161c5972-6bfe-47b5-92bd-e0399e025dec", @@ -28,7 +26,7 @@ metadata = RtaMetadata( @common.requires_os(metadata.platforms) def main(): # Write script - script_file = os.path.abspath("launchpowershell.vbs") + script_file = Path("launchpowershell.vbs").resolve() script = """Set objShell = CreateObject("Wscript.shell") objShell.run("powershell echo 'Doing evil things...'; sleep 3") """ diff --git a/rta/process_name_masquerade.py b/rta/process_name_masquerade.py index dc4e8cdef..f608b491a 100644 --- a/rta/process_name_masquerade.py +++ b/rta/process_name_masquerade.py @@ -3,11 +3,9 @@ # 2.0; you may not use this file except in compliance with the Elastic License # 2.0. -import os - -from . import common -from . import RtaMetadata +from pathlib import Path +from . import RtaMetadata, common metadata = RtaMetadata( uuid="98adf0ff-2d8e-4eea-8d68-42084204bb74", @@ -29,7 +27,7 @@ def main(): masquerades = ["svchost.exe", "lsass.exe"] for name in masquerades: - path = os.path.abspath(name) + path = Path(name).resolve() common.copy_file(CMD_PATH, path) common.execute(path, timeout=3, kill=True) common.remove_file(path) diff --git a/rta/recycle_bin_process.py b/rta/recycle_bin_process.py index 9c3837ff1..06f5e3e9e 100644 --- a/rta/recycle_bin_process.py +++ b/rta/recycle_bin_process.py @@ -8,12 +8,10 @@ # ATT&CK: T1158 # Description: Executes mock malware from the "C:\Recycler\" and "C:\$RECYCLE.BIN\" subdirectories. -import os import time +from pathlib import Path -from . import common -from . import RtaMetadata - +from . import RtaMetadata, common metadata = RtaMetadata( uuid="790cbe6f-ee44-4654-9998-039236dbe0d8", @@ -39,7 +37,7 @@ def main(): common.log("Execute files from the Recycle Bin") target_dir = None for recycle_path in RECYCLE_PATHS: - if os.path.exists(recycle_path): + if Path(recycle_path).exists(): target_dir = common.find_writeable_directory(recycle_path) if target_dir: break @@ -58,7 +56,7 @@ def main(): source_path = command[0] arguments = command[1:] - target_path = os.path.join(target_dir, "recycled_process.exe") + target_path = Path(target_dir) / "recycled_process.exe" common.copy_file(source_path, target_path) arguments.insert(0, target_path) common.execute(arguments) diff --git a/rta/registry_hive_export.py b/rta/registry_hive_export.py index 5ba09b263..8c56ca651 100644 --- a/rta/registry_hive_export.py +++ b/rta/registry_hive_export.py @@ -8,11 +8,9 @@ # ATT&CK: TBD # Description: Exports the SAM, SECURITY and SYSTEM hives - useful in credential harvesting and discovery attacks. -import os - -from . import common -from . import RtaMetadata +from pathlib import Path +from . import RtaMetadata, common metadata = RtaMetadata( uuid="dfdcc4f4-5aca-486a-8115-b15b653b9b4f", @@ -34,7 +32,7 @@ REG = "reg.exe" @common.requires_os(metadata.platforms) def main(): for hive in ["sam", "security", "system"]: - filename = os.path.abspath("%s.reg" % hive) + filename = Path("%s.reg" % hive).resolve() common.log("Exporting %s hive to %s" % (hive, filename)) common.execute([REG, "save", "hkey_local_machine\\%s" % hive, filename]) common.remove_file(filename) diff --git a/rta/schtask_escalation.py b/rta/schtask_escalation.py index 79f06cfef..91527f518 100644 --- a/rta/schtask_escalation.py +++ b/rta/schtask_escalation.py @@ -11,12 +11,10 @@ # signal.rule.name: Net command via SYSTEM account # ATT&CK: T1053 -import os import time +from pathlib import Path -from . import common -from . import RtaMetadata - +from . import RtaMetadata, common metadata = RtaMetadata( uuid="1a61241e-5b1b-44ec-8c9f-3ae4652550be", @@ -40,7 +38,7 @@ def main(): common.log("Scheduled Task Privilege Escalation") task_name = "test-task-rta" - file_path = os.path.abspath("task.log") + file_path = Path("task.log").resolve() command = "cmd.exe /c whoami.exe > " + file_path # Delete the task if it exists diff --git a/rta/secure_file_deletion.py b/rta/secure_file_deletion.py index 791f8386a..0d496dac2 100644 --- a/rta/secure_file_deletion.py +++ b/rta/secure_file_deletion.py @@ -6,10 +6,9 @@ import os import subprocess import tempfile +from pathlib import Path -from . import common -from . import RtaMetadata - +from . import RtaMetadata, common metadata = RtaMetadata( uuid="9cb42759-a161-4d93-b07d-3c8254dc8838", @@ -22,7 +21,7 @@ metadata = RtaMetadata( @common.requires_os(metadata.platforms) def main(): - temp_path = os.path.join(tempfile.gettempdir(), os.urandom(16).encode("hex")) + temp_path = Path(tempfile.gettempdir()) / os.urandom(16).encode("hex") sdelete_path = common.get_path("bin", "sdelete.exe") try: diff --git a/rta/sevenzip_encrypted.py b/rta/sevenzip_encrypted.py index 1fa3ce940..22df1fdfc 100644 --- a/rta/sevenzip_encrypted.py +++ b/rta/sevenzip_encrypted.py @@ -9,12 +9,10 @@ # Description: Uses "bin\.exe" to perform encryption of archives and archive headers. import base64 -import os import sys +from pathlib import Path -from . import common -from . import RtaMetadata - +from . import RtaMetadata, common metadata = RtaMetadata( uuid="6cd35061-278b-45e7-a9cb-86b48bc47884", @@ -28,7 +26,7 @@ metadata = RtaMetadata( SEVENZIP = common.get_path("bin", "7za.exe") -def create_exfil(path=os.path.abspath("secret_stuff.txt")): +def create_exfil(path=Path("secret_stuff.txt").resolve()): common.log("Writing dummy exfil to %s" % path) with open(path, "wb") as f: f.write(base64.b64encode(b"This is really secret stuff\n" * 100)) @@ -39,16 +37,16 @@ def create_exfil(path=os.path.abspath("secret_stuff.txt")): @common.dependencies(SEVENZIP) def main(password="s0l33t"): # create 7z.exe with not-7zip name, and exfil - svnz2 = os.path.abspath("a.exe") + svnz2 = Path("a.exe").resolve() common.copy_file(SEVENZIP, svnz2) exfil = create_exfil() exts = ["7z", "zip", "gzip", "tar", "bz2", "bzip2", "xz"] - out_jpg = os.path.abspath("out.jpg") + out_jpg = Path("out.jpg").resolve() for ext in exts: # Write archive for each type - out_file = os.path.abspath("out." + ext) + out_file = Path("out." + ext).resolve() common.execute([svnz2, "a", out_file, "-p" + password, exfil], mute=True) common.remove_file(out_file) diff --git a/rta/sticky_keys_write_execute.py b/rta/sticky_keys_write_execute.py index d80540c1e..c775c76e7 100644 --- a/rta/sticky_keys_write_execute.py +++ b/rta/sticky_keys_write_execute.py @@ -11,12 +11,10 @@ # ATT&CK: T1015 # Description: Writes different binaries into various accessibility locations. -import os import time +from pathlib import Path -from . import common -from . import RtaMetadata - +from . import RtaMetadata, common metadata = RtaMetadata( uuid="398933ec-f8d4-4d81-93ed-e7d7adcb9d97", @@ -48,13 +46,13 @@ def main(): "displayswitch.exe", "atbroker.exe", ] - calc = os.path.abspath("\\windows\\system32\\calc.exe") - temp = os.path.abspath("temp.exe") + calc = Path("\\windows\\system32\\calc.exe").resolve() + temp = Path("temp.exe").resolve() # loop over bins for bin_name in bins: - bin_path = os.path.abspath("\\Windows\\system32\\" + bin_name) + bin_path = Path("\\Windows\\system32\\" + bin_name).resolve() # Back up bin common.copy_file(bin_path, temp) diff --git a/rta/suspicious_office_descendant_fp.py b/rta/suspicious_office_descendant_fp.py index 6c1d902fe..27610a9a8 100644 --- a/rta/suspicious_office_descendant_fp.py +++ b/rta/suspicious_office_descendant_fp.py @@ -8,7 +8,7 @@ # ATT&CK: T1064 # Description: Generates various children processes from emulated Office processes. -import os +from pathlib import Path import time from . import common @@ -33,13 +33,13 @@ def main(): "wscript.exe //b", ] cmd_path = "c:\\windows\\system32\\cmd.exe" - browser_path = os.path.abspath("firefox.exe") + browser_path = Path("firefox.exe").resolve() common.copy_file(cmd_path, browser_path) for office_app in ["winword.exe", "excel.exe"]: common.log("Emulating %s" % office_app) - office_path = os.path.abspath(office_app) + office_path = Path(office_app).resolve() common.copy_file(cmd_path, office_path) for command in suspicious_apps: diff --git a/rta/suspicious_powershell_download.py b/rta/suspicious_powershell_download.py index 61c26b059..83141c18e 100644 --- a/rta/suspicious_powershell_download.py +++ b/rta/suspicious_powershell_download.py @@ -3,12 +3,10 @@ # 2.0; you may not use this file except in compliance with the Elastic License # 2.0. -import os import time +from pathlib import Path -from . import common -from . import RtaMetadata - +from . import RtaMetadata, common metadata = RtaMetadata( uuid="20b96aa7-609e-473f-ac35-5ac19d10f9a5", @@ -37,7 +35,7 @@ def main(): # Emulate Word user_app = "winword.exe" common.log("Emulating {}".format(user_app)) - user_app_path = os.path.abspath(user_app) + user_app_path = Path(user_app).resolve() common.copy_file(EXE_FILE, user_app_path) common.execute([user_app_path, "/c", cmd]) diff --git a/rta/suspicious_wscript_parent.py b/rta/suspicious_wscript_parent.py index 78004bdcd..a890fcf59 100644 --- a/rta/suspicious_wscript_parent.py +++ b/rta/suspicious_wscript_parent.py @@ -9,12 +9,10 @@ # ATT&CK: T1064, T1192, T1193 # Description: WScript run with suspicious parent processes -import os import time +from pathlib import Path -from . import common -from . import RtaMetadata - +from . import RtaMetadata, common metadata = RtaMetadata( uuid="a3cdd478-b817-4513-bb3d-897a5f92c836", @@ -41,7 +39,7 @@ def main(): for application in ["outlook.exe", "explorer.exe", "chrome.exe", "firefox.exe"]: common.log("Emulating %s" % application) - app_path = os.path.abspath(application) + app_path = Path(application).resolve() common.copy_file(cmd_path, app_path) common.execute([app_path, "/c", "wscript.exe", "script_path"], timeout=1, kill=True) diff --git a/rta/system_restore_process.py b/rta/system_restore_process.py index 9a23e2073..3580421e1 100644 --- a/rta/system_restore_process.py +++ b/rta/system_restore_process.py @@ -8,11 +8,9 @@ # ATT&CK: T1158 # Description: Copies mock malware into the System Volume Information directory and executes. -import os - -from . import common -from . import RtaMetadata +from pathlib import Path +from . import RtaMetadata, common metadata = RtaMetadata( uuid="0fcf5aeb-cebd-466d-8a2e-ddb710ec845d", @@ -42,7 +40,7 @@ def main(): common.log("No writeable directories in System Restore. Exiting...", "-") return common.UNSUPPORTED_RTA - target_path = os.path.join(target_directory, "restore-process.exe") + target_path = Path(target_directory) / "restore-process.exe" common.copy_file(program_path, target_path) common.execute(target_path) diff --git a/rta/uac_cdssync.py b/rta/uac_cdssync.py index 5f3838524..52b6bc60f 100644 --- a/rta/uac_cdssync.py +++ b/rta/uac_cdssync.py @@ -3,10 +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 shutil +from pathlib import Path +from . import RtaMetadata, common metadata = RtaMetadata( uuid="7e9a94f4-46aa-45eb-b95b-53da7c01a033", @@ -33,14 +33,14 @@ def main(): path = "C:\\Users\\Public\\System32" user32 = "C:\\Windows\\System32\\user32.dll" dll = path + "\\npmproxy.dll" - os.makedirs(path, exist_ok=True) + Path(path).mkdir(parents=True, exist_ok=True) common.copy_file(user32, dll) common.copy_file(EXE_FILE, taskhostw) common.log("Spawning PowerShell from fake taskhostw") common.execute([taskhostw, "/c", powershell], timeout=10, kill=True) common.remove_files(dll, taskhostw) - os.removedirs(path) + shutil.rmtree(path) if __name__ == "__main__": diff --git a/rta/uac_mmc_deserialization.py b/rta/uac_mmc_deserialization.py index 219617c1d..afe029bc8 100644 --- a/rta/uac_mmc_deserialization.py +++ b/rta/uac_mmc_deserialization.py @@ -3,10 +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 +from pathlib import Path +from . import RtaMetadata, common metadata = RtaMetadata( uuid="1d486055-38f8-4cf3-aec1-7f4f72d73fb2", @@ -27,17 +27,17 @@ EXE_FILE = common.get_path("bin", "renamed_posh.exe") @common.requires_os(metadata.platforms) def main(): appdata = os.getenv("LOCALAPPDATA") - path = appdata + "\\Microsoft\\Event Viewer" - recentfiles = path + "\\RecentViews" + path = Path(appdata) / "\\Microsoft\\Event Viewer" + recentfiles = path / "\\RecentViews" - if os.path.exists(path): + if path.is_dir(): common.copy_file(EXE_FILE, recentfiles) common.remove_file(recentfiles) else: - os.mkdir(path) + path.mkdir() common.copy_file(EXE_FILE, recentfiles) common.remove_file(recentfiles) - os.rmdir(path) + path.rmdir() if __name__ == "__main__": diff --git a/rta/unusual_ms_tool_network.py b/rta/unusual_ms_tool_network.py index c94443c32..ceec52563 100644 --- a/rta/unusual_ms_tool_network.py +++ b/rta/unusual_ms_tool_network.py @@ -9,12 +9,11 @@ # Description: Creates network traffic from a process which is named to match common administration and developer tools # that do not typically make network traffic unless being used maliciously. -import os import shutil import sys +from pathlib import Path -from . import common -from . import RtaMetadata +from . import RtaMetadata, common if sys.version_info > (3,): urlliblib = "urllib.request" @@ -53,7 +52,7 @@ process_names = [ def http_from_process(name, ip, port): - path = os.path.join(common.BASE_DIR, name) + path = Path(common.BASE_DIR) / name common.log("Making HTTP GET from %s" % path) shutil.copy(sys.executable, path) common.execute( diff --git a/rta/unusual_parent_child.py b/rta/unusual_parent_child.py index 160a378c7..262066f5c 100644 --- a/rta/unusual_parent_child.py +++ b/rta/unusual_parent_child.py @@ -9,12 +9,10 @@ # ATT&CK: T1093 # Description: Runs several Windows core processes directly, instead of from the proper parent in Windows. -import os import sys +from pathlib import Path -from . import common -from . import RtaMetadata - +from . import RtaMetadata, common metadata = RtaMetadata( uuid="6cf12026-f99f-4e5c-8cd4-3dbc7bce3e67", @@ -27,7 +25,7 @@ metadata = RtaMetadata( @common.requires_os(metadata.platforms) def main(): - common.log("Running Windows processes with an unexpected parent of %s" % os.path.basename(sys.executable)) + common.log("Running Windows processes with an unexpected parent of %s" % Path(sys.executable).name) process_names = [ # "C:\\Windows\\System32\\smss.exe", BSOD (avoid this) # "C:\\Windows\\System32\\csrss.exe", BSOD (avoid this) @@ -42,7 +40,7 @@ def main(): for process in process_names: # taskhostw.exe isn't on all versions of windows - if os.path.exists(process): + if Path(process).is_file(): common.execute([process], timeout=2, kill=True) else: common.log("Skipping %s" % process, "-") diff --git a/rta/user_dir_escalation.py b/rta/user_dir_escalation.py index 34882c0db..fe98895e6 100644 --- a/rta/user_dir_escalation.py +++ b/rta/user_dir_escalation.py @@ -9,10 +9,9 @@ # Description: Spawns mock malware written to a regular user directory and executes as System. import os +from pathlib import Path -from . import common -from . import RtaMetadata - +from . import RtaMetadata, common metadata = RtaMetadata( uuid="dc734786-66bd-4be6-bd06-eb41fa7b6745", @@ -35,10 +34,10 @@ def main(): source_path = common.get_path("bin", "myapp.exe") target_directory = "c:\\users\\fake_user_rta-%d" % os.getpid() - if not os.path.exists(target_directory): - os.makedirs(target_directory) + if not Path(target_directory).is_dir(): + Path(target_directory).mkdir(parents=True) - target_path = os.path.join(target_directory, "user_file.exe") + target_path = Path(target_directory) / "user_file.exe" common.copy_file(source_path, target_path) common.execute([target_path]) diff --git a/rta/winrar_encrypted.py b/rta/winrar_encrypted.py index 18669ded0..e36a5a2ad 100644 --- a/rta/winrar_encrypted.py +++ b/rta/winrar_encrypted.py @@ -9,12 +9,10 @@ # Description: Uses "bin\rar.exe" to perform encryption of archives and archive headers. import base64 -import os import sys +from pathlib import Path -from . import common -from . import RtaMetadata - +from . import RtaMetadata, common metadata = RtaMetadata( uuid="6d2d3c21-2d71-4395-8ab7-b1d0138d9225", @@ -29,7 +27,7 @@ MY_APP = common.get_path("bin", "myapp.exe") WINRAR = common.get_path("bin", "Rar.exe") -def create_exfil(path=os.path.abspath("secret_stuff.txt")): +def create_exfil(path=Path("secret_stuff.txt").resolve()): common.log("Writing dummy exfil to %s" % path) with open(path, "wb") as f: f.write(base64.b64encode(b"This is really secret stuff" * 100)) @@ -44,15 +42,15 @@ def main(password="s0l33t"): common.patch_file(WINRAR, b"win.rar GmbH", b"bad.bad GmbH", winrar_bin_modsig) # Renamed copies of executables - winrar_bin_modsig_a = os.path.abspath("a.exe") - winrar_bin_b = os.path.abspath("b.exe") + winrar_bin_modsig_a = Path("a.exe").resolve() + winrar_bin_b = Path("b.exe").resolve() common.copy_file(winrar_bin_modsig, winrar_bin_modsig_a) common.copy_file(WINRAR, winrar_bin_b) # Output options for various tests - rar_file = os.path.abspath("out.rar") - rar_file_jpg = os.path.abspath("out.jpg") + rar_file = Path("out.rar").resolve() + rar_file_jpg = Path("out.jpg").resolve() common.remove_files(rar_file, rar_file_jpg) # use case: rar with -hp to generate new rar file w/ .rar diff --git a/rta/winrar_startup_folder.py b/rta/winrar_startup_folder.py index 7fd825ae5..774ed1d11 100644 --- a/rta/winrar_startup_folder.py +++ b/rta/winrar_startup_folder.py @@ -9,10 +9,9 @@ # Description: Writes batch file into Windows Startup folder using process ancestry tied to exploit (CVE-2018-20250) import os +from pathlib import Path -from . import common -from . import RtaMetadata - +from . import RtaMetadata, common metadata = RtaMetadata( uuid="6d2d3c21-2d71-4395-8ab7-b1d0138d9225", @@ -26,8 +25,8 @@ metadata = RtaMetadata( @common.requires_os(metadata.platforms) def main(): common.log("WinRAR StartUp Folder Persistence") - win_rar_path = os.path.abspath("WinRAR.exe") - ace_loader_path = os.path.abspath("Ace32Loader.exe") + win_rar_path = Path("WinRAR.exe").resolve() + ace_loader_path = Path("Ace32Loader.exe").resolve() batch_file_path = "\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\mssconf.bat" startup_path = os.environ["USERPROFILE"] + batch_file_path common.copy_file("C:\\Windows\\System32\\cmd.exe", win_rar_path)