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 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)

View File

@ -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))

View File

@ -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
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)