From 94de1745637c3e4988ba89a3d6ea3289df4ec8d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Donncha=20=C3=93=20Cearbhaill?= Date: Fri, 21 Jul 2023 11:08:20 +0200 Subject: [PATCH] Remove duplicated detection logic from GetProp modules --- mvt/android/modules/adb/getprop.py | 27 ++-------------- mvt/android/modules/androidqf/getprop.py | 41 ++---------------------- mvt/android/modules/bugreport/getprop.py | 17 ++-------- mvt/android/modules/detection_mixins.py | 41 ++++++++++++++++++++++++ mvt/android/utils.py | 19 +++++++++++ 5 files changed, 66 insertions(+), 79 deletions(-) create mode 100644 mvt/android/modules/detection_mixins.py create mode 100644 mvt/android/utils.py diff --git a/mvt/android/modules/adb/getprop.py b/mvt/android/modules/adb/getprop.py index 12ae343..d5c0ff5 100644 --- a/mvt/android/modules/adb/getprop.py +++ b/mvt/android/modules/adb/getprop.py @@ -4,15 +4,15 @@ # https://license.mvt.re/1.1/ import logging -from datetime import datetime, timedelta from typing import Optional +from mvt.android.modules.detection_mixins import GetPropDetectionMixin from mvt.android.parsers import parse_getprop from .base import AndroidExtraction -class Getprop(AndroidExtraction): +class Getprop(GetPropDetectionMixin, AndroidExtraction): """This module extracts device properties from getprop command.""" def __init__( @@ -35,33 +35,10 @@ class Getprop(AndroidExtraction): self.results = {} if not results else results - def check_indicators(self) -> None: - if not self.indicators: - return - - for result in self.results: - ioc = self.indicators.check_android_property_name(result.get("name", "")) - if ioc: - result["matched_indicator"] = ioc - self.detected.append(result) - def run(self) -> None: self._adb_connect() output = self._adb_command("getprop") self._adb_disconnect() self.results = parse_getprop(output) - - # Alert if phone is outdated. - for entry in self.results: - if entry.get("name", "") != "ro.build.version.security_patch": - continue - patch_date = datetime.strptime(entry["value"], "%Y-%m-%d") - if (datetime.now() - patch_date) > timedelta(days=6 * 30): - self.log.warning( - "This phone has not received security updates " - "for more than six months (last update: %s)", - entry["value"], - ) - self.log.info("Extracted %d Android system properties", len(self.results)) diff --git a/mvt/android/modules/androidqf/getprop.py b/mvt/android/modules/androidqf/getprop.py index ab3f49d..237efa1 100644 --- a/mvt/android/modules/androidqf/getprop.py +++ b/mvt/android/modules/androidqf/getprop.py @@ -4,29 +4,15 @@ # https://license.mvt.re/1.1/ import logging -from datetime import datetime, timedelta from typing import Optional +from mvt.android.modules.detection_mixins import GetPropDetectionMixin from mvt.android.parsers.getprop import parse_getprop from .base import AndroidQFModule -INTERESTING_PROPERTIES = [ - "gsm.sim.operator.alpha", - "gsm.sim.operator.iso-country", - "persist.sys.timezone", - "ro.boot.serialno", - "ro.build.version.sdk", - "ro.build.version.security_patch", - "ro.product.cpu.abi", - "ro.product.locale", - "ro.product.vendor.manufacturer", - "ro.product.vendor.model", - "ro.product.vendor.name", -] - -class Getprop(AndroidQFModule): +class Getprop(GetPropDetectionMixin, AndroidQFModule): """This module extracts data from get properties.""" def __init__( @@ -48,16 +34,6 @@ class Getprop(AndroidQFModule): ) self.results = [] - def check_indicators(self) -> None: - if not self.indicators: - return - - for result in self.results: - ioc = self.indicators.check_android_property_name(result.get("name", "")) - if ioc: - result["matched_indicator"] = ioc - self.detected.append(result) - def run(self) -> None: getprop_files = self._get_files_by_pattern("*/getprop.txt") if not getprop_files: @@ -68,17 +44,4 @@ class Getprop(AndroidQFModule): data = f.read() self.results = parse_getprop(data) - for entry in self.results: - if entry["name"] in INTERESTING_PROPERTIES: - self.log.info("%s: %s", entry["name"], entry["value"]) - if entry["name"] == "ro.build.version.security_patch": - last_patch = datetime.strptime(entry["value"], "%Y-%m-%d") - if (datetime.now() - last_patch) > timedelta(days=6 * 31): - self.log.warning( - "This phone has not received security " - "updates for more than six months " - "(last update: %s)", - entry["value"], - ) - self.log.info("Extracted a total of %d properties", len(self.results)) diff --git a/mvt/android/modules/bugreport/getprop.py b/mvt/android/modules/bugreport/getprop.py index f272bf7..3459a5f 100644 --- a/mvt/android/modules/bugreport/getprop.py +++ b/mvt/android/modules/bugreport/getprop.py @@ -4,15 +4,15 @@ # https://license.mvt.re/1.1/ import logging -from datetime import datetime, timedelta from typing import Optional +from mvt.android.modules.detection_mixins import GetPropDetectionMixin from mvt.android.parsers import parse_getprop from .base import BugReportModule -class Getprop(BugReportModule): +class Getprop(GetPropDetectionMixin, BugReportModule): """This module extracts device properties from getprop command.""" def __init__( @@ -61,17 +61,4 @@ class Getprop(BugReportModule): lines.append(line) self.results = parse_getprop("\n".join(lines)) - - # Alert if phone is outdated. - for entry in self.results: - if entry["name"] == "ro.build.version.security_patch": - security_patch = entry["value"] - patch_date = datetime.strptime(security_patch, "%Y-%m-%d") - if (datetime.now() - patch_date) > timedelta(days=6 * 30): - self.log.warning( - "This phone has not received security updates " - "for more than six months (last update: %s)", - security_patch, - ) - self.log.info("Extracted %d Android system properties", len(self.results)) diff --git a/mvt/android/modules/detection_mixins.py b/mvt/android/modules/detection_mixins.py new file mode 100644 index 0000000..9054e44 --- /dev/null +++ b/mvt/android/modules/detection_mixins.py @@ -0,0 +1,41 @@ +# 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/ +from mvt.android.utils import warn_android_patch_level + +INTERESTING_PROPERTIES = [ + "gsm.sim.operator.alpha", + "gsm.sim.operator.iso-country", + "persist.sys.timezone", + "ro.boot.serialno", + "ro.build.version.sdk", + "ro.build.version.security_patch", + "ro.product.cpu.abi", + "ro.product.locale", + "ro.product.vendor.manufacturer", + "ro.product.vendor.model", + "ro.product.vendor.name", +] + + +class GetPropDetectionMixin(object): + """Mixin to have cosistent detection logic across various extraction modules.""" + + def check_indicators(self) -> None: + for entry in self.results: + if entry["name"] in INTERESTING_PROPERTIES: + self.log.info("%s: %s", entry["name"], entry["value"]) + + if entry["name"] == "ro.build.version.security_patch": + warn_android_patch_level(entry["value"], self.log) + + if not self.indicators: + return + + for result in self.results: + ioc = self.indicators.check_android_property_name(result.get("name", "")) + print(result.get("name", ""), ioc) + if ioc: + result["matched_indicator"] = ioc + self.detected.append(result) diff --git a/mvt/android/utils.py b/mvt/android/utils.py new file mode 100644 index 0000000..c84fae6 --- /dev/null +++ b/mvt/android/utils.py @@ -0,0 +1,19 @@ +# 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/ +from datetime import datetime, timedelta + + +def warn_android_patch_level(patch_level: str, log) -> bool: + """Alert if Android patch level out-of-date""" + patch_date = datetime.strptime(patch_level, "%Y-%m-%d") + if (datetime.now() - patch_date) > timedelta(months=6): + log.warning( + "This phone has not received security updates " + "for more than six months (last update: %s)", + patch_level, + ) + return True + + return False