"""iPhone Exploitation routes - Local USB device access via libimobiledevice.""" import os from flask import Blueprint, render_template, request, jsonify from web.auth import login_required iphone_exploit_bp = Blueprint('iphone_exploit', __name__, url_prefix='/iphone-exploit') def _get_mgr(): from core.iphone_exploit import get_iphone_manager return get_iphone_manager() def _get_udid(): data = request.get_json(silent=True) or {} udid = data.get('udid', '').strip() if not udid: return None, jsonify({'error': 'No UDID provided'}) return udid, None @iphone_exploit_bp.route('/') @login_required def index(): mgr = _get_mgr() status = mgr.get_status() return render_template('iphone_exploit.html', status=status) # ── Device Management ──────────────────────────────────────────── @iphone_exploit_bp.route('/devices', methods=['POST']) @login_required def list_devices(): return jsonify({'devices': _get_mgr().list_devices()}) @iphone_exploit_bp.route('/device-info', methods=['POST']) @login_required def device_info(): udid, err = _get_udid() if err: return err return jsonify(_get_mgr().device_info(udid)) @iphone_exploit_bp.route('/fingerprint', methods=['POST']) @login_required def fingerprint(): udid, err = _get_udid() if err: return err return jsonify(_get_mgr().full_fingerprint(udid)) @iphone_exploit_bp.route('/pair', methods=['POST']) @login_required def pair(): udid, err = _get_udid() if err: return err return jsonify(_get_mgr().pair_device(udid)) @iphone_exploit_bp.route('/unpair', methods=['POST']) @login_required def unpair(): udid, err = _get_udid() if err: return err return jsonify(_get_mgr().unpair_device(udid)) @iphone_exploit_bp.route('/validate-pair', methods=['POST']) @login_required def validate_pair(): udid, err = _get_udid() if err: return err return jsonify(_get_mgr().validate_pair(udid)) @iphone_exploit_bp.route('/get-name', methods=['POST']) @login_required def get_name(): udid, err = _get_udid() if err: return err return jsonify(_get_mgr().get_name(udid)) @iphone_exploit_bp.route('/set-name', methods=['POST']) @login_required def set_name(): udid, err = _get_udid() if err: return err data = request.get_json(silent=True) or {} name = data.get('name', '').strip() if not name: return jsonify({'error': 'No name provided'}) return jsonify(_get_mgr().set_name(udid, name)) @iphone_exploit_bp.route('/restart', methods=['POST']) @login_required def restart(): udid, err = _get_udid() if err: return err return jsonify(_get_mgr().restart_device(udid)) @iphone_exploit_bp.route('/shutdown', methods=['POST']) @login_required def shutdown(): udid, err = _get_udid() if err: return err return jsonify(_get_mgr().shutdown_device(udid)) @iphone_exploit_bp.route('/sleep', methods=['POST']) @login_required def sleep_dev(): udid, err = _get_udid() if err: return err return jsonify(_get_mgr().sleep_device(udid)) # ── Capture ────────────────────────────────────────────────────── @iphone_exploit_bp.route('/screenshot', methods=['POST']) @login_required def screenshot(): udid, err = _get_udid() if err: return err return jsonify(_get_mgr().screenshot(udid)) @iphone_exploit_bp.route('/syslog', methods=['POST']) @login_required def syslog(): udid, err = _get_udid() if err: return err data = request.get_json(silent=True) or {} duration = int(data.get('duration', 5)) return jsonify(_get_mgr().syslog_dump(udid, duration=duration)) @iphone_exploit_bp.route('/syslog-grep', methods=['POST']) @login_required def syslog_grep(): udid, err = _get_udid() if err: return err data = request.get_json(silent=True) or {} pattern = data.get('pattern', 'password|token|key|secret') duration = int(data.get('duration', 5)) return jsonify(_get_mgr().syslog_grep(udid, pattern, duration=duration)) @iphone_exploit_bp.route('/crash-reports', methods=['POST']) @login_required def crash_reports(): udid, err = _get_udid() if err: return err return jsonify(_get_mgr().crash_reports(udid)) # ── Apps ───────────────────────────────────────────────────────── @iphone_exploit_bp.route('/apps/list', methods=['POST']) @login_required def list_apps(): udid, err = _get_udid() if err: return err data = request.get_json(silent=True) or {} app_type = data.get('type', 'user') return jsonify(_get_mgr().list_apps(udid, app_type=app_type)) @iphone_exploit_bp.route('/apps/install', methods=['POST']) @login_required def install_app(): udid = request.form.get('udid', '').strip() if not udid: return jsonify({'error': 'No UDID provided'}) f = request.files.get('file') if not f: return jsonify({'error': 'No file uploaded'}) from core.paths import get_uploads_dir upload_path = str(get_uploads_dir() / f.filename) f.save(upload_path) return jsonify(_get_mgr().install_app(udid, upload_path)) @iphone_exploit_bp.route('/apps/uninstall', methods=['POST']) @login_required def uninstall_app(): udid, err = _get_udid() if err: return err data = request.get_json(silent=True) or {} bundle_id = data.get('bundle_id', '').strip() if not bundle_id: return jsonify({'error': 'No bundle_id provided'}) return jsonify(_get_mgr().uninstall_app(udid, bundle_id)) # ── Backup & Extraction ───────────────────────────────────────── @iphone_exploit_bp.route('/backup/create', methods=['POST']) @login_required def backup_create(): udid, err = _get_udid() if err: return err data = request.get_json(silent=True) or {} encrypted = data.get('encrypted', False) password = data.get('password', '') return jsonify(_get_mgr().create_backup(udid, encrypted=encrypted, password=password)) @iphone_exploit_bp.route('/backup/list', methods=['POST']) @login_required def backup_list(): return jsonify(_get_mgr().list_backups()) @iphone_exploit_bp.route('/backup/sms', methods=['POST']) @login_required def backup_sms(): data = request.get_json(silent=True) or {} backup_path = data.get('backup_path', '').strip() if not backup_path: return jsonify({'error': 'No backup_path provided'}) return jsonify(_get_mgr().extract_backup_sms(backup_path)) @iphone_exploit_bp.route('/backup/contacts', methods=['POST']) @login_required def backup_contacts(): data = request.get_json(silent=True) or {} backup_path = data.get('backup_path', '').strip() if not backup_path: return jsonify({'error': 'No backup_path provided'}) return jsonify(_get_mgr().extract_backup_contacts(backup_path)) @iphone_exploit_bp.route('/backup/calls', methods=['POST']) @login_required def backup_calls(): data = request.get_json(silent=True) or {} backup_path = data.get('backup_path', '').strip() if not backup_path: return jsonify({'error': 'No backup_path provided'}) return jsonify(_get_mgr().extract_backup_call_log(backup_path)) @iphone_exploit_bp.route('/backup/notes', methods=['POST']) @login_required def backup_notes(): data = request.get_json(silent=True) or {} backup_path = data.get('backup_path', '').strip() if not backup_path: return jsonify({'error': 'No backup_path provided'}) return jsonify(_get_mgr().extract_backup_notes(backup_path)) @iphone_exploit_bp.route('/backup/files', methods=['POST']) @login_required def backup_files(): data = request.get_json(silent=True) or {} backup_path = data.get('backup_path', '').strip() if not backup_path: return jsonify({'error': 'No backup_path provided'}) domain = data.get('domain', '') path_filter = data.get('path_filter', '') return jsonify(_get_mgr().list_backup_files(backup_path, domain=domain, path_filter=path_filter)) @iphone_exploit_bp.route('/backup/extract-file', methods=['POST']) @login_required def backup_extract_file(): data = request.get_json(silent=True) or {} backup_path = data.get('backup_path', '').strip() file_hash = data.get('file_hash', '').strip() if not backup_path or not file_hash: return jsonify({'error': 'Missing backup_path or file_hash'}) output_name = data.get('output_name') or None return jsonify(_get_mgr().extract_backup_file(backup_path, file_hash, output_name=output_name)) # ── Filesystem ─────────────────────────────────────────────────── @iphone_exploit_bp.route('/fs/mount', methods=['POST']) @login_required def fs_mount(): udid, err = _get_udid() if err: return err return jsonify(_get_mgr().mount_filesystem(udid)) @iphone_exploit_bp.route('/fs/mount-app', methods=['POST']) @login_required def fs_mount_app(): udid, err = _get_udid() if err: return err data = request.get_json(silent=True) or {} bundle_id = data.get('bundle_id', '').strip() if not bundle_id: return jsonify({'error': 'No bundle_id provided'}) return jsonify(_get_mgr().mount_app_documents(udid, bundle_id)) @iphone_exploit_bp.route('/fs/unmount', methods=['POST']) @login_required def fs_unmount(): data = request.get_json(silent=True) or {} mountpoint = data.get('mountpoint', '').strip() if not mountpoint: return jsonify({'error': 'No mountpoint provided'}) _get_mgr().unmount_filesystem(mountpoint) return jsonify({'success': True, 'output': 'Unmounted'}) # ── Profiles ───────────────────────────────────────────────────── @iphone_exploit_bp.route('/profiles/list', methods=['POST']) @login_required def profiles_list(): udid, err = _get_udid() if err: return err return jsonify(_get_mgr().list_profiles(udid)) @iphone_exploit_bp.route('/profiles/install', methods=['POST']) @login_required def profiles_install(): udid = request.form.get('udid', '').strip() if not udid: return jsonify({'error': 'No UDID provided'}) f = request.files.get('file') if not f: return jsonify({'error': 'No file uploaded'}) from core.paths import get_uploads_dir upload_path = str(get_uploads_dir() / f.filename) f.save(upload_path) return jsonify(_get_mgr().install_profile(udid, upload_path)) @iphone_exploit_bp.route('/profiles/remove', methods=['POST']) @login_required def profiles_remove(): udid, err = _get_udid() if err: return err data = request.get_json(silent=True) or {} profile_id = data.get('profile_id', '').strip() if not profile_id: return jsonify({'error': 'No profile_id provided'}) return jsonify(_get_mgr().remove_profile(udid, profile_id)) # ── Network ────────────────────────────────────────────────────── @iphone_exploit_bp.route('/port-forward', methods=['POST']) @login_required def port_forward(): udid, err = _get_udid() if err: return err data = request.get_json(silent=True) or {} local_port = data.get('local_port') device_port = data.get('device_port') if not local_port or not device_port: return jsonify({'error': 'Missing local_port or device_port'}) return jsonify(_get_mgr().port_forward(udid, int(local_port), int(device_port))) # ── Recon ──────────────────────────────────────────────────────── @iphone_exploit_bp.route('/recon/export', methods=['POST']) @login_required def recon_export(): udid, err = _get_udid() if err: return err return jsonify(_get_mgr().export_recon_report(udid))