Skip to content

Commit

Permalink
Merge pull request #563 from mvt-project/feature/add-package-detections
Browse files Browse the repository at this point in the history
Add additional detections for suspicious packages
  • Loading branch information
DonnchaC authored Oct 24, 2024
2 parents 787b0c1 + 5fe8238 commit cd99b29
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 10 deletions.
21 changes: 21 additions & 0 deletions src/mvt/android/modules/androidqf/packages.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
PLAY_STORE_INSTALLERS,
ROOT_PACKAGES,
THIRD_PARTY_STORE_INSTALLERS,
SECURITY_PACKAGES,
SYSTEM_UPDATE_PACKAGES,
)

from .base import AndroidQFModule
Expand Down Expand Up @@ -62,14 +64,29 @@ def check_indicators(self) -> None:
result["installer"],
result["name"],
)
self.detected.append(result)
elif result["installer"] == "null" and result["system"] is False:
self.log.warning(
'Found a non-system package installed via adb or another method: "%s"',
result["name"],
)
self.detected.append(result)
elif result["installer"] in PLAY_STORE_INSTALLERS:
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:
continue

Expand All @@ -96,6 +113,10 @@ def check_indicators(self) -> None:
self.detected.append(result)
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:
packages = self._get_files_by_pattern("*/packages.json")
if not packages:
Expand Down
49 changes: 39 additions & 10 deletions tests/android_androidqf/test_packages.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,33 +43,56 @@ def test_packages_list(self, module):
# There should just be 7 packages listed, no detections
assert len(module.results) == 7
assert len(module.timeline) == 0
assert len(module.detected) == 0

def test_non_appstore_warnings(self, caplog, 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
assert (
'Found a non-system package installed via adb or another method: "com.whatsapp"'
in caplog.text
)
whatsapp_detected = [
pkg for pkg in module.detected if pkg["name"] == "com.whatsapp"
]
assert len(whatsapp_detected) == 1

assert (
'Found a package installed via a browser (installer="com.google.android.packageinstaller"): '
'"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 (
'Found a package installed via a third party store (installer="org.fdroid.fdroid"): "org.nuclearfog.apollo"'
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):
module.indicators = indicators_factory(app_ids=["com.malware.blah"])

run_module(module)

assert len(module.detected) == 1
assert module.detected[0]["name"] == "com.malware.blah"
assert module.detected[0]["matched_indicator"]["value"] == "com.malware.blah"
possible_detected_app = [
pkg for pkg in module.detected if pkg["name"] == "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):
module.indicators = indicators_factory(
Expand All @@ -80,10 +103,13 @@ def test_packages_ioc_sha256(self, module, indicators_factory):

run_module(module)

assert len(module.detected) == 1
assert module.detected[0]["name"] == "com.malware.muahaha"
possible_detected_app = [
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 (
module.detected[0]["matched_indicator"]["value"]
possible_detected_app[0]["matched_indicator"]["value"]
== "31037a27af59d4914906c01ad14a318eee2f3e31d48da8954dca62a99174e3fa"
)

Expand All @@ -96,9 +122,12 @@ def test_packages_certificate_hash_ioc(self, module, indicators_factory):

run_module(module)

assert len(module.detected) == 1
assert module.detected[0]["name"] == "com.malware.muahaha"
possible_detected_app = [
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 (
module.detected[0]["matched_indicator"]["value"]
possible_detected_app[0]["matched_indicator"]["value"]
== "c7e56178748be1441370416d4c10e34817ea0c961eb636c8e9d98e0fd79bf730"
)

0 comments on commit cd99b29

Please sign in to comment.