mirror of
https://github.com/mvt-project/mvt
synced 2025-11-13 01:37:36 +01:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6d8de5b461 | ||
|
|
b0177d6104 | ||
|
|
e0c9a44b10 | ||
|
|
ef8c1ae895 | ||
|
|
3165801e2b | ||
|
|
1aa371a398 | ||
|
|
f8e380baa1 | ||
|
|
35559b09a8 | ||
|
|
daf5c1f3de | ||
|
|
f601db2174 | ||
|
|
3ce9641c23 |
@@ -6,7 +6,7 @@
|
|||||||
import requests
|
import requests
|
||||||
from packaging import version
|
from packaging import version
|
||||||
|
|
||||||
MVT_VERSION = "1.2.11"
|
MVT_VERSION = "1.2.13"
|
||||||
|
|
||||||
def check_for_updates():
|
def check_for_updates():
|
||||||
res = requests.get("https://pypi.org/pypi/mvt/json")
|
res = requests.get("https://pypi.org/pypi/mvt/json")
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
from .cache_files import CacheFiles
|
from .cache_files import CacheFiles
|
||||||
from .filesystem import Filesystem
|
from .filesystem import Filesystem
|
||||||
from .net_netusage import Netusage
|
from .net_netusage import Netusage
|
||||||
|
from .networking_analytics import NetworkingAnalytics
|
||||||
from .safari_favicon import SafariFavicon
|
from .safari_favicon import SafariFavicon
|
||||||
from .shutdownlog import ShutdownLog
|
from .shutdownlog import ShutdownLog
|
||||||
from .version_history import IOSVersionHistory
|
from .version_history import IOSVersionHistory
|
||||||
@@ -13,6 +14,6 @@ from .webkit_indexeddb import WebkitIndexedDB
|
|||||||
from .webkit_localstorage import WebkitLocalStorage
|
from .webkit_localstorage import WebkitLocalStorage
|
||||||
from .webkit_safariviewservice import WebkitSafariViewService
|
from .webkit_safariviewservice import WebkitSafariViewService
|
||||||
|
|
||||||
FS_MODULES = [CacheFiles, Filesystem, Netusage, SafariFavicon, ShutdownLog,
|
FS_MODULES = [CacheFiles, Filesystem, Netusage, NetworkingAnalytics, SafariFavicon, ShutdownLog,
|
||||||
IOSVersionHistory, WebkitIndexedDB, WebkitLocalStorage,
|
IOSVersionHistory, WebkitIndexedDB, WebkitLocalStorage,
|
||||||
WebkitSafariViewService,]
|
WebkitSafariViewService,]
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ class Filesystem(IOSExtraction):
|
|||||||
return {
|
return {
|
||||||
"timestamp": record["modified"],
|
"timestamp": record["modified"],
|
||||||
"module": self.__class__.__name__,
|
"module": self.__class__.__name__,
|
||||||
"event": "file_modified",
|
"event": "entry_modified",
|
||||||
"data": record["file_path"],
|
"data": record["path"],
|
||||||
}
|
}
|
||||||
|
|
||||||
def check_indicators(self):
|
def check_indicators(self):
|
||||||
@@ -37,16 +37,39 @@ class Filesystem(IOSExtraction):
|
|||||||
return
|
return
|
||||||
|
|
||||||
for result in self.results:
|
for result in self.results:
|
||||||
if self.indicators.check_file(result["file_path"]):
|
if self.indicators.check_file(result["path"]):
|
||||||
|
self.log.warning("Found a known malicious file at path: %s", result["path"])
|
||||||
self.detected.append(result)
|
self.detected.append(result)
|
||||||
|
|
||||||
|
# If we are instructed to run fast, we skip this.
|
||||||
|
if self.fast_mode:
|
||||||
|
self.log.info("Flag --fast was enabled: skipping extended search for suspicious files/processes")
|
||||||
|
else:
|
||||||
|
for ioc in self.indicators.ioc_processes:
|
||||||
|
parts = result["path"].split("/")
|
||||||
|
if ioc in parts:
|
||||||
|
self.log.warning("Found a known malicious file/process at path: %s", result["path"])
|
||||||
|
self.detected.append(result)
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
for root, dirs, files in os.walk(self.base_folder):
|
for root, dirs, files in os.walk(self.base_folder):
|
||||||
|
for dir_name in dirs:
|
||||||
|
try:
|
||||||
|
dir_path = os.path.join(root, dir_name)
|
||||||
|
result = {
|
||||||
|
"path": os.path.relpath(dir_path, self.base_folder),
|
||||||
|
"modified": convert_timestamp_to_iso(datetime.datetime.utcfromtimestamp(os.stat(dir_path).st_mtime)),
|
||||||
|
}
|
||||||
|
except:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
self.results.append(result)
|
||||||
|
|
||||||
for file_name in files:
|
for file_name in files:
|
||||||
try:
|
try:
|
||||||
file_path = os.path.join(root, file_name)
|
file_path = os.path.join(root, file_name)
|
||||||
result = {
|
result = {
|
||||||
"file_path": os.path.relpath(file_path, self.base_folder),
|
"path": os.path.relpath(file_path, self.base_folder),
|
||||||
"modified": convert_timestamp_to_iso(datetime.datetime.utcfromtimestamp(os.stat(file_path).st_mtime)),
|
"modified": convert_timestamp_to_iso(datetime.datetime.utcfromtimestamp(os.stat(file_path).st_mtime)),
|
||||||
}
|
}
|
||||||
except:
|
except:
|
||||||
|
|||||||
91
mvt/ios/modules/fs/networking_analytics.py
Normal file
91
mvt/ios/modules/fs/networking_analytics.py
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
# Mobile Verification Toolkit (MVT)
|
||||||
|
# Copyright (c) 2021 The MVT Project Authors.
|
||||||
|
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||||
|
# https://license.mvt.re/1.1/
|
||||||
|
|
||||||
|
import plistlib
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
|
from mvt.common.utils import convert_mactime_to_unix, convert_timestamp_to_iso
|
||||||
|
|
||||||
|
from ..base import IOSExtraction
|
||||||
|
|
||||||
|
NETWORKING_ANALYTICS_DB_PATH = [
|
||||||
|
"private/var/Keychains/Analytics/networking_analytics.db",
|
||||||
|
]
|
||||||
|
|
||||||
|
class NetworkingAnalytics(IOSExtraction):
|
||||||
|
"""This module extracts information from the networking_analytics.db file."""
|
||||||
|
|
||||||
|
def __init__(self, file_path=None, base_folder=None, output_folder=None,
|
||||||
|
fast_mode=False, log=None, results=[]):
|
||||||
|
super().__init__(file_path=file_path, base_folder=base_folder,
|
||||||
|
output_folder=output_folder, fast_mode=fast_mode,
|
||||||
|
log=log, results=results)
|
||||||
|
|
||||||
|
def serialize(self, record):
|
||||||
|
return {
|
||||||
|
"timestamp": record["timestamp"],
|
||||||
|
"module": self.__class__.__name__,
|
||||||
|
"event": "network_crash",
|
||||||
|
"data": f"{record}",
|
||||||
|
}
|
||||||
|
|
||||||
|
def check_indicators(self):
|
||||||
|
if not self.indicators:
|
||||||
|
return
|
||||||
|
|
||||||
|
for result in self.results:
|
||||||
|
for ioc in self.indicators.ioc_processes:
|
||||||
|
for key in result.keys():
|
||||||
|
if ioc == result[key]:
|
||||||
|
self.log.warning("Found mention of a known malicious process \"%s\" in networking_analytics.db at %s",
|
||||||
|
ioc, result["timestamp"])
|
||||||
|
self.detected.append(result)
|
||||||
|
break
|
||||||
|
|
||||||
|
def _extract_networking_analytics_data(self):
|
||||||
|
conn = sqlite3.connect(self.file_path)
|
||||||
|
cur = conn.cursor()
|
||||||
|
cur.execute("""
|
||||||
|
SELECT
|
||||||
|
timestamp,
|
||||||
|
data
|
||||||
|
FROM hard_failures
|
||||||
|
UNION
|
||||||
|
SELECT
|
||||||
|
timestamp,
|
||||||
|
data
|
||||||
|
FROM soft_failures;
|
||||||
|
""")
|
||||||
|
|
||||||
|
for row in cur:
|
||||||
|
if row[0] and row[1]:
|
||||||
|
timestamp = convert_timestamp_to_iso(convert_mactime_to_unix(row[0], False))
|
||||||
|
data = plistlib.loads(row[1])
|
||||||
|
data["timestamp"] = timestamp
|
||||||
|
elif row[0]:
|
||||||
|
timestamp = convert_timestamp_to_iso(convert_mactime_to_unix(row[0], False))
|
||||||
|
data = {}
|
||||||
|
data["timestamp"] = timestamp
|
||||||
|
elif row[1]:
|
||||||
|
timestamp = ""
|
||||||
|
data = plistlib.loads(row[1])
|
||||||
|
data["timestamp"] = timestamp
|
||||||
|
|
||||||
|
self.results.append(data)
|
||||||
|
|
||||||
|
self.results = sorted(self.results, key=lambda entry: entry["timestamp"])
|
||||||
|
|
||||||
|
cur.close()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
self.log.info("Extracted information on %d network crashes", len(self.results))
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
self._find_ios_database(root_paths=NETWORKING_ANALYTICS_DB_PATH)
|
||||||
|
if self.file_path:
|
||||||
|
self.log.info("Found networking_analytics.db log at path: %s", self.file_path)
|
||||||
|
self._extract_networking_analytics_data()
|
||||||
|
else:
|
||||||
|
self.log.info("networking_analytics.db not found")
|
||||||
@@ -224,6 +224,8 @@ IPHONE_IOS_VERSIONS = [
|
|||||||
{"build": "18G82", "version": "14.7.1"},
|
{"build": "18G82", "version": "14.7.1"},
|
||||||
{"build": "18H17", "version": "14.8"},
|
{"build": "18H17", "version": "14.8"},
|
||||||
{"build": "19A346", "version": "15.0"},
|
{"build": "19A346", "version": "15.0"},
|
||||||
|
{"build": "19A348", "version": "15.0.1"},
|
||||||
|
{"build": "19A404", "version": "15.0.2"}
|
||||||
]
|
]
|
||||||
|
|
||||||
def get_device_desc_from_id(identifier, devices_list=IPHONE_MODELS):
|
def get_device_desc_from_id(identifier, devices_list=IPHONE_MODELS):
|
||||||
|
|||||||
14
setup.py
14
setup.py
@@ -16,18 +16,18 @@ with open(readme_path, encoding="utf-8") as handle:
|
|||||||
|
|
||||||
requires = (
|
requires = (
|
||||||
# Base dependencies:
|
# Base dependencies:
|
||||||
"click>=8.0.1",
|
"click>=8.0.3",
|
||||||
"rich>=10.6.0",
|
"rich>=10.12.0",
|
||||||
"tld>=0.12.6",
|
"tld>=0.12.6",
|
||||||
"tqdm>=4.61.2",
|
"tqdm>=4.62.3",
|
||||||
"requests>=2.26.0",
|
"requests>=2.26.0",
|
||||||
"simplejson>=3.17.3",
|
"simplejson>=3.17.5",
|
||||||
"packaging>=21.0",
|
"packaging>=21.0",
|
||||||
# iOS dependencies:
|
# iOS dependencies:
|
||||||
"iOSbackup>=0.9.912",
|
"iOSbackup>=0.9.921",
|
||||||
# Android dependencies:
|
# Android dependencies:
|
||||||
"adb-shell>=0.4.1",
|
"adb-shell>=0.4.2",
|
||||||
"libusb1>=1.9.3",
|
"libusb1>=2.0.1",
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_package_data(package):
|
def get_package_data(package):
|
||||||
|
|||||||
Reference in New Issue
Block a user