diff --git a/modules/signatures/windows/bypass_uac.py b/modules/signatures/windows/bypass_uac.py index ba40b998..8f4adadb 100644 --- a/modules/signatures/windows/bypass_uac.py +++ b/modules/signatures/windows/bypass_uac.py @@ -218,3 +218,35 @@ def run(self): return True return False +class UACBypassWindowsBackup(Signature): + name = "uac_bypass_windows_Backup" + description = "Attempts to use Windows Backup and Restore (sdclt.exe) to bypass UAC" + severity = 3 + categories = ["bypass"] + authors = ["@para0x0dise"] + minimum = "0.5" + evented = True + ttps = ["T1548", "T1548.002"] + references = ["https://github.com/hfiref0x/UACME", + "https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/privilege_escalation_uac_bypass_via_sdclt.toml"] + + filter_apinames = set(["CreateProcessInternalW"]) + + def on_call(self, call, process): + pname = process["process_name"].lower() + + # Checking parent process for false positives. + if pname == "sdclt.exe": + if call["api"] == "CreateProcessInternalW": + cmdline = self.get_argument(call, "CommandLine") + lower = cmdline.lower() + if any(process in lower for process in ["control.exe", "werfault.exe", "wermgr.exe", "sdclt.exe"]): + return False + + def on_complete(self): + cmdlines = self.results.get("behavior").get("summary").get("executed_commands") + for cmdline in cmdlines: + lower = cmdline.lower() + if "sdclt.exe" in lower and "/kickoffelev" in lower: + return True + return False \ No newline at end of file diff --git a/modules/signatures/windows/credential_access.py b/modules/signatures/windows/credential_access.py index 29bab6bb..40523c92 100644 --- a/modules/signatures/windows/credential_access.py +++ b/modules/signatures/windows/credential_access.py @@ -84,3 +84,36 @@ def run(self): self.data.append({"command": cmdline}) return ret + +class AccessWindowsPasswordsVault(Signature): + name = "access_windows_passwords_vault" + description = "Attempts to access Vault passwords via PowerShell" + severity = 3 + categories = ["credential_access"] + authors = ["@para0x0dise"] + minimum = "0.5" + evented = True + ttps = ["T1059"] + references = [ + "https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/credential_access_access_to_windows_passwords_vault_via_powershell.toml"] + + filter_apinames = set(["CreateProcessInternalW"]) + + def on_call(self, call, process): + pname = process["process_name"].lower() + + # Checking parent process for false positives. + if pname == "keeperpasswordmanager.exe": + if call["api"] == "CreateProcessInternalW": + cmdline = self.get_argument(call, "CommandLine") + lower = cmdline.lower() + if any(arg in lower for arg in ["passwordvault", "retrievepassword", "retrieveall"]): + return False + + def on_complete(self): + cmdlines = self.results.get("behavior").get("summary").get("executed_commands") + for cmdline in cmdlines: + lower = cmdline.lower() + if "powershell" in lower and any(arg in lower for arg in ["passwordvault", "retrievepassword", "retrieveall"]): + return True + return False \ No newline at end of file diff --git a/modules/signatures/windows/credential_dumping.py b/modules/signatures/windows/credential_dumping.py index db1d397b..9f4216d7 100644 --- a/modules/signatures/windows/credential_dumping.py +++ b/modules/signatures/windows/credential_dumping.py @@ -214,3 +214,52 @@ def run(self): return True return False + +class DumpLSAViaWindowsErrorReporting(Signature): + name = "dump_lsa_via_windows_error_reporting" + description = "Attempts to create LSASS crash dump via Windows Error Reporting process" + severity = 3 + categories = ["credential_access", "credential_dumping"] + authors = ["@para0x0dise"] + minimum = "0.5" + evented = True + ttps = ["T1003"] + references = [ + "https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/credential_access_lsa_dump_via_windows_error_reporting.toml"] + + filter_apinames = set(["NtCreateFile"]) + + def on_call(self, call, process): + pname = process["process_name"].lower() + + # Checking parent process for false positives. + if pname in ["WerFaultSecure.exe", "WerFault.exe"]: + if call["api"] == "NtCreateFile": + filename = self.get_argument(call, "FileName") + if filename.endswith(".dmp") and "lsass_" in filename: + return True + +class KerberosCredentialAccessViaRubeus(Signature): + name = "kerberos_credential_access_via_rubeus" + description = "Attempts to manipulate/abuse Kerberos Ticketing System via Rubeus toolset" + severity = 3 + categories = ["credential_access", "credential_dumping"] + authors = ["@para0x0dise"] + minimum = "0.5" + evented = True + ttps = ["T1003"] + references = [ + "https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/credential_access_potential_credential_access_via_rubeus.toml"] + + def run(self): + cmdlines = self.results.get("behavior").get("summary").get("executed_commands") + for cmdline in cmdlines: + lower = cmdline.lower() + if "rebeus" in lower and any(arg in lower for arg in ["asreproast", "dump /service:krbtgt", "dump /luid", + "kerberoast", "createnetonly /program", "ptt /ticket", + "/impersonateuser", "renew /ticket", "asktgt /user", + "asktgs /ticket", "harvest /interval", "s4u /user", + "s4u /ticket", "hash /password", "tgtdeleg", "tgtdeleg /target", + "golden /des", "golden /rc4", "golden /aes128", "golden /aes256", "changpw /ticket"]): + return True + return False \ No newline at end of file diff --git a/modules/signatures/windows/deletes_consolehost_history.py b/modules/signatures/windows/deletes_consolehost_history.py new file mode 100644 index 00000000..62cb9620 --- /dev/null +++ b/modules/signatures/windows/deletes_consolehost_history.py @@ -0,0 +1,38 @@ +from lib.cuckoo.common.abstracts import Signature + + +class DeletesExecutedFiles(Signature): + name = "deletes_consolehost_history" + description = "Deletes PowerShell Console History to conceal the action undertaken during an intrusion" + severity = 3 + categories = ["stealth"] + authors = ["@para0x0dise"] + minimum = "1.2" + ttps = ["T1070.003"] + references = ["https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/defense_evasion_suspicious_powershell_console_history_deletion.toml"] + evented = True + + filter_apinames = set(["NtDeleteFile", "DeleteFileA", "DeleteFileW"]) + def __init__(self, *args, **kwargs): + Signature.__init__(self, *args, **kwargs) + self.isDeleted = False + self.blacklistedApps = ["powershell.exe", "rundll32.exe", "regsvr32.exe", "cmd.exe", "wscript.exe", + "cscript.exe", "mshta.exe", "winword.exe", "excel.exe"] + self.blacklistedPaths = ["\\users\\", "\\windows\\temp\\", "\\programdata\\", "\\windows\\microsoft.net\\"] + + def on_call(self, call, process): + if call["api"] == "NtDeleteFile" or call["api"] == "DeleteFileA" or call["api"] == "DeleteFileW": + if "ConsoleHost_history.txt" in self.get_argument(call, "FileName"): + self.isDeleted = True + if self.pid: + self.mark_call() + return + + def on_complete(self): + + # Verify True Positives + if self.isDeleted: + for proc in self.results.get("behavior").get("processtree"): + if proc.get("name") in self.blacklistedApps or proc["module_path"].lower() in self.blacklistedPaths: + return True + return False \ No newline at end of file diff --git a/modules/signatures/windows/exploit_spooler.py b/modules/signatures/windows/exploit_spooler.py index 63785dd7..771b5f46 100644 --- a/modules/signatures/windows/exploit_spooler.py +++ b/modules/signatures/windows/exploit_spooler.py @@ -63,3 +63,24 @@ def run(self): return True return False + +class EscalatePrivilegeViaNTLMRelay(Signature): + name = "escalate_privilege_via_ntlm_relay" + description = "Attempts to coerce a local NTLM authentication via HTTP using Printer Spooler service as a target" + severity = 3 + categories = ["bypass"] + authors = ["@para0x0dise"] + minimum = "1.2" + ttps = ["T1068"] + references = ["https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/privilege_escalation_privilege_escalation_via_ntlmrelay2self.toml"] + evented = True + + def run(self): + cmdlines = self.results.get("behavior").get("summary").get("executed_commands") + for cmdline in cmdlines: + lower = cmdline.lower() + + if ("rundll32.exe" in lower and any(arg in lower for arg in ["davclnt.dll,davsetcookie"]) + and any(arg in lower for arg in ["/print/pipe/", "/pipe/spoolss", "/pipe/srvsvc"])): + return True + return False \ No newline at end of file diff --git a/modules/signatures/windows/ipc_namedpipe.py b/modules/signatures/windows/ipc_namedpipe.py index bd16c5b5..72e3db88 100644 --- a/modules/signatures/windows/ipc_namedpipe.py +++ b/modules/signatures/windows/ipc_namedpipe.py @@ -96,3 +96,37 @@ def on_complete(self): self.data.append({"Interacts": desc}) return ret + +class EscalatePrivilegeViaNamedPipe(Signature): + name = "escalate_privilege_via_named_pipe" + description = "Attempts to escalate privilege via named pipe" + severity = 3 + categories = ["bypass"] + authors = ["@para0x0dise"] + minimum = "0.5" + evented = True + ttps = ["T1134"] + references = [ + "https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/privilege_escalation_privilege_escalation_via_named_pipe_impersonation.toml"] + + filter_apinames = set(["CreateProcessInternalW"]) + + def on_call(self, call, process): + pname = process["process_name"].lower() + + # Checking parent process for false positives. + if pname in ["chrome.exe", "msedge.exe"] and call["api"] == "CreateProcessInternalW": + cmdline = self.get_argument(call, "CommandLine") + lower = cmdline.lower() + if (any(process in lower for process in ["cmd.exe", "powershell.exe", "sc.exe", "schtasks.exe"]) + and "\\\\.\\pipe\\" in lower): + return False + + def on_complete(self): + cmdlines = self.results.get("behavior").get("summary").get("executed_commands") + for cmdline in cmdlines: + lower = cmdline.lower() + if (any(process in lower for process in ["cmd.exe", "powershell.exe", "sc.exe", "schtasks.exe"]) + and "\\\\.\\pipe\\" in lower): + return True + return False \ No newline at end of file diff --git a/modules/signatures/windows/lolbas.py b/modules/signatures/windows/lolbas.py new file mode 100644 index 00000000..4e809a45 --- /dev/null +++ b/modules/signatures/windows/lolbas.py @@ -0,0 +1,500 @@ +from lib.cuckoo.common.abstracts import Signature + +class LOLBAS_ExecuteBinaryViaPesterPSModule(Signature): + name = "Execute_Binary_Via_PesterPSModule" + description = "Attempts to execute a binary through a legitimate PowerShell Module (Pester)" + severity = 3 + categories = ["bypass", "execution"] + authors = ["@para0x0dise"] + minimum = "1.2" + ttps = ["T1218"] + references = ["https://lolbas-project.github.io/lolbas/Scripts/pester/"] + evented = True + + def run(self): + cmdlines = self.results.get("behavior").get("summary").get("executed_commands") + for cmdline in cmdlines: + lower = cmdline.lower() + if "pester" in lower and not "http" in lower: + self.data.append({"command": cmdline}) + return True + + return False + +class LOLBAS_ExecuteBinaryViaOpenSSH(Signature): + name = "Execute_Binary_Via_OpenSSH" + description = "Attempts to execute a binary through a Windows OpenSSH Client" + severity = 3 + categories = ["bypass", "execution"] + authors = ["@para0x0dise"] + minimum = "1.2" + ttps = ["T1218"] + references = ["https://lolbas-project.github.io/lolbas/Binaries/Ssh/"] + evented = True + + def run(self): + cmdlines = self.results.get("behavior").get("summary").get("executed_commands") + for cmdline in cmdlines: + lower = cmdline.lower() + if "ssh" in lower and (("-o" in lower and ("proxycommand=" in lower or "localcommand=" in lower)) + or ("localhost" in lower and ".exe" in lower)): + self.data.append({"command": cmdline}) + return True + + return False + +class LOLBAS_ExecuteBinaryVisualStudioLiveShare(Signature): + name = "Execute_Binary_Via_VisualStudioLiveShare" + description = "Attempts to execute a binary through Visual Studio Live Share" + severity = 3 + categories = ["bypass", "execution"] + authors = ["@para0x0dise"] + minimum = "1.2" + ttps = ["T1218"] + references = ["https://twitter.com/bohops/status/1583916360404729857"] + evented = True + + def run(self): + + cmdlines = self.results.get("behavior").get("summary").get("executed_commands") + for cmdline in cmdlines: + lower = cmdline.lower() + # False-Positives + # REF: https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/defense_evasion_dll_execution_via_visual_studio_live_share.toml + if "--pipe" in lower and "visualstudio.com/" in lower: + return False + + elif "vsls-agent.exe" in lower and "--agentExtensionPath" in lower: + self.data.append({"command": cmdline}) + return True + +class LOLBAS_EvadeExecutionViaDeviceCredentialDeployment(Signature): + name = "Evade_Execute_Via_DeviceCredentialDeployment" + description = "Attempts to hide Windows Command Console Window via DeviceCredentialDeployment" + severity = 3 + categories = ["bypass", "stealth", "execution"] + authors = ["@para0x0dise"] + minimum = "1.2" + ttps = ["T1218"] + references = ["https://lolbas-project.github.io/lolbas/Binaries/DeviceCredentialDeployment/"] + evented = True + + def run(self): + + cmdlines = self.results.get("behavior").get("summary").get("executed_commands") + for cmdline in cmdlines: + lower = cmdline.lower() + if ("cmd" in lower or "powershell" in lower) and "devicecredentialdeployment" in lower: + self.data.append({"command": cmdline}) + return True + return False + +class LOLBAS_IndirectCommandExecutionViaConsoleWindowHost(Signature): + name = "Indirect_Command_Execution_Via_ConsoleWindowHost" + description = "Abuses conhost.exe to execute an arbitrary executable" + severity = 3 + categories = ["bypass", "stealth", "execution"] + authors = ["@para0x0dise"] + minimum = "1.2" + ttps = ["T1218"] + references = ["https://lolbas-project.github.io/lolbas/Binaries/Conhost"] + evented = True + + def run(self): + cmdlines = self.results.get("behavior").get("summary").get("executed_commands") + for cmdline in cmdlines: + lower = cmdline.lower() + if any(process in lower for process in ["cmd /c", "powershell", "script", "mshta", "curl"]): + self.data.append({"command": cmdline}) + return True + return False + +class LOLBAS_EvadeExecutionViaFilterManagerControl(Signature): + name = "Evade_Execution_Via_Filter_Manager_Control" + description = "Attempts to unload a security driver via Filter Manager Control" + severity = 3 + categories = ["bypass", "stealth", "execution"] + authors = ["@para0x0dise"] + minimum = "1.2" + ttps = ["T1562.001"] + references = ["https://lolbas-project.github.io/lolbas/Binaries/FltMC/"] + evented = True + + def run(self): + cmdlines = self.results.get("behavior").get("summary").get("executed_commands") + for cmdline in cmdlines: + lower = cmdline.lower() + if "fltmc" in lower and "unload" in lower and \ + any(arg in lower for arg in ["security", "sysmon", "esensor", "Elastic"]): + self.data.append({"command": cmdline}) + return True + return False + +class LOLBAS_EvadeExecutionViaASPNetCompiler(Signature): + name = "Evade_Execution_Via_ASPNet_Compiler" + description = "Attempts to execute C# code via ASPNET Compiler" + severity = 3 + categories = ["bypass", "stealth", "execution"] + authors = ["@para0x0dise"] + minimum = "1.2" + ttps = ["T1218.004"] + references = ["https://lolbas-project.github.io/lolbas/Binaries/Aspnet_Compiler/", + "https://ijustwannared.team/2020/08/01/the-curious-case-of-aspnet_compiler-exe/"] + evented = True + + def run(self): + cmdlines = self.results.get("behavior").get("summary").get("executed_commands") + for cmdline in cmdlines: + lower = cmdline.lower() + if "aspnet_compiler.exe" in lower and "-v" in lower and "-f" in lower and "-u" in lower and not "-d" in lower: + self.data.append({"command": cmdline}) + return True + return False + +class LOLBAS_EvadeExecutionViaIntelGFXDownloadWrapper(Signature): + name = "Evade_Execution_Via_Intel_GFXDownloadWrapper" + description = "Attempts to load a DLL or download remote file using legitimate application shipped by Intel" + severity = 3 + categories = ["bypass", "stealth", "execution"] + authors = ["@para0x0dise"] + minimum = "1.2" + ttps = ["T1218"] + references = ["https://lolbas-project.github.io/lolbas/Binaries/GfxDownloadWrapper/", + "https://twitter.com/bohops/status/1318767376175976449"] + evented = True + + def run(self): + cmdlines = self.results.get("behavior").get("summary").get("executed_commands") + for cmdline in cmdlines: + lower = cmdline.lower() + if "gfxdownloadwrapper.exe" in lower and ("run" in lower and any(arg in lower for arg in ["0", "2"]) + or ("http" in lower and not "https://gameplayapi.intel.com" in lower)): + self.data.append({"command": cmdline}) + return True + return False + +class LOLBAS_ScriptletProxyExecutionViaPubprn(Signature): + name = "Scriptlet_Proxy_Execution_Via_Pubprn" + description = "Attempts to execute malicious processes via trusted PubPrn script" + severity = 3 + categories = ["bypass", "stealth", "execution"] + authors = ["@para0x0dise"] + minimum = "1.2" + ttps = ["T1059"] + references = ["https://lolbas-project.github.io/lolbas/Scripts/Pubprn/"] + evented = True + + def run(self): + cmdlines = self.results.get("behavior").get("summary").get("executed_commands") + for cmdline in cmdlines: + lower = cmdline.lower() + if ("wscript" in lower or "cscript" in lower) and "pubprn" in lower and "script:http" in lower: + self.data.append({"command": cmdline}) + return True + return False + +class LOLBAS_RegisterDLLViaMSIEXEC(Signature): + name = "Register_DLL_Via_MSIEXEC" + description = "Attempts to load suspicious DLL via Msiexec" + severity = 3 + categories = ["bypass", "stealth", "execution"] + authors = ["@para0x0dise"] + minimum = "1.2" + ttps = ["T1059"] + references = ["https://lolbas-project.github.io/lolbas/Binaries/Msiexec/"] + evented = True + + def run(self): + cmdlines = self.results.get("behavior").get("summary").get("executed_commands") + for cmdline in cmdlines: + lower = cmdline.lower() + if "msiexec" in lower and any(arg in lower for arg in ["/z", "/y", "-y", "-z"]) and ".dll" in lower and not \ + any(arg in lower for arg in ["\\Program Files\\", "\\Program Files %(x86%)\\"]): + self.data.append({"command": cmdline}) + return True + return False + +class LOLBAS_RegisterDLLViaOdbcconf(Signature): + name = "Register_DLL_Via_Odbcconf" + description = "Attempts to load suspicious DLL via Odbcconf" + severity = 3 + categories = ["bypass", "stealth", "execution"] + authors = ["@para0x0dise"] + minimum = "1.2" + ttps = ["T1218"] + references = ["https://lolbas-project.github.io/lolbas/Binaries/Odbcconf/"] + evented = True + + def run(self): + cmdlines = self.results.get("behavior").get("summary").get("executed_commands") + for cmdline in cmdlines: + lower = cmdline.lower() + + # Falses: + # REF: https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/defense_evasion_suspicious_imageload_via_odbc_driver_configuration_program.toml + if ("installmanager.exe" in lower and "\\windows\\syswow64\\odbcconf.rsp" in lower) or \ + ("{configsysdsn" in lower and "sql server" in lower): + return False + + if "odbcconf" in lower and any(arg in lower for arg in ["-a", "-f", "/a", "/f"]) and ".dll" in lower: + self.data.append({"command": cmdline}) + return True + return False + +class LOLBAS_RegisterDLLViaCertOC(Signature): + name = "Register_DLL_Via_CertOC" + description = "Attempts to load suspicious DLL via CertOC" + severity = 3 + categories = ["bypass", "stealth", "execution"] + authors = ["@para0x0dise"] + minimum = "1.2" + ttps = ["T1218"] + references = ["https://lolbas-project.github.io/lolbas/Binaries/Certoc/"] + evented = True + + def run(self): + cmdlines = self.results.get("behavior").get("summary").get("executed_commands") + for cmdline in cmdlines: + lower = cmdline.lower() + if "certoc" in lower and (("-loaddll" in lower and ".dll" in lower) or + ("-getcacaps" in lower and "http" in lower)): + self.data.append({"command": cmdline}) + return True + return False + +class LOLBAS_ExecuteBinaryViaScriptRunner(Signature): + name = "Execute_Binary_Via_ScriptRunner" + description = "Attempts to execute malicious binaries via ScriptRunner" + severity = 3 + categories = ["bypass", "stealth", "execution"] + authors = ["@para0x0dise"] + minimum = "1.2" + ttps = ["T1218"] + references = ["https://lolbas-project.github.io/lolbas/Binaries/Scriptrunner/"] + evented = True + + def run(self): + cmdlines = self.results.get("behavior").get("summary").get("executed_commands") + for cmdline in cmdlines: + lower = cmdline.lower() + + # Exclude conhost.exe (False-postive): + # REF: https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/defense_evasion_system_binary_proxy_execution_via_scriptrunner.toml + if "scriptrunner" in lower and "-appvscript" in lower and not \ + ("conhost" in lower and "0xffffffff" in lower): + self.data.append({"command": cmdline}) + return True + return False + +class LOLBAS_ExecuteMsiexecViaExplorer(Signature): + name = "Execute_Msiexec_Via_Explorer" + description = "Attempts to execute malicious Msiexec installer via Explorer in quite mode" + severity = 3 + categories = ["bypass", "stealth", "execution"] + authors = ["@para0x0dise"] + minimum = "1.2" + ttps = ["T1218"] + references = ["https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/defense_evasion_windows_installer_execution_via_explorer.toml"] + evented = True + + def run(self): + cmdlines = self.results.get("behavior").get("summary").get("executed_commands") + for cmdline in cmdlines: + lower = cmdline.lower() + if "explorer" in lower and "msiexec" in lower and any(arg in lower for arg in ["/i", "-i"]) and \ + any(arg in lower for arg in ["/qn", "-qn", "-q", "/q", "/quiet"]): + self.data.append({"command": cmdline}) + return True + return False + +class LOLBAS_PerformMaliciousActivitiesViaHeadlessBrowser(Signature): + name = "Perform_Malicious_Activities_Via_Headless_Browser" + description = "Attempts to execute/download malicious files via web browsers" + severity = 3 + categories = ["bypass", "stealth", "execution"] + authors = ["@para0x0dise"] + minimum = "1.2" + ttps = ["T1105"] + references = ["https://lolbas-project.github.io/lolbas/Binaries/Msedge/"] + evented = True + + def run(self): + cmdlines = self.results.get("behavior").get("summary").get("executed_commands") + for cmdline in cmdlines: + lower = cmdline.lower() + + # I have tried it on other browsers + if any(process in lower for process in ["chrome.exe", "msedge.exe", "brave.exe", + "browser.exe", "dragon.exe", "vivaldi.exe"]) and \ + ( + any(spawn in lower for spawn in ["cmd", "powershell", "wscript", "cscript"]) or + ("headless" in lower and "http" in lower and not "http://localhost/allure#graph" in lower) + ): + self.data.append({"command": cmdline}) + return True + return False +class LOLBAS_ExecuteBinaryViaRunExeHelperUtility(Signature): + name = "execute_binary_via_run_exe_helper_utility" + description = "Attempts to execute malicious binaries via RunExeHelper utility" + severity = 3 + categories = ["bypass", "stealth", "execution"] + authors = ["@para0x0dise"] + minimum = "0.5" + evented = True + ttps = ["T1218"] + references = [ + "https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/defense_evasion_binary_proxy_execution_via_runexehelper.toml"] + + filter_apinames = set(["CreateProcessInternalW"]) + + def on_call(self, call, process): + pname = process["process_name"].lower() + + # Checking parent process for false positives. + if pname in ["conhost.exe", "powercfg.exe", "wevtutil.exe", "wscollect.exe", "tpmtool.exe", "mdmdiagnosticstool.exe", "dsregcmd.exe", "stordiag.exe", "dxdiag.exe", "logman.exe", "licensingdiag.exe"]: + if call["api"] == "CreateProcessInternalW": + cmdline = self.get_argument(call, "CommandLine") + lower = cmdline.lower() + if "runexehelper.exe" in lower: + return False + def on_complete(self): + cmdlines = self.results.get("behavior").get("summary").get("executed_commands") + for cmdline in cmdlines: + lower = cmdline.lower() + if "runexehelper.exe" in lower and lower.endswith(".exe"): + self.data.append({"command": cmdline}) + return True + return False + +class LOLBAS_ExecuteBinaryViaTTDinject(Signature): + name = "execute_binary_via_ttdinject" + description = "Attempts to execute a binary via the Time Traver Debugging Application Injector utility" + severity = 3 + categories = ["bypass", "execution"] + authors = ["@para0x0dise"] + minimum = "1.2" + ttps = ["T1218"] + references = ["https://lolbas-project.github.io/lolbas/Binaries/Ttdinject/"] + evented = True + + def run(self): + cmdlines = self.results.get("behavior").get("summary").get("executed_commands") + for cmdline in cmdlines: + lower = cmdline.lower() + if "ttdinject.exe" in lower and "/launch" in lower and not "\\ttdinject.exe" in lower: + self.data.append({"command": cmdline}) + return True + + return False + +class LOLBAS_ExecuteBinaryViaAppVLP(Signature): + name = "execute_binary_via_appvlp" + description = "Attempts to execute a binary via the Application Virtualization Utility" + severity = 3 + categories = ["bypass", "execution"] + authors = ["@para0x0dise"] + minimum = "1.2" + ttps = ["T1218"] + references = ["https://lolbas-project.github.io/lolbas/OtherMSBinaries/Appvlp/", + "https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/defense_evasion_binary_proxy_execution_via_appvlp.toml"] + evented = True + + def run(self): + cmdlines = self.results.get("behavior").get("summary").get("executed_commands") + for cmdline in cmdlines: + lower = cmdline.lower() + if "appvlp.exe" in lower and not ("\\program files\\" in lower or "\\program files (x86)\\" in lower + or "rundll32.exe" in lower): + self.data.append({"command": cmdline}) + return True + + return False + +class LOLBAS_ExecuteBinaryViaInternetExplorerExporter(Signature): + name = "execute_binary_via_internet_explorer_exporter" + description = "Attempts to load malicious DLLs via the Internet Explorer Exporter" + severity = 3 + categories = ["bypass", "execution"] + authors = ["@para0x0dise"] + minimum = "1.2" + ttps = ["T1218"] + references = ["https://www.hexacorn.com/blog/2018/04/24/extexport-yet-another-lolbin/"] + evented = True + + filter_apinames = set(["NtCreateFile"]) + def __init__(self, *args, **kwargs): + Signature.__init__(self, *args, **kwargs) + self.detected = False + self.blacklistedNames = [ + "mozcrt19.dll", + "mozsqlite3.dll", + "sqlite3.dll" + ] + self.whitelistedDirectories = [ + "\\program files (x86)\\", + "\\program files\\", + "\\windows\\system32\\", + "\\windows\\syswow64\\" + ] + def on_call(self, call, _): + if call["api"] == "NtCreateFile": + filename = self.get_argument(call, "FileName").lower() + handle = int(self.get_argument(call, "FileHandle"), 16) + if handle: + if (any(dllName in filename for dllName in self.blacklistedNames) + and not any(Dir in filename for Dir in self.whitelistedDirectories)): + self.detected = True + def on_complete(self): + if self.detected: + cmdlines = self.results.get("behavior").get("summary").get("executed_commands") + for cmdline in cmdlines: + lower = cmdline.lower() + if "extexport.exe" in lower: + self.data.append({"command": cmdline}) + return True + return False + +class LOLBAS_ExecuteSuspiciousPowerShellViaSQLPS(Signature): + name = "execute_suspicious_powershell_via_sqlps" + description = "Attempts to execute a suspicious PowerShell commands via the Microsoft SQL Powershell Helper Tools" + severity = 3 + categories = ["bypass", "execution"] + authors = ["@para0x0dise"] + minimum = "1.2" + ttps = ["T1059", "T1218"] + references = ["https://lolbas-project.github.io/lolbas/OtherMSBinaries/Sqltoolsps/"] + evented = True + + def run(self): + cmdlines = self.results.get("behavior").get("summary").get("executed_commands") + for cmdline in cmdlines: + lower = cmdline.lower() + if (any(process in lower for process in ["sqltoolsps.exe", "sqlps.exe"]) and + any(arg in lower for arg in ["-e", "-enc", "-ep", "-encoded", ";iex", "start-process", "webclient", + "downloadfile", "downloadstring", "bitstransfer", "reflection.assembly"])): + self.data.append({"command": cmdline}) + return True + + return False + +class LOLBAS_ExecuteSuspiciousPowerShellViaRunscripthelper(Signature): + name = "execute_suspicious_powershell_via_runscripthelper" + description = "Attempts to execute a suspicious PowerShell commands via the RunScriptHelper utility" + severity = 3 + categories = ["bypass", "execution"] + authors = ["@para0x0dise"] + minimum = "1.2" + ttps = ["T1059", "T1218"] + references = ["https://lolbas-project.github.io/lolbas/Binaries/Runscripthelper/"] + evented = True + + def run(self): + cmdlines = self.results.get("behavior").get("summary").get("executed_commands") + for cmdline in cmdlines: + lower = cmdline.lower() + argumentCount = lower.split() + if "runscripthelper.exe" in lower and "surfacecheck" and (len(argumentCount) - 1) > 3: + self.data.append({"command": cmdline}) + return True + + return False \ No newline at end of file diff --git a/modules/signatures/windows/misc.py b/modules/signatures/windows/misc.py new file mode 100644 index 00000000..4efc70c3 --- /dev/null +++ b/modules/signatures/windows/misc.py @@ -0,0 +1,212 @@ +from lib.cuckoo.common.abstracts import Signature + +class SuspiciousExecutionViaMicrosoftExchangeTransportAgent(Signature): + name = "Suspicious_Execution_Via_MicrosoftExchangeTransportAgent" + description = "Attempts to execute a suspicious commands via MicrosoftExchangeTransportAgent for persistence or or malicious activities" + severity = 3 + categories = ["evasion", "execution", "persistence"] + authors = ["@para0x0dise"] + minimum = "0.5" + evented = True + ttps = ["T1505.002"] + references = ["https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/persistence_suspicious_execution_via_microsoft_exchange_transport_agent.toml"] + + filter_apinames = set(["CreateProcessInternalW"]) + def __init__(self, *args, **kwargs): + Signature.__init__(self, *args, **kwargs) + self.detected = False + + def on_call(self, call, process): + pname = process["process_name"].lower() + if pname in ["msexchangetransport.exe", "edgetransport.exe"]: + if call["api"] == "CreateProcessInternalW": + cmdline = self.get_argument(call, "CommandLine") + lower = cmdline.lower() + if any(process in lower for process in ["wscript.exe", "cscript.exe", "mshta.exe", "certutil.exe", + "certreq.exe", "bitsadmin.exe", "curl.exe", "reg.exe", "net.exe"]): + self.detected = True + return + + def on_complete(self): + if self.detected: + return True + return False + +class SuspiciousScheduledTaskCreationviaMasqueradedXMLFile(Signature): + name = "Suspicious_Scheduled_Task_Creation_Via_Masqueraded_XML_File" + description = "Attempts to schedule tasks using an XML files that doesn't have .xml extensions" + severity = 3 + categories = ["evasion", "execution", "persistence"] + authors = ["@para0x0dise"] + minimum = "0.5" + evented = True + ttps = ["T1053.005"] + references = [ + "https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/persistence_suspicious_scheduled_task_creation_via_masqueraded_xml_file.toml"] + + filter_apinames = set(["CreateProcessInternalW"]) + + def on_call(self, call, process): + pname = process["process_name"].lower() + + # Checking parent process for false positives. + if pname in ["setup_msi.exe", "setupactions.exe", "admsetupactions.exe","antimalware.exe", + "pcdrcui.exe", "setupactions.exe", "setupactions.exe", "wincompose.exe"]: + if call["api"] == "CreateProcessInternalW": + cmdline = self.get_argument(call, "CommandLine") + lower = cmdline.lower() + if "schtasks.exe" in lower: + return False + + if pname == "rundll32.exe": + if call["api"] == "CreateProcessInternalW": + cmdline = self.get_argument(call, "CommandLine") + lower = cmdline.lower() + if "tmp,zzzzinvokemanagedcustomactionoutofproc" in lower: + return False + + def on_complete(self): + cmdlines = self.results.get("behavior").get("summary").get("executed_commands") + for cmdline in cmdlines: + lower = cmdline.lower() + if ("schtasks.exe" in lower and any(arg in lower for arg in ["/create", "-create"]) and + any(arg in lower for arg in ["/xml", "-xml"])): + return True + return False + +class PotentialProtocolTunnelingViaLegitUtilities(Signature): + name = "potential_protocol_tunneling_via_legit_utilities" + description = "Attempts to use legit utilities to potentially tunnel network traffic" + severity = 3 + categories = ["network"] + authors = ["@para0x0dise"] + minimum = "1.2" + ttps = ["T1572"] + references = ["https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/command_and_control_potential_protocol_tunneling_via_legit_utilities.toml"] + evented = True + + def run(self): + cmdlines = self.results.get("behavior").get("summary").get("executed_commands") + for cmdline in cmdlines: + lower = cmdline.lower() + if ("3389" in lower and any(arg in lower for arg in ["-L", "-P", "-R", "-pw", "-ssh"]) + or "ssh.exe" in lower and any(arg in lower for arg in ["127.0.0", "localhost"]) + or "ngrok" in lower and any(arg in lower for arg in ["http", "tcp", "tunnel", "tls", "start", "3389"])): + return True + + return False + +class PotentialProtocolTunnelingViaQEMU(Signature): + name = "potential_protocol_tunneling_via_qemu" + description = "Attempts to use legit utilities to potentially tunnel network traffic via QEMU emulator" + severity = 3 + categories = ["network"] + authors = ["@para0x0dise"] + minimum = "1.2" + ttps = ["T1572"] + references = ["https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/command_and_control_potential_traffic_tunneling_with_qemu.toml"] + evented = True + + def run(self): + cmdlines = self.results.get("behavior").get("summary").get("executed_commands") + for cmdline in cmdlines: + lower = cmdline.lower() + if "qemu" in lower and "netdev" in lower and "nographic" in lower and "restrict=off" in lower: + return True + + return False + +class PotentialLocationDiscoveryViaUnusualProcess(Signature): + name = "potential_location_discovery_via_unusual_process" + description = "Attempts to perform browser or internet location discovery from an unusual process" + severity = 3 + categories = ["infostealer"] + authors = ["@para0x0dise"] + minimum = "1.2" + ttps = ["T1016", "T1016.001"] + references = ["https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/discovery_potential_hawkeyes_stealer_infection.toml"] + evented = True + + filter_apinames = set(["CreateProcessInternalW"]) + def __init__(self, *args, **kwargs): + Signature.__init__(self, *args, **kwargs) + self.detected = False + def on_call(self, call, process): + pnameFullPath = process["module_path"].lower() + if (not "\\endpoint protection sdk\\endpointprotection.exe" in pnameFullPath) or (not "\\aemagent\\rmm.advancedthreatdetection\\dattoav\\endpoint protection sdk\\endpointprotection.exe" in pnameFullPath): + if call["api"] == "CreateProcessInternalW": + if call["api"] == "CreateProcessInternalW": + cmdline = self.get_argument(call, "CommandLine") + lower = cmdline.lower() + if (any(process in lower for process in ["chrome.exe", "msedge.exe", "brave.exe", + "browser.exe", "dragon.exe"]) and "--dump-dom" in lower and + "http" in lower): + self.detected = True + + def on_complete(self): + if self.detected: + return True + return False + +class ExecutionFromSelfExtractingArchive(Signature): + name = "execution_from_self_extracting_archive" + description = "Attempts to execute a file from a password protected self-extracting archive" + severity = 3 + categories = ["bypass"] + authors = ["@para0x0dise"] + minimum = "1.2" + ttps = ["T1204"] + references = ["https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/execution_execution_from_a_password_protected_self_extracting_archive.toml"] + evented = True + + filter_apinames = set(["NtCreateFile"]) + def __init__(self, *args, **kwargs): + Signature.__init__(self, *args, **kwargs) + self.detected = False + def on_call(self, call, _): + if call["api"] == "NtCreateFile": + fileName = self.get_argument(call, "FileName") + handle = int(self.get_argument(call, "FileHandle"), 16) + if handle and "_sfx_access_check" in fileName: + self.detected = True + + def on_complete(self): + if self.detected: + cmdlines = self.results.get("behavior").get("summary").get("executed_commands") + for cmdline in cmdlines: + lower = cmdline.lower() + if "sfx.exe" in lower and "-p" in lower and "-d" in lower: + self.data.append({"command": cmdline}) + return True + return False + +class SuspiciousJavaExecutionViaWinScripts(Signature): + name = "suspicious_java_execution_via_win_scripts" + description = "Attempts to execute jar files via Win Scripts to bypass whitelisting" + severity = 3 + categories = ["bypass"] + authors = ["@para0x0dise"] + minimum = "1.2" + ttps = ["T1059"] + references = ["https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/execution_suspicious_java_execution_via_a_windows_script.toml"] + evented = True + + filter_apinames = set(["CreateProcessInternalW"]) + def __init__(self, *args, **kwargs): + Signature.__init__(self, *args, **kwargs) + self.detected = False + def on_call(self, call, process): + pname = process["name"] + if pname in ["wscript.exe", "cscript.exe"]: + if call["api"] == "CreateProcessInternalW": + if call["api"] == "CreateProcessInternalW": + cmdline = self.get_argument(call, "CommandLine") + lower = cmdline.lower() + if ("jave.exe" in lower and "-jar" in lower and + any(arg in lower for arg in ["\\appdata\\", "\\public\\", "\\programdata\\"])): + self.detected = True + + def on_complete(self): + if self.detected: + return True + return False diff --git a/modules/signatures/windows/ransomware_stopdjvu.py b/modules/signatures/windows/ransomware_stopdjvu.py new file mode 100644 index 00000000..708cf8c6 --- /dev/null +++ b/modules/signatures/windows/ransomware_stopdjvu.py @@ -0,0 +1,22 @@ +from lib.cuckoo.common.abstracts import Signature + +class RansomwareSTOPDJVU(Signature): + name = "ransomware_stopdjvu" + description = "Exhibits behavior characteristic of STOP/DJVU ransomware" + weight = 3 + severity = 3 + categories = ["ransomware"] + families = ["STOP"] + authors = ["@para0x0dise"] + minimum = "1.3" + evented = True + ttps = ["T1486"] + + def run(self): + cmdlines = self.results.get("behavior").get("summary").get("executed_commands") + for cmdline in cmdlines: + lower = cmdline.lower() + + if "--admin" in lower and "isnottask" in lower and "isnotautostart" in lower: + return True + return False \ No newline at end of file diff --git a/modules/signatures/windows/windows_utilities.py b/modules/signatures/windows/windows_utilities.py index 98307c08..36613d17 100644 --- a/modules/signatures/windows/windows_utilities.py +++ b/modules/signatures/windows/windows_utilities.py @@ -895,3 +895,102 @@ def run(self): return True return False + +class UsesMicrosoftHTMLHelpExecutable(Signature): + name = "uses_Microsoft_HTML_Help_Executable" + description = "Uses Microsoft HTML Help Executable for executing PE files" + severity = 3 + categories = ["evasion", "execution"] + authors = ["@para0x0dise"] + minimum = "0.5" + evented = True + ttps = ["T1566", "T1218.001"] + references = ["https://www.ptsecurity.com/ww-en/analytics/pt-esc-threat-intelligence/higaisa-or-winnti-apt-41-backdoors-old-and-new/", + "https://oddvar.moe/2017/08/13/bypassing-device-guard-umci-using-chm-cve-2017-8625/"] + + filter_apinames = set(["NtCreateFile", "CreateProcessInternalW"]) + def __init__(self, *args, **kwargs): + Signature.__init__(self, *args, **kwargs) + self.detected = False + + def on_call(self, call, process): + pname = process["process_name"].lower() + if pname == "hh.exe": + if call["api"] == "NtCreateFile": + fileName = self.get_argument(call, "FileName") + if ".exe" in fileName: + self.detected = True + return + if call["api"] == "CreateProcessInternalW": + cmdline = self.get_argument(call, "CommandLine") + lower = cmdline.lower() + if ".exe" in lower: + self.detected = True + return + + def on_complete(self): + if self.detected: + return True + return False + +class PotentialWebShellViaScreenConnectServer(Signature): + name = "potential_WebShell_Via_ScreenConnectServer" + description = "Uses ScreenConnect for executing scripts" + severity = 3 + categories = ["evasion", "execution"] + authors = ["@para0x0dise"] + minimum = "0.5" + evented = True + ttps = ["T1566", "T1218.001"] + references = ["https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows/initial_access_potential_webshell_via_screenconnect_server.toml"] + + filter_apinames = set(["CreateProcessInternalW"]) + def __init__(self, *args, **kwargs): + Signature.__init__(self, *args, **kwargs) + self.detected = False + + def on_call(self, call, process): + pname = process["process_name"].lower() + if pname == "screenConnect.service.exe": + if call["api"] == "CreateProcessInternalW": + cmdline = self.get_argument(call, "CommandLine") + lower = cmdline.lower() + if any(process in lower for process in ["cmd.exe", "powershell.exe", "pwsh.exe", "powershell_ise.exe", "csc.exe"]): + self.detected = True + return + + def on_complete(self): + if self.detected: + return True + return False + +class PotentialLateralMovementViaSMBEXEC(Signature): + name = "Potential_Lateral_Movement_Via_SMBEXEC" + description = "Attempts to execute a service via Windows Command Shell which may indicate lateral movement attempt" + severity = 3 + categories = ["evasion", "execution"] + authors = ["@para0x0dise"] + minimum = "0.5" + evented = True + ttps = ["T1059"] + references = ["https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/windows\lateral_movement_potential_lateral_movement_via_smbexec.toml"] + + filter_apinames = set(["CreateProcessInternalW"]) + def __init__(self, *args, **kwargs): + Signature.__init__(self, *args, **kwargs) + self.detected = False + + def on_call(self, call, process): + pname = process["process_name"].lower() + if pname == "services.exe": + if call["api"] == "CreateProcessInternalW": + cmdline = self.get_argument(call, "CommandLine") + lower = cmdline.lower() + if any(process in lower for process in ["cmd.exe"]) and any(arg in lower for arg in ["/q", "echo", ".bat", "del"]): + self.detected = True + return + + def on_complete(self): + if self.detected: + return True + return False \ No newline at end of file