Compare commits

...

3 Commits

Author SHA1 Message Date
Janik Besendorf
35a4dc82b6 Detect uninstall and downgrade in battery daily 2026-01-19 23:55:16 +01:00
viktor3002
7173e02a6f Check receiver names for IoCs (#721)
* receiver names are checked if a known malicious app id is a substring

* ruff syntax fixes

---------

Co-authored-by: Viktor <vik@tor.me>
Co-authored-by: besendorf <janik@besendorf.org>
2026-01-10 15:24:20 +01:00
Donncha Ó Cearbhaill
8f34902bed Bump version for release v2.7.0 (#727) 2025-12-19 13:48:15 +01:00
4 changed files with 91 additions and 12 deletions

View File

@@ -14,12 +14,23 @@ class DumpsysBatteryDailyArtifact(AndroidArtifact):
"""
def serialize(self, record: dict) -> Union[dict, list]:
action = record.get("action", "update")
package_name = record["package_name"]
vers = record["vers"]
if vers == "0":
data = f"Recorded uninstall of package {package_name} (vers 0)"
elif action == "downgrade":
prev_vers = record.get("previous_vers", "unknown")
data = f"Recorded downgrade of package {package_name} from vers {prev_vers} to vers {vers}"
else:
data = f"Recorded update of package {package_name} with vers {vers}"
return {
"timestamp": record["from"],
"module": self.__class__.__name__,
"event": "battery_daily",
"data": f"Recorded update of package {record['package_name']} "
f"with vers {record['vers']}",
"data": data,
}
def check_indicators(self) -> None:
@@ -36,6 +47,7 @@ class DumpsysBatteryDailyArtifact(AndroidArtifact):
def parse(self, output: str) -> None:
daily = None
daily_updates = []
package_versions = {} # Track package versions to detect downgrades
for line in output.splitlines():
if line.startswith(" Daily from "):
if len(daily_updates) > 0:
@@ -64,15 +76,44 @@ class DumpsysBatteryDailyArtifact(AndroidArtifact):
break
if not already_seen:
daily_updates.append(
{
"action": "update",
"from": daily["from"],
"to": daily["to"],
"package_name": package_name,
"vers": vers_nr,
}
)
update_record = {
"action": "update",
"from": daily["from"],
"to": daily["to"],
"package_name": package_name,
"vers": vers_nr,
}
# Check for uninstall (version 0)
if vers_nr == "0":
self.log.warning(
"Detected uninstall of package %s (vers 0) on %s",
package_name,
daily["from"],
)
# Check for downgrade
elif package_name in package_versions:
try:
current_vers = int(vers_nr)
previous_vers = int(package_versions[package_name])
if current_vers < previous_vers:
update_record["action"] = "downgrade"
update_record["previous_vers"] = str(previous_vers)
self.log.warning(
"Detected downgrade of package %s from vers %d to vers %d on %s",
package_name,
previous_vers,
current_vers,
daily["from"],
)
except ValueError:
# If version numbers aren't integers, skip comparison
pass
# Update tracking dictionary
package_versions[package_name] = vers_nr
daily_updates.append(update_record)
if len(daily_updates) > 0:
self.results.extend(daily_updates)

View File

@@ -34,6 +34,20 @@ class DumpsysReceivers(DumpsysReceiversArtifact, BugReportModule):
self.results = results if results else {}
def check_indicators(self) -> None:
for result in self.results:
if self.indicators:
receiver_name = self.results[result][0]["receiver"]
# return IoC if the stix2 process name a substring of the receiver name
ioc = self.indicators.check_receiver_prefix(receiver_name)
if ioc:
self.results[result][0]["matched_indicator"] = ioc
self.detected.append(result)
continue
def run(self) -> None:
content = self._get_dumpstate_file()
if not content:

View File

@@ -768,6 +768,30 @@ class Indicators:
return None
def check_receiver_prefix(self, receiver_name: str) -> Union[dict, None]:
"""Check the provided receiver name against the list of indicators.
An IoC match is detected when a substring of the receiver matches the indicator
:param app_id: App ID to check against the list of indicators
:type app_id: str
:returns: Indicator details if matched, otherwise None
"""
if not receiver_name:
return None
for ioc in self.get_iocs("app_ids"):
if ioc["value"].lower() in receiver_name.lower():
self.log.warning(
'Found a known suspicious receiver with name "%s" '
'matching indicators from "%s"',
receiver_name,
ioc["name"],
)
return ioc
return None
def check_android_property_name(self, property_name: str) -> Optional[dict]:
"""Check the android property name against the list of indicators.

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.6.1"
MVT_VERSION = "2.7.0"