จะถอดรหัสข้อมูลสำรอง Apple iTunes iPhone ที่เข้ารหัสได้อย่างไร


84

ฉันได้รับการร้องขอจากผู้ใช้ iPhone ที่โชคร้ายหลายคนให้ช่วยกู้คืนข้อมูลจากการสำรองข้อมูล iTunes ซึ่งทำได้ง่ายเมื่อไม่เข้ารหัส แต่ไม่ใช่เมื่อเข้ารหัสไม่ว่าจะทราบรหัสผ่านหรือไม่ก็ตาม

ดังนั้นฉันจึงพยายามหารูปแบบการเข้ารหัสที่ใช้กับไฟล์ mddata และ mdinfo เมื่อเข้ารหัส ฉันไม่มีปัญหาในการอ่านไฟล์เหล่านี้และได้สร้างไลบรารี C # ที่มีประสิทธิภาพสำหรับการทำเช่นนั้น (ถ้าคุณสามารถช่วยได้ฉันไม่สนใจว่าคุณจะใช้ภาษาใดมันเป็นหลักการที่ฉันอยู่ที่นี่!)

"คู่มือการปรับใช้ iPhone OS Enterprise" ของ Apple ระบุว่า "การสำรองข้อมูลอุปกรณ์สามารถจัดเก็บในรูปแบบที่เข้ารหัสได้โดยเลือกตัวเลือกเข้ารหัสการสำรองข้อมูล iPhone ในบานหน้าต่างสรุปอุปกรณ์ของ iTunes ไฟล์จะเข้ารหัสโดยใช้ AES128 ด้วยคีย์ 256 บิตที่สำคัญคือ จัดเก็บอย่างปลอดภัยในพวงกุญแจ iPhone "

นั่นเป็นเบาะแสที่ดีทีเดียวและมีข้อมูลที่ดีเกี่ยวกับ Stackoverflow บน iPhone AES / Rijndael ความสามารถในการทำงานร่วมกันที่แนะนำให้ใช้โหมดคีย์ขนาด 128 และ CBC

นอกเหนือจากการทำให้สับสนอื่น ๆ แล้วจำเป็นต้องมีคีย์และเวกเตอร์การเริ่มต้น (IV) / เกลือ

อาจมีคนคิดว่าคีย์ดังกล่าวเป็นการจัดการ "รหัสผ่านสำรอง" ที่ผู้ใช้จะได้รับแจ้งให้ป้อนโดย iTunes และส่งต่อไปยัง " AppleMobileBackup.exe " ซึ่งบรรจุในรูปแบบที่ CBC กำหนด อย่างไรก็ตามจากการอ้างอิงถึงพวงกุญแจ iPhone ฉันสงสัยว่า "รหัสผ่านสำรอง" อาจไม่ได้ใช้เป็นรหัสผ่านบนใบรับรอง X509 หรือคีย์ส่วนตัวแบบสมมาตรและอาจใช้ใบรับรองหรือคีย์ส่วนตัวเป็นคีย์ ( AESและกระบวนการเข้ารหัส / ถอดรหัส iTunes เป็นแบบสมมาตร)

IV เป็นอีกเรื่องหนึ่งและอาจมีไม่กี่อย่าง บางทีมันอาจจะเป็นหนึ่งในกุญแจยากรหัสลงใน iTunes หรือเข้าไปในอุปกรณ์ตัวเอง

แม้ว่าความคิดเห็นของ Apple ด้านบนจะแนะนำว่ามีคีย์อยู่ในพวงกุญแจของอุปกรณ์ แต่ฉันคิดว่านี่ไม่สำคัญ หนึ่งสามารถเรียกคืนการสำรองข้อมูลที่เข้ารหัสไปที่แตกต่างกันของอุปกรณ์ซึ่งแสดงให้เห็นข้อมูลทั้งหมดที่เกี่ยวข้องกับการถอดรหัสเป็นปัจจุบันในการกำหนดค่าการสำรองข้อมูลและ iTunes และสิ่ง แต่เพียงผู้เดียวบนอุปกรณ์ที่ไม่เกี่ยวข้องและ replacable ในบริบทนี้ แล้วกุญแจสำคัญอยู่ที่ไหน?

ฉันได้ระบุเส้นทางไว้ด้านล่างจากเครื่อง Windows แต่ก็มีความสำคัญมากไม่ว่าเราจะใช้ระบบปฏิบัติการใด

"\ appdata \ Roaming \ Apple Computer \ iTunes \ itunesprefs.xml" มี PList ที่มีรายการคำสั่ง "พวงกุญแจ" อยู่ในนั้น "\ programdata \ apple \ Lockdown \ 09037027da8f4bdefdea97d706703ca034c88bab.plist" ประกอบด้วย PList ที่มี "DeviceCertificate", "HostCertificate" และ "RootCertificate" ซึ่งทั้งหมดนี้ดูเหมือนจะเป็นใบรับรอง X509 ที่ถูกต้อง ไฟล์เดียวกันนี้ยังมีคีย์ที่ไม่สมมาตร "RootPrivateKey" และ "HostPrivateKey" (การอ่านของฉันแนะนำว่าสิ่งเหล่านี้อาจเป็น PKCS # 7 ที่ห่อหุ้มไว้) นอกจากนี้ในการสำรองข้อมูลแต่ละครั้งจะมีค่า "AuthSignature" และ "AuthData" ในไฟล์ Manifest.plist แม้ว่าจะมีการหมุนเมื่อแต่ละไฟล์ได้รับการสำรองข้อมูลเพิ่มขึ้น แต่ก็แนะนำว่าไม่มีประโยชน์ในฐานะคีย์เว้นแต่จะมีบางอย่างจริงๆ ค่อนข้างมีส่วนร่วม

มีสิ่งที่ทำให้เข้าใจผิดมากมายที่แนะนำให้รับข้อมูลจากการสำรองข้อมูลที่เข้ารหัสเป็นเรื่องง่าย มันไม่ใช่และสำหรับความรู้ของฉันมันยังไม่ได้ทำ การข้ามหรือปิดใช้งานการเข้ารหัสข้อมูลสำรองเป็นอีกเรื่องหนึ่งโดยสิ้นเชิงและไม่ใช่สิ่งที่ฉันต้องการทำ

นี่ไม่ได้เกี่ยวกับการแฮ็ค iPhone หรืออะไรทำนองนั้น ทั้งหมดที่ฉันอยู่ที่นี่คือวิธีการดึงข้อมูล (รูปภาพรายชื่อติดต่อ ฯลฯ ) จากข้อมูลสำรอง iTunes ที่เข้ารหัสเนื่องจากฉันไม่สามารถเข้ารหัสได้ ฉันได้ลองการเรียงสับเปลี่ยนทุกรูปแบบด้วยข้อมูลที่ฉันได้ใส่ไว้ข้างต้น แต่ไม่มีที่ไหนเลย ฉันขอขอบคุณสำหรับความคิดหรือเทคนิคที่อาจพลาดไป


3
อัปเดตตั้งแต่สามปีที่ผ่านมา: ฉันคิดออกและนำมารวมกันเป็นผลิตภัณฑ์ที่มีจำหน่ายอย่างอิสระ ฉันมาถูกทางแล้ว แต่มันยาก
Aidan Fitzpatrick

คุณมีลิงค์สำหรับผลิตภัณฑ์นั้นไหม
Thilo

1
ในขณะที่คุณถามว่ามันเป็นiPhone สำรองดูด ในขณะที่คุณจะเห็นว่ามีโปรแกรมรุ่นที่ต้องชำระเงิน แต่รุ่นเก่าฟรีแบบธรรมดาจะช่วยให้คุณสามารถรับไฟล์ที่เข้ารหัสได้ครั้งละ 4 ไฟล์
Aidan Fitzpatrick

1
ฉันเห็นว่าคุณสามารถถอดรหัสข้อมูลสำรอง 10.2 ได้ คุณช่วยแบ่งปันว่าคุณประสบความสำเร็จได้อย่างไร?
Niki

@Niki ฉันได้อัปเดตคำตอบของฉันด้านล่างสำหรับ iOS 10
andrewdotn

คำตอบ:


107

การรักษาความปลอดภัยนักวิจัย Jean-Baptiste Bédruneและฌอง Sigwald นำเสนอวิธีการที่จะทำเช่นนี้ที่สับ-in-the-กล่องอัมสเตอร์ดัม 2011

ตั้งแต่นั้นมา Apple ได้เปิดตัวเอกสารรายงานความปลอดภัยของ iOS พร้อมรายละเอียดเพิ่มเติมเกี่ยวกับคีย์และอัลกอริทึมและ Charlie Miller et al ได้เปิดตัวคู่มือiOS Hacker's Handbookซึ่งครอบคลุมเนื้อหาบางส่วนที่เหมือนกันในรูปแบบวิธีใช้ เมื่อ iOS ของ 10 แรกออกมามีการเปลี่ยนแปลงรูปแบบการสำรองข้อมูลที่แอปเปิ้ลไม่ได้เผยแพร่ในตอนแรก แต่หลายคนกลับวิศวกรรมการเปลี่ยนแปลงรูปแบบ

การสำรองข้อมูลที่เข้ารหัสนั้นยอดเยี่ยมมาก

สิ่งที่ยอดเยี่ยมเกี่ยวกับการสำรองข้อมูล iPhone ที่เข้ารหัสคือมีสิ่งต่างๆเช่นรหัสผ่าน WiFi ที่ไม่ได้อยู่ในการสำรองข้อมูลที่ไม่ได้เข้ารหัสตามปกติ ตามที่กล่าวไว้ในเอกสารรายงานความปลอดภัยของ iOS การสำรองข้อมูลที่เข้ารหัสนั้นถือว่า“ ปลอดภัยกว่า” ดังนั้น Apple จึงพิจารณาว่าควรรวมข้อมูลที่ละเอียดอ่อนไว้ในข้อมูลเหล่านี้

คำเตือนที่สำคัญ: เห็นได้ชัดว่าการถอดรหัสข้อมูลสำรองของอุปกรณ์ iOS ของคุณจะลบการเข้ารหัส เพื่อปกป้องความเป็นส่วนตัวและความปลอดภัยของคุณคุณควรเรียกใช้สคริปต์เหล่านี้บนเครื่องที่มีการเข้ารหัสแบบเต็มดิสก์เท่านั้น แม้ว่าผู้เชี่ยวชาญด้านความปลอดภัยจะสามารถเขียนซอฟต์แวร์ที่ปกป้องคีย์ในหน่วยความจำได้เช่นโดยใช้ฟังก์ชันที่เหมือนกับVirtualLock()และ SecureZeroMemory()เหนือสิ่งอื่นใดสคริปต์ Python เหล่านี้จะจัดเก็บคีย์การเข้ารหัสและรหัสผ่านของคุณไว้ในสตริงเพื่อให้ Python เก็บขยะ ซึ่งหมายความว่าคีย์ลับและรหัสผ่านของคุณจะอยู่ใน RAM สักระยะหนึ่งจากที่ใดสิ่งเหล่านี้จะรั่วไหลเข้าไปในไฟล์ swap ของคุณและลงในดิสก์ของคุณซึ่งฝ่ายตรงข้ามสามารถกู้คืนได้ สิ่งนี้เอาชนะจุดที่มีการสำรองข้อมูลที่เข้ารหัสอย่างสมบูรณ์

วิธีถอดรหัสข้อมูลสำรอง: ในทางทฤษฎี

เอกสารรายงานความปลอดภัยของ iOSอธิบายถึงแนวคิดพื้นฐานของคีย์ต่อไฟล์คลาสการป้องกันคีย์คลาสการป้องกันและคีย์แบ็กที่ดีกว่าที่ฉันทำได้ หากคุณยังไม่คุ้นเคยกับสิ่งเหล่านี้โปรดใช้เวลาสักครู่เพื่ออ่านส่วนที่เกี่ยวข้อง

ตอนนี้คุณรู้แล้วว่าทุกไฟล์ใน iOS ถูกเข้ารหัสด้วยคีย์การเข้ารหัสแบบสุ่มต่อไฟล์ของตัวเองเป็นของระดับการป้องกันและคีย์การเข้ารหัสต่อไฟล์จะถูกเก็บไว้ในข้อมูลเมตาของระบบไฟล์ซึ่งรวมอยู่ในคีย์คลาสการป้องกัน

ในการถอดรหัส:

  1. ถอดรหัส keybag ที่เก็บไว้ในการเข้ามาของBackupKeyBag Manifest.plistภาพรวมระดับสูงของโครงสร้างนี้จะได้รับในเอกสาร iPhone วิกิพีเดีย อธิบายถึงรูปแบบไบนารี: 4 ไบต์ประเภทสตริงฟิลด์ 4 ไบต์ big-ยาวเขตข้อมูลและแล้วค่าของตัวเอง

    ค่าที่สำคัญเป็น PBKDF2 ITERations และSALTเกลือป้องกันคู่DPSLและซ้ำนับDPICแล้วสำหรับแต่ละการป้องกันCLSที่WPKYสำคัญห่อ

  2. การใช้รหัสผ่านสำรองจะได้รับคีย์ 32 ไบต์โดยใช้เกลือ PBKDF2 ที่ถูกต้องและจำนวนการทำซ้ำ ใช้งานครั้งแรกรอบ SHA256 ด้วยDPSLและ DPICแล้วรอบ SHA1 ด้วยและITERSALT

    แกะห่อที่สำคัญแต่ละชนิดตาม RFC 3394

  3. ถอดรหัสฐานข้อมูลรายการโดยดึงคลาสการป้องกัน 4 ไบต์และคีย์ที่ยาวกว่าจากManifestKeyในManifest.plistและคลายออก ขณะนี้คุณมีฐานข้อมูล SQLite พร้อมข้อมูลเมตาของไฟล์ทั้งหมด

  4. สำหรับไฟล์ที่สนใจแต่ละไฟล์ให้รับคีย์การเข้ารหัสต่อไฟล์ที่เข้ารหัสคลาสและรหัสคลาสการป้องกันโดยดูในFiles.fileคอลัมน์ฐานข้อมูลเพื่อหา plist ไบนารีที่มีEncryptionKeyและ ProtectionClassรายการ ตัดแท็กความยาวสี่ไบต์เริ่มต้น EncryptionKeyก่อนใช้

    จากนั้นรับคีย์การถอดรหัสขั้นสุดท้ายโดยการแกะด้วยคีย์คลาสที่ไม่ได้ใส่รหัสผ่านสำรอง จากนั้นถอดรหัสไฟล์โดยใช้ AES ในโหมด CBC ด้วยศูนย์ IV

วิธีถอดรหัสข้อมูลสำรอง: ในทางปฏิบัติ

ก่อนอื่นคุณจะต้องมีการอ้างอิงไลบรารี หากคุณใช้ Mac โดยใช้ Python 2.7 หรือ 3.7 ที่ติดตั้ง homebrew คุณสามารถติดตั้งการอ้างอิงโดยใช้:

CFLAGS="-I$(brew --prefix)/opt/openssl/include" \
LDFLAGS="-L$(brew --prefix)/opt/openssl/lib" \    
    pip install biplist fastpbkdf2 pycrypto

ในรูปแบบซอร์สโค้ดที่รันได้นี่คือวิธีถอดรหัสไฟล์การตั้งค่ารายการเดียวจากข้อมูลสำรอง iPhone ที่เข้ารหัส:

#!/usr/bin/env python3.7
# coding: UTF-8

from __future__ import print_function
from __future__ import division

import argparse
import getpass
import os.path
import pprint
import random
import shutil
import sqlite3
import string
import struct
import tempfile
from binascii import hexlify

import Crypto.Cipher.AES # https://www.dlitz.net/software/pycrypto/
import biplist
import fastpbkdf2
from biplist import InvalidPlistException


def main():
    ## Parse options
    parser = argparse.ArgumentParser()
    parser.add_argument('--backup-directory', dest='backup_directory',
                    default='testdata/encrypted')
    parser.add_argument('--password-pipe', dest='password_pipe',
                        help="""\
Keeps password from being visible in system process list.
Typical use: --password-pipe=<(echo -n foo)
""")
    parser.add_argument('--no-anonymize-output', dest='anonymize',
                        action='store_false')
    args = parser.parse_args()
    global ANONYMIZE_OUTPUT
    ANONYMIZE_OUTPUT = args.anonymize
    if ANONYMIZE_OUTPUT:
        print('Warning: All output keys are FAKE to protect your privacy')

    manifest_file = os.path.join(args.backup_directory, 'Manifest.plist')
    with open(manifest_file, 'rb') as infile:
        manifest_plist = biplist.readPlist(infile)
    keybag = Keybag(manifest_plist['BackupKeyBag'])
    # the actual keys are unknown, but the wrapped keys are known
    keybag.printClassKeys()

    if args.password_pipe:
        password = readpipe(args.password_pipe)
        if password.endswith(b'\n'):
            password = password[:-1]
    else:
        password = getpass.getpass('Backup password: ').encode('utf-8')

    ## Unlock keybag with password
    if not keybag.unlockWithPasscode(password):
        raise Exception('Could not unlock keybag; bad password?')
    # now the keys are known too
    keybag.printClassKeys()

    ## Decrypt metadata DB
    manifest_key = manifest_plist['ManifestKey'][4:]
    with open(os.path.join(args.backup_directory, 'Manifest.db'), 'rb') as db:
        encrypted_db = db.read()

    manifest_class = struct.unpack('<l', manifest_plist['ManifestKey'][:4])[0]
    key = keybag.unwrapKeyForClass(manifest_class, manifest_key)
    decrypted_data = AESdecryptCBC(encrypted_db, key)

    temp_dir = tempfile.mkdtemp()
    try:
        # Does anyone know how to get Python’s SQLite module to open some
        # bytes in memory as a database?
        db_filename = os.path.join(temp_dir, 'db.sqlite3')
        with open(db_filename, 'wb') as db_file:
            db_file.write(decrypted_data)
        conn = sqlite3.connect(db_filename)
        conn.row_factory = sqlite3.Row
        c = conn.cursor()
        # c.execute("select * from Files limit 1");
        # r = c.fetchone()
        c.execute("""
            SELECT fileID, domain, relativePath, file
            FROM Files
            WHERE relativePath LIKE 'Media/PhotoData/MISC/DCIM_APPLE.plist'
            ORDER BY domain, relativePath""")
        results = c.fetchall()
    finally:
        shutil.rmtree(temp_dir)

    for item in results:
        fileID, domain, relativePath, file_bplist = item

        plist = biplist.readPlistFromString(file_bplist)
        file_data = plist['$objects'][plist['$top']['root'].integer]
        size = file_data['Size']

        protection_class = file_data['ProtectionClass']
        encryption_key = plist['$objects'][
            file_data['EncryptionKey'].integer]['NS.data'][4:]

        backup_filename = os.path.join(args.backup_directory,
                                    fileID[:2], fileID)
        with open(backup_filename, 'rb') as infile:
            data = infile.read()
            key = keybag.unwrapKeyForClass(protection_class, encryption_key)
            # truncate to actual length, as encryption may introduce padding
            decrypted_data = AESdecryptCBC(data, key)[:size]

        print('== decrypted data:')
        print(wrap(decrypted_data))
        print()

        print('== pretty-printed plist')
        pprint.pprint(biplist.readPlistFromString(decrypted_data))

##
# this section is mostly copied from parts of iphone-dataprotection
# http://code.google.com/p/iphone-dataprotection/

CLASSKEY_TAGS = [b"CLAS",b"WRAP",b"WPKY", b"KTYP", b"PBKY"]  #UUID
KEYBAG_TYPES = ["System", "Backup", "Escrow", "OTA (icloud)"]
KEY_TYPES = ["AES", "Curve25519"]
PROTECTION_CLASSES={
    1:"NSFileProtectionComplete",
    2:"NSFileProtectionCompleteUnlessOpen",
    3:"NSFileProtectionCompleteUntilFirstUserAuthentication",
    4:"NSFileProtectionNone",
    5:"NSFileProtectionRecovery?",

    6: "kSecAttrAccessibleWhenUnlocked",
    7: "kSecAttrAccessibleAfterFirstUnlock",
    8: "kSecAttrAccessibleAlways",
    9: "kSecAttrAccessibleWhenUnlockedThisDeviceOnly",
    10: "kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly",
    11: "kSecAttrAccessibleAlwaysThisDeviceOnly"
}
WRAP_DEVICE = 1
WRAP_PASSCODE = 2

class Keybag(object):
    def __init__(self, data):
        self.type = None
        self.uuid = None
        self.wrap = None
        self.deviceKey = None
        self.attrs = {}
        self.classKeys = {}
        self.KeyBagKeys = None #DATASIGN blob
        self.parseBinaryBlob(data)

    def parseBinaryBlob(self, data):
        currentClassKey = None

        for tag, data in loopTLVBlocks(data):
            if len(data) == 4:
                data = struct.unpack(">L", data)[0]
            if tag == b"TYPE":
                self.type = data
                if self.type > 3:
                    print("FAIL: keybag type > 3 : %d" % self.type)
            elif tag == b"UUID" and self.uuid is None:
                self.uuid = data
            elif tag == b"WRAP" and self.wrap is None:
                self.wrap = data
            elif tag == b"UUID":
                if currentClassKey:
                    self.classKeys[currentClassKey[b"CLAS"]] = currentClassKey
                currentClassKey = {b"UUID": data}
            elif tag in CLASSKEY_TAGS:
                currentClassKey[tag] = data
            else:
                self.attrs[tag] = data
        if currentClassKey:
            self.classKeys[currentClassKey[b"CLAS"]] = currentClassKey

    def unlockWithPasscode(self, passcode):
        passcode1 = fastpbkdf2.pbkdf2_hmac('sha256', passcode,
                                        self.attrs[b"DPSL"],
                                        self.attrs[b"DPIC"], 32)
        passcode_key = fastpbkdf2.pbkdf2_hmac('sha1', passcode1,
                                            self.attrs[b"SALT"],
                                            self.attrs[b"ITER"], 32)
        print('== Passcode key')
        print(anonymize(hexlify(passcode_key)))
        for classkey in self.classKeys.values():
            if b"WPKY" not in classkey:
                continue
            k = classkey[b"WPKY"]
            if classkey[b"WRAP"] & WRAP_PASSCODE:
                k = AESUnwrap(passcode_key, classkey[b"WPKY"])
                if not k:
                    return False
                classkey[b"KEY"] = k
        return True

    def unwrapKeyForClass(self, protection_class, persistent_key):
        ck = self.classKeys[protection_class][b"KEY"]
        if len(persistent_key) != 0x28:
            raise Exception("Invalid key length")
        return AESUnwrap(ck, persistent_key)

    def printClassKeys(self):
        print("== Keybag")
        print("Keybag type: %s keybag (%d)" % (KEYBAG_TYPES[self.type], self.type))
        print("Keybag version: %d" % self.attrs[b"VERS"])
        print("Keybag UUID: %s" % anonymize(hexlify(self.uuid)))
        print("-"*209)
        print("".join(["Class".ljust(53),
                    "WRAP".ljust(5),
                    "Type".ljust(11),
                    "Key".ljust(65),
                    "WPKY".ljust(65),
                    "Public key"]))
        print("-"*208)
        for k, ck in self.classKeys.items():
            if k == 6:print("")

            print("".join(
                [PROTECTION_CLASSES.get(k).ljust(53),
                str(ck.get(b"WRAP","")).ljust(5),
                KEY_TYPES[ck.get(b"KTYP",0)].ljust(11),
                anonymize(hexlify(ck.get(b"KEY", b""))).ljust(65),
                anonymize(hexlify(ck.get(b"WPKY", b""))).ljust(65),
            ]))
        print()

def loopTLVBlocks(blob):
    i = 0
    while i + 8 <= len(blob):
        tag = blob[i:i+4]
        length = struct.unpack(">L",blob[i+4:i+8])[0]
        data = blob[i+8:i+8+length]
        yield (tag,data)
        i += 8 + length

def unpack64bit(s):
    return struct.unpack(">Q",s)[0]
def pack64bit(s):
    return struct.pack(">Q",s)

def AESUnwrap(kek, wrapped):
    C = []
    for i in range(len(wrapped)//8):
        C.append(unpack64bit(wrapped[i*8:i*8+8]))
    n = len(C) - 1
    R = [0] * (n+1)
    A = C[0]

    for i in range(1,n+1):
        R[i] = C[i]

    for j in reversed(range(0,6)):
        for i in reversed(range(1,n+1)):
            todec = pack64bit(A ^ (n*j+i))
            todec += pack64bit(R[i])
            B = Crypto.Cipher.AES.new(kek).decrypt(todec)
            A = unpack64bit(B[:8])
            R[i] = unpack64bit(B[8:])

    if A != 0xa6a6a6a6a6a6a6a6:
        return None
    res = b"".join(map(pack64bit, R[1:]))
    return res

ZEROIV = "\x00"*16
def AESdecryptCBC(data, key, iv=ZEROIV, padding=False):
    if len(data) % 16:
        print("AESdecryptCBC: data length not /16, truncating")
        data = data[0:(len(data)/16) * 16]
    data = Crypto.Cipher.AES.new(key, Crypto.Cipher.AES.MODE_CBC, iv).decrypt(data)
    if padding:
        return removePadding(16, data)
    return data

##
# here are some utility functions, one making sure I don’t leak my
# secret keys when posting the output on Stack Exchange

anon_random = random.Random(0)
memo = {}
def anonymize(s):
    if type(s) == str:
        s = s.encode('utf-8')
    global anon_random, memo
    if ANONYMIZE_OUTPUT:
        if s in memo:
            return memo[s]
        possible_alphabets = [
            string.digits,
            string.digits + 'abcdef',
            string.ascii_letters,
            "".join(chr(x) for x in range(0, 256)),
        ]
        for a in possible_alphabets:
            if all((chr(c) if type(c) == int else c) in a for c in s):
                alphabet = a
                break
        ret = "".join([anon_random.choice(alphabet) for i in range(len(s))])
        memo[s] = ret
        return ret
    else:
        return s

def wrap(s, width=78):
    "Return a width-wrapped repr(s)-like string without breaking on \’s"
    s = repr(s)
    quote = s[0]
    s = s[1:-1]
    ret = []
    while len(s):
        i = s.rfind('\\', 0, width)
        if i <= width - 4: # "\x??" is four characters
            i = width
        ret.append(s[:i])
        s = s[i:]
    return '\n'.join("%s%s%s" % (quote, line ,quote) for line in ret)

def readpipe(path):
    if stat.S_ISFIFO(os.stat(path).st_mode):
        with open(path, 'rb') as pipe:
            return pipe.read()
    else:
        raise Exception("Not a pipe: {!r}".format(path))

if __name__ == '__main__':
    main()

ซึ่งจะพิมพ์ผลลัพธ์นี้:

Warning: All output keys are FAKE to protect your privacy
== Keybag
Keybag type: Backup keybag (1)
Keybag version: 3
Keybag UUID: dc6486c479e84c94efce4bea7169ef7d
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Class                                                WRAP Type       Key                                                              WPKY                                                             Public key
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
NSFileProtectionComplete                             2    AES                                                                         4c80b6da07d35d393fc7158e18b8d8f9979694329a71ceedee86b4cde9f97afec197ad3b13c5d12b
NSFileProtectionCompleteUnlessOpen                   2    AES                                                                         09e8a0a9965f00f213ce06143a52801f35bde2af0ad54972769845d480b5043f545fa9b66a0353a6
NSFileProtectionCompleteUntilFirstUserAuthentication 2    AES                                                                         e966b6a0742878ce747cec3fa1bf6a53b0d811ad4f1d6147cd28a5d400a8ffe0bbabea5839025cb5
NSFileProtectionNone                                 2    AES                                                                         902f46847302816561e7df57b64beea6fa11b0068779a65f4c651dbe7a1630f323682ff26ae7e577
NSFileProtectionRecovery?                            3    AES                                                                         a3935fed024cd9bc11d0300d522af8e89accfbe389d7c69dca02841df46c0a24d0067dba2f696072

kSecAttrAccessibleWhenUnlocked                       2    AES                                                                         09a1856c7e97a51a9c2ecedac8c3c7c7c10e7efa931decb64169ee61cb07a0efb115050fd1e33af1
kSecAttrAccessibleAfterFirstUnlock                   2    AES                                                                         0509d215f2f574efa2f192efc53c460201168b26a175f066b5347fc48bc76c637e27a730b904ca82
kSecAttrAccessibleAlways                             2    AES                                                                         b7ac3c4f1e04896144ce90c4583e26489a86a6cc45a2b692a5767b5a04b0907e081daba009fdbb3c
kSecAttrAccessibleWhenUnlockedThisDeviceOnly         3    AES                                                                         417526e67b82e7c6c633f9063120a299b84e57a8ffee97b34020a2caf6e751ec5750053833ab4d45
kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly     3    AES                                                                         b0e17b0cf7111c6e716cd0272de5684834798431c1b34bab8d1a1b5aba3d38a3a42c859026f81ccc
kSecAttrAccessibleAlwaysThisDeviceOnly               3    AES                                                                         9b3bdc59ae1d85703aa7f75d49bdc600bf57ba4a458b20a003a10f6e36525fb6648ba70e6602d8b2

== Passcode key
ee34f5bb635830d698074b1e3e268059c590973b0f1138f1954a2a4e1069e612

== Keybag
Keybag type: Backup keybag (1)
Keybag version: 3
Keybag UUID: dc6486c479e84c94efce4bea7169ef7d
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Class                                                WRAP Type       Key                                                              WPKY                                                             Public key
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
NSFileProtectionComplete                             2    AES        64e8fc94a7b670b0a9c4a385ff395fe9ba5ee5b0d9f5a5c9f0202ef7fdcb386f 4c80b6da07d35d393fc7158e18b8d8f9979694329a71ceedee86b4cde9f97afec197ad3b13c5d12b
NSFileProtectionCompleteUnlessOpen                   2    AES        22a218c9c446fbf88f3ccdc2ae95f869c308faaa7b3e4fe17b78cbf2eeaf4ec9 09e8a0a9965f00f213ce06143a52801f35bde2af0ad54972769845d480b5043f545fa9b66a0353a6
NSFileProtectionCompleteUntilFirstUserAuthentication 2    AES        1004c6ca6e07d2b507809503180edf5efc4a9640227ac0d08baf5918d34b44ef e966b6a0742878ce747cec3fa1bf6a53b0d811ad4f1d6147cd28a5d400a8ffe0bbabea5839025cb5
NSFileProtectionNone                                 2    AES        2e809a0cd1a73725a788d5d1657d8fd150b0e360460cb5d105eca9c60c365152 902f46847302816561e7df57b64beea6fa11b0068779a65f4c651dbe7a1630f323682ff26ae7e577
NSFileProtectionRecovery?                            3    AES        9a078d710dcd4a1d5f70ea4062822ea3e9f7ea034233e7e290e06cf0d80c19ca a3935fed024cd9bc11d0300d522af8e89accfbe389d7c69dca02841df46c0a24d0067dba2f696072

kSecAttrAccessibleWhenUnlocked                       2    AES        606e5328816af66736a69dfe5097305cf1e0b06d6eb92569f48e5acac3f294a4 09a1856c7e97a51a9c2ecedac8c3c7c7c10e7efa931decb64169ee61cb07a0efb115050fd1e33af1
kSecAttrAccessibleAfterFirstUnlock                   2    AES        6a4b5292661bac882338d5ebb51fd6de585befb4ef5f8ffda209be8ba3af1b96 0509d215f2f574efa2f192efc53c460201168b26a175f066b5347fc48bc76c637e27a730b904ca82
kSecAttrAccessibleAlways                             2    AES        c0ed717947ce8d1de2dde893b6026e9ee1958771d7a7282dd2116f84312c2dd2 b7ac3c4f1e04896144ce90c4583e26489a86a6cc45a2b692a5767b5a04b0907e081daba009fdbb3c
kSecAttrAccessibleWhenUnlockedThisDeviceOnly         3    AES        80d8c7be8d5103d437f8519356c3eb7e562c687a5e656cfd747532f71668ff99 417526e67b82e7c6c633f9063120a299b84e57a8ffee97b34020a2caf6e751ec5750053833ab4d45
kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly     3    AES        a875a15e3ff901351c5306019e3b30ed123e6c66c949bdaa91fb4b9a69a3811e b0e17b0cf7111c6e716cd0272de5684834798431c1b34bab8d1a1b5aba3d38a3a42c859026f81ccc
kSecAttrAccessibleAlwaysThisDeviceOnly               3    AES        1e7756695d337e0b06c764734a9ef8148af20dcc7a636ccfea8b2eb96a9e9373 9b3bdc59ae1d85703aa7f75d49bdc600bf57ba4a458b20a003a10f6e36525fb6648ba70e6602d8b2

== decrypted data:
'<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE plist PUBLIC "-//Apple//DTD '
'PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n<plist versi'
'on="1.0">\n<dict>\n\t<key>DCIMLastDirectoryNumber</key>\n\t<integer>100</integ'
'er>\n\t<key>DCIMLastFileNumber</key>\n\t<integer>3</integer>\n</dict>\n</plist'
'>\n'

== pretty-printed plist
{'DCIMLastDirectoryNumber': 100, 'DCIMLastFileNumber': 3}

สินเชื่อพิเศษ

รหัสป้องกันข้อมูลiphone ที่โพสต์โดยBédruneและ Sigwald สามารถถอดรหัสพวงกุญแจจากข้อมูลสำรองรวมถึงสิ่งสนุก ๆ เช่น wifi ที่บันทึกไว้และรหัสผ่านเว็บไซต์:

$ python iphone-dataprotection/python_scripts/keychain_tool.py ...

--------------------------------------------------------------------------------------
|                              Passwords                                             |
--------------------------------------------------------------------------------------
|Service           |Account          |Data           |Access group  |Protection class|
--------------------------------------------------------------------------------------
|AirPort           |Ed’s Coffee Shop |<3FrenchRoast  |apple         |AfterFirstUnlock|
...

รหัสดังกล่าวใช้ไม่ได้ในการสำรองข้อมูลจากโทรศัพท์ที่ใช้ iOS ล่าสุดอีกต่อไป แต่มีพอร์ตgolang บางพอร์ตที่ได้รับการอัปเดตอยู่เสมอเพื่อให้สามารถเข้าถึงพวงกุญแจได้


2
ฉันลองแล้วและได้ผลโดยที่เครื่องมืออื่น ๆ ล้มเหลว ฉันต้องเพิ่มโมดูล python ที่หายไปอีก: pip install --user pycrypto ขอบคุณ!
ALoopingIcon

2
วิเศษมาก! การใช้ macports ฉันติดตั้งการอ้างอิงเหล่านี้: py27-m2crypto py27-cryptography
hyperspasm

2
การเชื่อมโยง code.google.com ถูก 404ing สำหรับฉัน แต่ฉันพบรุ่นปรับปรุงของเครื่องมือ (สำหรับ OS X 10.10) ที่github.com/dinosec/iphone-dataprotection ทำงานบน OS X 10.11.5
Aaron Brager

2
ถ้าคุณจะอัปเดตโค้ดคุณจะใกล้เคียงกับเทพสำหรับฉัน!
Jonas Zaugg

3
@JonasZaugg ฉันได้อัปเดตโค้ดตัวอย่างสำหรับ iOS 10 แล้วฉันหวังว่าคุณจะพบว่ามีประโยชน์
andrewdotn

6

ขออภัยมันอาจจะซับซ้อนกว่านี้เกี่ยวข้องกับ pbkdf2 หรือแม้แต่รูปแบบของมัน ฟังเซสชัน WWDC 2010 # 209 ซึ่งส่วนใหญ่พูดถึงมาตรการรักษาความปลอดภัยใน iOS 4 แต่ยังกล่าวถึงการเข้ารหัสการสำรองข้อมูลแยกต่างหากโดยย่อและความเกี่ยวข้องกันอย่างไร

คุณค่อนข้างมั่นใจได้ว่าหากไม่ทราบรหัสผ่านก็ไม่มีทางที่คุณจะถอดรหัสได้แม้จะใช้กำลังดุร้ายก็ตาม

สมมติว่าคุณต้องการพยายามให้ผู้ที่รู้รหัสผ่านสามารถเข้าถึงข้อมูลสำรองของพวกเขาได้

ฉันกลัวว่าจะไม่มีวิธีใดในการดูรหัสจริงใน iTunes เพื่อดูว่าใช้ algos ตัวใด

ย้อนกลับไปในสมัยนิวตันฉันต้องถอดรหัสข้อมูลจากโปรแกรมและสามารถเรียกใช้ฟังก์ชันถอดรหัสได้โดยตรง (แน่นอนว่าต้องรู้รหัสผ่าน) โดยไม่จำเป็นต้องขีดเส้นใต้อัลกอริทึมด้วยซ้ำ ไม่ใช่เรื่องง่ายอีกต่อไป แต่น่าเสียดาย

ฉันแน่ใจว่ามีคนที่มีทักษะรอบตัวที่สามารถทำวิศวกรรมย้อนกลับรหัส iTunes - คุณต้องทำให้พวกเขาสนใจ

ตามทฤษฎีแล้ว algos ของ Apple ควรได้รับการออกแบบในลักษณะที่ทำให้ข้อมูลยังคงปลอดภัย (กล่าวคือไม่สามารถแตกได้จริงโดยวิธี brute force) สำหรับผู้โจมตีที่ทราบวิธีการเข้ารหัสที่แน่นอน และในเซสชั่น WWDC 209 พวกเขาได้ลงลึกในรายละเอียดเกี่ยวกับสิ่งที่พวกเขาทำเพื่อบรรลุเป้าหมายนี้ บางทีคุณอาจได้รับคำตอบโดยตรงจากทีมรักษาความปลอดภัยของ Apple หากคุณบอกเจตนาดีกับพวกเขา ท้ายที่สุดแม้ว่าพวกเขาควรรู้ว่าการรักษาความปลอดภัยโดยการทำให้สับสนนั้นไม่มีประสิทธิภาพจริงๆ ลองใช้รายชื่ออีเมลเพื่อความปลอดภัย แม้ว่าพวกเขาจะไม่ตอบกลับ แต่บางทีคนอื่นในรายการจะตอบกลับด้วยความช่วยเหลือ

โชคดี!


1

ยังไม่ได้ลองใช้ แต่ Elcomsoft เปิดตัวผลิตภัณฑ์ที่อ้างว่าสามารถถอดรหัสข้อมูลสำรองเพื่อวัตถุประสงค์ทางนิติเวช อาจจะไม่เจ๋งเท่าการแก้ปัญหาด้วยตัวคุณเอง แต่มันอาจเร็วกว่า

http://www.elcomsoft.com/eppb.html


1
ขอบคุณ. สิ่งนี้ไม่ได้ถอดรหัสการสำรองข้อมูลเช่นนี้เพียงแค่แตกคีย์ ฉันรู้วิธีทำอยู่แล้ว ... และง่ายกว่าการถอดรหัสข้อมูลสำรองเมื่อคุณมีคีย์
Aidan Fitzpatrick

-3

คุณควรคว้าสำเนายูทิลิตี้บรรทัดคำสั่ง mdhelper ของ Erica Sadun ( ไบนารีและแหล่งที่มาของOS X ) รองรับการแสดงรายการและแยกเนื้อหาของข้อมูลสำรองของ iPhone / iPod Touch รวมถึงสมุดที่อยู่และฐานข้อมูล SMS และข้อมูลเมตาและการตั้งค่าอื่น ๆ ของแอปพลิเคชัน


1
นั่นเป็นเพียงผู้อ่าน PList: ฉันสามารถทำสิ่งนั้นได้แล้ว ไม่รองรับการสำรองข้อมูลที่เข้ารหัสซึ่งเป็นสิ่งที่ฉันต้องการและอยู่นอกเหนือขอบเขตของยูทิลิตี้นั้น
Aidan Fitzpatrick

คุณใช้เวลาในการลองใช้ยูทิลิตี้นี้หรือไม่? ข้อมูลสำรองของฉันถูกเข้ารหัสและทำตามที่คุณพยายามทำ
Nathan de Vries

10
ใช่และฉันได้อ่านแหล่งที่มาแล้วด้วย ไม่จัดการข้อมูลสำรองที่เข้ารหัสและได้รับการแก้ไขล่าสุดก่อนที่จะปล่อยการสนับสนุนของ iTunes สำหรับการสำรองข้อมูลที่เข้ารหัส ฉันสงสัยว่าคุณหมายถึงการสำรองข้อมูลของคุณถูกเข้ารหัสหรือ iPhone ของคุณใช้ระบบไฟล์ที่เข้ารหัสซึ่งเป็นอีกเรื่องหนึ่งโดยสิ้นเชิง เช่นเดียวกับการไม่มีการรองรับการเข้ารหัสในรหัสเห็นได้ชัดว่าไม่มีตัวเลือกในการส่งรหัสผ่านในตัวเลือกบรรทัดคำสั่ง และรหัสไม่ได้ใช้ใบรับรองหรือพวงกุญแจใด ๆ ฉันชอบที่จะได้รับการพิสูจน์ว่าผิดในเรื่องนี้ แต่ฉันไม่คิดว่าตัวเองเป็น! ฉันขอขอบคุณสำหรับข้อเสนอแนะ
Aidan Fitzpatrick
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.