mirror of
https://github.com/mvt-project/mvt.git
synced 2026-10-27 00:07:05 +01:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
06cea62a40 |
No files matched your search
@@ -43,25 +43,11 @@ class DumpsysAppopsArtifact(AndroidArtifact):
|
||||
|
||||
def check_indicators(self) -> None:
|
||||
for result in self.results:
|
||||
# A package IOC match is not tied to one AppOps entry. Use the latest
|
||||
# recorded access or rejection to place the package-level alert in time.
|
||||
event_time = max(
|
||||
(
|
||||
entry["timestamp"]
|
||||
for permission in result["permissions"]
|
||||
for entry in permission.get("entries", [])
|
||||
if entry.get("timestamp")
|
||||
),
|
||||
default="",
|
||||
)
|
||||
if self.indicators:
|
||||
ioc_match = self.indicators.check_app_id(result.get("package_name"))
|
||||
if ioc_match:
|
||||
self.alertstore.critical(
|
||||
ioc_match.message,
|
||||
event_time,
|
||||
result,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
ioc_match.message, "", result, matched_indicator=ioc_match.ioc
|
||||
)
|
||||
continue
|
||||
|
||||
|
||||
@@ -43,10 +43,7 @@ class DumpsysBatteryDailyArtifact(AndroidArtifact):
|
||||
ioc_match = self.indicators.check_app_id(result["package_name"])
|
||||
if ioc_match:
|
||||
self.alertstore.critical(
|
||||
ioc_match.message,
|
||||
result.get("period_start") or "",
|
||||
result,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
ioc_match.message, "", result, matched_indicator=ioc_match.ioc
|
||||
)
|
||||
continue
|
||||
|
||||
|
||||
@@ -24,10 +24,7 @@ class DumpsysBatteryHistoryArtifact(AndroidArtifact):
|
||||
ioc_match = self.indicators.check_app_id(package_name)
|
||||
if ioc_match:
|
||||
self.alertstore.critical(
|
||||
ioc_match.message,
|
||||
result.get("timestamp") or "",
|
||||
result,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
ioc_match.message, "", result, matched_indicator=ioc_match.ioc
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
|
||||
@@ -23,10 +23,7 @@ class DumpsysDBInfoArtifact(AndroidArtifact):
|
||||
ioc_match = self.indicators.check_app_id(part)
|
||||
if ioc_match:
|
||||
self.alertstore.critical(
|
||||
ioc_match.message,
|
||||
result.get("timestamp") or "",
|
||||
result,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
ioc_match.message, "", result, matched_indicator=ioc_match.ioc
|
||||
)
|
||||
continue
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ class DumpsysPackagesArtifact(AndroidArtifact):
|
||||
alerted_root_packages.add(package_name)
|
||||
self.alertstore.medium(
|
||||
f'Found an installed package related to rooting/jailbreaking: "{package_name}"',
|
||||
result.get("timestamp") or "",
|
||||
"",
|
||||
result,
|
||||
)
|
||||
if not self.indicators:
|
||||
@@ -43,10 +43,7 @@ class DumpsysPackagesArtifact(AndroidArtifact):
|
||||
ioc_match = self.indicators.check_app_id(package_name)
|
||||
if ioc_match:
|
||||
self.alertstore.critical(
|
||||
ioc_match.message,
|
||||
result.get("timestamp") or "",
|
||||
result,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
ioc_match.message, "", result, matched_indicator=ioc_match.ioc
|
||||
)
|
||||
|
||||
def serialize(self, record: ModuleAtomicResult) -> ModuleSerializedResult:
|
||||
|
||||
@@ -99,10 +99,7 @@ class TombstoneCrashArtifact(AndroidArtifact):
|
||||
ioc_match = self.indicators.check_process(result["process_name"])
|
||||
if ioc_match:
|
||||
self.alertstore.critical(
|
||||
ioc_match.message,
|
||||
result.get("timestamp") or "",
|
||||
result,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
ioc_match.message, "", result, matched_indicator=ioc_match.ioc
|
||||
)
|
||||
continue
|
||||
|
||||
@@ -111,10 +108,7 @@ class TombstoneCrashArtifact(AndroidArtifact):
|
||||
ioc_match = self.indicators.check_process(command_name)
|
||||
if ioc_match:
|
||||
self.alertstore.critical(
|
||||
ioc_match.message,
|
||||
result.get("timestamp") or "",
|
||||
result,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
ioc_match.message, "", result, matched_indicator=ioc_match.ioc
|
||||
)
|
||||
continue
|
||||
|
||||
@@ -129,7 +123,7 @@ class TombstoneCrashArtifact(AndroidArtifact):
|
||||
f"Potentially suspicious crash in process '{result['process_name']}' "
|
||||
f"running as UID '{result['uid']}' in tombstone '{result['file_name']}' at {result['timestamp']}"
|
||||
),
|
||||
result.get("timestamp") or "",
|
||||
"",
|
||||
result,
|
||||
)
|
||||
|
||||
|
||||
@@ -90,10 +90,7 @@ class AQFFiles(AndroidQFModule):
|
||||
ioc_match = self.indicators.check_file_path(result["path"])
|
||||
if ioc_match:
|
||||
self.alertstore.critical(
|
||||
ioc_match.message,
|
||||
result.get("modified_time") or "",
|
||||
result,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
ioc_match.message, "", result, matched_indicator=ioc_match.ioc
|
||||
)
|
||||
continue
|
||||
|
||||
@@ -108,7 +105,7 @@ class AQFFiles(AndroidQFModule):
|
||||
file_type = "executable "
|
||||
|
||||
msg = f'Found {file_type}file at suspicious path "{result["path"]}"'
|
||||
self.alertstore.high(msg, result.get("modified_time") or "", result)
|
||||
self.alertstore.high(msg, "", result)
|
||||
|
||||
for hash_key in ("sha256", "sha1", "md5"):
|
||||
file_hash = result.get(hash_key, "")
|
||||
@@ -117,10 +114,7 @@ class AQFFiles(AndroidQFModule):
|
||||
ioc_match = self.indicators.check_file_hash(file_hash)
|
||||
if ioc_match:
|
||||
self.alertstore.critical(
|
||||
ioc_match.message,
|
||||
result.get("modified_time") or "",
|
||||
result,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
ioc_match.message, "", result, matched_indicator=ioc_match.ioc
|
||||
)
|
||||
break
|
||||
|
||||
|
||||
@@ -54,10 +54,7 @@ class SMS(BackupModule):
|
||||
):
|
||||
if ioc_match:
|
||||
self.alertstore.critical(
|
||||
ioc_match.message,
|
||||
message.get("isodate") or "",
|
||||
message,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
ioc_match.message, "", message, matched_indicator=ioc_match.ioc
|
||||
)
|
||||
|
||||
def collect_url_results(self) -> None:
|
||||
|
||||
@@ -7,6 +7,7 @@ import json
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
from datetime import datetime
|
||||
from functools import cached_property
|
||||
from heapq import heappop, heappush
|
||||
@@ -36,6 +37,17 @@ from .utils import (
|
||||
from .version import MVT_VERSION
|
||||
|
||||
|
||||
def _peak_rss_mb() -> float:
|
||||
"""The process's peak resident set size so far, in MB (0 where unknown)."""
|
||||
try:
|
||||
import resource
|
||||
except ImportError:
|
||||
return 0.0
|
||||
peak = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
|
||||
# ru_maxrss is in bytes on macOS and in kilobytes elsewhere.
|
||||
return peak / (1024 * 1024 if sys.platform == "darwin" else 1024)
|
||||
|
||||
|
||||
class Command:
|
||||
def __init__(
|
||||
self,
|
||||
@@ -77,6 +89,9 @@ class Command:
|
||||
# declaring `replaces` to the module which took their place.
|
||||
self.module_replacements: dict[type[MVTModule], type[MVTModule]] = {}
|
||||
|
||||
# Wall time and peak-RSS growth of every module run, in run order.
|
||||
self.module_stats: list[dict[str, Any]] = []
|
||||
|
||||
# This list will contain all executed modules.
|
||||
# We can use this to reference e.g. self.executed[0].results.
|
||||
self.executed: list[MVTModule] = []
|
||||
@@ -190,6 +205,7 @@ class Command:
|
||||
"date": convert_datetime_to_iso(datetime.now()),
|
||||
"ioc_files": [],
|
||||
"hashes": [],
|
||||
"module_stats": self.module_stats,
|
||||
}
|
||||
|
||||
for coll in self.iocs.ioc_collections:
|
||||
@@ -766,6 +782,8 @@ class Command:
|
||||
except NotImplementedError:
|
||||
pass
|
||||
|
||||
started = time.perf_counter()
|
||||
peak_before = _peak_rss_mb()
|
||||
try:
|
||||
run_module(m)
|
||||
except EncryptedBackupError:
|
||||
@@ -775,6 +793,19 @@ class Command:
|
||||
)
|
||||
return
|
||||
|
||||
stats = {
|
||||
"module": module.__name__,
|
||||
"seconds": round(time.perf_counter() - started, 2),
|
||||
"peak_rss_growth_mb": round(_peak_rss_mb() - peak_before),
|
||||
}
|
||||
self.module_stats.append(stats)
|
||||
self.log.info(
|
||||
"Module %s ran in %.1fs and raised the peak memory by %d MB",
|
||||
stats["module"],
|
||||
stats["seconds"],
|
||||
stats["peak_rss_growth_mb"],
|
||||
)
|
||||
|
||||
self.executed.append(m)
|
||||
executed_by_type[module] = m
|
||||
self.timeline.extend(m.timeline)
|
||||
|
||||
@@ -1271,9 +1271,5 @@
|
||||
{
|
||||
"version": "26.6.1",
|
||||
"build": "23G83"
|
||||
},
|
||||
{
|
||||
"version": "26.6.2",
|
||||
"build": "23G90"
|
||||
}
|
||||
]
|
||||
@@ -74,10 +74,7 @@ class ConfigurationProfiles(IOSExtraction):
|
||||
if ioc_match:
|
||||
warning_message = f'Found a known malicious configuration profile "{result["plist"]["PayloadDisplayName"]}" with UUID "{result["plist"]["PayloadUUID"]}"'
|
||||
self.alertstore.critical(
|
||||
warning_message,
|
||||
result.get("install_date") or "",
|
||||
result,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
warning_message, "", result, matched_indicator=ioc_match.ioc
|
||||
)
|
||||
continue
|
||||
|
||||
@@ -85,9 +82,7 @@ class ConfigurationProfiles(IOSExtraction):
|
||||
# to hide notifications.
|
||||
if payload_content["PayloadType"] in ["com.apple.notificationsettings"]:
|
||||
warning_message = f'Found a potentially suspicious configuration profile "{result["plist"]["PayloadDisplayName"]}" with payload type {payload_content["PayloadType"]}'
|
||||
self.alertstore.medium(
|
||||
warning_message, result.get("install_date") or "", result
|
||||
)
|
||||
self.alertstore.medium(warning_message, "", result)
|
||||
continue
|
||||
|
||||
@staticmethod
|
||||
|
||||
@@ -104,10 +104,7 @@ class Manifest(IOSExtraction):
|
||||
ioc_match = self.indicators.check_file_path("/" + result["relative_path"])
|
||||
if ioc_match:
|
||||
self.alertstore.high(
|
||||
ioc_match.message,
|
||||
result.get("modified") or "",
|
||||
result,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
ioc_match.message, "", result, matched_indicator=ioc_match.ioc
|
||||
)
|
||||
continue
|
||||
|
||||
@@ -123,7 +120,7 @@ class Manifest(IOSExtraction):
|
||||
if ioc_match:
|
||||
self.alertstore.high(
|
||||
f'Found mention of domain "{ioc_match.ioc.value}" in a backup file with path: {rel_path}',
|
||||
result.get("modified") or "",
|
||||
"",
|
||||
result,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
)
|
||||
|
||||
@@ -67,20 +67,14 @@ class ProfileEvents(IOSExtraction):
|
||||
ioc_match = self.indicators.check_process(result.get("process") or "")
|
||||
if ioc_match:
|
||||
self.alertstore.critical(
|
||||
ioc_match.message,
|
||||
result.get("timestamp") or "",
|
||||
result,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
ioc_match.message, "", result, matched_indicator=ioc_match.ioc
|
||||
)
|
||||
continue
|
||||
|
||||
ioc_match = self.indicators.check_profile(result.get("profile_id") or "")
|
||||
if ioc_match:
|
||||
self.alertstore.critical(
|
||||
ioc_match.message,
|
||||
result.get("timestamp") or "",
|
||||
result,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
ioc_match.message, "", result, matched_indicator=ioc_match.ioc
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
|
||||
@@ -68,10 +68,7 @@ class Analytics(IOSExtraction):
|
||||
warning_message = f'Found mention of a malicious process "{value}" in {result["artifact"]} file at {result["isodate"]}'
|
||||
new_result = copy.copy(result)
|
||||
self.alertstore.critical(
|
||||
warning_message,
|
||||
result.get("isodate") or "",
|
||||
new_result,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
warning_message, "", new_result, matched_indicator=ioc_match.ioc
|
||||
)
|
||||
continue
|
||||
|
||||
@@ -80,7 +77,7 @@ class Analytics(IOSExtraction):
|
||||
new_result = copy.copy(result)
|
||||
self.alertstore.critical(
|
||||
ioc_match.message,
|
||||
result.get("isodate") or "",
|
||||
"",
|
||||
new_result,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
)
|
||||
|
||||
@@ -59,10 +59,7 @@ class Filesystem(IOSExtraction):
|
||||
ioc_match = self.indicators.check_file_path(result["path"])
|
||||
if ioc_match:
|
||||
self.alertstore.high(
|
||||
ioc_match.message,
|
||||
result.get("modified") or "",
|
||||
result,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
ioc_match.message, "", result, matched_indicator=ioc_match.ioc
|
||||
)
|
||||
|
||||
# If we are instructed to run fast, we skip the rest.
|
||||
@@ -72,10 +69,7 @@ class Filesystem(IOSExtraction):
|
||||
ioc_match = self.indicators.check_file_path_process(result["path"])
|
||||
if ioc_match:
|
||||
self.alertstore.high(
|
||||
ioc_match.message,
|
||||
result.get("modified") or "",
|
||||
result,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
ioc_match.message, "", result, matched_indicator=ioc_match.ioc
|
||||
)
|
||||
|
||||
def run(self) -> None:
|
||||
|
||||
@@ -63,10 +63,7 @@ class SafariFavicon(IOSExtraction):
|
||||
|
||||
if ioc_match:
|
||||
self.alertstore.critical(
|
||||
ioc_match.message,
|
||||
result.get("isodate") or "",
|
||||
result,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
ioc_match.message, "", result, matched_indicator=ioc_match.ioc
|
||||
)
|
||||
|
||||
def _process_favicon_db(self, file_path):
|
||||
|
||||
@@ -60,10 +60,7 @@ class ShutdownLog(IOSExtraction):
|
||||
ioc_match = self.indicators.check_file_path(result["client"])
|
||||
if ioc_match:
|
||||
self.alertstore.critical(
|
||||
ioc_match.message,
|
||||
result.get("isodate") or "",
|
||||
result,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
ioc_match.message, "", result, matched_indicator=ioc_match.ioc
|
||||
)
|
||||
continue
|
||||
|
||||
@@ -72,7 +69,7 @@ class ShutdownLog(IOSExtraction):
|
||||
if ioc.value in parts:
|
||||
self.alertstore.critical(
|
||||
f'Found mention of a known malicious process "{ioc.value}" in shutdown.log',
|
||||
result.get("isodate") or "",
|
||||
"",
|
||||
result,
|
||||
matched_indicator=ioc,
|
||||
)
|
||||
|
||||
@@ -21,10 +21,7 @@ class WebkitBase(IOSExtraction):
|
||||
ioc_match = self.indicators.check_url(result["url"])
|
||||
if ioc_match:
|
||||
self.alertstore.critical(
|
||||
ioc_match.message,
|
||||
result.get("isodate") or "",
|
||||
result,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
ioc_match.message, "", result, matched_indicator=ioc_match.ioc
|
||||
)
|
||||
continue
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ class Applications(IOSExtraction):
|
||||
if "softwareVersionBundleId" not in result:
|
||||
self.alertstore.medium(
|
||||
"Suspicious application identified without softwareVersionBundleId",
|
||||
result.get("isodate") or "",
|
||||
"",
|
||||
result,
|
||||
)
|
||||
continue
|
||||
@@ -79,7 +79,7 @@ class Applications(IOSExtraction):
|
||||
if ioc_match:
|
||||
self.alertstore.critical(
|
||||
f"Malicious application {result['softwareVersionBundleId']} identified",
|
||||
result.get("isodate") or "",
|
||||
"",
|
||||
result,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
)
|
||||
@@ -91,7 +91,7 @@ class Applications(IOSExtraction):
|
||||
if ioc_match:
|
||||
self.alertstore.critical(
|
||||
f"Malicious application {result['softwareVersionBundleId']} identified",
|
||||
result.get("isodate") or "",
|
||||
"",
|
||||
result,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
)
|
||||
@@ -104,7 +104,7 @@ class Applications(IOSExtraction):
|
||||
):
|
||||
self.alertstore.medium(
|
||||
f"Suspicious app not installed from the App Store or MDM: {result['softwareVersionBundleId']}",
|
||||
result.get("isodate") or "",
|
||||
"",
|
||||
result,
|
||||
)
|
||||
|
||||
|
||||
@@ -72,10 +72,7 @@ class Calendar(IOSExtraction):
|
||||
ioc_match = self.indicators.check_email(result["participant_email"])
|
||||
if ioc_match:
|
||||
self.alertstore.critical(
|
||||
ioc_match.message,
|
||||
result.get("start_date") or "",
|
||||
result,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
ioc_match.message, "", result, matched_indicator=ioc_match.ioc
|
||||
)
|
||||
continue
|
||||
|
||||
@@ -83,7 +80,7 @@ class Calendar(IOSExtraction):
|
||||
if result["summary"] == "Meeting" and result["description"] == "Notes":
|
||||
self.alertstore.high(
|
||||
f"Potential Quadream exploit event identified: {result['uuid']}",
|
||||
result.get("start_date") or "",
|
||||
"",
|
||||
result,
|
||||
)
|
||||
|
||||
|
||||
@@ -61,10 +61,7 @@ class ChromeFavicon(IOSExtraction):
|
||||
|
||||
if ioc_match:
|
||||
self.alertstore.critical(
|
||||
ioc_match.message,
|
||||
result.get("isodate") or "",
|
||||
result,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
ioc_match.message, "", result, matched_indicator=ioc_match.ioc
|
||||
)
|
||||
continue
|
||||
|
||||
|
||||
@@ -62,10 +62,7 @@ class ChromeHistory(IOSExtraction):
|
||||
ioc_match = self.indicators.check_url(result["url"])
|
||||
if ioc_match:
|
||||
self.alertstore.critical(
|
||||
ioc_match.message,
|
||||
result.get("isodate") or "",
|
||||
result,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
ioc_match.message, "", result, matched_indicator=ioc_match.ioc
|
||||
)
|
||||
|
||||
def run(self) -> None:
|
||||
|
||||
@@ -64,10 +64,7 @@ class FirefoxFavicon(IOSExtraction):
|
||||
|
||||
if ioc_match:
|
||||
self.alertstore.critical(
|
||||
ioc_match.message,
|
||||
result.get("isodate") or "",
|
||||
result,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
ioc_match.message, "", result, matched_indicator=ioc_match.ioc
|
||||
)
|
||||
|
||||
def run(self) -> None:
|
||||
|
||||
@@ -64,10 +64,7 @@ class FirefoxHistory(IOSExtraction):
|
||||
ioc_match = self.indicators.check_url(result["url"])
|
||||
if ioc_match:
|
||||
self.alertstore.critical(
|
||||
ioc_match.message,
|
||||
result.get("isodate") or "",
|
||||
result,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
ioc_match.message, "", result, matched_indicator=ioc_match.ioc
|
||||
)
|
||||
|
||||
def run(self) -> None:
|
||||
|
||||
@@ -66,17 +66,14 @@ class IDStatusCache(IOSExtraction):
|
||||
ioc_match = self.indicators.check_email(email)
|
||||
if ioc_match:
|
||||
self.alertstore.critical(
|
||||
ioc_match.message,
|
||||
result.get("isodate") or "",
|
||||
result,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
ioc_match.message, "", result, matched_indicator=ioc_match.ioc
|
||||
)
|
||||
continue
|
||||
|
||||
if "\\x00\\x00" in result.get("user", ""):
|
||||
self.alertstore.high(
|
||||
f"Found an ID Status Cache entry with suspicious patterns: {result.get('user')}",
|
||||
result.get("isodate") or "",
|
||||
"",
|
||||
result,
|
||||
)
|
||||
|
||||
|
||||
@@ -79,14 +79,6 @@ class LocationdClients(IOSExtraction):
|
||||
return
|
||||
|
||||
for result in self.results:
|
||||
event_time = next(
|
||||
(
|
||||
result[timestamp]
|
||||
for timestamp in self.timestamps
|
||||
if result.get(timestamp)
|
||||
),
|
||||
"",
|
||||
)
|
||||
parts = result["package"].split("/")
|
||||
proc_name = parts[len(parts) - 1]
|
||||
|
||||
@@ -94,7 +86,7 @@ class LocationdClients(IOSExtraction):
|
||||
if ioc_match:
|
||||
self.alertstore.high(
|
||||
f"Found a suspicious process name in LocationD entry {result['package']}",
|
||||
event_time,
|
||||
"",
|
||||
result,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
)
|
||||
@@ -105,7 +97,7 @@ class LocationdClients(IOSExtraction):
|
||||
if ioc_match:
|
||||
self.alertstore.high(
|
||||
f"Found a suspicious process name in LocationD entry {result['package']}",
|
||||
event_time,
|
||||
"",
|
||||
result,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
)
|
||||
@@ -115,7 +107,7 @@ class LocationdClients(IOSExtraction):
|
||||
if ioc_match:
|
||||
self.alertstore.high(
|
||||
f"Found a known malicious domain in LocationD entry {result['package']}",
|
||||
event_time,
|
||||
"",
|
||||
result,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
)
|
||||
@@ -126,7 +118,7 @@ class LocationdClients(IOSExtraction):
|
||||
if ioc_match:
|
||||
self.alertstore.high(
|
||||
f"Found a suspicious file path in LocationD entry {result['Executable']}",
|
||||
event_time,
|
||||
"",
|
||||
result,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
)
|
||||
@@ -141,7 +133,7 @@ class LocationdClients(IOSExtraction):
|
||||
if ioc_match:
|
||||
self.alertstore.high(
|
||||
f"Found a suspicious file path in LocationD entry {result['Registered']}",
|
||||
event_time,
|
||||
"",
|
||||
result,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
)
|
||||
|
||||
@@ -65,10 +65,7 @@ class OSAnalyticsADDaily(IOSExtraction):
|
||||
ioc_match = self.indicators.check_process(result["package"])
|
||||
if ioc_match:
|
||||
self.alertstore.critical(
|
||||
ioc_match.message,
|
||||
result.get("ts") or "",
|
||||
result,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
ioc_match.message, "", result, matched_indicator=ioc_match.ioc
|
||||
)
|
||||
|
||||
def run(self) -> None:
|
||||
|
||||
@@ -73,10 +73,7 @@ class SafariBrowserState(IOSExtraction):
|
||||
ioc_match = self.indicators.check_url(result["tab_url"])
|
||||
if ioc_match:
|
||||
self.alertstore.critical(
|
||||
ioc_match.message,
|
||||
result.get("last_viewed_timestamp") or "",
|
||||
result,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
ioc_match.message, "", result, matched_indicator=ioc_match.ioc
|
||||
)
|
||||
continue
|
||||
|
||||
@@ -89,7 +86,7 @@ class SafariBrowserState(IOSExtraction):
|
||||
if ioc_match:
|
||||
self.alertstore.critical(
|
||||
ioc_match.message,
|
||||
result.get("last_viewed_timestamp") or "",
|
||||
"",
|
||||
result,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
)
|
||||
|
||||
@@ -126,10 +126,7 @@ class SafariHistory(IOSExtraction):
|
||||
ioc_match = self.indicators.check_url(result["url"])
|
||||
if ioc_match:
|
||||
self.alertstore.critical(
|
||||
ioc_match.message,
|
||||
result.get("isodate") or "",
|
||||
result,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
ioc_match.message, "", result, matched_indicator=ioc_match.ioc
|
||||
)
|
||||
|
||||
def _process_history_db(self, history_path):
|
||||
|
||||
@@ -82,10 +82,7 @@ class Shortcuts(IOSExtraction):
|
||||
):
|
||||
if ioc_match:
|
||||
self.alertstore.critical(
|
||||
ioc_match.message,
|
||||
result.get("isodate") or "",
|
||||
result,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
ioc_match.message, "", result, matched_indicator=ioc_match.ioc
|
||||
)
|
||||
|
||||
def run(self) -> None:
|
||||
|
||||
@@ -98,10 +98,7 @@ class SMS(IOSExtraction):
|
||||
):
|
||||
if ioc_match:
|
||||
self.alertstore.critical(
|
||||
ioc_match.message,
|
||||
result.get("isodate") or "",
|
||||
result,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
ioc_match.message, "", result, matched_indicator=ioc_match.ioc
|
||||
)
|
||||
|
||||
def collect_url_results(self) -> None:
|
||||
|
||||
@@ -67,7 +67,7 @@ class SMSAttachments(IOSExtraction):
|
||||
if ioc_match:
|
||||
self.alertstore.high(
|
||||
ioc_match.message,
|
||||
attachment.get("isodate") or "",
|
||||
"",
|
||||
attachment,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
)
|
||||
|
||||
@@ -97,10 +97,7 @@ class TCC(IOSExtraction):
|
||||
ioc_match = self.indicators.check_process(result["client"])
|
||||
if ioc_match:
|
||||
self.alertstore.critical(
|
||||
ioc_match.message,
|
||||
result.get("last_modified") or "",
|
||||
result,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
ioc_match.message, "", result, matched_indicator=ioc_match.ioc
|
||||
)
|
||||
|
||||
def process_db(self, file_path):
|
||||
|
||||
@@ -69,10 +69,7 @@ class WebkitResourceLoadStatistics(IOSExtraction):
|
||||
ioc_match = self.indicators.check_url(result["registrable_domain"])
|
||||
if ioc_match:
|
||||
self.alertstore.critical(
|
||||
ioc_match.message,
|
||||
result.get("last_seen_isodate") or "",
|
||||
result,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
ioc_match.message, "", result, matched_indicator=ioc_match.ioc
|
||||
)
|
||||
|
||||
def _process_observations_db(self, db_path: str, domain: str, path: str) -> None:
|
||||
|
||||
@@ -105,12 +105,7 @@ class WebkitSessionResourceLog(IOSExtraction):
|
||||
if ioc_match:
|
||||
entry, source_domains, destination_domains = record
|
||||
self.alertstore.critical(
|
||||
ioc_match.message,
|
||||
entry.get("last_seen")
|
||||
or entry.get("most_recent_interaction")
|
||||
or "",
|
||||
entry,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
ioc_match.message, "", entry, matched_indicator=ioc_match.ioc
|
||||
)
|
||||
|
||||
redirect_path = ""
|
||||
@@ -134,9 +129,7 @@ class WebkitSessionResourceLog(IOSExtraction):
|
||||
|
||||
self.alertstore.high(
|
||||
f"Found HTTP redirect between suspicious domains: {redirect_path}",
|
||||
entry.get("last_seen")
|
||||
or entry.get("most_recent_interaction")
|
||||
or "",
|
||||
"",
|
||||
entry,
|
||||
)
|
||||
|
||||
|
||||
@@ -189,10 +189,7 @@ class Whatsapp(IOSExtraction):
|
||||
):
|
||||
if ioc_match:
|
||||
self.alertstore.critical(
|
||||
ioc_match.message,
|
||||
result.get("isodate") or "",
|
||||
result,
|
||||
matched_indicator=ioc_match.ioc,
|
||||
ioc_match.message, "", result, matched_indicator=ioc_match.ioc
|
||||
)
|
||||
|
||||
def collect_url_results(self) -> None:
|
||||
|
||||
@@ -90,10 +90,4 @@ class TestDumpsysAppopsArtifact:
|
||||
assert len(da.alertstore.alerts) == 3
|
||||
assert len(detected_by_ioc) == 1
|
||||
assert detected_by_ioc[0].matched_indicator is not None
|
||||
assert detected_by_ioc[0].event_time == max(
|
||||
entry["timestamp"]
|
||||
for permission in detected_by_ioc[0].event["permissions"]
|
||||
for entry in permission.get("entries", [])
|
||||
if entry.get("timestamp")
|
||||
)
|
||||
assert len(detected_by_permission_heuristic) == 2
|
||||
@@ -298,6 +298,21 @@ class TestCommand:
|
||||
alerts = json.loads((tmp_path / "alerts.json").read_text())
|
||||
assert alerts[0]["event"]["payload"] == "\\xa8\\xa9"
|
||||
|
||||
def test_records_time_and_memory_per_module(self, tmp_path):
|
||||
cmd = RecordingCommand(results_path=str(tmp_path))
|
||||
cmd.modules = [FirstModule, SecondModule]
|
||||
|
||||
cmd.run()
|
||||
|
||||
info = json.loads((tmp_path / "info.json").read_text())
|
||||
assert [stat["module"] for stat in info["module_stats"]] == [
|
||||
"FirstModule",
|
||||
"SecondModule",
|
||||
]
|
||||
for stat in info["module_stats"]:
|
||||
assert stat["seconds"] >= 0
|
||||
assert stat["peak_rss_growth_mb"] >= 0
|
||||
|
||||
def test_stores_collected_urls(self, tmp_path):
|
||||
cmd = RecordingCommand(results_path=str(tmp_path))
|
||||
cmd.modules = [URLRecordingModule]
|
||||
|
||||
@@ -44,4 +44,3 @@ class TestCalendarModule:
|
||||
assert len(m.results) == 1
|
||||
assert len(m.timeline) == 4
|
||||
assert len(m.alertstore.alerts) == 1
|
||||
assert m.alertstore.alerts[0].event_time == m.results[0]["start_date"]
|
||||
Reference in new issue
Block a user