mirror of
https://github.com/mvt-project/mvt
synced 2025-10-21 22:42:15 +02:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7b107edf1f | ||
|
|
b97ce7651a | ||
|
|
52a204cab6 | ||
|
|
1b335fda1d | ||
|
|
2ad175eae2 |
@@ -20,8 +20,11 @@ class DumpsysAccessibility(AndroidExtraction):
|
||||
log=log, results=results)
|
||||
|
||||
def check_indicators(self):
|
||||
if not self.indicators:
|
||||
return
|
||||
|
||||
for result in self.results:
|
||||
ioc = self.indicators.check_app_id(result["package"])
|
||||
ioc = self.indicators.check_app_id(result["package_name"])
|
||||
if ioc:
|
||||
result["matched_indicator"] = ioc
|
||||
self.detected.append(result)
|
||||
@@ -47,7 +50,7 @@ class DumpsysAccessibility(AndroidExtraction):
|
||||
log.info("Found installed accessibility service \"%s\"", service)
|
||||
|
||||
results.append({
|
||||
"package": service.split("/")[0],
|
||||
"package_name": service.split("/")[0],
|
||||
"service": service,
|
||||
})
|
||||
|
||||
|
||||
@@ -22,9 +22,12 @@ class DumpsysActivities(AndroidExtraction):
|
||||
self.results = results if results else {}
|
||||
|
||||
def check_indicators(self):
|
||||
if not self.indicators:
|
||||
return
|
||||
|
||||
for intent, activities in self.results.items():
|
||||
for activity in activities:
|
||||
ioc = self.indicators.check_app_id(activity["package"])
|
||||
ioc = self.indicators.check_app_id(activity["package_name"])
|
||||
if ioc:
|
||||
activity["matched_indicator"] = ioc
|
||||
self.detected.append({intent: activity})
|
||||
@@ -77,10 +80,10 @@ class DumpsysActivities(AndroidExtraction):
|
||||
# If we got this far, we are processing receivers for the
|
||||
# activities we are interested in.
|
||||
activity = line.strip().split(" ")[1]
|
||||
package = activity.split("/")[0]
|
||||
package_name = activity.split("/")[0]
|
||||
|
||||
results[intent].append({
|
||||
"package": package,
|
||||
"package_name": package_name,
|
||||
"activity": activity,
|
||||
})
|
||||
|
||||
|
||||
@@ -24,12 +24,15 @@ class DumpsysBatteryDaily(AndroidExtraction):
|
||||
"timestamp": record["from"],
|
||||
"module": self.__class__.__name__,
|
||||
"event": "battery_daily",
|
||||
"data": f"Recorded update of package {record['package']} with vers {record['vers']}"
|
||||
"data": f"Recorded update of package {record['package_name']} with vers {record['vers']}"
|
||||
}
|
||||
|
||||
def check_indicators(self):
|
||||
if not self.indicators:
|
||||
return
|
||||
|
||||
for result in self.results:
|
||||
ioc = self.indicators.check_app_id(result["package"])
|
||||
ioc = self.indicators.check_app_id(result["package_name"])
|
||||
if ioc:
|
||||
result["matched_indicator"] = ioc
|
||||
self.detected.append(result)
|
||||
@@ -59,12 +62,12 @@ class DumpsysBatteryDaily(AndroidExtraction):
|
||||
continue
|
||||
|
||||
line = line.strip().replace("Update ", "")
|
||||
package, vers = line.split(" ", 1)
|
||||
package_name, vers = line.split(" ", 1)
|
||||
vers_nr = vers.split("=", 1)[1]
|
||||
|
||||
already_seen = False
|
||||
for update in daily_updates:
|
||||
if package == update["package"] and vers_nr == update["vers"]:
|
||||
if package_name == update["package_name"] and vers_nr == update["vers"]:
|
||||
already_seen = True
|
||||
break
|
||||
|
||||
@@ -73,7 +76,7 @@ class DumpsysBatteryDaily(AndroidExtraction):
|
||||
"action": "update",
|
||||
"from": daily["from"],
|
||||
"to": daily["to"],
|
||||
"package": package,
|
||||
"package_name": package_name,
|
||||
"vers": vers_nr,
|
||||
})
|
||||
|
||||
|
||||
@@ -20,8 +20,11 @@ class DumpsysBatteryHistory(AndroidExtraction):
|
||||
log=log, results=results)
|
||||
|
||||
def check_indicators(self):
|
||||
if not self.indicators:
|
||||
return
|
||||
|
||||
for result in self.results:
|
||||
ioc = self.indicators.check_app_id(result["package"])
|
||||
ioc = self.indicators.check_app_id(result["package_name"])
|
||||
if ioc:
|
||||
result["matched_indicator"] = ioc
|
||||
self.detected.append(result)
|
||||
@@ -56,14 +59,14 @@ class DumpsysBatteryHistory(AndroidExtraction):
|
||||
if event in ["start_job", "end_job"]:
|
||||
uid = line[line.find("=")+1:line.find(":")]
|
||||
service = line[line.find(":")+1:].strip('"')
|
||||
package = service.split("/")[0]
|
||||
package_name = service.split("/")[0]
|
||||
elif event == "wake":
|
||||
uid = line[line.find("=")+1:line.find(":")]
|
||||
service = line[line.find("*walarm*:")+9:].split(" ")[0].strip('"').strip()
|
||||
if service == "" or "/" not in service:
|
||||
continue
|
||||
|
||||
package = service.split("/")[0]
|
||||
package_name = service.split("/")[0]
|
||||
else:
|
||||
continue
|
||||
|
||||
@@ -71,7 +74,7 @@ class DumpsysBatteryHistory(AndroidExtraction):
|
||||
"time_elapsed": time_elapsed,
|
||||
"event": event,
|
||||
"uid": uid,
|
||||
"package": package,
|
||||
"package_name": package_name,
|
||||
"service": service,
|
||||
})
|
||||
|
||||
|
||||
@@ -23,6 +23,9 @@ class DumpsysDBInfo(AndroidExtraction):
|
||||
log=log, results=results)
|
||||
|
||||
def check_indicators(self):
|
||||
if not self.indicators:
|
||||
return
|
||||
|
||||
for result in self.results:
|
||||
path = result.get("path", "")
|
||||
for part in path.split("/"):
|
||||
|
||||
@@ -28,6 +28,9 @@ class DumpsysReceivers(AndroidExtraction):
|
||||
self.results = results if results else {}
|
||||
|
||||
def check_indicators(self):
|
||||
if not self.indicators:
|
||||
return
|
||||
|
||||
for intent, receivers in self.results.items():
|
||||
for receiver in receivers:
|
||||
if intent == INTENT_NEW_OUTGOING_SMS:
|
||||
@@ -46,7 +49,7 @@ class DumpsysReceivers(AndroidExtraction):
|
||||
self.log.info("Found a receiver monitoring outgoing calls: \"%s\"",
|
||||
receiver["receiver"])
|
||||
|
||||
ioc = self.indicators.check_app_id(receiver["package"])
|
||||
ioc = self.indicators.check_app_id(receiver["package_name"])
|
||||
if ioc:
|
||||
receiver["matched_indicator"] = ioc
|
||||
self.detected.append({intent: receiver})
|
||||
@@ -99,10 +102,10 @@ class DumpsysReceivers(AndroidExtraction):
|
||||
# If we got this far, we are processing receivers for the
|
||||
# activities we are interested in.
|
||||
receiver = line.strip().split(" ")[1]
|
||||
package = receiver.split("/")[0]
|
||||
package_name = receiver.split("/")[0]
|
||||
|
||||
results[intent].append({
|
||||
"package": package,
|
||||
"package_name": package_name,
|
||||
"receiver": receiver,
|
||||
})
|
||||
|
||||
|
||||
@@ -24,9 +24,9 @@ class Files(AndroidExtraction):
|
||||
log=log, results=results)
|
||||
self.full_find = False
|
||||
|
||||
def find_files(self, file_path):
|
||||
def find_files(self, folder):
|
||||
if self.full_find:
|
||||
output = self._adb_command(f"find '{file_path}' -printf '%T@ %m %s %u %g %p\n' 2> /dev/null")
|
||||
output = self._adb_command(f"find '{folder}' -printf '%T@ %m %s %u %g %p\n' 2> /dev/null")
|
||||
|
||||
for file_line in output.splitlines():
|
||||
[unix_timestamp, mode, size, owner, group, full_path] = file_line.rstrip().split(" ", 5)
|
||||
@@ -42,7 +42,7 @@ class Files(AndroidExtraction):
|
||||
"group": group,
|
||||
})
|
||||
else:
|
||||
output = self._adb_command(f"find '{file_path}' 2> /dev/null")
|
||||
output = self._adb_command(f"find '{folder}' 2> /dev/null")
|
||||
for file_line in output.splitlines():
|
||||
self.results.append({"path": file_line.rstrip()})
|
||||
|
||||
|
||||
@@ -15,6 +15,29 @@ from .base import AndroidExtraction
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
DANGEROUS_PERMISSIONS_THRESHOLD = 10
|
||||
DANGEROUS_PERMISSIONS = [
|
||||
"android.permission.ACCESS_COARSE_LOCATION",
|
||||
"android.permission.ACCESS_FINE_LOCATION",
|
||||
"android.permission.AUTHENTICATE_ACCOUNTS",
|
||||
"android.permission.CAMERA",
|
||||
"android.permission.DISABLE_KEYGUARD",
|
||||
"android.permission.PROCESS_OUTGOING_CALLS",
|
||||
"android.permission.READ_CALENDAR",
|
||||
"android.permission.READ_CALL_LOG",
|
||||
"android.permission.READ_CONTACTS",
|
||||
"android.permission.READ_PHONE_STATE",
|
||||
"android.permission.READ_SMS",
|
||||
"android.permission.RECEIVE_MMS",
|
||||
"android.permission.RECEIVE_SMS",
|
||||
"android.permission.RECEIVE_WAP_PUSH",
|
||||
"android.permission.RECORD_AUDIO",
|
||||
"android.permission.SEND_SMS",
|
||||
"android.permission.SYSTEM_ALERT_WINDOW",
|
||||
"android.permission.USE_CREDENTIALS",
|
||||
"android.permission.USE_SIP",
|
||||
"com.android.browser.permission.READ_HISTORY_BOOKMARKS",
|
||||
]
|
||||
|
||||
class Packages(AndroidExtraction):
|
||||
"""This module extracts the list of installed packages."""
|
||||
@@ -57,6 +80,9 @@ class Packages(AndroidExtraction):
|
||||
self.detected.append(result)
|
||||
continue
|
||||
|
||||
if not self.indicators:
|
||||
continue
|
||||
|
||||
ioc = self.indicators.check_app_id(result.get("package_name"))
|
||||
if ioc:
|
||||
result["matched_indicator"] = ioc
|
||||
@@ -69,6 +95,45 @@ class Packages(AndroidExtraction):
|
||||
result["matched_indicator"] = ioc
|
||||
self.detected.append(result)
|
||||
|
||||
def _get_package_details(self, package_name):
|
||||
details = {
|
||||
"uid": "",
|
||||
"version_name": "",
|
||||
"version_code": "",
|
||||
"timestamp": "",
|
||||
"first_install_time": "",
|
||||
"last_update_time": "",
|
||||
"requested_permissions": [],
|
||||
}
|
||||
|
||||
in_permissions = False
|
||||
for line in self._adb_command(f"dumpsys package {package_name}").split("\n"):
|
||||
if in_permissions:
|
||||
if line.startswith(" " * 4) and not line.startswith(" " * 6):
|
||||
in_permissions = False
|
||||
continue
|
||||
|
||||
permission = line.strip().split(":")[0]
|
||||
details["requested_permissions"].append(permission)
|
||||
|
||||
if line.strip().startswith("userId="):
|
||||
details["uid"] = line.split("=")[1].strip()
|
||||
elif line.strip().startswith("versionName="):
|
||||
details["version_name"] = line.split("=")[1].strip()
|
||||
elif line.strip().startswith("versionCode="):
|
||||
details["version_code"] = line.split("=", 1)[1].strip()
|
||||
elif line.strip().startswith("timeStamp="):
|
||||
details["timestamp"] = line.split("=")[1].strip()
|
||||
elif line.strip().startswith("firstInstallTime="):
|
||||
details["first_install_time"] = line.split("=")[1].strip()
|
||||
elif line.strip().startswith("lastUpdateTime="):
|
||||
details["last_update_time"] = line.split("=")[1].strip()
|
||||
elif line.strip() == "requested permissions:":
|
||||
in_permissions = True
|
||||
continue
|
||||
|
||||
return details
|
||||
|
||||
def _get_files_for_package(self, package_name):
|
||||
output = self._adb_command(f"pm path {package_name}")
|
||||
output = output.strip().replace("package:", "")
|
||||
@@ -97,9 +162,7 @@ class Packages(AndroidExtraction):
|
||||
def run(self):
|
||||
self._adb_connect()
|
||||
|
||||
packages = self._adb_command("pm list packages -U -u -i -f")
|
||||
if packages.strip() == "Error: Unknown option: -U":
|
||||
packages = self._adb_command("pm list packages -u -i -f")
|
||||
packages = self._adb_command("pm list packages -u -i -f")
|
||||
|
||||
for line in packages.split("\n"):
|
||||
line = line.strip()
|
||||
@@ -117,31 +180,21 @@ class Packages(AndroidExtraction):
|
||||
if installer == "null":
|
||||
installer = None
|
||||
|
||||
try:
|
||||
uid = fields[2].split(":")[1].strip()
|
||||
except IndexError:
|
||||
uid = None
|
||||
|
||||
dumpsys = self._adb_command(f"dumpsys package {package_name} | grep -A2 timeStamp").split("\n")
|
||||
timestamp = dumpsys[0].split("=")[1].strip()
|
||||
first_install = dumpsys[1].split("=")[1].strip()
|
||||
last_update = dumpsys[2].split("=")[1].strip()
|
||||
|
||||
package_files = self._get_files_for_package(package_name)
|
||||
|
||||
self.results.append({
|
||||
new_package = {
|
||||
"package_name": package_name,
|
||||
"file_name": file_name,
|
||||
"installer": installer,
|
||||
"timestamp": timestamp,
|
||||
"first_install_time": first_install,
|
||||
"last_update_time": last_update,
|
||||
"uid": uid,
|
||||
"disabled": False,
|
||||
"system": False,
|
||||
"third_party": False,
|
||||
"files": package_files,
|
||||
})
|
||||
}
|
||||
|
||||
package_details = self._get_package_details(package_name)
|
||||
new_package.update(package_details)
|
||||
|
||||
self.results.append(new_package)
|
||||
|
||||
cmds = [
|
||||
{"field": "disabled", "arg": "-d"},
|
||||
@@ -160,6 +213,19 @@ class Packages(AndroidExtraction):
|
||||
if result["package_name"] == package_name:
|
||||
self.results[i][cmd["field"]] = True
|
||||
|
||||
for result in self.results:
|
||||
if not result["third_party"]:
|
||||
continue
|
||||
|
||||
dangerous_permissions_count = 0
|
||||
for perm in result["requested_permissions"]:
|
||||
if perm in DANGEROUS_PERMISSIONS:
|
||||
dangerous_permissions_count += 1
|
||||
|
||||
if dangerous_permissions_count >= DANGEROUS_PERMISSIONS_THRESHOLD:
|
||||
self.log.info("Third-party package \"%s\" requested %d potentially dangerous permissions",
|
||||
result["package_name"], dangerous_permissions_count)
|
||||
|
||||
packages_to_lookup = []
|
||||
for result in self.results:
|
||||
if result["system"]:
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import requests
|
||||
from packaging import version
|
||||
|
||||
MVT_VERSION = "1.4.10"
|
||||
MVT_VERSION = "1.4.11"
|
||||
|
||||
|
||||
def check_for_updates():
|
||||
|
||||
Reference in New Issue
Block a user