1
mirror of https://github.com/mvt-project/mvt synced 2025-11-13 01:37:36 +01:00

Compare commits

..

16 Commits

Author SHA1 Message Date
Rory Flynn
ad3bc3470e Mark release 2.5.0 (#445) 2024-01-04 20:08:42 +01:00
github-actions[bot]
2c5ae696b1 Add new iOS versions and build numbers (#439)
Co-authored-by: DonnchaC <DonnchaC@users.noreply.github.com>
2024-01-03 19:08:15 +01:00
Christian Clauss
5d2ff32e3a dumpsys_accessibility.py: Spell accessibility correctly (#441)
* dumpsys_accessibility.py: Spell accessibility correctly

* Fix typo
2024-01-03 18:59:06 +01:00
Rory Flynn
2838bac63f Circular reference in SMS module serialization (#444)
* Fix circular reference in SMS module serialization
* Modify SMS test artifact to include date_read
2024-01-03 18:55:32 +01:00
msx98
b7df87a62f add uri=True to sqlite3.connect args (#442)
Co-authored-by: msx98 <msx98@xb.ax>
2023-12-28 11:44:38 +01:00
Donncha Ó Cearbhaill
013282dbba Impovements for SMS module (#438)
* Add indicator checking in the SMS module

* Don't add SMS entries when read timestamp not set

* Remove print() line
2023-12-17 12:59:35 +01:00
github-actions[bot]
ab33789f06 Add new iOS versions and build numbers (#437)
Co-authored-by: DonnchaC <DonnchaC@users.noreply.github.com>
2023-12-12 08:40:32 +01:00
Rory Flynn
a1571c127d Mark release 2.4.5 (#436) 2023-12-11 11:10:36 +01:00
Rory Flynn
61f33f7ecb Fix typo in ios_models.json (#435) 2023-12-09 19:41:43 +01:00
Rory Flynn
4a6b483ce3 Mark release 2.4.4 (#433) 2023-12-04 17:05:04 +01:00
github-actions[bot]
101098cbb7 Add new iOS versions and build numbers (#432)
Co-authored-by: DonnchaC <DonnchaC@users.noreply.github.com>
2023-12-01 10:40:09 +01:00
Rory Flynn
fd3ef76873 Open all iOS sqlite3 databases with immutable=1 (#430) 2023-11-28 12:46:18 +01:00
Rory Flynn
fb52f73556 Automatically add issues to development board (#428) 2023-11-27 14:10:54 +01:00
r-tx
acc950377f docker tweaks (#424)
Co-authored-by: r-tx <r-tx@users.noreply.github.com>
2023-11-27 12:53:03 +01:00
Rory Flynn
c8a0327768 Allow PR coverage comment to fail if running on a fork (#427) 2023-11-27 12:39:18 +01:00
Rory Flynn
1d075abde9 Make MVTModule.get_slug() a classmethod (#418) 2023-11-22 10:37:38 +01:00
34 changed files with 99 additions and 65 deletions

View File

@@ -0,0 +1,19 @@
name: Add issue to project
on:
issues:
types:
- opened
- reopened
jobs:
add-to-project:
name: Add issue to project
runs-on: ubuntu-latest
steps:
- uses: actions/add-to-project@v0.5.0
with:
# You can target a project in a different organization
# to the issue
project-url: https://github.com/orgs/mvt-project/projects/1
github-token: ${{ secrets.ADD_TO_PROJECT_PAT }}

View File

@@ -42,6 +42,7 @@ jobs:
- name: Test with pytest and coverage - name: Test with pytest and coverage
run: pytest --junitxml=pytest.xml --cov-report=term-missing:skip-covered --cov=mvt tests/ | tee pytest-coverage.txt run: pytest --junitxml=pytest.xml --cov-report=term-missing:skip-covered --cov=mvt tests/ | tee pytest-coverage.txt
- name: Pytest coverage comment - name: Pytest coverage comment
continue-on-error: true # Workflows running on a fork can't post comments
uses: MishaKav/pytest-coverage-comment@main uses: MishaKav/pytest-coverage-comment@main
if: github.event_name == 'pull_request' if: github.event_name == 'pull_request'
with: with:

View File

@@ -57,12 +57,12 @@ RUN git clone https://github.com/libimobiledevice/libplist \
# Installing MVT # Installing MVT
# -------------- # --------------
RUN pip3 install mvt RUN pip3 install git+https://github.com/mvt-project/mvt.git@main
# Installing ABE # Installing ABE
# -------------- # --------------
RUN mkdir /opt/abe \ RUN mkdir /opt/abe \
&& wget https://github.com/nelenkov/android-backup-extractor/releases/download/20210709062403-4c55371/abe.jar -O /opt/abe/abe.jar \ && wget https://github.com/nelenkov/android-backup-extractor/releases/download/master-20221109063121-8fdfc5e/abe.jar -O /opt/abe/abe.jar \
# Create alias for abe # Create alias for abe
&& echo 'alias abe="java -jar /opt/abe/abe.jar"' >> ~/.bashrc && echo 'alias abe="java -jar /opt/abe/abe.jar"' >> ~/.bashrc

View File

@@ -12,7 +12,7 @@ from .base import AndroidQFModule
class DumpsysAccessibility(DumpsysAccessibilityArtifact, AndroidQFModule): class DumpsysAccessibility(DumpsysAccessibilityArtifact, AndroidQFModule):
"""This module analyse dumpsys accessbility""" """This module analyses dumpsys accessibility"""
def __init__( def __init__(
self, self,

View File

@@ -53,7 +53,7 @@ class CmdCheckIOCS(Command):
if self.module_name and iocs_module.__name__ != self.module_name: if self.module_name and iocs_module.__name__ != self.module_name:
continue continue
if iocs_module().get_slug() != name_only: if iocs_module.get_slug() != name_only:
continue continue
log.info( log.info(

View File

@@ -10,7 +10,7 @@ from .version import MVT_VERSION
def check_updates() -> None: def check_updates() -> None:
# First we check for MVT version udpates. # First we check for MVT version updates.
mvt_updates = MVTUpdates() mvt_updates = MVTUpdates()
try: try:
latest_version = mvt_updates.check() latest_version = mvt_updates.check()

View File

@@ -74,12 +74,13 @@ class MVTModule:
log.info('Loaded %d results from "%s"', len(results), json_path) log.info('Loaded %d results from "%s"', len(results), json_path)
return cls(results=results, log=log) return cls(results=results, log=log)
def get_slug(self) -> str: @classmethod
def get_slug(cls) -> str:
"""Use the module's class name to retrieve a slug""" """Use the module's class name to retrieve a slug"""
if self.slug: if cls.slug:
return self.slug return cls.slug
sub = re.sub("(.)([A-Z][a-z]+)", r"\1_\2", self.__class__.__name__) sub = re.sub("(.)([A-Z][a-z]+)", r"\1_\2", cls.__name__)
return re.sub("([a-z0-9])([A-Z])", r"\1_\2", sub).lower() return re.sub("([a-z0-9])([A-Z])", r"\1_\2", sub).lower()
def check_indicators(self) -> None: def check_indicators(self) -> None:

View File

@@ -3,4 +3,4 @@
# Use of this software is governed by the MVT License 1.1 that can be found at # Use of this software is governed by the MVT License 1.1 that can be found at
# https://license.mvt.re/1.1/ # https://license.mvt.re/1.1/
MVT_VERSION = "2.4.3" MVT_VERSION = "2.5.0"

View File

@@ -169,7 +169,7 @@
}, },
{ {
"identifier": "iPhone14,8", "identifier": "iPhone14,8",
"decription": "iPhone 14 Plus" "description": "iPhone 14 Plus"
}, },
{ {
"identifier": "iPhone15,2", "identifier": "iPhone15,2",

View File

@@ -960,6 +960,14 @@
"version": "16.7.2", "version": "16.7.2",
"build": "20H115" "build": "20H115"
}, },
{
"version": "16.7.3",
"build": "20H232"
},
{
"version": "16.7.4",
"build": "20H240"
},
{ {
"version": "17.0", "version": "17.0",
"build": "21A327" "build": "21A327"
@@ -995,5 +1003,17 @@
{ {
"version": "17.1.1", "version": "17.1.1",
"build": "21B91" "build": "21B91"
},
{
"version": "17.1.2",
"build": "21B101"
},
{
"version": "17.2",
"build": "21C62"
},
{
"version": "17.2.1",
"build": "21C66"
} }
] ]

View File

@@ -8,7 +8,6 @@ import io
import logging import logging
import os import os
import plistlib import plistlib
import sqlite3
from typing import Optional from typing import Optional
from mvt.common.module import DatabaseNotFoundError 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) 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 = conn.cursor()
cur.execute("SELECT * FROM Files;") cur.execute("SELECT * FROM Files;")

View File

@@ -49,7 +49,7 @@ class IOSExtraction(MVTModule):
""" """
# TODO: Find a better solution. # TODO: Find a better solution.
if not forced: if not forced:
conn = sqlite3.connect(file_path) conn = self._open_sqlite_db(file_path)
cur = conn.cursor() cur = conn.cursor()
try: try:
@@ -91,6 +91,9 @@ class IOSExtraction(MVTModule):
self.log.info("Database at path %s recovered successfully!", file_path) 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", uri=True)
def _get_backup_files_from_manifest( def _get_backup_files_from_manifest(
self, relative_path: Optional[str] = None, domain: Optional[str] = None self, relative_path: Optional[str] = None, domain: Optional[str] = None
) -> Iterator[dict]: ) -> Iterator[dict]:
@@ -109,7 +112,7 @@ class IOSExtraction(MVTModule):
base_sql = "SELECT fileID, domain, relativePath FROM Files WHERE " base_sql = "SELECT fileID, domain, relativePath FROM Files WHERE "
try: try:
conn = sqlite3.connect(manifest_db_path) conn = self._open_sqlite_db(manifest_db_path)
cur = conn.cursor() cur = conn.cursor()
if relative_path and domain: if relative_path and domain:
cur.execute( cur.execute(

View File

@@ -85,7 +85,7 @@ class Analytics(IOSExtraction):
def _extract_analytics_data(self): def _extract_analytics_data(self):
artifact = self.file_path.split("/")[-1] artifact = self.file_path.split("/")[-1]
conn = sqlite3.connect(self.file_path) conn = self._open_sqlite_db(self.file_path)
cur = conn.cursor() cur = conn.cursor()
try: try:

View File

@@ -64,7 +64,7 @@ class CacheFiles(IOSExtraction):
def _process_cache_file(self, file_path): def _process_cache_file(self, file_path):
self.log.info("Processing cache file at path: %s", 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() cur = conn.cursor()
try: try:

View File

@@ -4,7 +4,6 @@
# https://license.mvt.re/1.1/ # https://license.mvt.re/1.1/
import logging import logging
import sqlite3
from typing import Optional, Union from typing import Optional, Union
from mvt.common.utils import convert_mactime_to_iso from mvt.common.utils import convert_mactime_to_iso
@@ -61,7 +60,7 @@ class SafariFavicon(IOSExtraction):
self.detected.append(result) self.detected.append(result)
def _process_favicon_db(self, file_path): def _process_favicon_db(self, file_path):
conn = sqlite3.connect(file_path) conn = self._open_sqlite_db(file_path)
# Fetch valid icon cache. # Fetch valid icon cache.
cur = conn.cursor() cur = conn.cursor()

View File

@@ -4,7 +4,6 @@
# https://license.mvt.re/1.1/ # https://license.mvt.re/1.1/
import logging import logging
import sqlite3
from typing import Optional, Union from typing import Optional, Union
from mvt.common.utils import convert_mactime_to_iso from mvt.common.utils import convert_mactime_to_iso
@@ -82,7 +81,7 @@ class Calendar(IOSExtraction):
""" """
Parse the calendar database Parse the calendar database
""" """
conn = sqlite3.connect(self.file_path) conn = self._open_sqlite_db(self.file_path)
cur = conn.cursor() cur = conn.cursor()
cur.execute( cur.execute(

View File

@@ -4,7 +4,6 @@
# https://license.mvt.re/1.1/ # https://license.mvt.re/1.1/
import logging import logging
import sqlite3
from typing import Optional, Union from typing import Optional, Union
from mvt.common.utils import convert_mactime_to_iso 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) 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 = conn.cursor()
cur.execute( cur.execute(
""" """

View File

@@ -4,7 +4,6 @@
# https://license.mvt.re/1.1/ # https://license.mvt.re/1.1/
import logging import logging
import sqlite3
from typing import Optional, Union from typing import Optional, Union
from mvt.common.utils import convert_chrometime_to_datetime, convert_datetime_to_iso 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) 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 # Fetch icon cache
cur = conn.cursor() cur = conn.cursor()

View File

@@ -4,7 +4,6 @@
# https://license.mvt.re/1.1/ # https://license.mvt.re/1.1/
import logging import logging
import sqlite3
from typing import Optional, Union from typing import Optional, Union
from mvt.common.utils import convert_chrometime_to_datetime, convert_datetime_to_iso 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) 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 = conn.cursor()
cur.execute( cur.execute(
""" """

View File

@@ -44,7 +44,7 @@ class Contacts(IOSExtraction):
) )
self.log.info("Found Contacts database at path: %s", self.file_path) 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() cur = conn.cursor()
try: try:
cur.execute( cur.execute(

View File

@@ -4,7 +4,6 @@
# https://license.mvt.re/1.1/ # https://license.mvt.re/1.1/
import logging import logging
import sqlite3
from typing import Optional, Union from typing import Optional, Union
from mvt.common.utils import convert_unix_to_iso 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) 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 = conn.cursor()
cur.execute( cur.execute(
""" """

View File

@@ -4,7 +4,6 @@
# https://license.mvt.re/1.1/ # https://license.mvt.re/1.1/
import logging import logging
import sqlite3
from typing import Optional, Union from typing import Optional, Union
from mvt.common.utils import convert_unix_to_iso 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) 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 = conn.cursor()
cur.execute( cur.execute(
""" """

View File

@@ -280,7 +280,7 @@ class InteractionC(IOSExtraction):
) )
self.log.info("Found InteractionC database at path: %s", self.file_path) 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() cur = conn.cursor()
try: try:

View File

@@ -76,7 +76,7 @@ class SafariBrowserState(IOSExtraction):
def _process_browser_state_db(self, db_path): def _process_browser_state_db(self, db_path):
self._recover_sqlite_db_if_needed(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() cur = conn.cursor()
try: try:

View File

@@ -5,7 +5,6 @@
import logging import logging
import os import os
import sqlite3
from typing import Optional, Union from typing import Optional, Union
from mvt.common.url import URL from mvt.common.url import URL
@@ -115,7 +114,7 @@ class SafariHistory(IOSExtraction):
def _process_history_db(self, history_path): def _process_history_db(self, history_path):
self._recover_sqlite_db_if_needed(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 = conn.cursor()
cur.execute( cur.execute(
""" """

View File

@@ -83,7 +83,7 @@ class Shortcuts(IOSExtraction):
) )
self.log.info("Found Shortcuts database at path: %s", self.file_path) 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 conn.text_factory = bytes
cur = conn.cursor() cur = conn.cursor()
try: try:

View File

@@ -44,20 +44,25 @@ class SMS(IOSExtraction):
def serialize(self, record: dict) -> Union[dict, list]: def serialize(self, record: dict) -> Union[dict, list]:
text = record["text"].replace("\n", "\\n") text = record["text"].replace("\n", "\\n")
sms_data = f"{record['service']}: {record['guid']} \"{text}\" from {record['phone_number']} ({record['account']})" sms_data = f"{record['service']}: {record['guid']} \"{text}\" from {record['phone_number']} ({record['account']})"
return [ records = [
{ {
"timestamp": record["isodate"], "timestamp": record["isodate"],
"module": self.__class__.__name__, "module": self.__class__.__name__,
"event": "sms_received", "event": "sms_received",
"data": sms_data, "data": sms_data,
}, },
]
# If the message was read, we add an extra event.
if record["isodate_read"]:
records.append(
{ {
"timestamp": record["isodate_read"], "timestamp": record["isodate_read"],
"module": self.__class__.__name__, "module": self.__class__.__name__,
"event": "sms_read", "event": "sms_read",
"data": sms_data, "data": sms_data,
}, }
] )
return records
def check_indicators(self) -> None: def check_indicators(self) -> None:
for message in self.results: for message in self.results:
@@ -86,7 +91,7 @@ class SMS(IOSExtraction):
self.log.info("Found SMS database at path: %s", self.file_path) self.log.info("Found SMS database at path: %s", self.file_path)
try: try:
conn = sqlite3.connect(self.file_path) conn = self._open_sqlite_db(self.file_path)
cur = conn.cursor() cur = conn.cursor()
cur.execute( cur.execute(
""" """
@@ -103,7 +108,7 @@ class SMS(IOSExtraction):
conn.close() conn.close()
if "database disk image is malformed" in str(exc): if "database disk image is malformed" in str(exc):
self._recover_sqlite_db_if_needed(self.file_path, forced=True) 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 = conn.cursor()
cur.execute( cur.execute(
""" """

View File

@@ -4,7 +4,6 @@
# https://license.mvt.re/1.1/ # https://license.mvt.re/1.1/
import logging import logging
import sqlite3
from base64 import b64encode from base64 import b64encode
from typing import Optional, Union from typing import Optional, Union
@@ -56,6 +55,10 @@ class SMSAttachments(IOSExtraction):
def check_indicators(self) -> None: def check_indicators(self) -> None:
for attachment in self.results: for attachment in self.results:
# Check for known malicious filenames.
if self.indicators.check_file_path(attachment["filename"]):
self.detected.append(attachment)
if ( if (
attachment["filename"].startswith("/var/tmp/") attachment["filename"].startswith("/var/tmp/")
and attachment["filename"].endswith("-1") and attachment["filename"].endswith("-1")
@@ -72,7 +75,7 @@ class SMSAttachments(IOSExtraction):
self._find_ios_database(backup_ids=SMS_BACKUP_IDS, root_paths=SMS_ROOT_PATHS) 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) 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 = conn.cursor()
cur.execute( cur.execute(
""" """

View File

@@ -95,7 +95,7 @@ class TCC(IOSExtraction):
self.detected.append(result) self.detected.append(result)
def process_db(self, file_path): def process_db(self, file_path):
conn = sqlite3.connect(file_path) conn = self._open_sqlite_db(file_path)
cur = conn.cursor() cur = conn.cursor()
db_version = "v3" db_version = "v3"
try: try:

View File

@@ -73,7 +73,7 @@ class WebkitResourceLoadStatistics(IOSExtraction):
self._recover_sqlite_db_if_needed(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() cur = conn.cursor()
try: try:

View File

@@ -4,7 +4,6 @@
# https://license.mvt.re/1.1/ # https://license.mvt.re/1.1/
import logging import logging
import sqlite3
from typing import Optional, Union from typing import Optional, Union
from mvt.common.utils import check_for_links, convert_mactime_to_iso 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) 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() cur = conn.cursor()
# Query all messages and join tables which can contain media attachments # Query all messages and join tables which can contain media attachments

Some files were not shown because too many files have changed in this diff Show More