Adds verbose mode

This commit is contained in:
tek 2023-04-25 11:13:46 +02:00
parent 15477cc187
commit fd81e3aa13
6 changed files with 71 additions and 34 deletions

View File

@ -6,14 +6,15 @@
import logging import logging
import click import click
from rich.logging import RichHandler
from mvt.common.cmd_check_iocs import CmdCheckIOCS from mvt.common.cmd_check_iocs import CmdCheckIOCS
from mvt.common.help import (HELP_MSG_FAST, HELP_MSG_HASHES, HELP_MSG_IOC, from mvt.common.help import (HELP_MSG_FAST, HELP_MSG_HASHES, HELP_MSG_IOC,
HELP_MSG_LIST_MODULES, HELP_MSG_MODULE, HELP_MSG_LIST_MODULES, HELP_MSG_MODULE,
HELP_MSG_OUTPUT, HELP_MSG_SERIAL) HELP_MSG_OUTPUT, HELP_MSG_SERIAL,
HELP_MSG_VERBOSE)
from mvt.common.logo import logo from mvt.common.logo import logo
from mvt.common.updates import IndicatorsUpdates from mvt.common.updates import IndicatorsUpdates
from mvt.common.utils import init_logging, set_verbose_logging
from .cmd_check_adb import CmdAndroidCheckADB from .cmd_check_adb import CmdAndroidCheckADB
from .cmd_check_androidqf import CmdAndroidCheckAndroidQF from .cmd_check_androidqf import CmdAndroidCheckAndroidQF
@ -25,11 +26,8 @@ from .modules.adb.packages import Packages
from .modules.backup import BACKUP_MODULES from .modules.backup import BACKUP_MODULES
from .modules.bugreport import BUGREPORT_MODULES from .modules.bugreport import BUGREPORT_MODULES
# Setup logging using Rich. init_logging()
LOG_FORMAT = "[%(name)s] %(message)s" log = logging.getLogger("mvt")
logging.basicConfig(level="INFO", format=LOG_FORMAT, handlers=[
RichHandler(show_path=False, log_time_format="%X")])
log = logging.getLogger(__name__)
CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help']) CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'])
@ -63,8 +61,10 @@ def version():
@click.option("--from-file", "-f", type=click.Path(exists=True), @click.option("--from-file", "-f", type=click.Path(exists=True),
help="Instead of acquiring from phone, load an existing packages.json file for " help="Instead of acquiring from phone, load an existing packages.json file for "
"lookups (mainly for debug purposes)") "lookups (mainly for debug purposes)")
@click.option("--verbose", "-v", is_flag=True, help=HELP_MSG_VERBOSE)
@click.pass_context @click.pass_context
def download_apks(ctx, all_apks, virustotal, output, from_file, serial): def download_apks(ctx, all_apks, virustotal, output, from_file, serial, verbose):
set_verbose_logging(verbose)
try: try:
if from_file: if from_file:
download = DownloadAPKs.from_json(from_file) download = DownloadAPKs.from_json(from_file)
@ -112,8 +112,10 @@ def download_apks(ctx, all_apks, virustotal, output, from_file, serial):
@click.option("--fast", "-f", is_flag=True, help=HELP_MSG_FAST) @click.option("--fast", "-f", is_flag=True, help=HELP_MSG_FAST)
@click.option("--list-modules", "-l", is_flag=True, help=HELP_MSG_LIST_MODULES) @click.option("--list-modules", "-l", is_flag=True, help=HELP_MSG_LIST_MODULES)
@click.option("--module", "-m", help=HELP_MSG_MODULE) @click.option("--module", "-m", help=HELP_MSG_MODULE)
@click.option("--verbose", "-v", is_flag=True, help=HELP_MSG_VERBOSE)
@click.pass_context @click.pass_context
def check_adb(ctx, serial, iocs, output, fast, list_modules, module): def check_adb(ctx, serial, iocs, output, fast, list_modules, module, verbose):
set_verbose_logging(verbose)
cmd = CmdAndroidCheckADB(results_path=output, ioc_files=iocs, cmd = CmdAndroidCheckADB(results_path=output, ioc_files=iocs,
module_name=module, serial=serial, fast_mode=fast) module_name=module, serial=serial, fast_mode=fast)
@ -141,9 +143,11 @@ def check_adb(ctx, serial, iocs, output, fast, list_modules, module):
help=HELP_MSG_OUTPUT) help=HELP_MSG_OUTPUT)
@click.option("--list-modules", "-l", is_flag=True, help=HELP_MSG_LIST_MODULES) @click.option("--list-modules", "-l", is_flag=True, help=HELP_MSG_LIST_MODULES)
@click.option("--module", "-m", help=HELP_MSG_MODULE) @click.option("--module", "-m", help=HELP_MSG_MODULE)
@click.option("--verbose", "-v", is_flag=True, help=HELP_MSG_VERBOSE)
@click.argument("BUGREPORT_PATH", type=click.Path(exists=True)) @click.argument("BUGREPORT_PATH", type=click.Path(exists=True))
@click.pass_context @click.pass_context
def check_bugreport(ctx, iocs, output, list_modules, module, bugreport_path): def check_bugreport(ctx, iocs, output, list_modules, module, verbose, bugreport_path):
set_verbose_logging(verbose)
# Always generate hashes as bug reports are small. # Always generate hashes as bug reports are small.
cmd = CmdAndroidCheckBugreport(target_path=bugreport_path, cmd = CmdAndroidCheckBugreport(target_path=bugreport_path,
results_path=output, ioc_files=iocs, results_path=output, ioc_files=iocs,
@ -172,9 +176,11 @@ def check_bugreport(ctx, iocs, output, list_modules, module, bugreport_path):
@click.option("--output", "-o", type=click.Path(exists=False), @click.option("--output", "-o", type=click.Path(exists=False),
help=HELP_MSG_OUTPUT) help=HELP_MSG_OUTPUT)
@click.option("--list-modules", "-l", is_flag=True, help=HELP_MSG_LIST_MODULES) @click.option("--list-modules", "-l", is_flag=True, help=HELP_MSG_LIST_MODULES)
@click.option("--verbose", "-v", is_flag=True, help=HELP_MSG_VERBOSE)
@click.argument("BACKUP_PATH", type=click.Path(exists=True)) @click.argument("BACKUP_PATH", type=click.Path(exists=True))
@click.pass_context @click.pass_context
def check_backup(ctx, iocs, output, list_modules, backup_path): def check_backup(ctx, iocs, output, list_modules, verbose, backup_path):
set_verbose_logging(verbose)
# Always generate hashes as backups are generally small. # Always generate hashes as backups are generally small.
cmd = CmdAndroidCheckBackup(target_path=backup_path, results_path=output, cmd = CmdAndroidCheckBackup(target_path=backup_path, results_path=output,
ioc_files=iocs, hashes=True) ioc_files=iocs, hashes=True)
@ -204,9 +210,11 @@ def check_backup(ctx, iocs, output, list_modules, backup_path):
@click.option("--list-modules", "-l", is_flag=True, help=HELP_MSG_LIST_MODULES) @click.option("--list-modules", "-l", is_flag=True, help=HELP_MSG_LIST_MODULES)
@click.option("--module", "-m", help=HELP_MSG_MODULE) @click.option("--module", "-m", help=HELP_MSG_MODULE)
@click.option("--hashes", "-H", is_flag=True, help=HELP_MSG_HASHES) @click.option("--hashes", "-H", is_flag=True, help=HELP_MSG_HASHES)
@click.option("--verbose", "-v", is_flag=True, help=HELP_MSG_VERBOSE)
@click.argument("ANDROIDQF_PATH", type=click.Path(exists=True)) @click.argument("ANDROIDQF_PATH", type=click.Path(exists=True))
@click.pass_context @click.pass_context
def check_androidqf(ctx, iocs, output, list_modules, module, hashes, androidqf_path): def check_androidqf(ctx, iocs, output, list_modules, module, hashes, verbose, androidqf_path):
set_verbose_logging(verbose)
cmd = CmdAndroidCheckAndroidQF(target_path=androidqf_path, cmd = CmdAndroidCheckAndroidQF(target_path=androidqf_path,
results_path=output, ioc_files=iocs, results_path=output, ioc_files=iocs,
module_name=module, hashes=hashes) module_name=module, hashes=hashes)

View File

@ -21,15 +21,13 @@ log = logging.getLogger(__name__)
class DownloadAPKs(AndroidExtraction): class DownloadAPKs(AndroidExtraction):
"""DownloadAPKs is the main class operating the download of APKs """DownloadAPKs is the main class operating the download of APKs
from the device. from the device.
""" """
def __init__( def __init__(
self, self,
results_path: Optional[str] = None, results_path: Optional[str] = None,
all_apks: Optional[bool] = False, all_apks: Optional[bool] = False,
packages: Optional[list] = None packages: Optional[list] = None,
) -> None: ) -> None:
"""Initialize module. """Initialize module.
:param results_path: Path to the folder where data should be stored :param results_path: Path to the folder where data should be stored

View File

@ -42,20 +42,21 @@ class Command:
self.fast_mode = fast_mode self.fast_mode = fast_mode
self.log = log self.log = log
self.iocs = Indicators(log=log)
self.iocs.load_indicators_files(self.ioc_files)
# This list will contain all executed modules. # This list will contain all executed modules.
# We can use this to reference e.g. self.executed[0].results. # We can use this to reference e.g. self.executed[0].results.
self.executed = [] self.executed = []
self.detected_count = 0 self.detected_count = 0
self.hashes = hashes self.hashes = hashes
self.hash_values = [] self.hash_values = []
self.timeline = [] self.timeline = []
self.timeline_detected = [] self.timeline_detected = []
# Load IOCs
self._create_storage()
self._setup_logging()
self.iocs = Indicators(log=log)
self.iocs.load_indicators_files(self.ioc_files)
def _create_storage(self) -> None: def _create_storage(self) -> None:
if self.results_path and not os.path.exists(self.results_path): if self.results_path and not os.path.exists(self.results_path):
try: try:
@ -65,10 +66,11 @@ class Command:
self.results_path, exc) self.results_path, exc)
sys.exit(1) sys.exit(1)
def _add_log_file_handler(self, logger: logging.Logger) -> None: def _setup_logging(self):
if not self.results_path: if not self.results_path:
return return
logger = logging.getLogger("mvt")
file_handler = logging.FileHandler(os.path.join(self.results_path, file_handler = logging.FileHandler(os.path.join(self.results_path,
"command.log")) "command.log"))
formatter = logging.Formatter("%(asctime)s - %(name)s - " formatter = logging.Formatter("%(asctime)s - %(name)s - "
@ -150,8 +152,6 @@ class Command:
raise NotImplementedError raise NotImplementedError
def run(self) -> None: def run(self) -> None:
self._create_storage()
self._add_log_file_handler(self.log)
try: try:
self.init() self.init()
@ -162,8 +162,8 @@ class Command:
if self.module_name and module.__name__ != self.module_name: if self.module_name and module.__name__ != self.module_name:
continue continue
# FIXME: do we need the logger here
module_logger = logging.getLogger(module.__module__) module_logger = logging.getLogger(module.__module__)
self._add_log_file_handler(module_logger)
m = module(target_path=self.target_path, m = module(target_path=self.target_path,
results_path=self.results_path, results_path=self.results_path,

View File

@ -10,6 +10,7 @@ HELP_MSG_FAST = "Avoid running time/resource consuming features"
HELP_MSG_LIST_MODULES = "Print list of available modules and exit" HELP_MSG_LIST_MODULES = "Print list of available modules and exit"
HELP_MSG_MODULE = "Name of a single module you would like to run instead of all" HELP_MSG_MODULE = "Name of a single module you would like to run instead of all"
HELP_MSG_HASHES = "Generate hashes of all the files analyzed" HELP_MSG_HASHES = "Generate hashes of all the files analyzed"
HELP_MSG_VERBOSE = "Verbose mode"
# Android-specific. # Android-specific.
HELP_MSG_SERIAL = "Specify a device serial number or HOST:PORT connection string" HELP_MSG_SERIAL = "Specify a device serial number or HOST:PORT connection string"

View File

@ -5,10 +5,13 @@
import datetime import datetime
import hashlib import hashlib
import logging
import os import os
import re import re
from typing import Any, Iterator, Union from typing import Any, Iterator, Union
from rich.logging import RichHandler
def convert_chrometime_to_datetime(timestamp: int) -> datetime.datetime: def convert_chrometime_to_datetime(timestamp: int) -> datetime.datetime:
"""Converts Chrome timestamp to a datetime. """Converts Chrome timestamp to a datetime.
@ -197,3 +200,28 @@ def generate_hashes_from_path(path: str, log) -> Iterator[dict]:
continue continue
yield {"file_path": file_path, "sha256": sha256} yield {"file_path": file_path, "sha256": sha256}
def init_logging(verbose: bool = False):
"""
Initialise logging for the MVT module
"""
# Setup logging using Rich.
log = logging.getLogger("mvt")
log.setLevel(logging.DEBUG)
consoleHandler = RichHandler(show_path=False, log_time_format="%X")
consoleHandler.setFormatter(logging.Formatter("[%(name)s] %(message)s"))
if verbose:
consoleHandler.setLevel(logging.DEBUG)
else:
consoleHandler.setLevel(logging.INFO)
log.addHandler(consoleHandler)
def set_verbose_logging(verbose: bool = False):
log = logging.getLogger("mvt")
handler = log.handlers[0]
if verbose:
handler.setLevel(logging.DEBUG)
else:
handler.setLevel(logging.INFO)

View File

@ -8,17 +8,17 @@ import logging
import os import os
import click import click
from rich.logging import RichHandler
from rich.prompt import Prompt from rich.prompt import Prompt
from mvt.common.cmd_check_iocs import CmdCheckIOCS from mvt.common.cmd_check_iocs import CmdCheckIOCS
from mvt.common.help import (HELP_MSG_FAST, HELP_MSG_HASHES, HELP_MSG_IOC, from mvt.common.help import (HELP_MSG_FAST, HELP_MSG_HASHES, HELP_MSG_IOC,
HELP_MSG_LIST_MODULES, HELP_MSG_MODULE, HELP_MSG_LIST_MODULES, HELP_MSG_MODULE,
HELP_MSG_OUTPUT) HELP_MSG_OUTPUT, HELP_MSG_VERBOSE)
from mvt.common.logo import logo from mvt.common.logo import logo
from mvt.common.options import MutuallyExclusiveOption from mvt.common.options import MutuallyExclusiveOption
from mvt.common.updates import IndicatorsUpdates from mvt.common.updates import IndicatorsUpdates
from mvt.common.utils import generate_hashes_from_path from mvt.common.utils import (generate_hashes_from_path, init_logging,
set_verbose_logging)
from .cmd_check_backup import CmdIOSCheckBackup from .cmd_check_backup import CmdIOSCheckBackup
from .cmd_check_fs import CmdIOSCheckFS from .cmd_check_fs import CmdIOSCheckFS
@ -27,11 +27,8 @@ from .modules.backup import BACKUP_MODULES
from .modules.fs import FS_MODULES from .modules.fs import FS_MODULES
from .modules.mixed import MIXED_MODULES from .modules.mixed import MIXED_MODULES
# Setup logging using Rich. init_logging()
LOG_FORMAT = "[%(name)s] %(message)s" log = logging.getLogger("mvt")
logging.basicConfig(level="INFO", format=LOG_FORMAT, handlers=[
RichHandler(show_path=False, log_time_format="%X")])
log = logging.getLogger(__name__)
# Set this environment variable to a password if needed. # Set this environment variable to a password if needed.
MVT_IOS_BACKUP_PASSWORD = "MVT_IOS_BACKUP_PASSWORD" MVT_IOS_BACKUP_PASSWORD = "MVT_IOS_BACKUP_PASSWORD"
@ -166,9 +163,12 @@ def extract_key(password, key_file, backup_path):
@click.option("--list-modules", "-l", is_flag=True, help=HELP_MSG_LIST_MODULES) @click.option("--list-modules", "-l", is_flag=True, help=HELP_MSG_LIST_MODULES)
@click.option("--module", "-m", help=HELP_MSG_MODULE) @click.option("--module", "-m", help=HELP_MSG_MODULE)
@click.option("--hashes", "-H", is_flag=True, help=HELP_MSG_HASHES) @click.option("--hashes", "-H", is_flag=True, help=HELP_MSG_HASHES)
@click.option("--verbose", "-v", is_flag=True, help=HELP_MSG_VERBOSE)
@click.argument("BACKUP_PATH", type=click.Path(exists=True)) @click.argument("BACKUP_PATH", type=click.Path(exists=True))
@click.pass_context @click.pass_context
def check_backup(ctx, iocs, output, fast, list_modules, module, hashes, backup_path): def check_backup(ctx, iocs, output, fast, list_modules, module, hashes, verbose, backup_path):
set_verbose_logging(verbose)
cmd = CmdIOSCheckBackup(target_path=backup_path, results_path=output, cmd = CmdIOSCheckBackup(target_path=backup_path, results_path=output,
ioc_files=iocs, module_name=module, fast_mode=fast, ioc_files=iocs, module_name=module, fast_mode=fast,
hashes=hashes) hashes=hashes)
@ -199,9 +199,11 @@ def check_backup(ctx, iocs, output, fast, list_modules, module, hashes, backup_p
@click.option("--list-modules", "-l", is_flag=True, help=HELP_MSG_LIST_MODULES) @click.option("--list-modules", "-l", is_flag=True, help=HELP_MSG_LIST_MODULES)
@click.option("--module", "-m", help=HELP_MSG_MODULE) @click.option("--module", "-m", help=HELP_MSG_MODULE)
@click.option("--hashes", "-H", is_flag=True, help=HELP_MSG_HASHES) @click.option("--hashes", "-H", is_flag=True, help=HELP_MSG_HASHES)
@click.option("--verbose", "-v", is_flag=True, help=HELP_MSG_VERBOSE)
@click.argument("DUMP_PATH", type=click.Path(exists=True)) @click.argument("DUMP_PATH", type=click.Path(exists=True))
@click.pass_context @click.pass_context
def check_fs(ctx, iocs, output, fast, list_modules, module, hashes, dump_path): def check_fs(ctx, iocs, output, fast, list_modules, module, hashes, verbose, dump_path):
set_verbose_logging(verbose)
cmd = CmdIOSCheckFS(target_path=dump_path, results_path=output, cmd = CmdIOSCheckFS(target_path=dump_path, results_path=output,
ioc_files=iocs, module_name=module, fast_mode=fast, ioc_files=iocs, module_name=module, fast_mode=fast,
hashes=hashes) hashes=hashes)