mirror of
https://github.com/mvt-project/mvt.git
synced 2024-06-01 18:55:31 +00:00
Merge branch 'pkirkovsky-extract-key'
This commit is contained in:
commit
444e70a6eb
|
@ -35,6 +35,7 @@ MVT provides two commands `mvt-ios` and `mvt-android` with the following subcomm
|
|||
* `check-fs`: Extract artifacts from a full filesystem dump
|
||||
* `check-iocs`: Compare stored JSON results to provided indicators
|
||||
* `decrypt-backup`: Decrypt an encrypted iTunes backup
|
||||
* `extract-key`: Extract decryption key from an iTunes backup
|
||||
* `mvt-android`:
|
||||
* `check-backup`: Check an Android Backup
|
||||
* `download-apks`: Download all or non-safelisted installed APKs
|
||||
|
|
|
@ -2,6 +2,32 @@
|
|||
|
||||
The backup might take some time. It is best to make sure the phone remains unlocked during the backup process. Afterwards, a new folder will be created under the path you specified using the UDID of the iPhone you backed up.
|
||||
|
||||
## Extracting and saving the decryption key (optional)
|
||||
|
||||
If you do not wish to enter a password every time when decrypting a backup, MVT can accept a key file instead. This key can be used with the `decrypt-backup` command.
|
||||
|
||||
To generate a key file, you will need your device backup and the backup password:
|
||||
|
||||
$ mvt-ios extract-key --help
|
||||
Usage: mvt-ios extract-key [OPTIONS] BACKUP_PATH
|
||||
|
||||
Extract decryption key from an iTunes backup
|
||||
|
||||
Options:
|
||||
-p, --password TEXT Password to use to decrypt the backup [required]
|
||||
-k, --key-file FILE Key file to be written (if unset, will print to STDOUT)
|
||||
--help Show this message and exit.
|
||||
|
||||
You can specify the password on the command line, or omit the `-p` option to have MVT prompt for a password. The `-k` option specifies where to save the file containing the decryption key. If `-k` is omitted, MVT will display the decryption key without saving.
|
||||
|
||||
_Note_: This decryption key is sensitive data! Keep the file safe.
|
||||
|
||||
To extract the key and have MVT prompt for a password:
|
||||
|
||||
```bash
|
||||
mvt-ios extract-key -k /path/to/save/key /path/to/backup
|
||||
```
|
||||
|
||||
## Decrypting a backup
|
||||
|
||||
In case you have an encrypted backup, you will need to decrypt it first. This can be done with `mvt-ios` as well:
|
||||
|
@ -25,7 +51,7 @@ In case you have an encrypted backup, you will need to decrypt it first. This ca
|
|||
|
||||
--help Show this message and exit.
|
||||
|
||||
You can specify either a password via command-line or pass a key file, and you need to specify a destination path where the decrypted backup will be stored. Following is an example usage of `decrypt-backup`:
|
||||
You can specify either a password via command-line or pass a key file, and you need to specify a destination path where the decrypted backup will be stored. If `-p` is omitted, MVT will ask for a password. Following is an example usage of `decrypt-backup`:
|
||||
|
||||
```bash
|
||||
mvt-ios decrypt-backup -p password -d /path/to/decrypted /path/to/backup
|
||||
|
|
|
@ -54,6 +54,7 @@ def cli():
|
|||
@click.argument("BACKUP_PATH", type=click.Path(exists=True))
|
||||
def decrypt_backup(destination, password, key_file, backup_path):
|
||||
backup = DecryptBackup(backup_path, destination)
|
||||
|
||||
if password:
|
||||
backup.decrypt_with_password(password)
|
||||
elif key_file:
|
||||
|
@ -62,6 +63,30 @@ def decrypt_backup(destination, password, key_file, backup_path):
|
|||
raise click.ClickException("Missing required option. Specify either "
|
||||
"--password or --key-file.")
|
||||
|
||||
backup.process_backup()
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# Command: extract-key
|
||||
#==============================================================================
|
||||
@cli.command("extract-key", help="Extract decryption key from an iTunes backup")
|
||||
@click.option("--password", "-p",
|
||||
help="Password to use to decrypt the backup",
|
||||
prompt="Enter backup password",
|
||||
hide_input=True, prompt_required=False, required=True)
|
||||
@click.option("--key-file", "-k",
|
||||
help="Key file to be written (if unset, will print to STDOUT)",
|
||||
required=False,
|
||||
type=click.Path(exists=False, file_okay=True, dir_okay=False, writable=True))
|
||||
@click.argument("BACKUP_PATH", type=click.Path(exists=True))
|
||||
def extract_key(password, backup_path, key_file):
|
||||
backup = DecryptBackup(backup_path)
|
||||
backup.decrypt_with_password(password)
|
||||
backup.get_key()
|
||||
|
||||
if key_file:
|
||||
backup.write_key(key_file)
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# Command: check-backup
|
||||
|
|
|
@ -18,7 +18,7 @@ class DecryptBackup:
|
|||
using either a password or a key file.
|
||||
"""
|
||||
|
||||
def __init__(self, backup_path, dest_path):
|
||||
def __init__(self, backup_path, dest_path=None):
|
||||
"""Decrypts an encrypted iOS backup.
|
||||
:param backup_path: Path to the encrypted backup folder
|
||||
:param dest_path: Path to the folder where to store the decrypted backup
|
||||
|
@ -26,8 +26,12 @@ class DecryptBackup:
|
|||
self.backup_path = backup_path
|
||||
self.dest_path = dest_path
|
||||
self._backup = None
|
||||
self._decryption_key = None
|
||||
|
||||
def process_backup(self):
|
||||
if not os.path.exists(self.dest_path):
|
||||
os.makedirs(self.dest_path)
|
||||
|
||||
def _process_backup(self):
|
||||
manifest_path = os.path.join(self.dest_path, "Manifest.db")
|
||||
# We extract a decrypted Manifest.db.
|
||||
self._backup.getManifestDB()
|
||||
|
@ -69,9 +73,6 @@ class DecryptBackup:
|
|||
"""
|
||||
log.info("Decrypting iOS backup at path %s with password", self.backup_path)
|
||||
|
||||
if not os.path.exists(self.dest_path):
|
||||
os.makedirs(self.dest_path)
|
||||
|
||||
try:
|
||||
self._backup = iOSbackup(udid=os.path.basename(self.backup_path),
|
||||
cleartextpassword=password,
|
||||
|
@ -79,9 +80,6 @@ class DecryptBackup:
|
|||
except Exception as e:
|
||||
log.exception(e)
|
||||
log.critical("Failed to decrypt backup. Did you provide the correct password?")
|
||||
return
|
||||
else:
|
||||
self._process_backup()
|
||||
|
||||
def decrypt_with_key_file(self, key_file):
|
||||
"""Decrypts an encrypted iOS backup using a key file.
|
||||
|
@ -90,9 +88,6 @@ class DecryptBackup:
|
|||
log.info("Decrypting iOS backup at path %s with key file %s",
|
||||
self.backup_path, key_file)
|
||||
|
||||
if not os.path.exists(self.dest_path):
|
||||
os.makedirs(self.dest_path)
|
||||
|
||||
with open(key_file, "rb") as handle:
|
||||
key_bytes = handle.read()
|
||||
|
||||
|
@ -109,6 +104,31 @@ class DecryptBackup:
|
|||
except Exception as e:
|
||||
log.exception(e)
|
||||
log.critical("Failed to decrypt backup. Did you provide the correct key file?")
|
||||
|
||||
def get_key(self):
|
||||
"""Retrieve and prints the encryption key.
|
||||
"""
|
||||
if not self._backup:
|
||||
return
|
||||
|
||||
self._decryption_key = self._backup.getDecryptionKey()
|
||||
log.info("Derived decryption key for backup at path %s is: \"%s\"",
|
||||
self.backup_path, self._decryption_key)
|
||||
|
||||
def write_key(self, key_path):
|
||||
"""Save extracted key to file.
|
||||
:param key_path: Path to the file where to write the derived decryption key.
|
||||
"""
|
||||
if not self._decryption_key:
|
||||
return
|
||||
|
||||
try:
|
||||
with open(key_path, 'w') as handle:
|
||||
handle.write(self._decryption_key)
|
||||
except Exception as e:
|
||||
log.exception(e)
|
||||
log.critical("Failed to write key to file: %s", key_path)
|
||||
return
|
||||
else:
|
||||
self._process_backup()
|
||||
log.info("Wrote decryption key to file: %s. This file is equivalent to a plaintext password. Keep it safe!",
|
||||
key_path)
|
||||
|
|
Loading…
Reference in New Issue
Block a user