암호화 된 Apple iTunes iPhone 백업을 해독하는 방법은 무엇입니까?


84

많은 불행한 iPhone 사용자로부터 iTunes 백업에서 데이터를 복원하도록 도와 달라는 요청을 받았습니다. 암호화되지 않은 경우에는 쉽지만 암호를 알고 있는지 여부에 관계없이 암호화 된 경우에는 그렇지 않습니다.

따라서 암호화 할 때 mddata 및 mdinfo 파일에 사용되는 암호화 체계를 파악하려고합니다. 다른 방법으로는이 파일을 읽는 데 문제가 없으며이를 위해 강력한 C # 라이브러리를 구축했습니다. (도움이된다면 어떤 언어를 사용하든 상관 없습니다. 이것이 제가 여기서 추구하는 원칙입니다!)

Apple "iPhone OS Enterprise Deployment Guide"에 따르면 "iTunes의 장비 요약 창에서 iPhone 백업 암호화 옵션을 선택하여 장비 백업을 암호화 된 형식으로 저장할 수 있습니다. 파일은 256 비트 키로 AES128을 사용하여 암호화됩니다. 키는 다음과 같습니다. iPhone 키 체인에 안전하게 저장됩니다. "

그것은 꽤 좋은 단서이며 여기에 iPhone AES / Rijndael 상호 운용성 에 대한 Stackoverflow에 대한 몇 가지 좋은 정보가 있습니다. 이는 키 크기가 128이고 CBC 모드가 사용될 수 있음을 시사합니다.

다른 난독 화 외에도 키 및 초기화 벡터 (IV) / 소금이 필요합니다.

키가 사용자가 iTunes에서 입력하라는 메시지를 표시 하고 CBC에서 지정한 방식으로 패딩 된 " AppleMobileBackup.exe "로 전달되는 "백업 암호"의 조작이라고 가정 할 수 있습니다 . 그러나 iPhone 키 체인에 대한 참조를 고려할 때 "백업 암호"가 X509 인증서 또는 대칭 개인 키에서 암호로 사용되지 않을 수 있는지, 인증서 또는 개인 키 자체가 키로 사용될 수 있는지 궁금합니다. ( AES 와 iTunes 암호화 / 복호화 프로세스는 대칭입니다.)

IV는 또 다른 문제이며 몇 가지가 될 수 있습니다. 아마도 iTunes 또는 기기 자체에 하드 코딩 된 키 중 하나 일 것입니다 .

위의 Apple의 의견은 키가 기기의 키 체인에 있음을 시사하지만, 이것이 그렇게 중요하지 않다고 생각합니다. 암호화 된 백업을 다른 장치 로 복원 할 수 있는데, 이는 암호 해독과 관련된 모든 정보가 백업 및 iTunes 구성에 있으며 장치에있는 모든 정보는이 맥락에서 관련이 없으며 대체 할 수 없음을 나타냅니다. 그렇다면 열쇠는 어디에 있습니까?

아래에 Windows 시스템의 경로를 나열했지만 우리가 사용하는 OS에 관계없이 많은 부분을 차지합니다.

"\ appdata \ Roaming \ Apple Computer \ iTunes \ itunesprefs.xml"에는 "Keychain"dict 항목이있는 PList가 포함되어 있습니다. "\ programdata \ apple \ Lockdown \ 09037027da8f4bdefdea97d706703ca034c88bab.plist"에는 "DeviceCertificate", "HostCertificate"및 "RootCertificate"가 포함 된 PList가 포함되어 있으며 모두 유효한 X509 인증서로 보입니다. 동일한 파일에는 "RootPrivateKey"및 "HostPrivateKey"비대칭 키도 포함되어있는 것으로 보입니다 (제가 읽은 결과 PKCS # 7-enveloped 일 수 있음). 또한 각 백업 내에 Manifest.plist 파일에 "AuthSignature"및 "AuthData"값이 있습니다. 각 파일이 증분 백업 될 때 회전하는 것처럼 보이지만 실제로 뭔가가없는 한 키로 유용하지 않다고 제안했습니다. 상당히 관여하고 있습니다.

암호화 된 백업에서 데이터를 가져 오는 것이 쉽다는 잘못된 정보가 많이 있습니다. 그것은 아닙니다. 그리고 제가 아는 한 그것은 이루어지지 않았습니다. 백업 암호화를 우회하거나 비활성화 하는 것은 전적으로 또 다른 문제이며 제가하려는 것이 아닙니다.

이것은 아이폰이나 그와 비슷한 것을 해킹하는 것이 아닙니다. 내가 여기서 추구하는 것은 암호화되지 않은 iTunes 백업에서 데이터 (사진, 연락처 등)를 추출하는 수단입니다. 나는 위에 적어 놓은 정보로 모든 종류의 순열을 시도했지만 어디에도 없습니다. 내가 놓친 생각이나 기술에 감사드립니다.


3
3 년 후의 업데이트 : 나는 그것을 파악하고 자유롭게 사용할 수있는 제품으로 롤링했습니다. 나는 위의 올바른 길을 가고 있었지만 힘들었습니다.
Aidan Fitzpatrick 2012 년

해당 제품에 대한 링크가 있습니까?
Thilo

1
요청하신대로 iPhone Backup Extractor 입니다. 프로그램의 유료 버전이 있지만 평범한 이전 무료 버전을 사용하면 한 번에 4 개의 암호화 된 파일을 가져올 수 있습니다.
Aidan Fitzpatrick

1
10.2 백업의 암호를 해독 한 것을 확인했습니다. 어떻게 성취했는지 공유해 주시겠습니까?
Niki

@Niki iOS 10에 대한 아래 내 답변을 업데이트했습니다
andrewdotn

답변:


105

보안 연구원 Jean-Baptiste Bédrune과 Jean Sigwald Hack-in-the-box Amsterdam 2011 에서 이를 수행하는 방법을 발표했습니다 .

그 이후로 Apple은 키 및 알고리즘에 대한 자세한 내용 이 포함 된 iOS 보안 백서 를 발표 했으며 Charlie Miller et al. 하우투 방식으로 동일한 영역을 다루는 iOS Hacker 's Handbook 을 발표했습니다 . iOS 10이 처음 나왔을 때 Apple이 처음에 공개하지 않은 백업 형식이 변경되었지만 여러 사람들 이 형식 변경을 리버스 엔지니어링했습니다 .

암호화 된 백업은 훌륭합니다

암호화 된 iPhone 백업의 가장 좋은 점은 암호화되지 않은 일반 백업에없는 WiFi 암호와 같은 항목이 포함되어 있다는 것입니다. iOS 보안 백서 에서 논의한 것처럼 암호화 된 백업은 더 "안전한"것으로 간주되므로 Apple은 더 민감한 정보를 포함해도 괜찮다고 생각합니다.

중요한 경고 : 분명히 iOS 기기의 백업을 해독하면 암호화가 제거됩니다. 개인 정보와 보안을 보호하려면 전체 디스크 암호화를 사용하는 시스템에서만 이러한 스크립트를 실행해야합니다. 이 같은 함수를 사용하여 예를 들어 메모리에 키를 보호 쓰기 소프트웨어 보안 전문가에 대한 수 있지만 VirtualLock()SecureZeroMemory()많은 다른 것들 중, 문자열의 암호화 키 및 암호를 저장합니다이 파이썬 스크립트는 가비지 수집 파이썬으로합니다. 즉, 비밀 키와 암호가 잠시 동안 RAM에 저장되어 스왑 파일과 디스크로 유출되어 공격자가이를 복구 할 수 있습니다. 이것은 암호화 된 백업의 요점을 완전히 무효화합니다.

백업 암호 해독 방법 : 이론상

아이폰 OS 보안 백서는 내가 할 수있는 것보다 당 파일 키, 보호 등급, 보호 등급 키, 그리고 더 나은 keybags의 기본 개념을 설명합니다. 이것에 익숙하지 않은 경우 몇 분 동안 관련 부분을 읽으십시오.

이제 iOS의 모든 파일이 임의의 파일 별 암호화 키로 암호화되고 보호 클래스에 속하며 파일 별 암호화 키가 보호 클래스 키에 래핑 된 파일 시스템 메타 데이터에 저장된다는 것을 알았습니다.

암호를 해독하려면 :

  1. BackupKeyBag항목에 저장된 키백을 디코딩합니다 Manifest.plist. 이 구조에 대한 높은 수준의 개요는 백서에 나와 있습니다. 아이폰 위키는 4 바이트 문자열 유형 필드, 4 바이트 빅 엔디안 길이 필드, 다음 값 자체 : 바이너리 형식을 설명합니다.

    중요한 값은 PBKDF2 ITERSALT, 이중 보호 솔트 DPSL및 반복 횟수 DPIC, 그리고 각 보호 CLS에 대해 WPKY래핑 된 키입니다.

  2. 백업 암호를 사용하여 올바른 PBKDF2 솔트 및 반복 횟수를 사용하여 32 바이트 키를 파생합니다. 첫 번째와 SHA256 내내 사용 DPSL하고 DPIC, 다음과 SHA1 라운드 ITERSALT.

    RFC 3394 에 따라 래핑 된 각 키를 풉니 다 .

  3. ManifestKeyin 에서 4 바이트 보호 클래스와 더 긴 키를 가져 와서 압축을 풀어 매니페스트 데이터베이스를 해독합니다 Manifest.plist. 이제 모든 파일 메타 데이터가 포함 된 SQLite 데이터베이스가 있습니다.

  4. 관심있는 각 파일에 대해 및 항목을 Files.file포함하는 이진 plist 에 대한 데이터베이스 열을 찾아서 클래스 암호화 파일 별 암호화 키 및 보호 클래스 코드를 가져옵니다 . 사용하기 전에 초기 4 바이트 길이 태그를 제거하십시오 .EncryptionKeyProtectionClassEncryptionKey

    그런 다음 백업 암호로 래핑 해제 된 클래스 키로 래핑을 해제하여 최종 암호 해독 키를 파생합니다. 그런 다음 IV가 0 인 CBC 모드에서 AES를 사용하여 파일을 해독합니다.

백업 암호 해독 방법 : 실제로

먼저 라이브러리 종속성이 필요합니다. 홈브류 설치 Python 2.7 또는 3.7을 사용하는 Mac을 사용하는 경우 다음을 사용하여 종속성을 설치할 수 있습니다.

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}

추가 크레딧

아이폰 - dataprotection 코드는 해독 할 수 Bédrune 및 Sigwald 게시 한 키 체인을 저장 와이파이 및 웹 사이트 암호와 같은 재미있는 것들을 포함하여, 백업에서 :

$ 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
나는 그것을 시도했고 다른 모든 도구가 실패한 곳에서 작동했습니다. 또 다른 누락 된 파이썬 모듈을 추가해야했습니다. pip install --user pycrypto 감사합니다!
ALoopingIcon

2
훌륭한! macports를 사용하여 다음 종속성을 설치했습니다. py27-m2crypto py27-cryptography
hyperspasm

2
code.google.com 링크는 404ing 이었지만 github.com/dinosec/iphone-dataprotection에서 업데이트 된 버전의 도구 (OS X 10.10 용)를 찾았습니다 . OS X 10.11.5에서 작동했습니다.
아론 Brager

2
당신이 코드를 업데이트한다면, 당신은 나를 위해 신과 가까워 질 것입니다!
Jonas Zaugg

3
@JonasZaugg iOS 10 용 샘플 코드를 업데이트했습니다. 도움이 되셨기를 바랍니다.
andrewdotn

6

미안하지만 pbkdf2 또는 그 변형과 관련하여 더 복잡 할 수 있습니다. 주로 iOS 4의 보안 조치에 대해 이야기하지만 백업의 개별 암호화 및 관련 방법에 대해 간략하게 설명하는 WWDC 2010 세션 # 209를 들어보십시오.

암호를 모르면 무차별 대입으로도 암호를 해독 할 수 없습니다.

암호를 알고있는 사람들이 백업 데이터에 액세스 할 수 있도록하려고한다고 가정 해 보겠습니다.

어떤 알고리즘이 사용되는지 알아 내기 위해 iTunes에서 실제 코드를 살펴볼 방법이 없을까 두렵습니다.

Newton 시절에 저는 프로그램에서 데이터를 해독해야했고 알고리즘을 이해하지 않고도 암호 해독 기능을 직접 호출 할 수있었습니다 (물론 암호를 알고 있음). 불행히도 더 이상 쉽지 않습니다.

iTunes 코드를 리버스 엔지니어링 할 수있는 숙련 된 사람들이있을 것입니다. 관심을 갖기 만하면됩니다.

이론적으로 Apple의 알고리즘은 정확한 암호화 방법을 알고있는 모든 공격자에게 데이터를 여전히 안전하게 (즉, 무차별 대입 방법으로 거의 깨지지 않는) 방식으로 설계해야합니다. 그리고 WWDC 세션 209에서 그들은 이것을 달성하기 위해 무엇을하는지에 대한 세부 사항에 대해 자세히 설명했습니다. 좋은 의도를 말하면 실제로 Apple의 보안 팀으로부터 직접 답변을 얻을 수 있습니다. 결국 그들은 난독 화에 의한 보안이 실제로 효율적이지 않다는 것을 알아야합니다. 보안 메일 링리스트를 사용해보십시오. 그들이 응답하지 않더라도 목록에있는 다른 누군가가 약간의 도움으로 응답 할 것입니다.

행운을 빕니다!


1

시도하지 않았지만 Elcomsoft는 법의학 목적으로 백업을 해독 할 수 있다고 주장하는 제품을 출시했습니다. 솔루션을 직접 설계하는 것만 큼 멋지지는 않지만 더 빠를 수 있습니다.

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


1
감사. 이것은 백업을 해독하는 것이 아니라 키를 해독 할뿐입니다. 나는 이미 그것을하는 방법을 알고 있습니다 ... 그리고 그것은 당신이 키를 가지고 있으면 백업을 해독하는 것보다 훨씬 간단합니다.
Aidan Fitzpatrick

-3

Erica Sadun의 mdhelper 명령 줄 유틸리티 ( OS X 바이너리소스 ) 사본을 가져와야 합니다. 주소록 및 SMS 데이터베이스, 기타 애플리케이션 메타 데이터 및 설정을 포함하여 iPhone / iPod Touch 백업의 내용을 나열하고 추출하는 것을 지원합니다.


1
그것은 단지 PList 리더 일뿐입니다. 저는 이미 그 일을 기본적으로 할 수 있습니다. 내가 추구하는 암호화 된 백업은 지원하지 않으며 해당 유틸리티의 범위를 벗어납니다.
Aidan Fitzpatrick

시간을내어 유틸리티를 사용해 보셨습니까? 내 백업은 암호화되어 있으며 사용자가하려는 작업을 정확히 수행합니다.
Nathan de Vries

10
예, 저도 소스를 읽었습니다. 암호화 된 백업을 처리하지 않으며, 암호화 된 백업에 대한 iTunes의 지원이 출시되기 전에 마지막으로 수정되었습니다. 백업이 인코딩되었거나 iPhone이 암호화 된 파일 시스템을 사용한다는 뜻이라고 생각합니다. 이는 완전히 또 다른 문제입니다. 코드에서 암호화를 지원하지 않을뿐만 아니라 명령 줄 옵션에서 암호를 전달할 수있는 옵션이 더 분명합니다. 그리고 코드는 인증서 나 키 체인을 사용하지 않습니다. 나는 이것에 대해 틀렸다는 것을 증명하고 싶지만 나는 정말로 내가 생각하지 않는다! 그래도 제안에 감사드립니다.
Aidan Fitzpatrick
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.