Adding support for iOS lockdown management

This commit is contained in:
Nex 2022-07-05 18:12:10 +02:00
parent 459ff8c51c
commit a30d7b2871
4 changed files with 156 additions and 37 deletions

View File

@ -5,6 +5,7 @@
import datetime
import hashlib
import os
import re
@ -119,3 +120,14 @@ def keys_bytes_to_string(obj) -> str:
new_obj[key] = value
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)

View File

@ -8,7 +8,8 @@ import os
import click
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.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_usb import CmdIOSCheckUSB
from .decrypt import DecryptBackup
from .lockdown import Lockdown
from .modules.backup import BACKUP_MODULES
from .modules.fs import FS_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))
#==============================================================================
# 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
#==============================================================================
@ -216,34 +295,3 @@ def check_iocs(ctx, iocs, list_modules, module, folder):
def download_iocs():
ioc_updates = IndicatorsUpdates()
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))

View File

@ -6,7 +6,8 @@
import logging
import sys
from pymobiledevice3.exceptions import ConnectionFailedError
from pymobiledevice3.exceptions import (ConnectionFailedError,
FatalPairingError, NotTrustedError)
from pymobiledevice3.lockdown import LockdownClient
from mvt.common.command import Command
@ -35,11 +36,11 @@ class CmdIOSCheckUSB(Command):
self.lockdown = LockdownClient(udid=self.serial)
else:
self.lockdown = LockdownClient()
except ConnectionRefusedError:
log.error("Unable to connect to the device over USB. Try to unplug, plug the device and start again.")
except NotTrustedError:
log.error("Trust this computer from the prompt appearing on the iOS device and try again")
sys.exit(-1)
except ConnectionFailedError:
log.error("Unable to connect to the device %s", self.serial)
except (ConnectionRefusedError, ConnectionFailedError, FatalPairingError):
log.error("Unable to connect to the device over USB: try to unplug, plug the device and start again")
sys.exit(-1)
def module_init(self, module):

58
mvt/ios/lockdown.py Normal file
View 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)