mirror of
https://github.com/mvt-project/mvt.git
synced 2026-08-17 08:30:38 +02:00
Merge pull request #563 from mvt-project/feature/add-package-detections
Add additional detections for suspicious packages
This commit is contained in:
@@ -12,6 +12,8 @@ from mvt.android.utils import (
|
|||||||
PLAY_STORE_INSTALLERS,
|
PLAY_STORE_INSTALLERS,
|
||||||
ROOT_PACKAGES,
|
ROOT_PACKAGES,
|
||||||
THIRD_PARTY_STORE_INSTALLERS,
|
THIRD_PARTY_STORE_INSTALLERS,
|
||||||
|
SECURITY_PACKAGES,
|
||||||
|
SYSTEM_UPDATE_PACKAGES,
|
||||||
)
|
)
|
||||||
|
|
||||||
from .base import AndroidQFModule
|
from .base import AndroidQFModule
|
||||||
@@ -62,14 +64,29 @@ class Packages(AndroidQFModule):
|
|||||||
result["installer"],
|
result["installer"],
|
||||||
result["name"],
|
result["name"],
|
||||||
)
|
)
|
||||||
|
self.detected.append(result)
|
||||||
elif result["installer"] == "null" and result["system"] is False:
|
elif result["installer"] == "null" and result["system"] is False:
|
||||||
self.log.warning(
|
self.log.warning(
|
||||||
'Found a non-system package installed via adb or another method: "%s"',
|
'Found a non-system package installed via adb or another method: "%s"',
|
||||||
result["name"],
|
result["name"],
|
||||||
)
|
)
|
||||||
|
self.detected.append(result)
|
||||||
elif result["installer"] in PLAY_STORE_INSTALLERS:
|
elif result["installer"] in PLAY_STORE_INSTALLERS:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# Check for disabled security or software update packages
|
||||||
|
package_disabled = result.get("disabled", None)
|
||||||
|
if result["name"] in SECURITY_PACKAGES and package_disabled:
|
||||||
|
self.log.warning(
|
||||||
|
'Security package "%s" disabled on the phone', result["name"]
|
||||||
|
)
|
||||||
|
|
||||||
|
if result["name"] in SYSTEM_UPDATE_PACKAGES and package_disabled:
|
||||||
|
self.log.warning(
|
||||||
|
'System OTA update package "%s" disabled on the phone',
|
||||||
|
result["name"],
|
||||||
|
)
|
||||||
|
|
||||||
if not self.indicators:
|
if not self.indicators:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@@ -96,6 +113,10 @@ class Packages(AndroidQFModule):
|
|||||||
self.detected.append(result)
|
self.detected.append(result)
|
||||||
break
|
break
|
||||||
|
|
||||||
|
# Deduplicate the detected packages
|
||||||
|
dedupe_detected_dict = {str(item): item for item in self.detected}
|
||||||
|
self.detected = list(dedupe_detected_dict.values())
|
||||||
|
|
||||||
def run(self) -> None:
|
def run(self) -> None:
|
||||||
packages = self._get_files_by_pattern("*/packages.json")
|
packages = self._get_files_by_pattern("*/packages.json")
|
||||||
if not packages:
|
if not packages:
|
||||||
|
|||||||
@@ -43,33 +43,56 @@ class TestAndroidqfPackages:
|
|||||||
# There should just be 7 packages listed, no detections
|
# There should just be 7 packages listed, no detections
|
||||||
assert len(module.results) == 7
|
assert len(module.results) == 7
|
||||||
assert len(module.timeline) == 0
|
assert len(module.timeline) == 0
|
||||||
assert len(module.detected) == 0
|
|
||||||
|
|
||||||
def test_non_appstore_warnings(self, caplog, module):
|
def test_non_appstore_warnings(self, caplog, module):
|
||||||
run_module(module)
|
run_module(module)
|
||||||
|
|
||||||
|
assert len(module.detected) == 4
|
||||||
|
|
||||||
# Not a super test to be searching logs for this but heuristic detections not yet formalised
|
# Not a super test to be searching logs for this but heuristic detections not yet formalised
|
||||||
assert (
|
assert (
|
||||||
'Found a non-system package installed via adb or another method: "com.whatsapp"'
|
'Found a non-system package installed via adb or another method: "com.whatsapp"'
|
||||||
in caplog.text
|
in caplog.text
|
||||||
)
|
)
|
||||||
|
whatsapp_detected = [
|
||||||
|
pkg for pkg in module.detected if pkg["name"] == "com.whatsapp"
|
||||||
|
]
|
||||||
|
assert len(whatsapp_detected) == 1
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
'Found a package installed via a browser (installer="com.google.android.packageinstaller"): '
|
'Found a package installed via a browser (installer="com.google.android.packageinstaller"): '
|
||||||
'"app.revanced.manager.flutter"' in caplog.text
|
'"app.revanced.manager.flutter"' in caplog.text
|
||||||
)
|
)
|
||||||
|
revanced_detected = [
|
||||||
|
pkg
|
||||||
|
for pkg in module.detected
|
||||||
|
if pkg["name"] == "app.revanced.manager.flutter"
|
||||||
|
]
|
||||||
|
assert len(revanced_detected) == 1
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
'Found a package installed via a third party store (installer="org.fdroid.fdroid"): "org.nuclearfog.apollo"'
|
'Found a package installed via a third party store (installer="org.fdroid.fdroid"): "org.nuclearfog.apollo"'
|
||||||
in caplog.text
|
in caplog.text
|
||||||
)
|
)
|
||||||
|
# We do not currently flag a third party store as a detection, we only flag the app in the logs.
|
||||||
|
appollo_detected = [
|
||||||
|
pkg for pkg in module.detected if pkg["name"] == "org.nuclearfog.apollo"
|
||||||
|
]
|
||||||
|
assert len(appollo_detected) == 0
|
||||||
|
|
||||||
def test_packages_ioc_package_names(self, module, indicators_factory):
|
def test_packages_ioc_package_names(self, module, indicators_factory):
|
||||||
module.indicators = indicators_factory(app_ids=["com.malware.blah"])
|
module.indicators = indicators_factory(app_ids=["com.malware.blah"])
|
||||||
|
|
||||||
run_module(module)
|
run_module(module)
|
||||||
|
|
||||||
assert len(module.detected) == 1
|
possible_detected_app = [
|
||||||
assert module.detected[0]["name"] == "com.malware.blah"
|
pkg for pkg in module.detected if pkg["name"] == "com.malware.blah"
|
||||||
assert module.detected[0]["matched_indicator"]["value"] == "com.malware.blah"
|
]
|
||||||
|
assert len(possible_detected_app) == 1
|
||||||
|
assert possible_detected_app[0]["name"] == "com.malware.blah"
|
||||||
|
assert (
|
||||||
|
possible_detected_app[0]["matched_indicator"]["value"] == "com.malware.blah"
|
||||||
|
)
|
||||||
|
|
||||||
def test_packages_ioc_sha256(self, module, indicators_factory):
|
def test_packages_ioc_sha256(self, module, indicators_factory):
|
||||||
module.indicators = indicators_factory(
|
module.indicators = indicators_factory(
|
||||||
@@ -80,10 +103,13 @@ class TestAndroidqfPackages:
|
|||||||
|
|
||||||
run_module(module)
|
run_module(module)
|
||||||
|
|
||||||
assert len(module.detected) == 1
|
possible_detected_app = [
|
||||||
assert module.detected[0]["name"] == "com.malware.muahaha"
|
pkg for pkg in module.detected if pkg["name"] == "com.malware.muahaha"
|
||||||
|
]
|
||||||
|
assert len(possible_detected_app) == 1
|
||||||
|
assert possible_detected_app[0]["name"] == "com.malware.muahaha"
|
||||||
assert (
|
assert (
|
||||||
module.detected[0]["matched_indicator"]["value"]
|
possible_detected_app[0]["matched_indicator"]["value"]
|
||||||
== "31037a27af59d4914906c01ad14a318eee2f3e31d48da8954dca62a99174e3fa"
|
== "31037a27af59d4914906c01ad14a318eee2f3e31d48da8954dca62a99174e3fa"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -96,9 +122,12 @@ class TestAndroidqfPackages:
|
|||||||
|
|
||||||
run_module(module)
|
run_module(module)
|
||||||
|
|
||||||
assert len(module.detected) == 1
|
possible_detected_app = [
|
||||||
assert module.detected[0]["name"] == "com.malware.muahaha"
|
pkg for pkg in module.detected if pkg["name"] == "com.malware.muahaha"
|
||||||
|
]
|
||||||
|
assert len(possible_detected_app) == 1
|
||||||
|
assert possible_detected_app[0]["name"] == "com.malware.muahaha"
|
||||||
assert (
|
assert (
|
||||||
module.detected[0]["matched_indicator"]["value"]
|
possible_detected_app[0]["matched_indicator"]["value"]
|
||||||
== "c7e56178748be1441370416d4c10e34817ea0c961eb636c8e9d98e0fd79bf730"
|
== "c7e56178748be1441370416d4c10e34817ea0c961eb636c8e9d98e0fd79bf730"
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user