diff --git a/docs/android/adb.md b/docs/android/adb.md index d5c0660..ed4fb7c 100644 --- a/docs/android/adb.md +++ b/docs/android/adb.md @@ -37,6 +37,15 @@ mvt-android check-adb --serial 192.168.1.20:5555 --output /path/to/results Where `192.168.1.20` is the correct IP address of your device. +Connection may not work and fail with STLS error messages (if the TCP connection requires encryption what is not supported in the default adb-shell Python library). +In this case switching to the [pure-python-adb (ppadb)](https://pypi.org/project/pure-python-adb/) +ADB library is preferred. It requires an already running ADB server connected to the Android device. The ADB server should be available at +`127.0.0.1:5037`. The ADB server connection to the device may be USB or Network, it does not matter. The ppadb method is included in MVT: + +```bash +mvt-android check-adp --ppadb --serial 192.168.1.20:5555 --output /path/to/results +``` + ## MVT modules requiring root privileges Of the currently available `mvt-android check-adb` modules a handful require root privileges to function correctly. This is because certain files, such as browser history and SMS messages databases are not accessible with user privileges through adb. These modules are to be considered OPTIONALLY available in case the device was already jailbroken. **Do NOT jailbreak your own device unless you are sure of what you are doing!** Jailbreaking your phone exposes it to considerable security risks! diff --git a/mvt/android/cli.py b/mvt/android/cli.py index 9046e9c..7df8687 100644 --- a/mvt/android/cli.py +++ b/mvt/android/cli.py @@ -58,6 +58,8 @@ def version(): # Command: download-apks #============================================================================== @cli.command("download-apks", help="Download all or only non-system installed APKs") +@click.option("--ppadb", "-p", is_flag=True, + help="Use pure-python-adb library on 127.0.0.1:5037 instead of adb-shell (useful for TCP instead of USB connection, ADB server should be up and connected)") @click.option("--serial", "-s", type=str, help=HELP_MSG_SERIAL) @click.option("--all-apks", "-a", is_flag=True, help="Extract all packages installed on the phone, including system packages") @@ -90,6 +92,8 @@ def download_apks(ctx, all_apks, virustotal, koodous, all_checks, output, from_f log=logging.getLogger(DownloadAPKs.__module__)) if serial: download.serial = serial + if ppadb: + download.ppadb = True download.run() packages = download.packages @@ -111,6 +115,8 @@ def download_apks(ctx, all_apks, virustotal, koodous, all_checks, output, from_f # Command: check-adb #============================================================================== @cli.command("check-adb", help="Check an Android device over adb") +@click.option("--ppadb", "-p", is_flag=True, + help="Use pure-python-adb library on 127.0.0.1:5037 instead of adb-shell (useful for TCP instead of USB connection, ADB server should be up and connected)") @click.option("--serial", "-s", type=str, help=HELP_MSG_SERIAL) @click.option("--iocs", "-i", type=click.Path(exists=True), multiple=True, default=[], help=HELP_MSG_IOC) @@ -120,7 +126,7 @@ def download_apks(ctx, all_apks, virustotal, koodous, all_checks, output, from_f @click.option("--list-modules", "-l", is_flag=True, help=HELP_MSG_LIST_MODULES) @click.option("--module", "-m", help=HELP_MSG_MODULE) @click.pass_context -def check_adb(ctx, iocs, output, fast, list_modules, module, serial): +def check_adb(ctx, iocs, output, fast, list_modules, module, serial, ppadb): if list_modules: log.info("Following is the list of available check-adb modules:") for adb_module in ADB_MODULES: @@ -153,6 +159,8 @@ def check_adb(ctx, iocs, output, fast, list_modules, module, serial): m.indicators.log = m.log if serial: m.serial = serial + if ppadb: + m.ppadb = True run_module(m) timeline.extend(m.timeline) diff --git a/mvt/android/modules/adb/base.py b/mvt/android/modules/adb/base.py index cce06f2..feaf2b4 100644 --- a/mvt/android/modules/adb/base.py +++ b/mvt/android/modules/adb/base.py @@ -20,6 +20,8 @@ from adb_shell.exceptions import (AdbCommandFailureException, DeviceAuthError, UsbDeviceNotFoundError, UsbReadFailedError) from usb1 import USBErrorAccess, USBErrorBusy +from ppadb.client import Client as AdbClient + from mvt.android.parsers.backup import (InvalidBackupPassword, parse_ab_header, parse_backup_file) from mvt.common.module import InsufficientPrivileges, MVTModule @@ -41,6 +43,7 @@ class AndroidExtraction(MVTModule): self.device = None self.serial = None + self.ppadb = False @staticmethod def _adb_check_keys(): @@ -55,7 +58,19 @@ class AndroidExtraction(MVTModule): write_public_keyfile(ADB_KEY_PATH, ADB_PUB_KEY_PATH) def _adb_connect(self): - """Connect to the device over adb.""" + """Connect wrapper.""" + if self.ppadb: + self._adb_connect_ppadb() + else: + self._adb_connect_adbshell() + + def _adb_connect_ppadb(self): + """Connect to the device over adb using ppadb.""" + client = AdbClient(host="127.0.0.1", port=5037) + self.device = client.device(self.serial) + + def _adb_connect_adbshell(self): + """Connect to the device over adb using adb-shell.""" self._adb_check_keys() with open(ADB_KEY_PATH, "rb") as handle: @@ -105,7 +120,8 @@ class AndroidExtraction(MVTModule): def _adb_disconnect(self): """Close adb connection to the device.""" - self.device.close() + if not self.ppadb: + self.device.close() def _adb_reconnect(self): """Reconnect to device using adb.""" @@ -120,7 +136,10 @@ class AndroidExtraction(MVTModule): :returns: Output of command """ - return self.device.shell(command, read_timeout_s=200.0) + if self.ppadb: + return self.device.shell(command) + else: + return self.device.shell(command, read_timeout_s=200.0) def _adb_check_if_root(self): """Check if we have a `su` binary on the Android device. @@ -172,7 +191,10 @@ class AndroidExtraction(MVTModule): """ try: - self.device.pull(remote_path, local_path, progress_callback) + if self.ppadb: + self.device.pull(remote_path, local_path) + else: + self.device.pull(remote_path, local_path, progress_callback) except AdbCommandFailureException as e: if retry_root: self._adb_download_root(remote_path, local_path, progress_callback) diff --git a/setup.py b/setup.py index 6a39db0..f7455c1 100755 --- a/setup.py +++ b/setup.py @@ -29,7 +29,8 @@ requires = ( # Android dependencies: "adb-shell>=0.4.2", "libusb1>=2.0.1", - "cryptography>=36.0.1" + "cryptography>=36.0.1", + "pure-python-adb" )