mirror of
https://github.com/mvt-project/mvt.git
synced 2024-07-01 16:39:03 +00:00
Adding support for iOS lockdown management
This commit is contained in:
parent
459ff8c51c
commit
a30d7b2871
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
import hashlib
|
import hashlib
|
||||||
|
import os
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
|
||||||
|
@ -119,3 +120,14 @@ def keys_bytes_to_string(obj) -> str:
|
||||||
new_obj[key] = value
|
new_obj[key] = value
|
||||||
|
|
||||||
return new_obj
|
return new_obj
|
||||||
|
|
||||||
|
|
||||||
|
def secure_delete(file_path, rounds=10):
|
||||||
|
file_size = os.path.getsize(file_path)
|
||||||
|
|
||||||
|
with open(file_path, "br+", buffering=-1) as handle:
|
||||||
|
for i in range(rounds):
|
||||||
|
handle.seek(0)
|
||||||
|
handle.write(os.urandom(file_size))
|
||||||
|
|
||||||
|
os.remove(file_path)
|
||||||
|
|
112
mvt/ios/cli.py
112
mvt/ios/cli.py
|
@ -8,7 +8,8 @@ import os
|
||||||
|
|
||||||
import click
|
import click
|
||||||
from rich.logging import RichHandler
|
from rich.logging import RichHandler
|
||||||
from rich.prompt import Prompt
|
from rich.prompt import Confirm, Prompt
|
||||||
|
from simple_term_menu import TerminalMenu
|
||||||
|
|
||||||
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_IOC,
|
from mvt.common.help import (HELP_MSG_FAST, HELP_MSG_IOC,
|
||||||
|
@ -22,6 +23,7 @@ from .cmd_check_backup import CmdIOSCheckBackup
|
||||||
from .cmd_check_fs import CmdIOSCheckFS
|
from .cmd_check_fs import CmdIOSCheckFS
|
||||||
from .cmd_check_usb import CmdIOSCheckUSB
|
from .cmd_check_usb import CmdIOSCheckUSB
|
||||||
from .decrypt import DecryptBackup
|
from .decrypt import DecryptBackup
|
||||||
|
from .lockdown import Lockdown
|
||||||
from .modules.backup import BACKUP_MODULES
|
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
|
||||||
|
@ -188,6 +190,83 @@ def check_fs(ctx, iocs, output, fast, list_modules, module, dump_path):
|
||||||
len(cmd.timeline_detected))
|
len(cmd.timeline_detected))
|
||||||
|
|
||||||
|
|
||||||
|
#==============================================================================
|
||||||
|
# Command: check-usb
|
||||||
|
#==============================================================================
|
||||||
|
@cli.command("check-usb", help="Extract artifacts from a live iPhone through USB")
|
||||||
|
@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)
|
||||||
|
@click.option("--output", "-o", type=click.Path(exists=False), help=HELP_MSG_OUTPUT)
|
||||||
|
@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("--module", "-m", help=HELP_MSG_MODULE)
|
||||||
|
@click.pass_context
|
||||||
|
def check_usb(ctx, serial, iocs, output, fast, list_modules, module):
|
||||||
|
cmd = CmdIOSCheckUSB(results_path=output, ioc_files=iocs,
|
||||||
|
module_name=module, fast_mode=fast,
|
||||||
|
serial=serial)
|
||||||
|
|
||||||
|
if list_modules:
|
||||||
|
cmd.list_modules()
|
||||||
|
return
|
||||||
|
|
||||||
|
log.info("Checking iPhone through USB, this may take a while")
|
||||||
|
cmd.run()
|
||||||
|
|
||||||
|
if len(cmd.timeline_detected) > 0:
|
||||||
|
log.warning("The analysis of the data produced %d detections!",
|
||||||
|
len(cmd.timeline_detected))
|
||||||
|
|
||||||
|
|
||||||
|
#==============================================================================
|
||||||
|
# Command: clear-certs
|
||||||
|
#==============================================================================
|
||||||
|
@cli.command("clear-certs", help="Clear iOS lockdown certificates")
|
||||||
|
@click.pass_context
|
||||||
|
def clear_certs(ctx):
|
||||||
|
lock = Lockdown()
|
||||||
|
certs = lock.find_certs()
|
||||||
|
|
||||||
|
if not certs:
|
||||||
|
log.info("No iOS lockdown certificates found")
|
||||||
|
return
|
||||||
|
|
||||||
|
choices = []
|
||||||
|
for cert in certs:
|
||||||
|
choices.append(os.path.basename(cert))
|
||||||
|
log.info("Found lockdown certificate at %s", cert)
|
||||||
|
|
||||||
|
choices.append("Cancel")
|
||||||
|
|
||||||
|
terminal_menu = TerminalMenu(
|
||||||
|
choices,
|
||||||
|
title="Select which certificates to delete:",
|
||||||
|
multi_select=True,
|
||||||
|
show_multi_select_hint=True,
|
||||||
|
)
|
||||||
|
terminal_menu.show()
|
||||||
|
|
||||||
|
if "Cancel" in terminal_menu.chosen_menu_entries:
|
||||||
|
log.info("Cancel, not proceeding")
|
||||||
|
return
|
||||||
|
|
||||||
|
confirmed = Confirm.ask(f"You have selected {', '.join(terminal_menu.chosen_menu_entries)}. "
|
||||||
|
"Are you sure you want to proceed deleting them?")
|
||||||
|
if not confirmed:
|
||||||
|
log.info("Not proceeding")
|
||||||
|
return
|
||||||
|
|
||||||
|
for choice in terminal_menu.chosen_menu_entries:
|
||||||
|
try:
|
||||||
|
lock.delete_cert(choice)
|
||||||
|
except PermissionError:
|
||||||
|
log.error("Not enough permissions to delete certificate at \"%s\": "
|
||||||
|
"try launching this command with sudo", choice)
|
||||||
|
else:
|
||||||
|
log.info("Deleted lockdown certificate \"%s\"", choice)
|
||||||
|
|
||||||
|
|
||||||
#==============================================================================
|
#==============================================================================
|
||||||
# Command: check-iocs
|
# Command: check-iocs
|
||||||
#==============================================================================
|
#==============================================================================
|
||||||
|
@ -216,34 +295,3 @@ def check_iocs(ctx, iocs, list_modules, module, folder):
|
||||||
def download_iocs():
|
def download_iocs():
|
||||||
ioc_updates = IndicatorsUpdates()
|
ioc_updates = IndicatorsUpdates()
|
||||||
ioc_updates.update()
|
ioc_updates.update()
|
||||||
|
|
||||||
|
|
||||||
#==============================================================================
|
|
||||||
# Command: check-usb
|
|
||||||
#==============================================================================
|
|
||||||
@cli.command("check-usb", help="Extract artifacts from a live iPhone through USB / lockdown")
|
|
||||||
@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)
|
|
||||||
@click.option("--output", "-o", type=click.Path(exists=False), help=HELP_MSG_OUTPUT)
|
|
||||||
@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("--module", "-m", help=HELP_MSG_MODULE)
|
|
||||||
# TODO: serial
|
|
||||||
# @click.argument("BACKUP_PATH", type=click.Path(exists=True))
|
|
||||||
@click.pass_context
|
|
||||||
def check_usb(ctx, serial, iocs, output, fast, list_modules, module):
|
|
||||||
cmd = CmdIOSCheckUSB(results_path=output, ioc_files=iocs,
|
|
||||||
module_name=module, fast_mode=fast,
|
|
||||||
serial=serial)
|
|
||||||
|
|
||||||
if list_modules:
|
|
||||||
cmd.list_modules()
|
|
||||||
return
|
|
||||||
|
|
||||||
log.info("Checking iPhone through USB, this may take a while")
|
|
||||||
cmd.run()
|
|
||||||
|
|
||||||
if len(cmd.timeline_detected) > 0:
|
|
||||||
log.warning("The analysis of the data produced %d detections!",
|
|
||||||
len(cmd.timeline_detected))
|
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
import logging
|
import logging
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from pymobiledevice3.exceptions import ConnectionFailedError
|
from pymobiledevice3.exceptions import (ConnectionFailedError,
|
||||||
|
FatalPairingError, NotTrustedError)
|
||||||
from pymobiledevice3.lockdown import LockdownClient
|
from pymobiledevice3.lockdown import LockdownClient
|
||||||
|
|
||||||
from mvt.common.command import Command
|
from mvt.common.command import Command
|
||||||
|
@ -35,11 +36,11 @@ class CmdIOSCheckUSB(Command):
|
||||||
self.lockdown = LockdownClient(udid=self.serial)
|
self.lockdown = LockdownClient(udid=self.serial)
|
||||||
else:
|
else:
|
||||||
self.lockdown = LockdownClient()
|
self.lockdown = LockdownClient()
|
||||||
except ConnectionRefusedError:
|
except NotTrustedError:
|
||||||
log.error("Unable to connect to the device over USB. Try to unplug, plug the device and start again.")
|
log.error("Trust this computer from the prompt appearing on the iOS device and try again")
|
||||||
sys.exit(-1)
|
sys.exit(-1)
|
||||||
except ConnectionFailedError:
|
except (ConnectionRefusedError, ConnectionFailedError, FatalPairingError):
|
||||||
log.error("Unable to connect to the device %s", self.serial)
|
log.error("Unable to connect to the device over USB: try to unplug, plug the device and start again")
|
||||||
sys.exit(-1)
|
sys.exit(-1)
|
||||||
|
|
||||||
def module_init(self, module):
|
def module_init(self, module):
|
||||||
|
|
58
mvt/ios/lockdown.py
Normal file
58
mvt/ios/lockdown.py
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
# Mobile Verification Toolkit (MVT)
|
||||||
|
# Copyright (c) 2021-2022 Claudio Guarnieri.
|
||||||
|
# Use of this software is governed by the MVT License 1.1 that can be found at
|
||||||
|
# https://license.mvt.re/1.1/
|
||||||
|
|
||||||
|
import os
|
||||||
|
import platform
|
||||||
|
|
||||||
|
from mvt.common.utils import secure_delete
|
||||||
|
|
||||||
|
|
||||||
|
class Lockdown:
|
||||||
|
|
||||||
|
def __init__(self, uuids: list = []) -> None:
|
||||||
|
self.uuids = uuids
|
||||||
|
self.lockdown_folder = self._get_lockdown_folder()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_lockdown_folder():
|
||||||
|
system = platform.system()
|
||||||
|
if system == "Linux":
|
||||||
|
return "/var/lib/lockdown/"
|
||||||
|
elif system == "Darwin":
|
||||||
|
return "/var/db/lockdown/"
|
||||||
|
elif system == "Windows":
|
||||||
|
return os.path.join(os.environ.get("ALLUSERSPROFILE", ""),
|
||||||
|
"Apple", "Lockdown")
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_pymobiledevice_folder():
|
||||||
|
return os.path.expanduser("~/.pymobiledevice3")
|
||||||
|
|
||||||
|
def delete_cert(self, cert_file) -> None:
|
||||||
|
if not self.lockdown_folder:
|
||||||
|
return
|
||||||
|
|
||||||
|
cert_path = os.path.join(self.lockdown_folder, cert_file)
|
||||||
|
if not os.path.exists(cert_path):
|
||||||
|
return
|
||||||
|
|
||||||
|
secure_delete(cert_path)
|
||||||
|
|
||||||
|
def find_certs(self) -> list:
|
||||||
|
if not self.lockdown_folder or not os.path.exists(self.lockdown_folder):
|
||||||
|
return []
|
||||||
|
|
||||||
|
lockdown_certs = []
|
||||||
|
for file_name in os.listdir(self.lockdown_folder):
|
||||||
|
if not file_name.endswith(".plist"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if file_name == "SystemConfiguration.plist":
|
||||||
|
continue
|
||||||
|
|
||||||
|
file_path = os.path.join(self.lockdown_folder, file_name)
|
||||||
|
lockdown_certs.append(file_path)
|
||||||
|
|
||||||
|
return sorted(lockdown_certs)
|
Loading…
Reference in New Issue
Block a user