diff --git a/mvt/android/cli.py b/mvt/android/cli.py index 1881a03..40e8651 100644 --- a/mvt/android/cli.py +++ b/mvt/android/cli.py @@ -199,6 +199,72 @@ def check_backup(ctx, iocs, output, backup_path, serial): run_module(m) +#============================================================================== +# Command: check-iocs +#============================================================================== +@cli.command("check-iocs", help="Compare stored JSON results to provided indicators") +@click.option("--iocs", "-i", type=click.Path(exists=True), multiple=True, + default=[], help=HELP_MSG_IOC) +@click.option("--list-modules", "-l", is_flag=True, help=HELP_MSG_LIST_MODULES) +@click.option("--module", "-m", help=HELP_MSG_MODULE) +@click.argument("FOLDER", type=click.Path(exists=True)) +@click.pass_context +def check_iocs(ctx, iocs, list_modules, module, folder): + all_modules = [] + for entry in BACKUP_MODULES + ADB_MODULES: + if entry not in all_modules: + all_modules.append(entry) + + if list_modules: + log.info("Following is the list of available check-iocs modules:") + for iocs_module in all_modules: + log.info(" - %s", iocs_module.__name__) + + return + + log.info("Checking stored results against provided indicators...") + + indicators = Indicators(log=log) + indicators.load_indicators_files(iocs) + + total_detections = 0 + for file_name in os.listdir(folder): + name_only, ext = os.path.splitext(file_name) + file_path = os.path.join(folder, file_name) + + # TODO: Skipping processing of result files that are not json. + # We might want to revisit this eventually. + if ext != ".json": + continue + + for iocs_module in all_modules: + if module and iocs_module.__name__ != module: + continue + + if iocs_module().get_slug() != name_only: + continue + + log.info("Loading results from \"%s\" with module %s", file_name, + iocs_module.__name__) + + m = iocs_module.from_json(file_path, + log=logging.getLogger(iocs_module.__module__)) + if indicators.total_ioc_count > 0: + m.indicators = indicators + m.indicators.log = m.log + + try: + m.check_indicators() + except NotImplementedError: + continue + else: + total_detections += len(m.detected) + + if total_detections > 0: + log.warning("The check of the results produced %d detections!", + total_detections) + + #============================================================================== # Command: download-iocs #============================================================================== diff --git a/mvt/android/modules/adb/dumpsys_receivers.py b/mvt/android/modules/adb/dumpsys_receivers.py index 342fc37..83af963 100644 --- a/mvt/android/modules/adb/dumpsys_receivers.py +++ b/mvt/android/modules/adb/dumpsys_receivers.py @@ -24,6 +24,21 @@ class DumpsysReceivers(AndroidExtraction): output_folder=output_folder, fast_mode=fast_mode, log=log, results=results) + def check_indicators(self): + for result in self.results: + if result["activity"] == ACTION_NEW_OUTGOING_SMS: + self.log.info("Found a receiver to intercept outgoing SMS messages: \"%s\"", + result["receiver"]) + elif result["activity"] == ACTION_SMS_RECEIVED: + self.log.info("Found a receiver to intercept incoming SMS messages: \"%s\"", + result["receiver"]) + elif result["activity"] == ACTION_DATA_SMS_RECEIVED: + self.log.info("Found a receiver to intercept incoming data SMS message: \"%s\"", + result["receiver"]) + elif result["activity"] == ACTION_PHONE_STATE: + self.log.info("Found a receiver monitoring telephony state: \"%s\"", + result["receiver"]) + def run(self): self._adb_connect() @@ -65,19 +80,6 @@ class DumpsysReceivers(AndroidExtraction): if package_name == "com.google.android.gms": continue - if activity == ACTION_NEW_OUTGOING_SMS: - self.log.info("Found a receiver to intercept outgoing SMS messages: \"%s\"", - receiver) - elif activity == ACTION_SMS_RECEIVED: - self.log.info("Found a receiver to intercept incoming SMS messages: \"%s\"", - receiver) - elif activity == ACTION_DATA_SMS_RECEIVED: - self.log.info("Found a receiver to intercept incoming data SMS message: \"%s\"", - receiver) - elif activity == ACTION_PHONE_STATE: - self.log.info("Found a receiver monitoring telephony state: \"%s\"", - receiver) - self.results.append({ "activity": activity, "package_name": package_name, diff --git a/mvt/android/modules/adb/getprop.py b/mvt/android/modules/adb/getprop.py index 232ffe0..e7dbac2 100644 --- a/mvt/android/modules/adb/getprop.py +++ b/mvt/android/modules/adb/getprop.py @@ -21,7 +21,7 @@ class Getprop(AndroidExtraction): output_folder=output_folder, fast_mode=fast_mode, log=log, results=results) - self.results = {} + self.results = {} if not results else results def run(self): self._adb_connect() diff --git a/mvt/android/modules/adb/settings.py b/mvt/android/modules/adb/settings.py index b7588bd..4c8240f 100644 --- a/mvt/android/modules/adb/settings.py +++ b/mvt/android/modules/adb/settings.py @@ -69,7 +69,18 @@ class Settings(AndroidExtraction): output_folder=output_folder, fast_mode=fast_mode, log=log, results=results) - self.results = {} + self.results = {} if not results else results + + def check_indicators(self): + for namespace, settings in self.results.items(): + for key, value in settings.items(): + for danger in ANDROID_DANGEROUS_SETTINGS: + # Check if one of the dangerous settings is using an unsafe + # value (different than the one specified). + if danger["key"] == key and danger["safe_value"] != value: + self.log.warning("Found suspicious setting \"%s = %s\" (%s)", + key, value, danger["description"]) + break def run(self): self._adb_connect() @@ -92,12 +103,4 @@ class Settings(AndroidExtraction): except IndexError: continue - for danger in ANDROID_DANGEROUS_SETTINGS: - # Check if one of the dangerous settings is using an unsafe - # value (different than the one specified). - if danger["key"] == fields[0] and danger["safe_value"] != fields[1]: - self.log.warning("Found suspicious setting \"%s = %s\" (%s)", - fields[0], fields[1], danger["description"]) - break - self._adb_disconnect() diff --git a/mvt/ios/modules/mixed/webkit_resource_load_statistics.py b/mvt/ios/modules/mixed/webkit_resource_load_statistics.py index 3a53a40..44e5c22 100644 --- a/mvt/ios/modules/mixed/webkit_resource_load_statistics.py +++ b/mvt/ios/modules/mixed/webkit_resource_load_statistics.py @@ -28,7 +28,7 @@ class WebkitResourceLoadStatistics(IOSExtraction): output_folder=output_folder, fast_mode=fast_mode, log=log, results=results) - self.results = {} + self.results = {} if not results else results def check_indicators(self): if not self.indicators: diff --git a/mvt/ios/modules/mixed/webkit_session_resource_log.py b/mvt/ios/modules/mixed/webkit_session_resource_log.py index 4a3e41d..2fadaf2 100644 --- a/mvt/ios/modules/mixed/webkit_session_resource_log.py +++ b/mvt/ios/modules/mixed/webkit_session_resource_log.py @@ -35,7 +35,7 @@ class WebkitSessionResourceLog(IOSExtraction): output_folder=output_folder, fast_mode=fast_mode, log=log, results=results) - self.results = {} + self.results = {} if not results else results @staticmethod def _extract_domains(entries):