def create_missing_profiles(): """ Creates usermode profiles by restoring vm-1 and extracting the DLLs. Assumes that injector is configured properly, i.e. kernel and runtime profiles exist and that vm-1 is free to use. """ # Prepare injector with open(os.path.join(PROFILE_DIR, "runtime.json"), "r") as runtime_f: runtime_info = RuntimeInfo.load(runtime_f) kernel_profile = os.path.join(PROFILE_DIR, "kernel.json") injector = Injector("vm-1", runtime_info, kernel_profile) # restore vm-1 out_interface = conf["drakrun"].get("out_interface", "") dns_server = conf["drakrun"].get("dns_server", "") install_info = InstallInfo.load() backend = get_storage_backend(install_info) generate_vm_conf(install_info, 1) setup_vm_network(vm_id=1, net_enable=False, out_interface=out_interface, dns_server=dns_server) vm = VirtualMachine(backend, 1) vm.restore() # Ensure that all declared usermode profiles exist # This is important when upgrade defines new entries in dll_file_list and compulsory_dll_file_list for profile in compulsory_dll_file_list: if not profiles_exist(profile.dest): create_rekall_profile(injector, profile, True) for profile in dll_file_list: if not profiles_exist(profile.dest): try: create_rekall_profile(injector, profile) except Exception: log.exception( "Unexpected exception from create_rekall_profile!") build_os_info(APISCOUT_PROFILE_DIR, vmi_win_guid(vm.vm_name), backend) dll_basename_list = [dll.dest for dll in dll_file_list] static_apiscout_profile = build_static_apiscout_profile( APISCOUT_PROFILE_DIR, dll_basename_list) with open( Path(APISCOUT_PROFILE_DIR) / "static_apiscout_profile.json", "w") as f: json.dump(static_apiscout_profile, f) vm.destroy() delete_vm_network(vm_id=1, net_enable=False, out_interface=out_interface, dns_server=dns_server)
def memdump_export(bucket, instance): install_info = InstallInfo.try_load() if install_info is None: logging.error( "Missing installation info. Did you forget to set up the sandbox?") return backend = get_storage_backend(install_info) vm = VirtualMachine(backend, instance) if vm.is_running: logging.exception(f"vm-{instance} is running") return logging.info("Calculating snapshot hash...") snapshot_sha256 = file_sha256(os.path.join(VOLUME_DIR, "snapshot.sav")) name = f"{snapshot_sha256}_pre_sample.raw_memdump.gz" mc = get_minio_client(conf) if not mc.bucket_exists(bucket): logging.error("Bucket %s doesn't exist", bucket) return try: mc.stat_object(bucket, name) logging.info("This file already exists in specified bucket") return except NoSuchKey: pass except Exception: logging.exception("Failed to check if object exists on minio") logging.info("Restoring VM and performing memory dump") try: vm.restore(pause=True) except subprocess.CalledProcessError: logging.exception(f"Failed to restore VM {vm.vm_name}") with open(f"/var/log/xen/qemu-dm-{vm.vm_name}.log", "rb") as f: logging.error(f.read()) logging.info("VM restored") with tempfile.NamedTemporaryFile() as compressed_memdump: vm.memory_dump(compressed_memdump.name) logging.info(f"Uploading {name} to {bucket}") mc.fput_object(bucket, name, compressed_memdump.name) try: vm.destroy() except Exception: logging.exception("Failed to destroy VM") logging.info("Done")
def postupgrade(): if not check_root(): return with open(os.path.join(ETC_DIR, 'scripts/cfg.template'), 'r') as f: template = f.read() passwd_characters = string.ascii_letters + string.digits passwd = ''.join(secrets.choice(passwd_characters) for _ in range(20)) template = template.replace('{{ VNC_PASS }}', passwd) with open(os.path.join(ETC_DIR, 'scripts', 'cfg.template'), 'w') as f: f.write(template) detect_defaults() install_info = InstallInfo.try_load() if not install_info: logging.info("Postupgrade done. DRAKVUF Sandbox not installed.") return # Prepare injector with open(os.path.join(PROFILE_DIR, "runtime.json"), 'r') as runtime_f: runtime_info = RuntimeInfo.load(runtime_f) kernel_profile = os.path.join(PROFILE_DIR, "kernel.json") injector = Injector('vm-1', runtime_info, kernel_profile) stop_all_drakruns() # Use vm-1 for generating profiles out_interface = conf['drakrun'].get('out_interface', '') dns_server = conf['drakrun'].get('dns_server', '') setup_vm_network(vm_id=1, net_enable=False, out_interface=out_interface, dns_server=dns_server) backend = get_storage_backend(install_info) vm = VirtualMachine(backend, 1) vm.restore() create_missing_profiles(injector) vm.destroy() delete_vm_network(vm_id=1, net_enable=False, out_interface=out_interface, dns_server=dns_server) start_enabled_drakruns()
def create_missing_profiles(): """ Creates usermode profiles by restoring vm-1 and extracting the DLLs. Assumes that injector is configured properly, i.e. kernel and runtime profiles exist and that vm-1 is free to use. """ # Prepare injector with open(os.path.join(PROFILE_DIR, "runtime.json"), "r") as runtime_f: runtime_info = RuntimeInfo.load(runtime_f) kernel_profile = os.path.join(PROFILE_DIR, "kernel.json") injector = Injector("vm-1", runtime_info, kernel_profile) # restore vm-1 out_interface = conf["drakrun"].get("out_interface", "") dns_server = conf["drakrun"].get("dns_server", "") install_info = InstallInfo.load() backend = get_storage_backend(install_info) generate_vm_conf(install_info, 1) setup_vm_network(vm_id=1, net_enable=False, out_interface=out_interface, dns_server=dns_server) vm = VirtualMachine(backend, 1) vm.restore() # Ensure that all declared usermode profiles exist # This is important when upgrade defines new entries in dll_file_list and compulsory_dll_file_list for profile in compulsory_dll_file_list: if not profile_exists(profile): create_rekall_profile(injector, profile, True) for profile in dll_file_list: if not profile_exists(profile): try: create_rekall_profile(injector, profile) except Exception: # silence per-dll errors pass vm.destroy() delete_vm_network(vm_id=1, net_enable=False, out_interface=out_interface, dns_server=dns_server)
def run_vm(self): backend = get_storage_backend(self.install_info) vm = VirtualMachine(backend, self.instance_id) try: vm.restore() except subprocess.CalledProcessError: self.log.exception(f"Failed to restore VM {self.vm_name}") with open(f"/var/log/xen/qemu-dm-{self.vm_name}.log", "rb") as f: logging.error(f.read()) self.log.info("VM restored") try: yield vm finally: try: vm.destroy() except Exception: self.log.exception("Failed to destroy VM")
class DrakmonShell: def __init__(self, vm_id: int, dns: str): self.cleanup(vm_id) install_info = InstallInfo.load() backend = get_storage_backend(install_info) generate_vm_conf(install_info, vm_id) self.vm = VirtualMachine(backend, vm_id) self._dns = dns with open(Path(PROFILE_DIR) / "runtime.json", "r") as f: self.runtime_info = RuntimeInfo.load(f) self.desktop = WinPath(r"%USERPROFILE%") / "Desktop" self.kernel_profile = Path(PROFILE_DIR) / "kernel.json" self.injector = Injector( self.vm.vm_name, self.runtime_info, self.kernel_profile, ) setup_vm_network(vm_id, True, find_default_interface(), dns) def cleanup(self, vm_id: int): logging.info(f"Ensuring that drakrun@{vm_id} service is stopped...") try: subprocess.run( ["systemctl", "stop", f"drakrun@{vm_id}"], stderr=subprocess.STDOUT, check=True, ) except subprocess.CalledProcessError: raise Exception(f"drakrun@{vm_id} not stopped") def drakvuf(self, plugins, timeout=60): d = tempfile.TemporaryDirectory(prefix="drakvuf_") workdir = Path(d.name) log = open(workdir / "drakmon.log", "wb") cmd = ["drakvuf"] cmd.extend([ "-o", "json", "F", "-j", "5", "-t", str(timeout), "-i", str(self.runtime_info.inject_pid), "-k", str(self.runtime_info.vmi_offsets.kpgd), "-r", self.kernel_profile, "-d", self.vm.vm_name, "--dll-hooks-list", Path(ETC_DIR) / "hooks.txt", ]) if "memdump" in plugins: dumps = workdir / "dumps" dumps.mkdir() cmd.extend(["--memdump-dir", dumps]) if "ipt" in plugins: ipt = workdir / "ipt" ipt.mkdir() cmd.extend(["--ipt-dir", ipt]) for chk in (["-a", plugin] for plugin in plugins): cmd.extend(chk) subprocess.run(cmd, stdout=log) return d def help(self): usage = dedent("""\ Available commands: - copy(file_path) # copy file onto vm desktop - mount(iso_path) # mount iso, useful for installing software, e.g. office - drakvuf(plugins) # start drakvuf with provided set of plugins - run(cmd) # run command inside vm - exit() # exit playground """) print(usage) def copy(self, local): local = Path(local) self.injector.write_file(local, self.desktop / local.name) def mount(self, local_iso_path, drive=FIRST_CDROM_DRIVE): local_iso_path = Path(local_iso_path) insert_cd(self.vm.vm_name, drive, local_iso_path) def run(self, cmd): self.injector.create_process(cmd) def __enter__(self): self.vm.restore() return self def __exit__(self, exc_type, exc_value, exc_traceback): self.vm.destroy() delete_vm_network(self.vm.vm_id, True, find_default_interface(), self._dns)
class DrakmonShell: def __init__(self, vm_id: int, dns: str): self.cleanup(vm_id) install_info = InstallInfo.load() backend = get_storage_backend(install_info) generate_vm_conf(install_info, vm_id) self.vm = VirtualMachine(backend, vm_id) self._dns = dns with open(Path(PROFILE_DIR) / "runtime.json", 'r') as f: self.runtime_info = RuntimeInfo.load(f) self.desktop = WinPath(r"%USERPROFILE%") / "Desktop" self.kernel_profile = Path(PROFILE_DIR) / "kernel.json" self.injector = Injector( self.vm.vm_name, self.runtime_info, self.kernel_profile, ) setup_vm_network(vm_id, True, find_default_interface(), dns) def cleanup(self, vm_id: int): logging.info(f"Ensuring that drakrun@{vm_id} service is stopped...") try: subprocess.run(['systemctl', 'stop', f'drakrun@{vm_id}'], stderr=subprocess.STDOUT, check=True) except subprocess.CalledProcessError: raise Exception(f"drakrun@{vm_id} not stopped") def drakvuf(self, plugins, timeout=60): d = tempfile.TemporaryDirectory(prefix="drakvuf_") workdir = Path(d.name) log = open(workdir / "drakmon.log", "wb") cmd = ["drakvuf"] cmd.extend([ "-o", "json", "F", "-j", "5", "-t", str(timeout), "-i", str(self.runtime_info.inject_pid), "-k", str(self.runtime_info.vmi_offsets.kpgd), "-r", self.kernel_profile, "-d", self.vm.vm_name, "--dll-hooks-list", Path(ETC_DIR) / "hooks.txt", ]) if "memdump" in plugins: dumps = workdir / "dumps" dumps.mkdir() cmd.extend(["--memdump-dir", dumps]) if "ipt" in plugins: ipt = workdir / "ipt" ipt.mkdir() cmd.extend(["--ipt-dir", ipt]) for chk in (["-a", plugin] for plugin in plugins): cmd.extend(chk) subprocess.run(cmd, stdout=log) return d def copy(self, local): local = Path(local) self.injector.write_file(local, self.desktop / local.name) def run(self, cmd): self.injector.create_process(cmd) def __enter__(self): self.vm.restore() return self def __exit__(self, exc_type, exc_value, exc_traceback): self.vm.destroy() delete_vm_network(self.vm.vm_id, True, find_default_interface(), self._dns)