mirror of https://github.com/mvt-project/mvt.git
Open all iOS sqlite3 databases with immutable=1 (#430)
This commit is contained in:
parent
fb52f73556
commit
fd3ef76873
|
@ -8,7 +8,6 @@ import io
|
|||
import logging
|
||||
import os
|
||||
import plistlib
|
||||
import sqlite3
|
||||
from typing import Optional
|
||||
|
||||
from mvt.common.module import DatabaseNotFoundError
|
||||
|
@ -124,7 +123,7 @@ class Manifest(IOSExtraction):
|
|||
|
||||
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;")
|
||||
|
|
|
@ -49,7 +49,7 @@ class IOSExtraction(MVTModule):
|
|||
"""
|
||||
# TODO: Find a better solution.
|
||||
if not forced:
|
||||
conn = sqlite3.connect(file_path)
|
||||
conn = self._open_sqlite_db(file_path)
|
||||
cur = conn.cursor()
|
||||
|
||||
try:
|
||||
|
@ -91,6 +91,9 @@ class IOSExtraction(MVTModule):
|
|||
|
||||
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]:
|
||||
|
@ -109,7 +112,7 @@ class IOSExtraction(MVTModule):
|
|||
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(
|
||||
|
|
|
@ -85,7 +85,7 @@ class Analytics(IOSExtraction):
|
|||
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:
|
||||
|
|
|
@ -64,7 +64,7 @@ class CacheFiles(IOSExtraction):
|
|||
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:
|
||||
|
|
|
@ -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
|
||||
|
@ -61,7 +60,7 @@ class SafariFavicon(IOSExtraction):
|
|||
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()
|
||||
|
|
|
@ -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
|
||||
|
@ -82,7 +81,7 @@ class Calendar(IOSExtraction):
|
|||
"""
|
||||
Parse the calendar database
|
||||
"""
|
||||
conn = sqlite3.connect(self.file_path)
|
||||
conn = self._open_sqlite_db(self.file_path)
|
||||
cur = conn.cursor()
|
||||
|
||||
cur.execute(
|
||||
|
|
|
@ -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
|
||||
|
@ -53,7 +52,7 @@ class Calls(IOSExtraction):
|
|||
)
|
||||
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(
|
||||
"""
|
||||
|
|
|
@ -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
|
||||
|
@ -66,7 +65,7 @@ class ChromeFavicon(IOSExtraction):
|
|||
)
|
||||
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()
|
||||
|
|
|
@ -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
|
||||
|
@ -67,7 +66,7 @@ class ChromeHistory(IOSExtraction):
|
|||
)
|
||||
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(
|
||||
"""
|
||||
|
|
|
@ -44,7 +44,7 @@ class Contacts(IOSExtraction):
|
|||
)
|
||||
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(
|
||||
|
|
|
@ -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
|
||||
|
@ -68,7 +67,7 @@ class FirefoxFavicon(IOSExtraction):
|
|||
)
|
||||
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(
|
||||
"""
|
||||
|
|
|
@ -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
|
||||
|
@ -68,7 +67,7 @@ class FirefoxHistory(IOSExtraction):
|
|||
)
|
||||
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(
|
||||
"""
|
||||
|
|
|
@ -280,7 +280,7 @@ class InteractionC(IOSExtraction):
|
|||
)
|
||||
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:
|
||||
|
|
|
@ -76,7 +76,7 @@ class SafariBrowserState(IOSExtraction):
|
|||
|
||||
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:
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
|
||||
import logging
|
||||
import os
|
||||
import sqlite3
|
||||
from typing import Optional, Union
|
||||
|
||||
from mvt.common.url import URL
|
||||
|
@ -115,7 +114,7 @@ class SafariHistory(IOSExtraction):
|
|||
|
||||
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(
|
||||
"""
|
||||
|
|
|
@ -83,7 +83,7 @@ class Shortcuts(IOSExtraction):
|
|||
)
|
||||
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:
|
||||
|
|
|
@ -86,7 +86,7 @@ class SMS(IOSExtraction):
|
|||
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(
|
||||
"""
|
||||
|
@ -103,7 +103,7 @@ class SMS(IOSExtraction):
|
|||
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(
|
||||
"""
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
# https://license.mvt.re/1.1/
|
||||
|
||||
import logging
|
||||
import sqlite3
|
||||
from base64 import b64encode
|
||||
from typing import Optional, Union
|
||||
|
||||
|
@ -72,7 +71,7 @@ class SMSAttachments(IOSExtraction):
|
|||
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(
|
||||
"""
|
||||
|
|
|
@ -95,7 +95,7 @@ class TCC(IOSExtraction):
|
|||
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:
|
||||
|
|
|
@ -73,7 +73,7 @@ class WebkitResourceLoadStatistics(IOSExtraction):
|
|||
|
||||
self._recover_sqlite_db_if_needed(db_path)
|
||||
|
||||
conn = sqlite3.connect(db_path)
|
||||
conn = self._open_sqlite_db(db_path)
|
||||
cur = conn.cursor()
|
||||
|
||||
try:
|
||||
|
|
|
@ -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
|
||||
|
@ -69,7 +68,7 @@ class Whatsapp(IOSExtraction):
|
|||
)
|
||||
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
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue