2021-07-16 06:05:01 +00:00
|
|
|
# Mobile Verification Toolkit (MVT)
|
2022-05-08 12:53:50 +00:00
|
|
|
# Copyright (c) 2021-2022 Claudio Guarnieri.
|
2021-08-01 19:11:08 +00:00
|
|
|
# Use of this software is governed by the MVT License 1.1 that can be found at
|
|
|
|
# https://license.mvt.re/1.1/
|
2021-07-16 06:05:01 +00:00
|
|
|
|
2022-03-10 10:33:54 +00:00
|
|
|
import logging
|
2021-07-30 09:40:09 +00:00
|
|
|
|
2021-07-16 06:05:01 +00:00
|
|
|
import click
|
|
|
|
from rich.logging import RichHandler
|
|
|
|
|
2022-06-16 15:02:38 +00:00
|
|
|
from mvt.common.cmd_check_iocs import CmdCheckIOCS
|
2022-01-11 15:02:44 +00:00
|
|
|
from mvt.common.help import (HELP_MSG_FAST, HELP_MSG_IOC,
|
|
|
|
HELP_MSG_LIST_MODULES, HELP_MSG_MODULE,
|
|
|
|
HELP_MSG_OUTPUT, HELP_MSG_SERIAL)
|
2021-08-26 10:36:37 +00:00
|
|
|
from mvt.common.logo import logo
|
2022-06-28 13:03:52 +00:00
|
|
|
from mvt.common.updates import IndicatorsUpdates
|
2021-07-30 09:40:09 +00:00
|
|
|
|
2022-06-16 13:18:50 +00:00
|
|
|
from .cmd_check_adb import CmdAndroidCheckADB
|
|
|
|
from .cmd_check_backup import CmdAndroidCheckBackup
|
|
|
|
from .cmd_check_bugreport import CmdAndroidCheckBugreport
|
2022-06-15 15:41:19 +00:00
|
|
|
from .cmd_download_apks import DownloadAPKs
|
2021-07-16 06:05:01 +00:00
|
|
|
from .modules.adb import ADB_MODULES
|
2022-06-14 13:46:01 +00:00
|
|
|
from .modules.adb.packages import Packages
|
2021-07-16 06:05:01 +00:00
|
|
|
from .modules.backup import BACKUP_MODULES
|
2022-06-16 15:02:38 +00:00
|
|
|
from .modules.bugreport import BUGREPORT_MODULES
|
2021-07-16 06:05:01 +00:00
|
|
|
|
|
|
|
# Setup logging using Rich.
|
|
|
|
LOG_FORMAT = "[%(name)s] %(message)s"
|
|
|
|
logging.basicConfig(level="INFO", format=LOG_FORMAT, handlers=[
|
|
|
|
RichHandler(show_path=False, log_time_format="%X")])
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
2021-11-19 14:27:51 +00:00
|
|
|
|
2021-07-16 06:05:01 +00:00
|
|
|
#==============================================================================
|
|
|
|
# Main
|
|
|
|
#==============================================================================
|
|
|
|
@click.group(invoke_without_command=False)
|
|
|
|
def cli():
|
2021-08-26 10:36:37 +00:00
|
|
|
logo()
|
2021-07-16 06:05:01 +00:00
|
|
|
|
|
|
|
|
2021-09-17 12:19:03 +00:00
|
|
|
#==============================================================================
|
|
|
|
# Command: version
|
|
|
|
#==============================================================================
|
|
|
|
@cli.command("version", help="Show the currently installed version of MVT")
|
|
|
|
def version():
|
|
|
|
return
|
|
|
|
|
|
|
|
|
2021-07-16 06:05:01 +00:00
|
|
|
#==============================================================================
|
2022-02-01 23:09:53 +00:00
|
|
|
# Command: download-apks
|
2021-07-16 06:05:01 +00:00
|
|
|
#==============================================================================
|
2022-02-04 12:42:32 +00:00
|
|
|
@cli.command("download-apks", help="Download all or only non-system installed APKs")
|
2021-08-21 13:48:52 +00:00
|
|
|
@click.option("--serial", "-s", type=str, help=HELP_MSG_SERIAL)
|
2021-07-16 06:05:01 +00:00
|
|
|
@click.option("--all-apks", "-a", is_flag=True,
|
2021-08-25 11:35:21 +00:00
|
|
|
help="Extract all packages installed on the phone, including system packages")
|
2021-07-16 06:05:01 +00:00
|
|
|
@click.option("--virustotal", "-v", is_flag=True, help="Check packages on VirusTotal")
|
2021-07-20 01:09:53 +00:00
|
|
|
@click.option("--output", "-o", type=click.Path(exists=False),
|
2021-07-30 09:08:32 +00:00
|
|
|
help="Specify a path to a folder where you want to store the APKs")
|
2021-07-16 06:05:01 +00:00
|
|
|
@click.option("--from-file", "-f", type=click.Path(exists=True),
|
2022-08-12 17:14:05 +00:00
|
|
|
help="Instead of acquiring from phone, load an existing packages.json file for "
|
|
|
|
"lookups (mainly for debug purposes)")
|
2021-08-17 11:06:31 +00:00
|
|
|
@click.pass_context
|
2022-06-14 13:46:01 +00:00
|
|
|
def download_apks(ctx, all_apks, virustotal, output, from_file, serial):
|
2021-07-16 06:05:01 +00:00
|
|
|
try:
|
|
|
|
if from_file:
|
|
|
|
download = DownloadAPKs.from_json(from_file)
|
|
|
|
else:
|
2022-08-12 17:14:05 +00:00
|
|
|
# TODO: Do we actually want to be able to run without storing any
|
|
|
|
# file?
|
2021-08-17 11:06:31 +00:00
|
|
|
if not output:
|
|
|
|
log.critical("You need to specify an output folder with --output!")
|
|
|
|
ctx.exit(1)
|
|
|
|
|
2022-07-06 16:38:16 +00:00
|
|
|
download = DownloadAPKs(results_path=output, all_apks=all_apks)
|
2021-08-12 16:21:21 +00:00
|
|
|
if serial:
|
|
|
|
download.serial = serial
|
2021-07-16 06:05:01 +00:00
|
|
|
download.run()
|
|
|
|
|
2022-06-14 13:46:01 +00:00
|
|
|
packages_to_lookup = []
|
|
|
|
if all_apks:
|
|
|
|
packages_to_lookup = download.packages
|
|
|
|
else:
|
|
|
|
for package in download.packages:
|
|
|
|
if not package.get("system", False):
|
|
|
|
packages_to_lookup.append(package)
|
2021-07-16 06:05:01 +00:00
|
|
|
|
2022-06-14 13:46:01 +00:00
|
|
|
if len(packages_to_lookup) == 0:
|
|
|
|
return
|
2021-07-16 06:05:01 +00:00
|
|
|
|
2022-06-14 13:46:01 +00:00
|
|
|
if virustotal:
|
|
|
|
m = Packages()
|
|
|
|
m.check_virustotal(packages_to_lookup)
|
2021-07-16 06:05:01 +00:00
|
|
|
except KeyboardInterrupt:
|
|
|
|
print("")
|
2021-08-17 11:06:31 +00:00
|
|
|
ctx.exit(1)
|
2021-07-16 06:05:01 +00:00
|
|
|
|
|
|
|
|
|
|
|
#==============================================================================
|
2022-02-01 23:09:53 +00:00
|
|
|
# Command: check-adb
|
2021-07-16 06:05:01 +00:00
|
|
|
#==============================================================================
|
|
|
|
@cli.command("check-adb", help="Check an Android device over adb")
|
2021-08-21 13:48:52 +00:00
|
|
|
@click.option("--serial", "-s", type=str, help=HELP_MSG_SERIAL)
|
2021-08-18 11:19:34 +00:00
|
|
|
@click.option("--iocs", "-i", type=click.Path(exists=True), multiple=True,
|
2021-08-21 13:48:52 +00:00
|
|
|
default=[], help=HELP_MSG_IOC)
|
2021-07-20 01:09:53 +00:00
|
|
|
@click.option("--output", "-o", type=click.Path(exists=False),
|
2021-08-21 13:48:52 +00:00
|
|
|
help=HELP_MSG_OUTPUT)
|
2021-12-16 18:16:24 +00:00
|
|
|
@click.option("--fast", "-f", is_flag=True, help=HELP_MSG_FAST)
|
2021-08-21 13:48:52 +00:00
|
|
|
@click.option("--list-modules", "-l", is_flag=True, help=HELP_MSG_LIST_MODULES)
|
|
|
|
@click.option("--module", "-m", help=HELP_MSG_MODULE)
|
2021-08-17 11:06:31 +00:00
|
|
|
@click.pass_context
|
2022-06-17 15:16:20 +00:00
|
|
|
def check_adb(ctx, serial, iocs, output, fast, list_modules, module):
|
2022-06-15 15:41:19 +00:00
|
|
|
cmd = CmdAndroidCheckADB(results_path=output, ioc_files=iocs,
|
|
|
|
module_name=module, serial=serial, fast_mode=fast)
|
2021-07-16 06:05:01 +00:00
|
|
|
|
2022-06-15 15:41:19 +00:00
|
|
|
if list_modules:
|
|
|
|
cmd.list_modules()
|
2021-07-16 06:05:01 +00:00
|
|
|
return
|
|
|
|
|
2022-06-16 15:02:38 +00:00
|
|
|
log.info("Checking Android device over debug bridge")
|
|
|
|
|
2022-06-15 15:41:19 +00:00
|
|
|
cmd.run()
|
2021-07-16 06:05:01 +00:00
|
|
|
|
2022-06-16 15:02:38 +00:00
|
|
|
if len(cmd.timeline_detected) > 0:
|
|
|
|
log.warning("The analysis of the Android device produced %d detections!",
|
|
|
|
len(cmd.timeline_detected))
|
|
|
|
|
2021-08-17 20:54:33 +00:00
|
|
|
|
2021-07-16 06:05:01 +00:00
|
|
|
#==============================================================================
|
2022-02-01 23:09:53 +00:00
|
|
|
# Command: check-bugreport
|
|
|
|
#==============================================================================
|
|
|
|
@cli.command("check-bugreport", help="Check an Android Bug Report")
|
|
|
|
@click.option("--iocs", "-i", type=click.Path(exists=True), multiple=True,
|
|
|
|
default=[], help=HELP_MSG_IOC)
|
2022-08-12 17:14:05 +00:00
|
|
|
@click.option("--output", "-o", type=click.Path(exists=False),
|
|
|
|
help=HELP_MSG_OUTPUT)
|
2022-02-01 23:09:53 +00:00
|
|
|
@click.option("--list-modules", "-l", is_flag=True, help=HELP_MSG_LIST_MODULES)
|
|
|
|
@click.option("--module", "-m", help=HELP_MSG_MODULE)
|
|
|
|
@click.argument("BUGREPORT_PATH", type=click.Path(exists=True))
|
|
|
|
@click.pass_context
|
|
|
|
def check_bugreport(ctx, iocs, output, list_modules, module, bugreport_path):
|
2022-08-12 17:14:05 +00:00
|
|
|
cmd = CmdAndroidCheckBugreport(target_path=bugreport_path,
|
|
|
|
results_path=output, ioc_files=iocs,
|
|
|
|
module_name=module)
|
2022-02-01 23:09:53 +00:00
|
|
|
|
2022-06-15 15:41:19 +00:00
|
|
|
if list_modules:
|
|
|
|
cmd.list_modules()
|
2022-02-01 23:09:53 +00:00
|
|
|
return
|
|
|
|
|
2022-06-16 15:02:38 +00:00
|
|
|
log.info("Checking Android bug report at path: %s", bugreport_path)
|
|
|
|
|
2022-06-15 15:41:19 +00:00
|
|
|
cmd.run()
|
2022-02-01 23:09:53 +00:00
|
|
|
|
2022-06-16 15:02:38 +00:00
|
|
|
if len(cmd.timeline_detected) > 0:
|
|
|
|
log.warning("The analysis of the Android bug report produced %d detections!",
|
|
|
|
len(cmd.timeline_detected))
|
|
|
|
|
2022-02-01 23:09:53 +00:00
|
|
|
|
|
|
|
#==============================================================================
|
|
|
|
# Command: check-backup
|
2021-07-16 06:05:01 +00:00
|
|
|
#==============================================================================
|
|
|
|
@cli.command("check-backup", help="Check an Android Backup")
|
2021-08-18 11:19:34 +00:00
|
|
|
@click.option("--iocs", "-i", type=click.Path(exists=True), multiple=True,
|
2021-08-21 13:48:52 +00:00
|
|
|
default=[], help=HELP_MSG_IOC)
|
2022-08-12 17:14:05 +00:00
|
|
|
@click.option("--output", "-o", type=click.Path(exists=False),
|
|
|
|
help=HELP_MSG_OUTPUT)
|
2022-06-15 15:41:19 +00:00
|
|
|
@click.option("--list-modules", "-l", is_flag=True, help=HELP_MSG_LIST_MODULES)
|
2021-07-16 06:05:01 +00:00
|
|
|
@click.argument("BACKUP_PATH", type=click.Path(exists=True))
|
2021-08-17 11:06:31 +00:00
|
|
|
@click.pass_context
|
2022-08-12 14:20:16 +00:00
|
|
|
def check_backup(ctx, iocs, output, list_modules, backup_path):
|
2022-06-15 15:41:19 +00:00
|
|
|
cmd = CmdAndroidCheckBackup(target_path=backup_path, results_path=output,
|
|
|
|
ioc_files=iocs)
|
2022-03-04 09:10:56 +00:00
|
|
|
|
2022-06-15 15:41:19 +00:00
|
|
|
if list_modules:
|
|
|
|
cmd.list_modules()
|
|
|
|
return
|
2022-03-04 09:10:56 +00:00
|
|
|
|
2022-06-16 15:02:38 +00:00
|
|
|
log.info("Checking Android backup at path: %s", backup_path)
|
|
|
|
|
2022-06-15 15:41:19 +00:00
|
|
|
cmd.run()
|
2022-01-07 15:11:01 +00:00
|
|
|
|
2022-06-16 15:02:38 +00:00
|
|
|
if len(cmd.timeline_detected) > 0:
|
|
|
|
log.warning("The analysis of the Android backup produced %d detections!",
|
|
|
|
len(cmd.timeline_detected))
|
|
|
|
|
2022-01-11 15:02:01 +00:00
|
|
|
|
2022-01-27 17:23:19 +00:00
|
|
|
#==============================================================================
|
|
|
|
# Command: check-iocs
|
|
|
|
#==============================================================================
|
|
|
|
@cli.command("check-iocs", help="Compare stored JSON results to provided indicators")
|
|
|
|
@click.option("--iocs", "-i", type=click.Path(exists=True), multiple=True,
|
|
|
|
default=[], help=HELP_MSG_IOC)
|
|
|
|
@click.option("--list-modules", "-l", is_flag=True, help=HELP_MSG_LIST_MODULES)
|
|
|
|
@click.option("--module", "-m", help=HELP_MSG_MODULE)
|
|
|
|
@click.argument("FOLDER", type=click.Path(exists=True))
|
|
|
|
@click.pass_context
|
|
|
|
def check_iocs(ctx, iocs, list_modules, module, folder):
|
2022-06-16 15:02:38 +00:00
|
|
|
cmd = CmdCheckIOCS(target_path=folder, ioc_files=iocs, module_name=module)
|
|
|
|
cmd.modules = BACKUP_MODULES + ADB_MODULES + BUGREPORT_MODULES
|
2022-01-27 17:23:19 +00:00
|
|
|
|
|
|
|
if list_modules:
|
2022-06-16 15:02:38 +00:00
|
|
|
cmd.list_modules()
|
2022-01-27 17:23:19 +00:00
|
|
|
return
|
|
|
|
|
2022-06-16 15:02:38 +00:00
|
|
|
cmd.run()
|
2022-01-27 17:23:19 +00:00
|
|
|
|
|
|
|
|
2022-01-07 15:11:01 +00:00
|
|
|
#==============================================================================
|
2022-01-11 14:59:01 +00:00
|
|
|
# Command: download-iocs
|
2022-01-07 15:11:01 +00:00
|
|
|
#==============================================================================
|
2022-01-11 14:59:01 +00:00
|
|
|
@cli.command("download-iocs", help="Download public STIX2 indicators")
|
2022-01-07 15:11:01 +00:00
|
|
|
def download_indicators():
|
2022-06-28 13:03:52 +00:00
|
|
|
ioc_updates = IndicatorsUpdates()
|
|
|
|
ioc_updates.update()
|