mirror of
https://github.com/mvt-project/mvt.git
synced 2024-07-01 08:29:03 +00:00
Adds Applications iOS module
This commit is contained in:
parent
179b6976fa
commit
0d653be4dd
|
@ -3,6 +3,7 @@
|
||||||
# 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/
|
||||||
|
|
||||||
|
from .applications import Applications
|
||||||
from .calls import Calls
|
from .calls import Calls
|
||||||
from .chrome_favicon import ChromeFavicon
|
from .chrome_favicon import ChromeFavicon
|
||||||
from .chrome_history import ChromeHistory
|
from .chrome_history import ChromeHistory
|
||||||
|
@ -28,4 +29,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, Shortcuts]
|
WebkitSessionResourceLog, Whatsapp, Shortcuts, Applications]
|
||||||
|
|
124
mvt/ios/modules/mixed/applications.py
Normal file
124
mvt/ios/modules/mixed/applications.py
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
# Mobile Verification Toolkit (MVT)
|
||||||
|
# Copyright (c) 2021-2023 Claudio Guarnieri.
|
||||||
|
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||||
|
# https://license.mvt.re/1.1/
|
||||||
|
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
import plistlib
|
||||||
|
import hashlib
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
from typing import Optional, Union, Dict, Any
|
||||||
|
|
||||||
|
from mvt.common.utils import convert_datetime_to_iso
|
||||||
|
from mvt.common.module import DatabaseNotFoundError
|
||||||
|
|
||||||
|
from mvt.ios.modules.base import IOSExtraction
|
||||||
|
|
||||||
|
APPLICATIONS_DB_PATH = [
|
||||||
|
"private/var/containers/Bundle/Application/*/iTunesMetadata.plist"
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class Applications(IOSExtraction):
|
||||||
|
"""Extract information from accounts installed on the phone."""
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
file_path: Optional[str] = None,
|
||||||
|
target_path: Optional[str] = None,
|
||||||
|
results_path: Optional[str] = None,
|
||||||
|
fast_mode: Optional[bool] = False,
|
||||||
|
log: logging.Logger = logging.getLogger(__name__),
|
||||||
|
results: Optional[list] = None
|
||||||
|
) -> None:
|
||||||
|
super().__init__(file_path=file_path, target_path=target_path,
|
||||||
|
results_path=results_path, fast_mode=fast_mode,
|
||||||
|
log=log, results=results)
|
||||||
|
|
||||||
|
def serialize(self, record: dict) -> Union[dict, list]:
|
||||||
|
if "isodate" in record:
|
||||||
|
return {
|
||||||
|
"timestamp": record["isodate"],
|
||||||
|
"module": self.__class__.__name__,
|
||||||
|
"event": "app_installed",
|
||||||
|
"data": f"App {record.get('name', '')} version {record.get('bundleShortVersionString', '')} from {record.get('artistName', '')} installed from {record.get('sourceApp', '')}"
|
||||||
|
}
|
||||||
|
return []
|
||||||
|
|
||||||
|
def check_indicators(self) -> None:
|
||||||
|
for result in self.results:
|
||||||
|
if self.indicators:
|
||||||
|
ioc = self.indicators.check_process(result["softwareVersionBundleId"])
|
||||||
|
if ioc:
|
||||||
|
self.log.warning("Malicious application %s identified", result["softwareVersionBundleId"])
|
||||||
|
result["matched_indicator"] = ioc
|
||||||
|
self.detected.append(result)
|
||||||
|
continue
|
||||||
|
|
||||||
|
ioc = self.indicators.check_app_id(result["softwareVersionBundleId"])
|
||||||
|
if ioc:
|
||||||
|
self.log.warning("Malicious application %s identified", result["softwareVersionBundleId"])
|
||||||
|
result["matched_indicator"] = ioc
|
||||||
|
self.detected.append(result)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if result.get("sourceApp", "com.apple.AppStore") != "com.apple.AppStore":
|
||||||
|
self.log.warning("Suspicious app not installed from the App Store: %s", result["softwareVersionBundleId"])
|
||||||
|
self.detected.append(result)
|
||||||
|
|
||||||
|
def _parse_itunes_timestamp(self, entry: Dict[str, Any]) -> None:
|
||||||
|
"""
|
||||||
|
Parse the iTunes metadata info
|
||||||
|
"""
|
||||||
|
if entry.get("com.apple.iTunesStore.downloadInfo", {}).get("purchaseDate", None):
|
||||||
|
timestamp = datetime.strptime(
|
||||||
|
entry["com.apple.iTunesStore.downloadInfo"]["purchaseDate"],
|
||||||
|
"%Y-%m-%dT%H:%M:%SZ")
|
||||||
|
timestamp_utc = timestamp.astimezone(timezone.utc)
|
||||||
|
entry["isodate"] = convert_datetime_to_iso(timestamp_utc)
|
||||||
|
|
||||||
|
def _parse_itunes_metadata(self, plist_path: str) -> None:
|
||||||
|
"""
|
||||||
|
Parse iTunesMetadata.plist file from an application in fs dump
|
||||||
|
"""
|
||||||
|
with open(plist_path, "rb") as f:
|
||||||
|
entry = plistlib.load(f)
|
||||||
|
|
||||||
|
entry["file_path"] = plist_path
|
||||||
|
self._parse_itunes_timestamp(entry)
|
||||||
|
self.results.append(entry)
|
||||||
|
|
||||||
|
def _parse_info_plist(self, plist_path: str) -> None:
|
||||||
|
"""
|
||||||
|
Parse Info.plist file from backup
|
||||||
|
"""
|
||||||
|
with open(plist_path, "rb") as f:
|
||||||
|
data = plistlib.load(f)
|
||||||
|
|
||||||
|
for app in data.get("Applications", {}):
|
||||||
|
app_data = data["Applications"][app]
|
||||||
|
entry = {"name": app}
|
||||||
|
metadata = plistlib.loads(app_data["iTunesMetadata"])
|
||||||
|
entry.update(metadata)
|
||||||
|
|
||||||
|
self._parse_itunes_timestamp(entry)
|
||||||
|
|
||||||
|
if "PlaceholderIcon" in app_data:
|
||||||
|
sha256_hash = hashlib.sha256()
|
||||||
|
sha256_hash.update(app_data["PlaceholderIcon"])
|
||||||
|
entry["icon_sha256"] = sha256_hash.hexdigest()
|
||||||
|
|
||||||
|
self.results.append(entry)
|
||||||
|
|
||||||
|
def run(self) -> None:
|
||||||
|
if self.is_backup:
|
||||||
|
plist_path = os.path.join(self.target_path, "Info.plist")
|
||||||
|
if not os.path.isfile(plist_path):
|
||||||
|
raise DatabaseNotFoundError("Impossible to find Info.plist file")
|
||||||
|
self._parse_info_plist(plist_path)
|
||||||
|
elif self.is_fs_dump:
|
||||||
|
for file_path in self._get_fs_files_from_patterns(APPLICATIONS_DB_PATH):
|
||||||
|
self._parse_itunes_metadata(file_path)
|
||||||
|
|
||||||
|
self.log.info("Extracted a total of %d applications",
|
||||||
|
len(self.results))
|
Loading…
Reference in New Issue
Block a user