diff --git a/acquire/acquire.py b/acquire/acquire.py index 39b251a0..9588902c 100644 --- a/acquire/acquire.py +++ b/acquire/acquire.py @@ -1813,6 +1813,21 @@ 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 +1895,18 @@ 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" + ) - for mod in PROFILES[profile][target.os]: - modules_selected[mod.__modname__] = mod + modules_selected.update(profile_modules) + modules_selected.update(volatile_modules) + + if not (profile_modules or volatile_modules): + return files log.info("Modules selected: %s", ", ".join(sorted(modules_selected))) @@ -2144,8 +2164,35 @@ class OSXProfile: } +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..bc3cb8de 100644 --- a/acquire/utils.py +++ b/acquire/utils.py @@ -36,26 +36,33 @@ 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", description=desc, @@ -101,6 +108,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")