From 73f434d06c722760b550d32ae8f3f1ebe57077e2 Mon Sep 17 00:00:00 2001 From: Miauwkeru Date: Thu, 16 Nov 2023 12:48:51 +0000 Subject: [PATCH] Add volatile profiles --- acquire/acquire.py | 59 ++++++++++++++++++++++++++++++++++++++++------ acquire/utils.py | 24 +++++++++++++------ 2 files changed, 69 insertions(+), 14 deletions(-) diff --git a/acquire/acquire.py b/acquire/acquire.py index 39b251a0..963d2fd2 100644 --- a/acquire/acquire.py +++ b/acquire/acquire.py @@ -1813,6 +1813,22 @@ def acquire_target_targetd(target: Target, args: argparse.Namespace, output_ts: return files +def _add_modules_for_profile(choice: str, operating_system: str, profile: dict, msg: str): + + modules_selected = dict() + + if choice and choice != "none": + profile_dict = profile[choice] + if operating_system not in profile_dict: + log.error(msg, operating_system, choice) + return {} + + for mod in profile_dict[operating_system]: + modules_selected[mod.__modname__] = mod + + return modules_selected + + def acquire_target_regular(target: Target, args: argparse.Namespace, output_ts: Optional[str] = None) -> list[str]: files = [] output_ts = output_ts or get_utc_now_str() @@ -1880,13 +1896,15 @@ def acquire_target_regular(target: Target, args: argparse.Namespace, output_ts: profile = "default" log.info("") - if profile and profile != "none": - if target.os not in PROFILES[profile]: - log.error("No collection set for OS %s with profile %s", target.os, profile) - return files + profile_modules = _add_modules_for_profile(profile, target.os, PROFILES, "No collection set for OS %s with profile %s") + volatile_modules = _add_modules_for_profile(args.volatile, target.os, VOLATILE, "No collection set for OS %s with volatile profile %s") + + modules_selected.update(profile_modules) + modules_selected.update(volatile_modules) + + if not (profile_modules or volatile_modules): + return files - for mod in PROFILES[profile][target.os]: - modules_selected[mod.__modname__] = mod log.info("Modules selected: %s", ", ".join(sorted(modules_selected))) @@ -2143,9 +2161,36 @@ class OSXProfile: "none": None, } +class VolatileProfile: + DEFAULT = [ + Netstat, + WinProcesses, + WinProcEnv, + WinArpCache, + WinRDPSessions, + WinDnsClientCache + ] + EXTENSIVE = [ + Proc, + Sys + ] + +VOLATILE = { + "default":{ + "windows": VolatileProfile.DEFAULT + }, + "extensive": { + "windows": VolatileProfile.DEFAULT, + "linux": VolatileProfile.EXTENSIVE, + "bsd": VolatileProfile.EXTENSIVE, + "esxi": VolatileProfile.EXTENSIVE + }, + "none": None +} + def main() -> None: - parser = create_argument_parser(PROFILES, MODULES) + parser = create_argument_parser(PROFILES, VOLATILE, MODULES) args = parse_acquire_args(parser, config=CONFIG) try: diff --git a/acquire/utils.py b/acquire/utils.py index 673cc2c0..daaeff79 100644 --- a/acquire/utils.py +++ b/acquire/utils.py @@ -36,25 +36,34 @@ class StrEnum(str, Enum): """Sortable and serializible string-based enum""" -def create_argument_parser(profiles: dict, modules: dict) -> argparse.ArgumentParser: +def _create_profile_information(profiles: dict): desc = "" profile_names = (name for name in profiles.keys() if name != "none") - for name in profile_names: + profile_dict = profiles[name] desc += f"{name} profile:\n" - minindent = max([len(os_) for os_ in profiles[name].keys()]) + + minindent = max([len(os_) for os_ in profile_dict.keys()]) descfmt = f" {{:{minindent}s}}: {{}}\n" - for os_ in profiles[name].keys(): - indent = 4 + len(os_) - modlist = textwrap.wrap(", ".join([mod.__modname__ for mod in profiles[name][os_]]), 50) + for os_, modlist in profile_dict.items(): + indent = 4 + len(os_) + modlist = textwrap.wrap(", ".join([mod.__modname__ for mod in modlist]), 50) moddesc = modlist.pop(0) for ml in modlist: moddesc += "\n" + (" " * indent) + ml - desc += descfmt.format(os_, moddesc) desc += "\n" + + return desc + + + +def create_argument_parser(profiles: dict, volatile: dict, modules: dict) -> argparse.ArgumentParser: + + desc = _create_profile_information(profiles) + desc += _create_profile_information(volatile) parser = argparse.ArgumentParser( prog="acquire", @@ -101,6 +110,7 @@ def create_argument_parser(profiles: dict, modules: dict) -> argparse.ArgumentPa parser.add_argument("-l", "--log", type=Path, help="log directory location") parser.add_argument("--no-log", action="store_true", help=argparse.SUPPRESS) parser.add_argument("-p", "--profile", choices=profiles.keys(), help="collection profile") + parser.add_argument("--volatile", choices=volatile.keys(), help="volatile profile") parser.add_argument("-f", "--file", action="append", help="acquire file") parser.add_argument("-d", "--directory", action="append", help="acquire directory recursively")