Skip to content

Commit

Permalink
Merge branch 'master' into pr/397
Browse files Browse the repository at this point in the history
  • Loading branch information
doomedraven committed Mar 7, 2024
2 parents f5045d9 + efcc90e commit 4bd62c5
Show file tree
Hide file tree
Showing 481 changed files with 586 additions and 61 deletions.
125 changes: 125 additions & 0 deletions analyzer/windows/modules/auxiliary/autoruns.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import csv
import logging
import os
import platform
import shlex
import subprocess
from winreg import HKEY_CURRENT_USER, KEY_ALL_ACCESS, REG_DWORD, CreateKeyEx, SetValueEx

from lib.common.abstracts import Auxiliary
from lib.common.exceptions import CuckooPackageError
from lib.common.results import upload_to_host
from lib.core.config import Config

log = logging.getLogger(__name__)


__author__ = "[Canadian Centre for Cyber Security] @CybercentreCanada"


class Autoruns(Auxiliary):
"""Autoruns from sysinternals"""

def __init__(self, options, config):
Auxiliary.__init__(self, options, config)
self.config = Config(cfg="analysis.conf")
self.enabled = self.config.autoruns
self.output_dir = "C:\\\\autoruns"
self.output_file_start = "autoruns_start.txt"
self.output_file_end = "autoruns_end.txt"
self.output_file_diff = "autoruns.diff"
self.startupinfo = subprocess.STARTUPINFO()
self.startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW

if not os.path.exists(self.output_dir):
os.makedirs(self.output_dir)
# reg.exe ADD "HKCU\Software\Sysinternals\Autoruns" /v EulaAccepted /t REG_DWORD /d 1 /f
try:
with CreateKeyEx(HKEY_CURRENT_USER, "Software\Sysinternals\Autoruns", 0, KEY_ALL_ACCESS) as key:
SetValueEx(key, "EulaAccepted", 0, REG_DWORD, 1)
except OSError as e:
pass

bin_path = os.path.join(os.getcwd(), "bin")
# First figure out what architecture the system in running (64 or 86)
if "AMD64" in platform.uname():
autoruns = os.path.join(bin_path, "autorunsc64.exe")
else:
autoruns = os.path.join(bin_path, "autorunsc.exe")

if not os.path.exists(autoruns):
raise CuckooPackageError(
"In order to use the Autorun functionality, it "
"is required to have the appropriate Autorunsc executable in the analyzer/windows/bin/ path."
)
autoruns = autoruns.replace("\\", "\\\\")

run_args = self.options.get("run_args")
if not run_args:
# -a : entry selection * for all entries
# -c : Print output as csv
# -o : Output file path
run_args = f"-a * -c -o {self.output_dir}\\\\{self.output_file_end}"

run_cmd = f"{autoruns} {run_args}"
self.run_cmd = shlex.split(run_cmd)

def start(self):

log.debug(self.run_cmd)
subprocess.Popen(self.run_cmd, startupinfo=self.startupinfo)

def stop(self):
log.debug(self.run_cmd)
process = subprocess.Popen(self.run_cmd, startupinfo=self.startupinfo)
process.wait()

start_elements = []
end_elements = []
diff_elements = []
path_start = os.path.join(self.output_dir, self.output_file_start)
path_end = os.path.join(self.output_dir, self.output_file_end)
path_diff = os.path.join(self.output_dir, self.output_file_diff)

with open(path_start, mode="r") as f:
reader = csv.DictReader(f, delimiter=",")
for row in reader:
start_elements.append(row)
with open(path_end, mode="r") as f:
reader = csv.DictReader(f, delimiter=",")
for row in reader:
keys = row.keys()
end_elements.append(row)

for element in start_elements:
if element not in end_elements:
diff_elements.append(f"--,{element}")
for element in end_elements:
if element not in start_elements:
diff_elements.append(f"++,{element}")

with open(path_diff, mode="w") as f:
if len(diff_elements) > 0:
f.write(f"Operation,{keys}\n")
f.writelines(f"{s}\n" for s in diff_elements)

files_to_upload = set()

if os.path.isfile(path_diff):
try:
if os.path.getsize(path_diff) > 0:
files_to_upload.add(path_diff)
else:
log.debug("Diff file is empty")
except Exception as e:
log.debug("Diff file doesn't seem to exist")

# Upload the autoruns diff file to the host.
log.debug(files_to_upload)
for f in files_to_upload:
# Prepend file name with autoruns to indicate autoruns
file_path_list = f.split("\\")
file_name = file_path_list[-1]
dumppath = os.path.join("autoruns", file_name)
log.debug("Autoruns Aux Module is uploading %s" % f)
upload_to_host(f, dumppath)
7 changes: 2 additions & 5 deletions data/yara/CAPE/DanaBot.yar
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,13 @@ rule DanaBot {
$s10 = "InjectionProcess" fullword ascii
$s11 = "proxylogin" fullword wide
$s12 = "\\FS_Morff\\FS_Temp\\" wide
$ds1 = "C:\\Windows\\System32\\rundll32.exe" fullword wide
$ds2 = "PExtended4" fullword ascii
$ds3 = "%s-%s" fullword wide
$ds4 = "00010203040506070809101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF0123456789ABCDEF" fullword wide
$s13 = "00010203040506070809101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF0123456789ABCDEF" fullword wide
//$o1 = { 55 8b ec 33 c0 55 68 d7 60 4f 00 64 ff 30 64 89 }
//$o2 = { e8 45 ec f0 ff e8 3c e2 f0 ff 68 00 04 00 00 e8 }
//$o3 = { e8 98 3a f2 ff 84 c0 74 0a 8d 44 24 0c 50 e8 fe }
//$o4 = { ba 80 d7 4f 00 a1 54 90 4f 00 e8 7e 4a f1 ff e9 }
//$o5 = { 80 bc 24 4a 01 00 00 01 75 14 ba 80 d7 4f 00 a1 }
//$o6 = { ba 80 d7 4f 00 a1 80 8f 4f 00 e8 4c 4a f1 ff e9 }
condition:
uint16(0) == 0x5a4d and (7 of ($s*) or 3 of ($ds*))
uint16(0) == 0x5a4d and (7 of ($s*))
}
File renamed without changes.
56 changes: 0 additions & 56 deletions data/yara/binaries/LNK_Ruleset.yar
Original file line number Diff line number Diff line change
Expand Up @@ -64,24 +64,6 @@ condition:
isLNK and any of them
}

rule EXE_in_LNK
{
meta:
description = "Identifies executable artefacts in shortcut (LNK) files."
author = "@bartblaze"
date = "2020-01"
tlp = "White"
strings:
$ = ".exe" ascii wide nocase
$ = ".dll" ascii wide nocase
$ = ".scr" ascii wide nocase
$ = ".pif" ascii wide nocase
$ = "This program" ascii wide nocase
$ = "TVqQAA" ascii wide nocase //MZ Base64
condition:
isLNK and any of them
}

rule Archive_in_LNK
{
meta:
Expand Down Expand Up @@ -161,30 +143,6 @@ condition:
isLNK and any of them
}

rule MSOffice_in_LNK
{
meta:
description = "Identifies Microsoft Office artefacts in shortcut (LNK) files."
author = "@bartblaze"
date = "2020-01"
tlp = "White"
strings:
$ = "winword" ascii wide nocase
$ = "excel" ascii wide nocase
$ = "powerpnt" ascii wide nocase
$ = ".rtf" ascii wide nocase
$ = ".doc" ascii wide nocase //.doc and .docx
$ = ".dot" ascii wide nocase //.dot and .dotm
$ = ".xls" ascii wide nocase //.xls and .xlsx
$ = ".xla" ascii wide nocase
$ = ".csv" ascii wide nocase
$ = ".ppt" ascii wide nocase //.ppt and .pptx
$ = ".pps" ascii wide nocase //.pps and .ppsx
$ = ".xml" ascii wide nocase
condition:
isLNK and any of them
}

rule PDF_in_LNK
{
meta:
Expand Down Expand Up @@ -226,20 +184,6 @@ condition:
isLNK and any of them
}


rule Long_RelativePath_LNK
{
meta:
description = "Identifies shortcut (LNK) file with a long relative path. Might be used in an attempt to hide the path."
author = "@bartblaze"
date = "2020-01"
tlp = "White"
strings:
$ = "..\\..\\..\\..\\" ascii wide nocase
condition:
isLNK and any of them
}

rule Large_filesize_LNK
{
meta:
Expand Down
54 changes: 54 additions & 0 deletions data/yara/deprecated/LNK_Ruleset.yar
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
rule EXE_in_LNK
{
meta:
description = "Identifies executable artefacts in shortcut (LNK) files."
author = "@bartblaze"
date = "2020-01"
tlp = "White"
strings:
$ = ".exe" ascii wide nocase
$ = ".dll" ascii wide nocase
$ = ".scr" ascii wide nocase
$ = ".pif" ascii wide nocase
$ = "This program" ascii wide nocase
$ = "TVqQAA" ascii wide nocase //MZ Base64
condition:
isLNK and any of them
}

rule Long_RelativePath_LNK
{
meta:
description = "Identifies shortcut (LNK) file with a long relative path. Might be used in an attempt to hide the path."
author = "@bartblaze"
date = "2020-01"
tlp = "White"
strings:
$ = "..\\..\\..\\..\\" ascii wide nocase
condition:
isLNK and any of them
}

rule MSOffice_in_LNK
{
meta:
description = "Identifies Microsoft Office artefacts in shortcut (LNK) files."
author = "@bartblaze"
date = "2020-01"
tlp = "White"
strings:
$ = "winword" ascii wide nocase
$ = "excel" ascii wide nocase
$ = "powerpnt" ascii wide nocase
$ = ".rtf" ascii wide nocase
$ = ".doc" ascii wide nocase //.doc and .docx
$ = ".dot" ascii wide nocase //.dot and .dotm
$ = ".xls" ascii wide nocase //.xls and .xlsx
$ = ".xla" ascii wide nocase
$ = ".csv" ascii wide nocase
$ = ".ppt" ascii wide nocase //.ppt and .pptx
$ = ".pps" ascii wide nocase //.pps and .ppsx
$ = ".xml" ascii wide nocase
condition:
isLNK and any of them
}
41 changes: 41 additions & 0 deletions modules/processing/autoruns.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import csv
import logging
import os

from lib.cuckoo.common.abstracts import Processing
from lib.cuckoo.common.exceptions import CuckooProcessingError

log = logging.getLogger(__name__)

__author__ = "[Canadian Centre for Cyber Security] @CybercentreCanada"
__version__ = "1.0.0"


class Autoruns(Processing):
def run(self):
self.key = "autoruns"
autoruns_dir = os.path.join(self.analysis_path, "autoruns")
autoruns_data_path = os.path.join(autoruns_dir, "autoruns.diff")

if os.path.exists(autoruns_data_path):
autoruns_path = autoruns_data_path
else:
return

data = {}
try:
with open(autoruns_path, "r") as f:
# Operation,Time,Entry Location,Entry,Enabled,Category,Profile,Description,Company,Image Path,Version,Launch String
reader = csv.DictReader(f, delimiter=",")
count = 0
for row in reader:
count += 1
data[str(count)] = str(row)

if count == 0:
data = None

except Exception as e:
raise CuckooProcessingError(f"Failed parsing {autoruns_path}: {e}")

return data
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
77 changes: 77 additions & 0 deletions modules/signatures/linux/deletes_files.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
from lib.cuckoo.common.abstracts import Signature


class LinuxDeletesFiles(Signature):
name = "deletes_files"
description = "Deletes files from disk"
os = "linux"
severity = 3
categories = ["persistence", "stealth"]
authors = ["winson0123"]
minimum = "1.3"
evented = True
ttps = ["T1107"] # MITRE v6
ttps += ["T1070", "T1070.004"] # MITRE v7,8
mbcs = ["OB0006", "F0007"]
mbcs += ["OC0001", "C0047"] # micro-behaviour

filter_apinames = set(
[
"truncate",
"ftruncate",
"open",
"openat",
"openat2",
"unlink",
"unlinkat",
]
)
flags = "O_TRUNC" # truncating makes file empty, take as a form of deletion

def __init__(self, *args, **kwargs):
Signature.__init__(self, *args, **kwargs)
self.loadctr = 0

def get_filename(self, call):
"""Retrieves the filename of read-related API call.
@param call: API call object.
@return: value of the required argument.
"""
# Check if the call passed to it was cached already.
# If not, we can start caching it and store a copy converted to a dict.
if call is not self._current_call_cache:
self._current_call_cache = call
self._current_call_list = [argument["value"] for argument in call["arguments"]]

# Return the filename from retrieved from the api call.
if self._current_call_list:
return self._current_call_list[0].split(" ")[1][1:-1]

return None

def on_call(self, call, process):
if call["api"] in ["truncate", "ftruncate"] and call["return"] == "0":
self.loadctr += 1
if call["api"] == "truncate":
self.data.append({"DeletedFile": self.get_argument(call, "const char *path")})
if call["api"] == "ftruncate":
self.data.append({"DeletedFile": self.get_filename(call)})
if call["api"] in ["unlink", "unlinkat"] and call["return"] == "0":
self.loadctr += 1
self.data.append({"DeletedFile": self.get_argument(call, "const char *pathname")})
if call["api"] == "open" and call["return"] > "-1":
if self.flags in self.get_argument(call, "int flags"):
self.loadctr += 1
self.data.append({"DeletedFile": self.get_filename(call)})
if call["api"] == "openat" and call["return"] > "-1":
if self.flags in self.get_argument(call, "int flags"):
self.loadctr += 1
self.data.append({"DeletedFile": self.get_argument(call, "const char *filename")})
if call["api"] == "openat2" and call["return"] > "-1":
if self.flags in self.get_argument(call, "struct open_how *how"):
self.loadctr += 1
self.data.append({"DeletedFile": self.get_argument(call, "const char *filename")})

def on_complete(self):
if self.loadctr > 0:
return True
Loading

0 comments on commit 4bd62c5

Please sign in to comment.