diff --git a/dissect/target/plugins/apps/browser/chrome.py b/dissect/target/plugins/apps/browser/chrome.py index 3374df60b..9bf63ff27 100644 --- a/dissect/target/plugins/apps/browser/chrome.py +++ b/dissect/target/plugins/apps/browser/chrome.py @@ -25,6 +25,7 @@ class ChromePlugin(ChromiumMixin, BrowserPlugin): DIRS = [ # Windows "AppData/Local/Google/Chrome/User Data/Default", + "AppData/Local/Google/Chrome/User Data/Snapshots/*/Default", "AppData/Local/Google/Chrome/continuousUpdates/User Data/Default", "Local Settings/Application Data/Google/Chrome/User Data/Default", # Linux diff --git a/dissect/target/plugins/apps/browser/chromium.py b/dissect/target/plugins/apps/browser/chromium.py index 514eedf2f..5b0f834e7 100644 --- a/dissect/target/plugins/apps/browser/chromium.py +++ b/dissect/target/plugins/apps/browser/chromium.py @@ -79,11 +79,12 @@ def _build_userdirs(self, hist_paths: list[str]) -> list[tuple[UserDetails, Targ users_dirs: list[tuple] = [] for user_details in self.target.user_details.all_with_home(): for d in hist_paths: - cur_dir: TargetPath = user_details.home_path.joinpath(d) - cur_dir = cur_dir.resolve() - if not cur_dir.exists() or (user_details, cur_dir) in users_dirs: - continue - users_dirs.append((user_details, cur_dir)) + home_dir: TargetPath = user_details.home_path + for cur_dir in home_dir.glob(d): + cur_dir = cur_dir.resolve() + if not cur_dir.exists() or (user_details.user, cur_dir) in users_dirs: + continue + users_dirs.append((user_details, cur_dir)) return users_dirs def _iter_db( diff --git a/dissect/target/plugins/apps/browser/edge.py b/dissect/target/plugins/apps/browser/edge.py index 3ed7d3543..7fe10c4be 100644 --- a/dissect/target/plugins/apps/browser/edge.py +++ b/dissect/target/plugins/apps/browser/edge.py @@ -28,6 +28,7 @@ class EdgePlugin(ChromiumMixin, BrowserPlugin): ".var/app/com.microsoft.Edge/config/microsoft-edge/Default", # Windows "AppData/Local/Microsoft/Edge/User Data/Default", + "AppData/Local/Microsoft/Edge/User Data/Snapshots/*/Default", # Macos "Library/Application Support/Microsoft Edge/Default", ] diff --git a/tests/plugins/apps/browser/test_chrome.py b/tests/plugins/apps/browser/test_chrome.py index 8679575ff..f5a49434f 100644 --- a/tests/plugins/apps/browser/test_chrome.py +++ b/tests/plugins/apps/browser/test_chrome.py @@ -32,9 +32,21 @@ def target_chrome_unix(target_unix_users: Target, fs_unix: VirtualFilesystem) -> yield target_unix_users +@pytest.fixture +def target_chrome_win_snapshot(target_win_users: Target, fs_win: VirtualFilesystem) -> Iterator[Target]: + fs_win.map_dir( + "Users\\John\\AppData\\Local\\Google\\Chrome\\User Data\\Snapshots\\116.0.5038.150\\Default", + absolute_path("_data/plugins/apps/browser/chrome/"), + ) + + target_win_users.add_plugin(ChromePlugin) + + yield target_win_users + + @pytest.mark.parametrize( "target_platform", - ["target_chrome_win", "target_chrome_unix"], + ["target_chrome_win", "target_chrome_unix", "target_chrome_win_snapshot"], ) def test_chrome_history(target_platform: Target, request: pytest.FixtureRequest) -> None: target_platform = request.getfixturevalue(target_platform) @@ -54,7 +66,7 @@ def test_chrome_history(target_platform: Target, request: pytest.FixtureRequest) @pytest.mark.parametrize( "target_platform", - ["target_chrome_win", "target_chrome_unix"], + ["target_chrome_win", "target_chrome_unix", "target_chrome_win_snapshot"], ) def test_chrome_downloads(target_platform: Target, request: pytest.FixtureRequest) -> None: target_platform = request.getfixturevalue(target_platform) @@ -71,7 +83,7 @@ def test_chrome_downloads(target_platform: Target, request: pytest.FixtureReques @pytest.mark.parametrize( "target_platform", - ["target_chrome_win", "target_chrome_unix"], + ["target_chrome_win", "target_chrome_unix", "target_chrome_win_snapshot"], ) def test_chrome_extensions(target_platform: Target, request: pytest.FixtureRequest) -> None: target_platform = request.getfixturevalue(target_platform) @@ -204,3 +216,39 @@ def test_windows_chrome_cookies_dpapi(target_win_users_dpapi: Target, fs_win: Vi "GPS": "1", "PREF": "tz=Europe.Berlin", } + + +def test_chrome_windows_snapshots(target_win_users: Target, fs_win: VirtualFilesystem) -> None: + base_dir = "Users\\John\\AppData\\Local\\Google\\Chrome\\User Data\\Default" + snapshot_dirs = [ + "Users\\John\\AppData\\Local\\Google\\Chrome\\User Data\\Snapshots\\116.0.5038.150\\Default", + "Users\\John\\AppData\\Local\\Google\\Chrome\\User Data\\Snapshots\\119.0.7845.119\\Default", + ] + profile_dirs = [base_dir] + snapshot_dirs + + for dir in profile_dirs: + fs_win.map_dir( + dir, + absolute_path("_data/plugins/apps/browser/chrome/"), + ) + + target_win_users.add_plugin(ChromePlugin) + + records_list = [ + list(target_win_users.chrome.history()), + list(target_win_users.chrome.extensions()), + list(target_win_users.chrome.downloads()), + ] + + # Loop over the different types of records and verify we have the same amount of records in each profile directory. + for records in records_list: + assert set(["chrome"]) == set(record.browser for record in records) + + base_path_records = [r for r in records if str(r.source.parent).endswith(base_dir)] + + for snapshot_dir in snapshot_dirs: + # Retrieve records that are in the snapshot's directory. + snapshot_records = [r for r in records if str(r.source.parent).endswith(snapshot_dir)] + + # We map the same files in each of the snapshot directories. + assert len(base_path_records) == len(snapshot_records) diff --git a/tests/plugins/apps/browser/test_edge.py b/tests/plugins/apps/browser/test_edge.py index 5043d31a1..7dfe65ac1 100644 --- a/tests/plugins/apps/browser/test_edge.py +++ b/tests/plugins/apps/browser/test_edge.py @@ -31,9 +31,21 @@ def target_edge_unix(target_unix_users, fs_unix): yield target_unix_users +@pytest.fixture +def target_edge_win_snapshot(target_win_users: Target, fs_win: VirtualFilesystem) -> Iterator[Target]: + fs_win.map_dir( + "Users\\John\\AppData\\Local\\Microsoft\\Edge\\User Data\\Snapshots\\116.0.5038.150\\Default", + absolute_path("_data/plugins/apps/browser/edge/"), + ) + + target_win_users.add_plugin(EdgePlugin) + + yield target_win_users + + @pytest.mark.parametrize( "target_platform", - ["target_edge_win", "target_edge_unix"], + ["target_edge_win", "target_edge_unix", "target_edge_win_snapshot"], ) def test_edge_history(target_platform: Target, request: pytest.FixtureRequest) -> None: target_platform = request.getfixturevalue(target_platform) @@ -50,7 +62,7 @@ def test_edge_history(target_platform: Target, request: pytest.FixtureRequest) - @pytest.mark.parametrize( "target_platform", - ["target_edge_win", "target_edge_unix"], + ["target_edge_win", "target_edge_unix", "target_edge_win_snapshot"], ) def test_edge_downloads(target_platform: Target, request: pytest.FixtureRequest) -> None: target_platform = request.getfixturevalue(target_platform) @@ -67,7 +79,7 @@ def test_edge_downloads(target_platform: Target, request: pytest.FixtureRequest) @pytest.mark.parametrize( "target_platform", - ["target_edge_win", "target_edge_unix"], + ["target_edge_win", "target_edge_unix", "target_edge_win_snapshot"], ) def test_edge_extensions(target_platform: Target, request: pytest.FixtureRequest) -> None: target_platform = request.getfixturevalue(target_platform) @@ -129,3 +141,39 @@ def test_unix_edge_passwords_gnome_plugin(target_edge_unix: Target, fs_unix: Vir assert records[0].decrypted_username == "username" assert records[0].decrypted_password is None assert records[0].url == "https://test.com/" + + +def test_edge_windows_snapshots(target_win_users: Target, fs_win: VirtualFilesystem) -> None: + base_dir = "Users\\John\\AppData\\Local\\Microsoft\\Edge\\User Data\\Default" + snapshot_dirs = [ + "Users\\John\\AppData\\Local\\Microsoft\\Edge\\User Data\\Snapshots\\116.0.5038.150\\Default", + "Users\\John\\AppData\\Local\\Microsoft\\Edge\\User Data\\Snapshots\\119.0.7845.119\\Default", + ] + profile_dirs = [base_dir] + snapshot_dirs + + for dir in profile_dirs: + fs_win.map_dir( + dir, + absolute_path("_data/plugins/apps/browser/edge/"), + ) + + target_win_users.add_plugin(EdgePlugin) + + records_list = [ + list(target_win_users.edge.history()), + list(target_win_users.edge.extensions()), + list(target_win_users.edge.downloads()), + ] + + # Loop over the different types of records and verify we have the same amount of records in each profile directory. + for records in records_list: + assert set(["edge"]) == set(record.browser for record in records) + + base_path_records = [r for r in records if str(r.source.parent).endswith(base_dir)] + + for snapshot_dir in snapshot_dirs: + # Retrieve records that are in the snapshot's directory. + snapshot_records = [r for r in records if str(r.source.parent).endswith(snapshot_dir)] + + # We map the same files in each of the snapshot directories. + assert len(base_path_records) == len(snapshot_records)