Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open all iOS sqlite3 databases with immutable=1 #430

Merged
merged 1 commit into from
Nov 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions mvt/ios/modules/backup/manifest.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import logging
import os
import plistlib
import sqlite3
from typing import Optional

from mvt.common.module import DatabaseNotFoundError
Expand Down Expand Up @@ -124,7 +123,7 @@ def run(self) -> None:

self.log.info("Found Manifest.db database at path: %s", manifest_db_path)

conn = sqlite3.connect(manifest_db_path)
conn = self._open_sqlite_db(manifest_db_path)
cur = conn.cursor()

cur.execute("SELECT * FROM Files;")
Expand Down
7 changes: 5 additions & 2 deletions mvt/ios/modules/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def _recover_sqlite_db_if_needed(
"""
# TODO: Find a better solution.
if not forced:
conn = sqlite3.connect(file_path)
conn = self._open_sqlite_db(file_path)
cur = conn.cursor()

try:
Expand Down Expand Up @@ -91,6 +91,9 @@ def _recover_sqlite_db_if_needed(

self.log.info("Database at path %s recovered successfully!", file_path)

def _open_sqlite_db(self, file_path: str) -> sqlite3.Connection:
return sqlite3.connect(f"file:{file_path}?immutable=1")

def _get_backup_files_from_manifest(
self, relative_path: Optional[str] = None, domain: Optional[str] = None
) -> Iterator[dict]:
Expand All @@ -109,7 +112,7 @@ def _get_backup_files_from_manifest(
base_sql = "SELECT fileID, domain, relativePath FROM Files WHERE "

try:
conn = sqlite3.connect(manifest_db_path)
conn = self._open_sqlite_db(manifest_db_path)
cur = conn.cursor()
if relative_path and domain:
cur.execute(
Expand Down
2 changes: 1 addition & 1 deletion mvt/ios/modules/fs/analytics.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ def check_indicators(self) -> None:
def _extract_analytics_data(self):
artifact = self.file_path.split("/")[-1]

conn = sqlite3.connect(self.file_path)
conn = self._open_sqlite_db(self.file_path)
cur = conn.cursor()

try:
Expand Down
2 changes: 1 addition & 1 deletion mvt/ios/modules/fs/cache_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def check_indicators(self) -> None:
def _process_cache_file(self, file_path):
self.log.info("Processing cache file at path: %s", file_path)

conn = sqlite3.connect(file_path)
conn = self._open_sqlite_db(file_path)
cur = conn.cursor()

try:
Expand Down
3 changes: 1 addition & 2 deletions mvt/ios/modules/fs/safari_favicon.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
# https://license.mvt.re/1.1/

import logging
import sqlite3
from typing import Optional, Union

from mvt.common.utils import convert_mactime_to_iso
Expand Down Expand Up @@ -61,7 +60,7 @@ def check_indicators(self) -> None:
self.detected.append(result)

def _process_favicon_db(self, file_path):
conn = sqlite3.connect(file_path)
conn = self._open_sqlite_db(file_path)

# Fetch valid icon cache.
cur = conn.cursor()
Expand Down
3 changes: 1 addition & 2 deletions mvt/ios/modules/mixed/calendar.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
# https://license.mvt.re/1.1/

import logging
import sqlite3
from typing import Optional, Union

from mvt.common.utils import convert_mactime_to_iso
Expand Down Expand Up @@ -82,7 +81,7 @@ def _parse_calendar_db(self):
"""
Parse the calendar database
"""
conn = sqlite3.connect(self.file_path)
conn = self._open_sqlite_db(self.file_path)
cur = conn.cursor()

cur.execute(
Expand Down
3 changes: 1 addition & 2 deletions mvt/ios/modules/mixed/calls.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
# https://license.mvt.re/1.1/

import logging
import sqlite3
from typing import Optional, Union

from mvt.common.utils import convert_mactime_to_iso
Expand Down Expand Up @@ -53,7 +52,7 @@ def run(self) -> None:
)
self.log.info("Found Calls database at path: %s", self.file_path)

conn = sqlite3.connect(self.file_path)
conn = self._open_sqlite_db(self.file_path)
cur = conn.cursor()
cur.execute(
"""
Expand Down
3 changes: 1 addition & 2 deletions mvt/ios/modules/mixed/chrome_favicon.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
# https://license.mvt.re/1.1/

import logging
import sqlite3
from typing import Optional, Union

from mvt.common.utils import convert_chrometime_to_datetime, convert_datetime_to_iso
Expand Down Expand Up @@ -66,7 +65,7 @@ def run(self) -> None:
)
self.log.info("Found Chrome favicon cache database at path: %s", self.file_path)

conn = sqlite3.connect(self.file_path)
conn = self._open_sqlite_db(self.file_path)

# Fetch icon cache
cur = conn.cursor()
Expand Down
3 changes: 1 addition & 2 deletions mvt/ios/modules/mixed/chrome_history.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
# https://license.mvt.re/1.1/

import logging
import sqlite3
from typing import Optional, Union

from mvt.common.utils import convert_chrometime_to_datetime, convert_datetime_to_iso
Expand Down Expand Up @@ -67,7 +66,7 @@ def run(self) -> None:
)
self.log.info("Found Chrome history database at path: %s", self.file_path)

conn = sqlite3.connect(self.file_path)
conn = self._open_sqlite_db(self.file_path)
cur = conn.cursor()
cur.execute(
"""
Expand Down
2 changes: 1 addition & 1 deletion mvt/ios/modules/mixed/contacts.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def run(self) -> None:
)
self.log.info("Found Contacts database at path: %s", self.file_path)

conn = sqlite3.connect(self.file_path)
conn = self._open_sqlite_db(self.file_path)
cur = conn.cursor()
try:
cur.execute(
Expand Down
3 changes: 1 addition & 2 deletions mvt/ios/modules/mixed/firefox_favicon.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
# https://license.mvt.re/1.1/

import logging
import sqlite3
from typing import Optional, Union

from mvt.common.utils import convert_unix_to_iso
Expand Down Expand Up @@ -68,7 +67,7 @@ def run(self) -> None:
)
self.log.info("Found Firefox favicon database at path: %s", self.file_path)

conn = sqlite3.connect(self.file_path)
conn = self._open_sqlite_db(self.file_path)
cur = conn.cursor()
cur.execute(
"""
Expand Down
3 changes: 1 addition & 2 deletions mvt/ios/modules/mixed/firefox_history.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
# https://license.mvt.re/1.1/

import logging
import sqlite3
from typing import Optional, Union

from mvt.common.utils import convert_unix_to_iso
Expand Down Expand Up @@ -68,7 +67,7 @@ def run(self) -> None:
)
self.log.info("Found Firefox history database at path: %s", self.file_path)

conn = sqlite3.connect(self.file_path)
conn = self._open_sqlite_db(self.file_path)
cur = conn.cursor()
cur.execute(
"""
Expand Down
2 changes: 1 addition & 1 deletion mvt/ios/modules/mixed/interactionc.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ def run(self) -> None:
)
self.log.info("Found InteractionC database at path: %s", self.file_path)

conn = sqlite3.connect(self.file_path)
conn = self._open_sqlite_db(self.file_path)
cur = conn.cursor()

try:
Expand Down
2 changes: 1 addition & 1 deletion mvt/ios/modules/mixed/safari_browserstate.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def check_indicators(self) -> None:

def _process_browser_state_db(self, db_path):
self._recover_sqlite_db_if_needed(db_path)
conn = sqlite3.connect(db_path)
conn = self._open_sqlite_db(db_path)

cur = conn.cursor()
try:
Expand Down
3 changes: 1 addition & 2 deletions mvt/ios/modules/mixed/safari_history.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

import logging
import os
import sqlite3
from typing import Optional, Union

from mvt.common.url import URL
Expand Down Expand Up @@ -115,7 +114,7 @@ def check_indicators(self) -> None:

def _process_history_db(self, history_path):
self._recover_sqlite_db_if_needed(history_path)
conn = sqlite3.connect(history_path)
conn = self._open_sqlite_db(history_path)
cur = conn.cursor()
cur.execute(
"""
Expand Down
2 changes: 1 addition & 1 deletion mvt/ios/modules/mixed/shortcuts.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ def run(self) -> None:
)
self.log.info("Found Shortcuts database at path: %s", self.file_path)

conn = sqlite3.connect(self.file_path)
conn = self._open_sqlite_db(self.file_path)
conn.text_factory = bytes
cur = conn.cursor()
try:
Expand Down
4 changes: 2 additions & 2 deletions mvt/ios/modules/mixed/sms.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ def run(self) -> None:
self.log.info("Found SMS database at path: %s", self.file_path)

try:
conn = sqlite3.connect(self.file_path)
conn = self._open_sqlite_db(self.file_path)
cur = conn.cursor()
cur.execute(
"""
Expand All @@ -103,7 +103,7 @@ def run(self) -> None:
conn.close()
if "database disk image is malformed" in str(exc):
self._recover_sqlite_db_if_needed(self.file_path, forced=True)
conn = sqlite3.connect(self.file_path)
conn = self._open_sqlite_db(self.file_path)
cur = conn.cursor()
cur.execute(
"""
Expand Down
3 changes: 1 addition & 2 deletions mvt/ios/modules/mixed/sms_attachments.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
# https://license.mvt.re/1.1/

import logging
import sqlite3
from base64 import b64encode
from typing import Optional, Union

Expand Down Expand Up @@ -72,7 +71,7 @@ def run(self) -> None:
self._find_ios_database(backup_ids=SMS_BACKUP_IDS, root_paths=SMS_ROOT_PATHS)
self.log.info("Found SMS database at path: %s", self.file_path)

conn = sqlite3.connect(self.file_path)
conn = self._open_sqlite_db(self.file_path)
cur = conn.cursor()
cur.execute(
"""
Expand Down
2 changes: 1 addition & 1 deletion mvt/ios/modules/mixed/tcc.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ def check_indicators(self) -> None:
self.detected.append(result)

def process_db(self, file_path):
conn = sqlite3.connect(file_path)
conn = self._open_sqlite_db(file_path)
cur = conn.cursor()
db_version = "v3"
try:
Expand Down
2 changes: 1 addition & 1 deletion mvt/ios/modules/mixed/webkit_resource_load_statistics.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def _process_observations_db(self, db_path: str, domain: str, path: str) -> None

self._recover_sqlite_db_if_needed(db_path)

conn = sqlite3.connect(db_path)
conn = self._open_sqlite_db(db_path)
cur = conn.cursor()

try:
Expand Down
3 changes: 1 addition & 2 deletions mvt/ios/modules/mixed/whatsapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
# https://license.mvt.re/1.1/

import logging
import sqlite3
from typing import Optional, Union

from mvt.common.utils import check_for_links, convert_mactime_to_iso
Expand Down Expand Up @@ -69,7 +68,7 @@ def run(self) -> None:
)
self.log.info("Found WhatsApp database at path: %s", self.file_path)

conn = sqlite3.connect(self.file_path)
conn = self._open_sqlite_db(self.file_path)
cur = conn.cursor()

# Query all messages and join tables which can contain media attachments
Expand Down
14 changes: 3 additions & 11 deletions tests/ios_fs/test_filesystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,23 @@
# https://license.mvt.re/1.1/
import logging

import pytest

from mvt.common.indicators import Indicators
from mvt.common.module import run_module
from mvt.ios.modules.fs.filesystem import Filesystem

from ..utils import delete_tmp_db_files, get_ios_backup_folder


@pytest.fixture()
def cleanup_tmp_artifacts():
ios_backup_folder = get_ios_backup_folder()
delete_tmp_db_files(ios_backup_folder)
return
from ..utils import get_ios_backup_folder


class TestFilesystem:
def test_filesystem(self, cleanup_tmp_artifacts):
def test_filesystem(self):
m = Filesystem(target_path=get_ios_backup_folder())
run_module(m)
assert len(m.results) == 15
assert len(m.timeline) == 15
assert len(m.detected) == 0

def test_detection(self, indicator_file, cleanup_tmp_artifacts):
def test_detection(self, indicator_file):
m = Filesystem(target_path=get_ios_backup_folder())
ind = Indicators(log=logging.getLogger())
ind.parse_stix2(indicator_file)
Expand Down
Loading