1
mirror of https://github.com/mvt-project/mvt synced 2025-10-21 22:42:15 +02:00

Compare commits

..

20 Commits
v2.0 ... v2.1.2

Author SHA1 Message Date
Nex
6333cafd38 Bumped version 2022-07-25 17:43:37 +02:00
Nex
03c59811a3 Ordered imports 2022-07-25 17:43:27 +02:00
Nex
cfd3b5bbcb Merge branch 'main' of github.com:mvt-project/mvt 2022-07-25 17:43:08 +02:00
Nex
97ab67240f Creating MVT data folder when missing 2022-07-25 17:42:51 +02:00
Nex
7fc664185c Flake8 fixes 2022-07-20 15:49:51 +02:00
Nex
93094367c7 Bumped version 2022-07-20 15:41:42 +02:00
Nex
e8fa9c6eea Passing binary data to parse rather than a file path 2022-07-20 15:41:07 +02:00
Nex
79a01c45cc Bumped version 2022-07-20 14:12:17 +02:00
Nex
a440d12377 Merge branch 'main' of github.com:mvt-project/mvt 2022-07-20 14:12:08 +02:00
Nex
8085888c0c Improved parsing of profile events to support new formats as well 2022-07-20 14:11:36 +02:00
Nex
c2617fe778 Checking profile IDs in profile_events 2022-07-20 13:25:51 +02:00
Nex
2e1243864c Added check_indicators to profile_events 2022-07-20 13:24:20 +02:00
tek
ba5ff9b38c Fixes a minor typing bug 2022-07-18 14:25:01 +02:00
Nex
3fccebe132 Merge branch 'main' of github.com:mvt-project/mvt 2022-07-14 12:06:52 +02:00
Nex
1265b366c1 Added install_non_market_apps to settings warnings 2022-07-14 09:09:01 +02:00
Nex
c944fb3234 Enforcing quotes in timeline csv writing 2022-07-12 12:03:20 +02:00
Nex
e6b4d17027 Using error instead of warning for failed apk download 2022-07-12 11:55:31 +02:00
Nex
f55ac36189 Code style fixes 2022-07-12 11:55:10 +02:00
Nex
550d6037a6 Bumped version 2022-07-08 19:54:46 +02:00
Nex
e875c978c9 Optional address in SMS serialize 2022-07-08 19:54:33 +02:00
8 changed files with 82 additions and 29 deletions

View File

@@ -78,8 +78,8 @@ class DownloadAPKs(AndroidExtraction):
try:
self._adb_download(remote_path, local_path)
except InsufficientPrivileges:
log.warn("Unable to pull package file from %s: insufficient privileges, it might be a system app",
remote_path)
log.error("Unable to pull package file from %s: insufficient privileges, it might be a system app",
remote_path)
self._adb_reconnect()
return None
except Exception as e:

View File

@@ -51,6 +51,11 @@ ANDROID_DANGEROUS_SETTINGS = [
"key": "send_action_app_error",
"safe_value": "1",
},
{
"description": "enabled installation of non Google Play apps",
"key": "install_non_market_apps",
"safe_value": "0",
}
]

View File

@@ -59,7 +59,7 @@ class SMS(AndroidExtraction):
"timestamp": record["isodate"],
"module": self.__class__.__name__,
"event": f"sms_{record['direction']}",
"data": f"{record['address']}: \"{body}\""
"data": f"{record.get('address', 'unknown source')}: \"{body}\""
}
def check_indicators(self) -> None:
@@ -70,7 +70,7 @@ class SMS(AndroidExtraction):
if "body" not in message:
continue
# FIXME: check links exported from the body previously
# TODO: check links exported from the body previously.
message_links = check_for_links(message["body"])
if self.indicators.check_domains(message_links):
self.detected.append(message)
@@ -110,10 +110,12 @@ class SMS(AndroidExtraction):
log.info("Extracted a total of %d SMS messages containing links", len(self.results))
def _extract_sms_adb(self) -> None:
"""Use the Android backup command to extract SMS data from the native SMS app
"""Use the Android backup command to extract SMS data from the native SMS
app.
It is crucial to use the under-documented "-nocompress" flag to disable the non-standard Java compression
algorithim. This module only supports an unencrypted ADB backup.
It is crucial to use the under-documented "-nocompress" flag to disable
the non-standard Java compression algorithm. This module only supports
an unencrypted ADB backup.
"""
backup_tar = self._generate_backup("com.android.providers.telephony")
if not backup_tar:
@@ -122,7 +124,8 @@ class SMS(AndroidExtraction):
try:
self.results = parse_tar_for_sms(backup_tar)
except AndroidBackupParsingError:
self.log.info("Impossible to read SMS from the Android Backup, please extract the SMS and try extracting it with Android Backup Extractor")
self.log.info("Impossible to read SMS from the Android Backup, please extract "
"the SMS and try extracting it with Android Backup Extractor")
return
log.info("Extracted a total of %d SMS messages containing links", len(self.results))
@@ -139,5 +142,6 @@ class SMS(AndroidExtraction):
except InsufficientPrivileges:
pass
self.log.warn("No SMS database found. Trying extraction of SMS data using Android backup feature.")
self.log.warn("No SMS database found. Trying extraction of SMS data using "
"Android backup feature.")
self._extract_sms_adb()

View File

@@ -195,7 +195,8 @@ def save_timeline(timeline: list, timeline_path: str) -> None:
"""
with open(timeline_path, "a+", encoding="utf-8") as handle:
csvoutput = csv.writer(handle, delimiter=",", quotechar="\"")
csvoutput = csv.writer(handle, delimiter=",", quotechar="\"",
quoting=csv.QUOTE_ALL)
csvoutput.writerow(["UTC Timestamp", "Plugin", "Event", "Description"])
for event in sorted(timeline, key=lambda x: x["timestamp"] if x["timestamp"] is not None else ""):
csvoutput.writerow([

View File

@@ -43,6 +43,9 @@ class IndicatorsUpdates:
self.index_branch = "main"
self.index_path = "indicators.yaml"
if not os.path.exists(MVT_DATA_FOLDER):
os.makedirs(MVT_DATA_FOLDER)
self.latest_update_path = os.path.join(MVT_DATA_FOLDER,
"latest_indicators_update")
self.latest_check_path = os.path.join(MVT_DATA_FOLDER,

View File

@@ -3,6 +3,8 @@
# Use of this software is governed by the MVT License 1.1 that can be found at
# https://license.mvt.re/1.1/
from typing import Optional
import requests
from tld import get_tld
@@ -308,7 +310,7 @@ class URL:
return self.is_shortened
def unshorten(self) -> None:
def unshorten(self) -> Optional[str]:
"""Unshorten the URL by requesting an HTTP HEAD response."""
res = requests.head(self.url)
if str(res.status_code).startswith("30"):

View File

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

View File

@@ -31,32 +31,70 @@ class ProfileEvents(IOSExtraction):
"timestamp": record.get("timestamp"),
"module": self.__class__.__name__,
"event": "profile_operation",
"data": f"Process {record.get('process')} started operation {record.get('operation')} of profile {record.get('profile_id')}"
"data": f"Process {record.get('process')} started operation "
f"{record.get('operation')} of profile {record.get('profile_id')}"
}
def check_indicators(self) -> None:
if not self.indicators:
return
for result in self.results:
ioc = self.indicators.check_process(result.get("process"))
if ioc:
result["matched_indicator"] = ioc
self.detected.append(result)
continue
ioc = self.indicators.check_profile(result.get("profile_id"))
if ioc:
result["matched_indicator"] = ioc
self.detected.append(result)
@staticmethod
def parse_profile_events(file_data: bytes) -> list:
results = []
events_plist = plistlib.loads(file_data)
if "ProfileEvents" not in events_plist:
return results
for event in events_plist["ProfileEvents"]:
key = list(event.keys())[0]
result = {
"profile_id": key,
"timestamp": "",
"operation": "",
"process": "",
}
for key, value in event[key].items():
key = key.lower()
if key == "timestamp":
result["timestamp"] = str(convert_timestamp_to_iso(value))
else:
result[key] = value
results.append(result)
return results
def run(self) -> None:
for events_file in self._get_backup_files_from_manifest(relative_path=CONF_PROFILES_EVENTS_RELPATH):
events_file_path = self._get_backup_file_from_id(events_file["file_id"])
if not events_file_path:
continue
self.log.info("Found MCProfileEvents.plist file at %s", events_file_path)
with open(events_file_path, "rb") as handle:
events_plist = plistlib.load(handle)
self.results.extend(self.parse_profile_events(handle.read()))
if "ProfileEvents" not in events_plist:
continue
for event in events_plist["ProfileEvents"]:
key = list(event.keys())[0]
self.log.info("On %s process \"%s\" started operation \"%s\" of profile \"%s\"",
event[key].get("timestamp"), event[key].get("process"),
event[key].get("operation"), key)
self.results.append({
"profile_id": key,
"timestamp": convert_timestamp_to_iso(event[key].get("timestamp")),
"operation": event[key].get("operation"),
"process": event[key].get("process"),
})
for result in self.results:
self.log.info("On %s process \"%s\" started operation \"%s\" of profile \"%s\"",
result.get("timestamp"), result.get("process"),
result.get("operation"), result.get("profile_id"))
self.log.info("Extracted %d profile events", len(self.results))