diff --git a/dissect/target/loaders/dir.py b/dissect/target/loaders/dir.py index 4dda9fabd..a86a540b0 100644 --- a/dissect/target/loaders/dir.py +++ b/dissect/target/loaders/dir.py @@ -34,12 +34,12 @@ def find_entry_path(path: Path) -> str | None: return prefix -def map_dirs(target: Target, dirs: list[Path], os_type: str, **kwargs) -> None: +def map_dirs(target: Target, dirs: list[Path | tuple[str, Path]], os_type: str, **kwargs) -> None: """Map directories as filesystems into the given target. Args: target: The target to map into. - dirs: The directories to map as filesystems. + dirs: The directories to map as filesystems. If a list member is a tuple, the first element is the drive letter. os_type: The operating system type, used to determine how the filesystem should be mounted. """ alt_separator = "" @@ -49,6 +49,12 @@ def map_dirs(target: Target, dirs: list[Path], os_type: str, **kwargs) -> None: case_sensitive = False for path in dirs: + drive_letter = None + if isinstance(path, tuple): + drive_letter, path = path + elif is_drive_letter_path(path): + drive_letter = path.name[0] + if isinstance(path, zipfile.Path): dfs = ZipFilesystem(path.root.fp, path.at, alt_separator=alt_separator, case_sensitive=case_sensitive) else: @@ -58,8 +64,8 @@ def map_dirs(target: Target, dirs: list[Path], os_type: str, **kwargs) -> None: if os_type == OperatingSystem.WINDOWS: loaderutil.add_virtual_ntfs_filesystem(target, dfs, **kwargs) - if is_drive_letter_path(path): - target.fs.mount(path.name[0] + ":", dfs) + if drive_letter is not None: + target.fs.mount(drive_letter.lower() + ":", dfs) def find_and_map_dirs(target: Target, path: Path, **kwargs) -> None: diff --git a/dissect/target/loaders/velociraptor.py b/dissect/target/loaders/velociraptor.py index a0f66e79e..c570337f6 100644 --- a/dissect/target/loaders/velociraptor.py +++ b/dissect/target/loaders/velociraptor.py @@ -43,6 +43,8 @@ def find_fs_directories(path: Path) -> tuple[Optional[OperatingSystem], Optional # https://github.com/Velocidex/velociraptor/blob/87368e7cc678144592a1614bb3bbd0a0f900ded9/accessors/ntfs/vss.go#L82 if "HarddiskVolumeShadowCopy" in volume.name: vss_volumes.add(volume) + elif (drive_letter := extract_drive_letter(volume.name)) is not None: + volumes.add((drive_letter, volume)) else: volumes.add(volume) @@ -54,6 +56,12 @@ def find_fs_directories(path: Path) -> tuple[Optional[OperatingSystem], Optional return None, None +def extract_drive_letter(name: str) -> Optional[str]: + # \\.\X: in URL encoding + if len(name) == 14 and name.startswith("%5C%5C.%5C") and name.endswith("%3A"): + return name[10].lower() + + class VelociraptorLoader(DirLoader): """Load Rapid7 Velociraptor forensic image files. diff --git a/tests/loaders/test_kape.py b/tests/loaders/test_kape.py index 15c7fffc6..fb224fdd8 100644 --- a/tests/loaders/test_kape.py +++ b/tests/loaders/test_kape.py @@ -25,8 +25,15 @@ def test_kape_loader(target_bare, tmp_path): loader = KapeLoader(root) loader.map(target_bare) + target_bare.apply() + + assert "sysvol" in target_bare.fs.mounts + assert "c:" in target_bare.fs.mounts + assert "d:" in target_bare.fs.mounts + assert "e:" in target_bare.fs.mounts # The 3 found drive letter directories + the fake NTFS filesystem assert len(target_bare.filesystems) == 4 - assert len(target_bare.fs.mounts) == 3 - assert len(list(target_bare.fs.mounts["C:"].ntfs.usnjrnl.records())) == 1 + # The 3 found drive letters + sysvol + the fake NTFS filesystem at /$fs$ + assert len(target_bare.fs.mounts) == 5 + assert len(list(target_bare.fs.mounts["c:"].ntfs.usnjrnl.records())) == 1 diff --git a/tests/loaders/test_tanium.py b/tests/loaders/test_tanium.py index 05d017be2..ee1ae0c42 100644 --- a/tests/loaders/test_tanium.py +++ b/tests/loaders/test_tanium.py @@ -25,8 +25,15 @@ def test_tanium_loader(target_bare, tmp_path): loader = TaniumLoader(root) loader.map(target_bare) + target_bare.apply() + + assert "sysvol" in target_bare.fs.mounts + assert "c:" in target_bare.fs.mounts + assert "d:" in target_bare.fs.mounts + assert "e:" in target_bare.fs.mounts # The 3 found drive letter directories + the fake NTFS filesystem assert len(target_bare.filesystems) == 4 - assert len(target_bare.fs.mounts) == 3 - assert len(list(target_bare.fs.mounts["C:"].ntfs.usnjrnl.records())) == 1 + # The 3 found drive letters + sysvol + the fake NTFS filesystem at /$fs$ + assert len(target_bare.fs.mounts) == 5 + assert len(list(target_bare.fs.mounts["c:"].ntfs.usnjrnl.records())) == 1 diff --git a/tests/loaders/test_velociraptor.py b/tests/loaders/test_velociraptor.py index f0b299c38..bf2318401 100644 --- a/tests/loaders/test_velociraptor.py +++ b/tests/loaders/test_velociraptor.py @@ -55,6 +55,9 @@ def test_velociraptor_loader_windows_ntfs(sub_dir: str, target_bare: Target, tmp loader.map(target_bare) target_bare.apply() + assert "sysvol" in target_bare.fs.mounts + assert "c:" in target_bare.fs.mounts + usnjrnl_records = 0 for fs in target_bare.filesystems: if isinstance(fs, NtfsFilesystem): @@ -80,6 +83,9 @@ def test_velociraptor_loader_windows_ntfs_zip(sub_dir: str, target_bare: Target, loader.map(target_bare) target_bare.apply() + assert "sysvol" in target_bare.fs.mounts + assert "c:" in target_bare.fs.mounts + usnjrnl_records = 0 for fs in target_bare.filesystems: if isinstance(fs, NtfsFilesystem):