mirror of https://github.com/mvt-project/mvt.git
Compare commits
2 Commits
529df85f0f
...
512f40dcb4
Author | SHA1 | Date |
---|---|---|
Nex | 512f40dcb4 | |
Nex | b3a464ba58 |
|
@ -9,7 +9,9 @@ import os
|
||||||
import click
|
import click
|
||||||
from rich.logging import RichHandler
|
from rich.logging import RichHandler
|
||||||
|
|
||||||
from mvt.common.help import *
|
from mvt.common.help import HELP_MSG_MODULE, HELP_MSG_IOC
|
||||||
|
from mvt.common.help import HELP_MSG_OUTPUT, HELP_MSG_LIST_MODULES
|
||||||
|
from mvt.common.help import HELP_MSG_SERIAL
|
||||||
from mvt.common.indicators import Indicators, IndicatorsFileBadFormat
|
from mvt.common.indicators import Indicators, IndicatorsFileBadFormat
|
||||||
from mvt.common.logo import logo
|
from mvt.common.logo import logo
|
||||||
from mvt.common.module import run_module, save_timeline
|
from mvt.common.module import run_module, save_timeline
|
||||||
|
@ -26,6 +28,7 @@ logging.basicConfig(level="INFO", format=LOG_FORMAT, handlers=[
|
||||||
RichHandler(show_path=False, log_time_format="%X")])
|
RichHandler(show_path=False, log_time_format="%X")])
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
#==============================================================================
|
#==============================================================================
|
||||||
# Main
|
# Main
|
||||||
#==============================================================================
|
#==============================================================================
|
||||||
|
@ -191,7 +194,7 @@ def check_backup(ctx, iocs, output, backup_path, serial):
|
||||||
log.critical("The path you specified is a not a folder!")
|
log.critical("The path you specified is a not a folder!")
|
||||||
|
|
||||||
if os.path.basename(backup_path) == "backup.ab":
|
if os.path.basename(backup_path) == "backup.ab":
|
||||||
log.info("You can use ABE (https://github.com/nelenkov/android-backup-extractor) " \
|
log.info("You can use ABE (https://github.com/nelenkov/android-backup-extractor) "
|
||||||
"to extract 'backup.ab' files!")
|
"to extract 'backup.ab' files!")
|
||||||
ctx.exit(1)
|
ctx.exit(1)
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@ import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
|
||||||
import pkg_resources
|
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
|
|
||||||
from mvt.common.module import InsufficientPrivileges
|
from mvt.common.module import InsufficientPrivileges
|
||||||
|
@ -17,6 +16,7 @@ from .modules.adb.packages import Packages
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
# TODO: Would be better to replace tqdm with rich.progress to reduce
|
# TODO: Would be better to replace tqdm with rich.progress to reduce
|
||||||
# the number of dependencies. Need to investigate whether
|
# the number of dependencies. Need to investigate whether
|
||||||
# it's possible to have a similar callback system.
|
# it's possible to have a similar callback system.
|
||||||
|
|
|
@ -13,6 +13,7 @@ from rich.text import Text
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def koodous_lookup(packages):
|
def koodous_lookup(packages):
|
||||||
log.info("Looking up all extracted files on Koodous (www.koodous.com)")
|
log.info("Looking up all extracted files on Koodous (www.koodous.com)")
|
||||||
log.info("This might take a while...")
|
log.info("This might take a while...")
|
||||||
|
|
|
@ -13,6 +13,7 @@ from rich.text import Text
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def get_virustotal_report(hashes):
|
def get_virustotal_report(hashes):
|
||||||
apikey = "233f22e200ca5822bd91103043ccac138b910db79f29af5616a9afe8b6f215ad"
|
apikey = "233f22e200ca5822bd91103043ccac138b910db79f29af5616a9afe8b6f215ad"
|
||||||
url = f"https://www.virustotal.com/partners/sysinternals/file-reports?apikey={apikey}"
|
url = f"https://www.virustotal.com/partners/sysinternals/file-reports?apikey={apikey}"
|
||||||
|
@ -36,6 +37,7 @@ def get_virustotal_report(hashes):
|
||||||
log.error("Unexpected response from VirusTotal: %s", res.status_code)
|
log.error("Unexpected response from VirusTotal: %s", res.status_code)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def virustotal_lookup(packages):
|
def virustotal_lookup(packages):
|
||||||
log.info("Looking up all extracted files on VirusTotal (www.virustotal.com)")
|
log.info("Looking up all extracted files on VirusTotal (www.virustotal.com)")
|
||||||
|
|
||||||
|
@ -48,6 +50,7 @@ def virustotal_lookup(packages):
|
||||||
total_unique_hashes = len(unique_hashes)
|
total_unique_hashes = len(unique_hashes)
|
||||||
|
|
||||||
detections = {}
|
detections = {}
|
||||||
|
|
||||||
def virustotal_query(batch):
|
def virustotal_query(batch):
|
||||||
report = get_virustotal_report(batch)
|
report = get_virustotal_report(batch)
|
||||||
if not report:
|
if not report:
|
||||||
|
|
|
@ -25,6 +25,7 @@ log = logging.getLogger(__name__)
|
||||||
ADB_KEY_PATH = os.path.expanduser("~/.android/adbkey")
|
ADB_KEY_PATH = os.path.expanduser("~/.android/adbkey")
|
||||||
ADB_PUB_KEY_PATH = os.path.expanduser("~/.android/adbkey.pub")
|
ADB_PUB_KEY_PATH = os.path.expanduser("~/.android/adbkey.pub")
|
||||||
|
|
||||||
|
|
||||||
class AndroidExtraction(MVTModule):
|
class AndroidExtraction(MVTModule):
|
||||||
"""This class provides a base for all Android extraction modules."""
|
"""This class provides a base for all Android extraction modules."""
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ log = logging.getLogger(__name__)
|
||||||
|
|
||||||
CHROME_HISTORY_PATH = "data/data/com.android.chrome/app_chrome/Default/History"
|
CHROME_HISTORY_PATH = "data/data/com.android.chrome/app_chrome/Default/History"
|
||||||
|
|
||||||
|
|
||||||
class ChromeHistory(AndroidExtraction):
|
class ChromeHistory(AndroidExtraction):
|
||||||
"""This module extracts records from Android's Chrome browsing history."""
|
"""This module extracts records from Android's Chrome browsing history."""
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ from .base import AndroidExtraction
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class DumpsysBatterystats(AndroidExtraction):
|
class DumpsysBatterystats(AndroidExtraction):
|
||||||
"""This module extracts stats on battery consumption by processes."""
|
"""This module extracts stats on battery consumption by processes."""
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ from .base import AndroidExtraction
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class DumpsysFull(AndroidExtraction):
|
class DumpsysFull(AndroidExtraction):
|
||||||
"""This module extracts stats on battery consumption by processes."""
|
"""This module extracts stats on battery consumption by processes."""
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ from .base import AndroidExtraction
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class DumpsysProcstats(AndroidExtraction):
|
class DumpsysProcstats(AndroidExtraction):
|
||||||
"""This module extracts stats on memory consumption by processes."""
|
"""This module extracts stats on memory consumption by processes."""
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
# https://license.mvt.re/1.1/
|
# https://license.mvt.re/1.1/
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
|
||||||
|
|
||||||
from .base import AndroidExtraction
|
from .base import AndroidExtraction
|
||||||
|
|
||||||
|
@ -15,6 +14,7 @@ ACTION_SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED"
|
||||||
ACTION_DATA_SMS_RECEIVED = "android.intent.action.DATA_SMS_RECEIVED"
|
ACTION_DATA_SMS_RECEIVED = "android.intent.action.DATA_SMS_RECEIVED"
|
||||||
ACTION_PHONE_STATE = "android.intent.action.PHONE_STATE"
|
ACTION_PHONE_STATE = "android.intent.action.PHONE_STATE"
|
||||||
|
|
||||||
|
|
||||||
class DumpsysReceivers(AndroidExtraction):
|
class DumpsysReceivers(AndroidExtraction):
|
||||||
"""This module extracts details on receivers for risky activities."""
|
"""This module extracts details on receivers for risky activities."""
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ from .base import AndroidExtraction
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class Files(AndroidExtraction):
|
class Files(AndroidExtraction):
|
||||||
"""This module extracts the list of installed packages."""
|
"""This module extracts the list of installed packages."""
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ from .base import AndroidExtraction
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class Packages(AndroidExtraction):
|
class Packages(AndroidExtraction):
|
||||||
"""This module extracts the list of installed packages."""
|
"""This module extracts the list of installed packages."""
|
||||||
|
|
||||||
|
@ -49,7 +50,6 @@ class Packages(AndroidExtraction):
|
||||||
root_packages = root_packages_string.decode("utf-8").split("\n")
|
root_packages = root_packages_string.decode("utf-8").split("\n")
|
||||||
root_packages = [rp.strip() for rp in root_packages]
|
root_packages = [rp.strip() for rp in root_packages]
|
||||||
|
|
||||||
|
|
||||||
for result in self.results:
|
for result in self.results:
|
||||||
if result["package_name"] in root_packages:
|
if result["package_name"] in root_packages:
|
||||||
self.log.warning("Found an installed package related to rooting/jailbreaking: \"%s\"",
|
self.log.warning("Found an installed package related to rooting/jailbreaking: \"%s\"",
|
||||||
|
|
|
@ -9,6 +9,7 @@ from .base import AndroidExtraction
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class Processes(AndroidExtraction):
|
class Processes(AndroidExtraction):
|
||||||
"""This module extracts details on running processes."""
|
"""This module extracts details on running processes."""
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ from .base import AndroidExtraction
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class RootBinaries(AndroidExtraction):
|
class RootBinaries(AndroidExtraction):
|
||||||
"""This module extracts the list of installed packages."""
|
"""This module extracts the list of installed packages."""
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@ SELECT
|
||||||
FROM sms;
|
FROM sms;
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class SMS(AndroidExtraction):
|
class SMS(AndroidExtraction):
|
||||||
"""This module extracts all SMS messages containing links."""
|
"""This module extracts all SMS messages containing links."""
|
||||||
|
|
||||||
|
@ -62,7 +63,7 @@ class SMS(AndroidExtraction):
|
||||||
return
|
return
|
||||||
|
|
||||||
for message in self.results:
|
for message in self.results:
|
||||||
if not "text" in message:
|
if "text" not in message:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
message_links = check_for_links(message["text"])
|
message_links = check_for_links(message["text"])
|
||||||
|
|
|
@ -16,6 +16,7 @@ log = logging.getLogger(__name__)
|
||||||
|
|
||||||
WHATSAPP_PATH = "data/data/com.whatsapp/databases/msgstore.db"
|
WHATSAPP_PATH = "data/data/com.whatsapp/databases/msgstore.db"
|
||||||
|
|
||||||
|
|
||||||
class Whatsapp(AndroidExtraction):
|
class Whatsapp(AndroidExtraction):
|
||||||
"""This module extracts all WhatsApp messages containing links."""
|
"""This module extracts all WhatsApp messages containing links."""
|
||||||
|
|
||||||
|
@ -39,7 +40,7 @@ class Whatsapp(AndroidExtraction):
|
||||||
return
|
return
|
||||||
|
|
||||||
for message in self.results:
|
for message in self.results:
|
||||||
if not "data" in message:
|
if "data" not in message:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
message_links = check_for_links(message["data"])
|
message_links = check_for_links(message["data"])
|
||||||
|
|
|
@ -5,4 +5,4 @@
|
||||||
|
|
||||||
from .sms import SMS
|
from .sms import SMS
|
||||||
|
|
||||||
BACKUP_MODULES = [SMS,]
|
BACKUP_MODULES = [SMS]
|
||||||
|
|
|
@ -24,7 +24,7 @@ class SMS(MVTModule):
|
||||||
return
|
return
|
||||||
|
|
||||||
for message in self.results:
|
for message in self.results:
|
||||||
if not "body" in message:
|
if "body" not in message:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
message_links = check_for_links(message["body"])
|
message_links = check_for_links(message["body"])
|
||||||
|
|
|
@ -12,6 +12,7 @@ from .url import URL
|
||||||
class IndicatorsFileBadFormat(Exception):
|
class IndicatorsFileBadFormat(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class Indicators:
|
class Indicators:
|
||||||
"""This class is used to parse indicators from a STIX2 file and provide
|
"""This class is used to parse indicators from a STIX2 file and provide
|
||||||
functions to compare extracted artifacts to the indicators.
|
functions to compare extracted artifacts to the indicators.
|
||||||
|
@ -115,7 +116,7 @@ class Indicators:
|
||||||
else:
|
else:
|
||||||
# If it's not shortened, we just use the original URL object.
|
# If it's not shortened, we just use the original URL object.
|
||||||
final_url = orig_url
|
final_url = orig_url
|
||||||
except Exception as e:
|
except Exception:
|
||||||
# If URL parsing failed, we just try to do a simple substring
|
# If URL parsing failed, we just try to do a simple substring
|
||||||
# match.
|
# match.
|
||||||
for ioc in self.ioc_domains:
|
for ioc in self.ioc_domains:
|
||||||
|
|
|
@ -16,7 +16,7 @@ def logo():
|
||||||
|
|
||||||
try:
|
try:
|
||||||
latest_version = check_for_updates()
|
latest_version = check_for_updates()
|
||||||
except:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
if latest_version:
|
if latest_version:
|
||||||
|
|
|
@ -10,18 +10,19 @@ import re
|
||||||
|
|
||||||
import simplejson as json
|
import simplejson as json
|
||||||
|
|
||||||
from .indicators import Indicators
|
|
||||||
|
|
||||||
|
|
||||||
class DatabaseNotFoundError(Exception):
|
class DatabaseNotFoundError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class DatabaseCorruptedError(Exception):
|
class DatabaseCorruptedError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class InsufficientPrivileges(Exception):
|
class InsufficientPrivileges(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class MVTModule(object):
|
class MVTModule(object):
|
||||||
"""This class provides a base for all extraction modules."""
|
"""This class provides a base for all extraction modules."""
|
||||||
|
|
||||||
|
|
|
@ -250,6 +250,7 @@ SHORTENER_DOMAINS = [
|
||||||
"zz.gd",
|
"zz.gd",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class URL:
|
class URL:
|
||||||
|
|
||||||
def __init__(self, url):
|
def __init__(self, url):
|
||||||
|
@ -273,7 +274,7 @@ class URL:
|
||||||
# TODO: Properly handle exception.
|
# TODO: Properly handle exception.
|
||||||
try:
|
try:
|
||||||
return get_tld(self.url, as_object=True, fix_protocol=True).parsed_url.netloc.lower().lstrip("www.")
|
return get_tld(self.url, as_object=True, fix_protocol=True).parsed_url.netloc.lower().lstrip("www.")
|
||||||
except:
|
except Exception:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_top_level(self):
|
def get_top_level(self):
|
||||||
|
@ -288,7 +289,7 @@ class URL:
|
||||||
# TODO: Properly handle exception.
|
# TODO: Properly handle exception.
|
||||||
try:
|
try:
|
||||||
return get_tld(self.url, as_object=True, fix_protocol=True).fld.lower()
|
return get_tld(self.url, as_object=True, fix_protocol=True).fld.lower()
|
||||||
except:
|
except Exception:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def check_if_shortened(self) -> bool:
|
def check_if_shortened(self) -> bool:
|
||||||
|
|
|
@ -45,7 +45,7 @@ def convert_chrometime_to_unix(timestamp):
|
||||||
:returns: Unix epoch timestamp.
|
:returns: Unix epoch timestamp.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
epoch_start = datetime.datetime(1601, 1 , 1)
|
epoch_start = datetime.datetime(1601, 1, 1)
|
||||||
delta = datetime.timedelta(microseconds=timestamp)
|
delta = datetime.timedelta(microseconds=timestamp)
|
||||||
return epoch_start + delta
|
return epoch_start + delta
|
||||||
|
|
||||||
|
@ -64,6 +64,7 @@ def convert_timestamp_to_iso(timestamp):
|
||||||
except Exception:
|
except Exception:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def check_for_links(text):
|
def check_for_links(text):
|
||||||
"""Checks if a given text contains HTTP links.
|
"""Checks if a given text contains HTTP links.
|
||||||
|
|
||||||
|
@ -74,6 +75,7 @@ def check_for_links(text):
|
||||||
"""
|
"""
|
||||||
return re.findall("(?P<url>https?://[^\s]+)", text, re.IGNORECASE)
|
return re.findall("(?P<url>https?://[^\s]+)", text, re.IGNORECASE)
|
||||||
|
|
||||||
|
|
||||||
def get_sha256_from_file_path(file_path):
|
def get_sha256_from_file_path(file_path):
|
||||||
"""Calculate the SHA256 hash of a file from a file path.
|
"""Calculate the SHA256 hash of a file from a file path.
|
||||||
|
|
||||||
|
@ -88,6 +90,7 @@ def get_sha256_from_file_path(file_path):
|
||||||
|
|
||||||
return sha256_hash.hexdigest()
|
return sha256_hash.hexdigest()
|
||||||
|
|
||||||
|
|
||||||
# Note: taken from here:
|
# Note: taken from here:
|
||||||
# https://stackoverflow.com/questions/57014259/json-dumps-on-dictionary-with-bytes-for-keys
|
# https://stackoverflow.com/questions/57014259/json-dumps-on-dictionary-with-bytes-for-keys
|
||||||
def keys_bytes_to_string(obj):
|
def keys_bytes_to_string(obj):
|
||||||
|
|
|
@ -8,6 +8,7 @@ from packaging import version
|
||||||
|
|
||||||
MVT_VERSION = "1.2.14"
|
MVT_VERSION = "1.2.14"
|
||||||
|
|
||||||
|
|
||||||
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")
|
||||||
data = res.json()
|
data = res.json()
|
||||||
|
|
|
@ -10,7 +10,9 @@ import click
|
||||||
from rich.logging import RichHandler
|
from rich.logging import RichHandler
|
||||||
from rich.prompt import Prompt
|
from rich.prompt import Prompt
|
||||||
|
|
||||||
from mvt.common.help import *
|
from mvt.common.help import HELP_MSG_MODULE, HELP_MSG_IOC
|
||||||
|
from mvt.common.help import HELP_MSG_FAST, HELP_MSG_OUTPUT
|
||||||
|
from mvt.common.help import HELP_MSG_LIST_MODULES
|
||||||
from mvt.common.indicators import Indicators, IndicatorsFileBadFormat
|
from mvt.common.indicators import Indicators, IndicatorsFileBadFormat
|
||||||
from mvt.common.logo import logo
|
from mvt.common.logo import logo
|
||||||
from mvt.common.module import run_module, save_timeline
|
from mvt.common.module import run_module, save_timeline
|
||||||
|
@ -30,6 +32,7 @@ log = logging.getLogger(__name__)
|
||||||
# Set this environment variable to a password if needed.
|
# Set this environment variable to a password if needed.
|
||||||
PASSWD_ENV = "MVT_IOS_BACKUP_PASSWORD"
|
PASSWD_ENV = "MVT_IOS_BACKUP_PASSWORD"
|
||||||
|
|
||||||
|
|
||||||
#==============================================================================
|
#==============================================================================
|
||||||
# Main
|
# Main
|
||||||
#==============================================================================
|
#==============================================================================
|
||||||
|
|
|
@ -14,6 +14,7 @@ from iOSbackup import iOSbackup
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class DecryptBackup:
|
class DecryptBackup:
|
||||||
"""This class provides functions to decrypt an encrypted iTunes backup
|
"""This class provides functions to decrypt an encrypted iTunes backup
|
||||||
using either a password or a key file.
|
using either a password or a key file.
|
||||||
|
|
|
@ -10,6 +10,7 @@ from ..base import IOSExtraction
|
||||||
|
|
||||||
CONF_PROFILES_DOMAIN = "SysSharedContainerDomain-systemgroup.com.apple.configurationprofiles"
|
CONF_PROFILES_DOMAIN = "SysSharedContainerDomain-systemgroup.com.apple.configurationprofiles"
|
||||||
|
|
||||||
|
|
||||||
class ConfigurationProfiles(IOSExtraction):
|
class ConfigurationProfiles(IOSExtraction):
|
||||||
"""This module extracts the full plist data from configuration profiles."""
|
"""This module extracts the full plist data from configuration profiles."""
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ class Manifest(IOSExtraction):
|
||||||
"""Unserialized plist objects can have keys which are str or byte types
|
"""Unserialized plist objects can have keys which are str or byte types
|
||||||
This is a helper to try fetch a key as both a byte or string type.
|
This is a helper to try fetch a key as both a byte or string type.
|
||||||
|
|
||||||
:param dictionary: param key:
|
:param dictionary:
|
||||||
:param key:
|
:param key:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -72,7 +72,7 @@ class Manifest(IOSExtraction):
|
||||||
return
|
return
|
||||||
|
|
||||||
for result in self.results:
|
for result in self.results:
|
||||||
if not "relative_path" in result:
|
if "relative_path" not in result:
|
||||||
continue
|
continue
|
||||||
if not result["relative_path"]:
|
if not result["relative_path"]:
|
||||||
continue
|
continue
|
||||||
|
@ -133,7 +133,7 @@ class Manifest(IOSExtraction):
|
||||||
"owner": self._get_key(file_metadata, "UserID"),
|
"owner": self._get_key(file_metadata, "UserID"),
|
||||||
"size": self._get_key(file_metadata, "Size"),
|
"size": self._get_key(file_metadata, "Size"),
|
||||||
})
|
})
|
||||||
except:
|
except Exception:
|
||||||
self.log.exception("Error reading manifest file metadata for file with ID %s and relative path %s",
|
self.log.exception("Error reading manifest file metadata for file with ID %s and relative path %s",
|
||||||
file_data["fileID"], file_data["relativePath"])
|
file_data["fileID"], file_data["relativePath"])
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -11,6 +11,7 @@ from ..base import IOSExtraction
|
||||||
|
|
||||||
CONF_PROFILES_EVENTS_RELPATH = "Library/ConfigurationProfiles/MCProfileEvents.plist"
|
CONF_PROFILES_EVENTS_RELPATH = "Library/ConfigurationProfiles/MCProfileEvents.plist"
|
||||||
|
|
||||||
|
|
||||||
class ProfileEvents(IOSExtraction):
|
class ProfileEvents(IOSExtraction):
|
||||||
"""This module extracts events related to the installation of configuration
|
"""This module extracts events related to the installation of configuration
|
||||||
profiles.
|
profiles.
|
||||||
|
|
|
@ -16,4 +16,4 @@ from .webkit_safariviewservice import WebkitSafariViewService
|
||||||
|
|
||||||
FS_MODULES = [CacheFiles, Filesystem, Netusage, Analytics, SafariFavicon, ShutdownLog,
|
FS_MODULES = [CacheFiles, Filesystem, Netusage, Analytics, SafariFavicon, ShutdownLog,
|
||||||
IOSVersionHistory, WebkitIndexedDB, WebkitLocalStorage,
|
IOSVersionHistory, WebkitIndexedDB, WebkitLocalStorage,
|
||||||
WebkitSafariViewService,]
|
WebkitSafariViewService]
|
||||||
|
|
|
@ -14,6 +14,7 @@ ANALYTICS_DB_PATH = [
|
||||||
"private/var/Keychains/Analytics/*.db",
|
"private/var/Keychains/Analytics/*.db",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class Analytics(IOSExtraction):
|
class Analytics(IOSExtraction):
|
||||||
"""This module extracts information from the private/var/Keychains/Analytics/*.db files."""
|
"""This module extracts information from the private/var/Keychains/Analytics/*.db files."""
|
||||||
|
|
||||||
|
@ -87,7 +88,6 @@ class Analytics(IOSExtraction):
|
||||||
FROM soft_failures;
|
FROM soft_failures;
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
|
||||||
for row in cur:
|
for row in cur:
|
||||||
if row[0] and row[1]:
|
if row[0] and row[1]:
|
||||||
timestamp = convert_timestamp_to_iso(convert_mactime_to_unix(row[0], False))
|
timestamp = convert_timestamp_to_iso(convert_mactime_to_unix(row[0], False))
|
||||||
|
|
|
@ -38,7 +38,7 @@ class CacheFiles(IOSExtraction):
|
||||||
for item in items:
|
for item in items:
|
||||||
if self.indicators.check_domain(item["url"]):
|
if self.indicators.check_domain(item["url"]):
|
||||||
if key not in self.detected:
|
if key not in self.detected:
|
||||||
self.detected[key] = [item,]
|
self.detected[key] = [item, ]
|
||||||
else:
|
else:
|
||||||
self.detected[key].append(item)
|
self.detected[key].append(item)
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ class CacheFiles(IOSExtraction):
|
||||||
return
|
return
|
||||||
|
|
||||||
key_name = os.path.relpath(file_path, self.base_folder)
|
key_name = os.path.relpath(file_path, self.base_folder)
|
||||||
if not key_name in self.results:
|
if key_name not in self.results:
|
||||||
self.results[key_name] = []
|
self.results[key_name] = []
|
||||||
|
|
||||||
for row in cur:
|
for row in cur:
|
||||||
|
|
|
@ -60,7 +60,7 @@ class Filesystem(IOSExtraction):
|
||||||
"path": os.path.relpath(dir_path, self.base_folder),
|
"path": os.path.relpath(dir_path, self.base_folder),
|
||||||
"modified": convert_timestamp_to_iso(datetime.datetime.utcfromtimestamp(os.stat(dir_path).st_mtime)),
|
"modified": convert_timestamp_to_iso(datetime.datetime.utcfromtimestamp(os.stat(dir_path).st_mtime)),
|
||||||
}
|
}
|
||||||
except:
|
except Exception:
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
self.results.append(result)
|
self.results.append(result)
|
||||||
|
@ -72,7 +72,7 @@ class Filesystem(IOSExtraction):
|
||||||
"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 Exception:
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
self.results.append(result)
|
self.results.append(result)
|
||||||
|
|
|
@ -12,6 +12,7 @@ NETUSAGE_ROOT_PATHS = [
|
||||||
"private/var/networkd/db/netusage.sqlite"
|
"private/var/networkd/db/netusage.sqlite"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class Netusage(NetBase):
|
class Netusage(NetBase):
|
||||||
"""This class extracts data from netusage.sqlite and attempts to identify
|
"""This class extracts data from netusage.sqlite and attempts to identify
|
||||||
any suspicious processes if running on a full filesystem dump.
|
any suspicious processes if running on a full filesystem dump.
|
||||||
|
|
|
@ -14,6 +14,7 @@ SAFARI_FAVICON_ROOT_PATHS = [
|
||||||
"private/var/mobile/Containers/Data/Application/*/Library/Image Cache/Favicons/Favicons.db",
|
"private/var/mobile/Containers/Data/Application/*/Library/Image Cache/Favicons/Favicons.db",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class SafariFavicon(IOSExtraction):
|
class SafariFavicon(IOSExtraction):
|
||||||
"""This module extracts all Safari favicon records."""
|
"""This module extracts all Safari favicon records."""
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ SHUTDOWN_LOG_PATH = [
|
||||||
"private/var/db/diagnostics/shutdown.log",
|
"private/var/db/diagnostics/shutdown.log",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class ShutdownLog(IOSExtraction):
|
class ShutdownLog(IOSExtraction):
|
||||||
"""This module extracts processes information from the shutdown log file."""
|
"""This module extracts processes information from the shutdown log file."""
|
||||||
|
|
||||||
|
@ -57,7 +58,7 @@ class ShutdownLog(IOSExtraction):
|
||||||
try:
|
try:
|
||||||
start = line.find(" @")+2
|
start = line.find(" @")+2
|
||||||
mac_timestamp = int(line[start:start+10])
|
mac_timestamp = int(line[start:start+10])
|
||||||
except:
|
except Exception:
|
||||||
mac_timestamp = 0
|
mac_timestamp = 0
|
||||||
|
|
||||||
timestamp = convert_mactime_to_unix(mac_timestamp, from_2001=False)
|
timestamp = convert_mactime_to_unix(mac_timestamp, from_2001=False)
|
||||||
|
|
|
@ -14,6 +14,7 @@ IOS_ANALYTICS_JOURNAL_PATHS = [
|
||||||
"private/var/db/analyticsd/Analytics-Journal-*.ips",
|
"private/var/db/analyticsd/Analytics-Journal-*.ips",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class IOSVersionHistory(IOSExtraction):
|
class IOSVersionHistory(IOSExtraction):
|
||||||
"""This module extracts iOS update history from Analytics Journal log files."""
|
"""This module extracts iOS update history from Analytics Journal log files."""
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ WEBKIT_INDEXEDDB_ROOT_PATHS = [
|
||||||
"private/var/mobile/Containers/Data/Application/*/Library/WebKit/WebsiteData/IndexedDB",
|
"private/var/mobile/Containers/Data/Application/*/Library/WebKit/WebsiteData/IndexedDB",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class WebkitIndexedDB(WebkitBase):
|
class WebkitIndexedDB(WebkitBase):
|
||||||
"""This module looks extracts records from WebKit IndexedDB folders,
|
"""This module looks extracts records from WebKit IndexedDB folders,
|
||||||
and checks them against any provided list of suspicious domains.
|
and checks them against any provided list of suspicious domains.
|
||||||
|
|
|
@ -9,6 +9,7 @@ WEBKIT_LOCALSTORAGE_ROOT_PATHS = [
|
||||||
"private/var/mobile/Containers/Data/Application/*/Library/WebKit/WebsiteData/LocalStorage/",
|
"private/var/mobile/Containers/Data/Application/*/Library/WebKit/WebsiteData/LocalStorage/",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class WebkitLocalStorage(WebkitBase):
|
class WebkitLocalStorage(WebkitBase):
|
||||||
"""This module looks extracts records from WebKit LocalStorage folders,
|
"""This module looks extracts records from WebKit LocalStorage folders,
|
||||||
and checks them against any provided list of suspicious domains.
|
and checks them against any provided list of suspicious domains.
|
||||||
|
|
|
@ -9,6 +9,7 @@ WEBKIT_SAFARIVIEWSERVICE_ROOT_PATHS = [
|
||||||
"private/var/mobile/Containers/Data/Application/*/SystemData/com.apple.SafariViewService/Library/WebKit/WebsiteData/",
|
"private/var/mobile/Containers/Data/Application/*/SystemData/com.apple.SafariViewService/Library/WebKit/WebsiteData/",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class WebkitSafariViewService(WebkitBase):
|
class WebkitSafariViewService(WebkitBase):
|
||||||
"""This module looks extracts records from WebKit LocalStorage folders,
|
"""This module looks extracts records from WebKit LocalStorage folders,
|
||||||
and checks them against any provided list of suspicious domains.
|
and checks them against any provided list of suspicious domains.
|
||||||
|
|
|
@ -27,4 +27,4 @@ MIXED_MODULES = [Calls, ChromeFavicon, ChromeHistory, Contacts, FirefoxFavicon,
|
||||||
FirefoxHistory, IDStatusCache, InteractionC, LocationdClients,
|
FirefoxHistory, IDStatusCache, InteractionC, LocationdClients,
|
||||||
OSAnalyticsADDaily, Datausage, SafariBrowserState, SafariHistory,
|
OSAnalyticsADDaily, Datausage, SafariBrowserState, SafariHistory,
|
||||||
TCC, SMS, SMSAttachments, WebkitResourceLoadStatistics,
|
TCC, SMS, SMSAttachments, WebkitResourceLoadStatistics,
|
||||||
WebkitSessionResourceLog, Whatsapp,]
|
WebkitSessionResourceLog, Whatsapp]
|
||||||
|
|
|
@ -16,6 +16,7 @@ CALLS_ROOT_PATHS = [
|
||||||
"private/var/mobile/Library/CallHistoryDB/CallHistory.storedata"
|
"private/var/mobile/Library/CallHistoryDB/CallHistory.storedata"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class Calls(IOSExtraction):
|
class Calls(IOSExtraction):
|
||||||
"""This module extracts phone calls details"""
|
"""This module extracts phone calls details"""
|
||||||
|
|
||||||
|
@ -45,7 +46,7 @@ class Calls(IOSExtraction):
|
||||||
ZDATE, ZDURATION, ZLOCATION, ZADDRESS, ZSERVICE_PROVIDER
|
ZDATE, ZDURATION, ZLOCATION, ZADDRESS, ZSERVICE_PROVIDER
|
||||||
FROM ZCALLRECORD;
|
FROM ZCALLRECORD;
|
||||||
""")
|
""")
|
||||||
names = [description[0] for description in cur.description]
|
# names = [description[0] for description in cur.description]
|
||||||
|
|
||||||
for row in cur:
|
for row in cur:
|
||||||
self.results.append({
|
self.results.append({
|
||||||
|
|
|
@ -19,6 +19,7 @@ CHROME_FAVICON_ROOT_PATHS = [
|
||||||
"private/var/mobile/Containers/Data/Application/*/Library/Application Support/Google/Chrome/Default/Favicons",
|
"private/var/mobile/Containers/Data/Application/*/Library/Application Support/Google/Chrome/Default/Favicons",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class ChromeFavicon(IOSExtraction):
|
class ChromeFavicon(IOSExtraction):
|
||||||
"""This module extracts all Chrome favicon records."""
|
"""This module extracts all Chrome favicon records."""
|
||||||
|
|
||||||
|
|
|
@ -13,12 +13,12 @@ from ..base import IOSExtraction
|
||||||
CHROME_HISTORY_BACKUP_IDS = [
|
CHROME_HISTORY_BACKUP_IDS = [
|
||||||
"faf971ce92c3ac508c018dce1bef2a8b8e9838f1",
|
"faf971ce92c3ac508c018dce1bef2a8b8e9838f1",
|
||||||
]
|
]
|
||||||
|
|
||||||
# TODO: Confirm Chrome database path.
|
# TODO: Confirm Chrome database path.
|
||||||
CHROME_HISTORY_ROOT_PATHS = [
|
CHROME_HISTORY_ROOT_PATHS = [
|
||||||
"private/var/mobile/Containers/Data/Application/*/Library/Application Support/Google/Chrome/Default/History",
|
"private/var/mobile/Containers/Data/Application/*/Library/Application Support/Google/Chrome/Default/History",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class ChromeHistory(IOSExtraction):
|
class ChromeHistory(IOSExtraction):
|
||||||
"""This module extracts all Chome visits."""
|
"""This module extracts all Chome visits."""
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ CONTACTS_ROOT_PATHS = [
|
||||||
"private/var/mobile/Library/AddressBook/AddressBook.sqlitedb",
|
"private/var/mobile/Library/AddressBook/AddressBook.sqlitedb",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class Contacts(IOSExtraction):
|
class Contacts(IOSExtraction):
|
||||||
"""This module extracts all contact details from the phone's address book."""
|
"""This module extracts all contact details from the phone's address book."""
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ FIREFOX_HISTORY_ROOT_PATHS = [
|
||||||
"private/var/mobile/profile.profile/browser.db",
|
"private/var/mobile/profile.profile/browser.db",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class FirefoxFavicon(IOSExtraction):
|
class FirefoxFavicon(IOSExtraction):
|
||||||
"""This module extracts all Firefox favicon"""
|
"""This module extracts all Firefox favicon"""
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ FIREFOX_HISTORY_ROOT_PATHS = [
|
||||||
"private/var/mobile/profile.profile/browser.db",
|
"private/var/mobile/profile.profile/browser.db",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class FirefoxHistory(IOSExtraction):
|
class FirefoxHistory(IOSExtraction):
|
||||||
"""This module extracts all Firefox visits and tries to detect potential
|
"""This module extracts all Firefox visits and tries to detect potential
|
||||||
network injection attacks.
|
network injection attacks.
|
||||||
|
|
|
@ -18,6 +18,7 @@ IDSTATUSCACHE_ROOT_PATHS = [
|
||||||
"private/var/mobile/Library/IdentityServices/idstatuscache.plist",
|
"private/var/mobile/Library/IdentityServices/idstatuscache.plist",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class IDStatusCache(IOSExtraction):
|
class IDStatusCache(IOSExtraction):
|
||||||
"""Extracts Apple Authentication information from idstatuscache.plist"""
|
"""Extracts Apple Authentication information from idstatuscache.plist"""
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ INTERACTIONC_ROOT_PATHS = [
|
||||||
"private/var/mobile/Library/CoreDuet/People/interactionC.db",
|
"private/var/mobile/Library/CoreDuet/People/interactionC.db",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class InteractionC(IOSExtraction):
|
class InteractionC(IOSExtraction):
|
||||||
"""This module extracts data from InteractionC db."""
|
"""This module extracts data from InteractionC db."""
|
||||||
|
|
||||||
|
@ -54,8 +55,8 @@ class InteractionC(IOSExtraction):
|
||||||
"timestamp": record[ts],
|
"timestamp": record[ts],
|
||||||
"module": self.__class__.__name__,
|
"module": self.__class__.__name__,
|
||||||
"event": ts,
|
"event": ts,
|
||||||
"data": f"[{record['bundle_id']}] {record['account']} - from {record['sender_display_name']} " \
|
"data": f"[{record['bundle_id']}] {record['account']} - from {record['sender_display_name']} "
|
||||||
f"({record['sender_identifier']}) to {record['recipient_display_name']} " \
|
f"({record['sender_identifier']}) to {record['recipient_display_name']} "
|
||||||
f"({record['recipient_identifier']}): {record['content']}"
|
f"({record['recipient_identifier']}): {record['content']}"
|
||||||
})
|
})
|
||||||
processed.append(record[ts])
|
processed.append(record[ts])
|
||||||
|
@ -123,8 +124,7 @@ class InteractionC(IOSExtraction):
|
||||||
LEFT JOIN Z_2INTERACTIONRECIPIENT ON ZINTERACTIONS.Z_PK== Z_2INTERACTIONRECIPIENT.Z_3INTERACTIONRECIPIENT
|
LEFT JOIN Z_2INTERACTIONRECIPIENT ON ZINTERACTIONS.Z_PK== Z_2INTERACTIONRECIPIENT.Z_3INTERACTIONRECIPIENT
|
||||||
LEFT JOIN ZCONTACTS RECEIPIENTCONACT ON Z_2INTERACTIONRECIPIENT.Z_2RECIPIENTS== RECEIPIENTCONACT.Z_PK;
|
LEFT JOIN ZCONTACTS RECEIPIENTCONACT ON Z_2INTERACTIONRECIPIENT.Z_2RECIPIENTS== RECEIPIENTCONACT.Z_PK;
|
||||||
""")
|
""")
|
||||||
|
# names = [description[0] for description in cur.description]
|
||||||
names = [description[0] for description in cur.description]
|
|
||||||
|
|
||||||
for row in cur:
|
for row in cur:
|
||||||
self.results.append({
|
self.results.append({
|
||||||
|
|
|
@ -17,6 +17,7 @@ LOCATIOND_ROOT_PATHS = [
|
||||||
"private/var/root/Library/Caches/locationd/clients.plist"
|
"private/var/root/Library/Caches/locationd/clients.plist"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class LocationdClients(IOSExtraction):
|
class LocationdClients(IOSExtraction):
|
||||||
"""Extract information from apps who used geolocation."""
|
"""Extract information from apps who used geolocation."""
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ DATAUSAGE_ROOT_PATHS = [
|
||||||
"private/var/wireless/Library/Databases/DataUsage.sqlite",
|
"private/var/wireless/Library/Databases/DataUsage.sqlite",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class Datausage(NetBase):
|
class Datausage(NetBase):
|
||||||
"""This class extracts data from DataUsage.sqlite and attempts to identify
|
"""This class extracts data from DataUsage.sqlite and attempts to identify
|
||||||
any suspicious processes if running on a full filesystem dump.
|
any suspicious processes if running on a full filesystem dump.
|
||||||
|
|
|
@ -16,6 +16,7 @@ OSANALYTICS_ADDAILY_ROOT_PATHS = [
|
||||||
"private/var/mobile/Library/Preferences/com.apple.osanalytics.addaily.plist",
|
"private/var/mobile/Library/Preferences/com.apple.osanalytics.addaily.plist",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class OSAnalyticsADDaily(IOSExtraction):
|
class OSAnalyticsADDaily(IOSExtraction):
|
||||||
"""Extract network usage information by process, from com.apple.osanalytics.addaily.plist"""
|
"""Extract network usage information by process, from com.apple.osanalytics.addaily.plist"""
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ SAFARI_BROWSER_STATE_ROOT_PATHS = [
|
||||||
"private/var/mobile/Containers/Data/Application/*/Library/Safari/BrowserState.db",
|
"private/var/mobile/Containers/Data/Application/*/Library/Safari/BrowserState.db",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class SafariBrowserState(IOSExtraction):
|
class SafariBrowserState(IOSExtraction):
|
||||||
"""This module extracts all Safari browser state records."""
|
"""This module extracts all Safari browser state records."""
|
||||||
|
|
||||||
|
@ -47,7 +48,7 @@ class SafariBrowserState(IOSExtraction):
|
||||||
self.detected.append(result)
|
self.detected.append(result)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if not "session_data" in result:
|
if "session_data" not in result:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
for session_entry in result["session_data"]:
|
for session_entry in result["session_data"]:
|
||||||
|
|
|
@ -17,6 +17,7 @@ SAFARI_HISTORY_ROOT_PATHS = [
|
||||||
"private/var/mobile/Containers/Data/Application/*/Library/Safari/History.db",
|
"private/var/mobile/Containers/Data/Application/*/Library/Safari/History.db",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class SafariHistory(IOSExtraction):
|
class SafariHistory(IOSExtraction):
|
||||||
"""This module extracts all Safari visits and tries to detect potential
|
"""This module extracts all Safari visits and tries to detect potential
|
||||||
network injection attacks.
|
network injection attacks.
|
||||||
|
|
|
@ -18,6 +18,7 @@ SMS_ROOT_PATHS = [
|
||||||
"private/var/mobile/Library/SMS/sms.db",
|
"private/var/mobile/Library/SMS/sms.db",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class SMS(IOSExtraction):
|
class SMS(IOSExtraction):
|
||||||
"""This module extracts all SMS messages containing links."""
|
"""This module extracts all SMS messages containing links."""
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ SMS_ROOT_PATHS = [
|
||||||
"private/var/mobile/Library/SMS/sms.db",
|
"private/var/mobile/Library/SMS/sms.db",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class SMSAttachments(IOSExtraction):
|
class SMSAttachments(IOSExtraction):
|
||||||
"""This module extracts all info about SMS/iMessage attachments."""
|
"""This module extracts all info about SMS/iMessage attachments."""
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,7 @@ AUTH_REASONS = {
|
||||||
12: "app_type_policy",
|
12: "app_type_policy",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class TCC(IOSExtraction):
|
class TCC(IOSExtraction):
|
||||||
"""This module extracts records from the TCC.db SQLite database."""
|
"""This module extracts records from the TCC.db SQLite database."""
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ WEBKIT_RESOURCELOADSTATICS_ROOT_PATHS = [
|
||||||
"private/var/mobile/Containers/Data/Application/*/SystemData/com.apple.SafariViewService/Library/WebKit/WebsiteData/observations.db",
|
"private/var/mobile/Containers/Data/Application/*/SystemData/com.apple.SafariViewService/Library/WebKit/WebsiteData/observations.db",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class WebkitResourceLoadStatistics(IOSExtraction):
|
class WebkitResourceLoadStatistics(IOSExtraction):
|
||||||
"""This module extracts records from WebKit ResourceLoadStatistics observations.db."""
|
"""This module extracts records from WebKit ResourceLoadStatistics observations.db."""
|
||||||
# TODO: Add serialize().
|
# TODO: Add serialize().
|
||||||
|
@ -38,7 +39,7 @@ class WebkitResourceLoadStatistics(IOSExtraction):
|
||||||
for item in items:
|
for item in items:
|
||||||
if self.indicators.check_domain(item["registrable_domain"]):
|
if self.indicators.check_domain(item["registrable_domain"]):
|
||||||
if key not in self.detected:
|
if key not in self.detected:
|
||||||
self.detected[key] = [item,]
|
self.detected[key] = [item, ]
|
||||||
else:
|
else:
|
||||||
self.detected[key].append(item)
|
self.detected[key].append(item)
|
||||||
|
|
||||||
|
@ -55,7 +56,7 @@ class WebkitResourceLoadStatistics(IOSExtraction):
|
||||||
except sqlite3.OperationalError:
|
except sqlite3.OperationalError:
|
||||||
return
|
return
|
||||||
|
|
||||||
if not key in self.results:
|
if key not in self.results:
|
||||||
self.results[key] = []
|
self.results[key] = []
|
||||||
|
|
||||||
for row in cur:
|
for row in cur:
|
||||||
|
|
|
@ -20,6 +20,7 @@ WEBKIT_SESSION_RESOURCE_LOG_ROOT_PATHS = [
|
||||||
"private/var/mobile/Library/WebClips/*/Storage/full_browsing_session_resourceLog.plist",
|
"private/var/mobile/Library/WebClips/*/Storage/full_browsing_session_resourceLog.plist",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class WebkitSessionResourceLog(IOSExtraction):
|
class WebkitSessionResourceLog(IOSExtraction):
|
||||||
"""This module extracts records from WebKit browsing session
|
"""This module extracts records from WebKit browsing session
|
||||||
resource logs, and checks them against any provided list of
|
resource logs, and checks them against any provided list of
|
||||||
|
|
|
@ -20,6 +20,7 @@ WHATSAPP_ROOT_PATHS = [
|
||||||
"private/var/mobile/Containers/Shared/AppGroup/*/ChatStorage.sqlite",
|
"private/var/mobile/Containers/Shared/AppGroup/*/ChatStorage.sqlite",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class Whatsapp(IOSExtraction):
|
class Whatsapp(IOSExtraction):
|
||||||
"""This module extracts all WhatsApp messages containing links."""
|
"""This module extracts all WhatsApp messages containing links."""
|
||||||
|
|
||||||
|
|
|
@ -233,11 +233,13 @@ IPHONE_IOS_VERSIONS = [
|
||||||
{"build": "19B74", "version": "15.1"},
|
{"build": "19B74", "version": "15.1"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def get_device_desc_from_id(identifier, devices_list=IPHONE_MODELS):
|
def get_device_desc_from_id(identifier, devices_list=IPHONE_MODELS):
|
||||||
for model in IPHONE_MODELS:
|
for model in IPHONE_MODELS:
|
||||||
if identifier == model["identifier"]:
|
if identifier == model["identifier"]:
|
||||||
return model["description"]
|
return model["description"]
|
||||||
|
|
||||||
|
|
||||||
def find_version_by_build(build):
|
def find_version_by_build(build):
|
||||||
build = build.upper()
|
build = build.upper()
|
||||||
for version in IPHONE_IOS_VERSIONS:
|
for version in IPHONE_IOS_VERSIONS:
|
||||||
|
|
2
setup.py
2
setup.py
|
@ -30,6 +30,7 @@ requires = (
|
||||||
"libusb1>=2.0.1",
|
"libusb1>=2.0.1",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_package_data(package):
|
def get_package_data(package):
|
||||||
walk = [(dirpath.replace(package + os.sep, "", 1), filenames)
|
walk = [(dirpath.replace(package + os.sep, "", 1), filenames)
|
||||||
for dirpath, dirnames, filenames in os.walk(package)
|
for dirpath, dirnames, filenames in os.walk(package)
|
||||||
|
@ -41,6 +42,7 @@ def get_package_data(package):
|
||||||
for filename in filenames])
|
for filename in filenames])
|
||||||
return {package: filepaths}
|
return {package: filepaths}
|
||||||
|
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name="mvt",
|
name="mvt",
|
||||||
version=MVT_VERSION,
|
version=MVT_VERSION,
|
||||||
|
|
Loading…
Reference in New Issue