Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Jailbreaking Apple Watch

Jailbreaking Apple Watch

DEFCON 25, Las Vegas, NV

Max Bazaliy

July 27, 2017
Tweet

More Decks by Max Bazaliy

Other Decks in Technology

Transcript

  1. July 27-30, 2017
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    Max Bazaliy
    Jailbreaking
    Apple Watch

    View full-size slide

  2. July 27-30, 2017
    whoami 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    o  Security researcher at Lookout
    o  Lead researcher on Pegasus exploit chain
    o  Focused on advanced exploitation techniques
    o  Fried Apple team co-founder
    o  iOS/tvOS/WatchOS jailbreak author

    View full-size slide

  3. July 27-30, 2017
    o  Released in 2015
    o  Apple S1/S2 processor
    o  ARMv7k 32 bit architecture
    o  Taptic engine
    o  512 MB RAM
    o  WatchOS
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    What is Apple Watch ?

    View full-size slide

  4. July 27-30, 2017
    o  Access to file system
    o  Run tools like radare or frida on a watch
    o  iPhone attack vector
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    Why to jailbreak a watch ?

    View full-size slide

  5. July 27-30, 2017
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    Apple Watch security
    o  Secure boot chain
    o  Mandatory Code Signing
    o  Sandbox
    o  Exploit Mitigations
    o  Secure Enclave Processor (2-nd gen only)
    o  Data Protection

    View full-size slide

  6. July 27-30, 2017
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    Possible attack vectors
    o  Malformed USB descriptor over debug port
    Debug port

    View full-size slide

  7. July 27-30, 2017
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    Possible attack vectors
    o  Malformed email, message, photo, etc
    Still limited by sandbox
    o  Application extension based
    More freedom on bug choice

    View full-size slide

  8. July 27-30, 2017
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    Jailbreak step by step
    o  Leak kernel base
    o  Dump whole kernel
    o  Find gadgets and setup primitives
    o  Disable security restrictions
    o  Run ssh client on a watch

    View full-size slide

  9. July 27-30, 2017
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    Bugs of interest
    o  WatchOS 2.x
    - CVE-2016-4656 - osunserialize bug
    - CVE-2016-4669 - mach_port register bug
    o  WatchOS 3.1.3
    - CVE-2016-7644 - set_dp_control_port bug
    - CVE-2017-2370 - voucher extract recipe bug

    View full-size slide

  10. July 27-30, 2017
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    Leaking kernel base
    o  CVE-2016-4655 and CVE-2016-4680
    o  Object constructor missing bounds checking
    o  OSNumber object with high number of bits
    o  Object length used to copy value from stack
    o  Kernel stack memory leaked
    o  Can be triggered from an app’s sandbox

    View full-size slide

  11. July 27-30, 2017
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    OSObject * OSUnserializeBinary(const char *buffer, size_t bufferSize,
    OSString **errorString) {
    uint32_t key, len, wordLen;
    len = (key & kOSSerializeDataMask);
    ...
    case kOSSerializeNumber:
    bufferPos += sizeof(long long);
    if (bufferPos > bufferSize) break;
    value = next[1];
    value <<= 32;
    value |= next[0];
    o = OSNumber::withNumber(value, len);
    next += 2;
    break;
    No number length check

    View full-size slide

  12. July 27-30, 2017
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    bool OSNumber::init(unsigned long long inValue,
    unsigned int newNumberOfBits) {
    if (!super::init())
    return false;
    size = newNumberOfBits;
    value = (inValue & sizeMask);
    return true;
    }
    unsigned int OSNumber::numberOfBytes() const {
    return (size + 7) / 8;
    }
    No number length check
    Return value is under control

    View full-size slide

  13. July 27-30, 2017
    kern_return_t is_io_registry_entry_get_property_bytes( io_object_t registry_entry,
    io_name_t property_name, io_struct_inband_t buf, … ) {
    ...
    UInt64 offsetBytes; // stack based buffer
    ...
    } else if( (off = OSDynamicCast( OSNumber, obj ))) {
    offsetBytes = off->unsigned64BitValue();
    len = off->numberOfBytes();
    bytes = &offsetBytes;
    ...
    if (bytes) {
    if( *dataCnt < len)
    ret = kIOReturnIPCError;
    else {
    *dataCnt = len;
    bcopy( bytes, buf, len ); // copy from stack based buffer
    Will be returned to userland
    We control this value
    Points to stack based buffer
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24

    View full-size slide

  14. July 27-30, 2017
    CVE-2016-4656 exploitation
    o  Kernel mode UAF in OSUnserializeBinary
    o  OSString object deallocated
    o  retain() called on deallocated object
    o  Fake object with fake vtable –> code exec
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24

    View full-size slide

  15. July 27-30, 2017
    OSObject * OSUnserializeBinary(const char *buffer, size_t bufferSize, …) {
    newCollect = isRef = false;
    ...
    case kOSSerializeDictionary:
    o = newDict = OSDictionary::withCapacity(len);
    newCollect = (len != 0);
    break;
    ...
    if (!isRef)
    {
    setAtIndex(objs, objsIdx, o);
    if (!ok) break;
    objsIdx++;
    }
    Save object to objs array
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24

    View full-size slide

  16. July 27-30, 2017
    if (dict) {
    if (sym)

    else {
    sym = OSDynamicCast(OSSymbol, o);
    if (!sym && (str = OSDynamicCast(OSString, o))) {
    sym = (OSSymbol *) OSSymbol::withString(str);
    o->release();
    o = 0;
    }
    ok = (sym != 0);
    }
    }
    case kOSSerializeObject:
    if (len >= objsIdx) break;
    o = objsArray[len];
    o->retain();
    isRef = true;
    break;
    Object saved to objs array destroyed
    Deallocated object retained
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24

    View full-size slide

  17. July 27-30, 2017
    o  Problem: No WatchOS kernel dumps
    o  No keys for WatchOS kernels
    o  Idea: read kernel as OSString chunks
    o  vtable offset required to fake OSString
    o  vtable stored in __DATA.__const in kernel
    Dumping kernel 13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24

    View full-size slide

  18. July 27-30, 2017
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24

    View full-size slide

  19. July 27-30, 2017
    Getting vtable - __DATA.__const leak
    o  __DATA.__const address is in Mach-O header
    o  Kernel base + 0x224 == __DATA.__const
    o  Deref and branch to address via fake vtable
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24

    View full-size slide

  20. July 27-30, 2017
    Getting vtable - known offset
    o  Get vtable offset from similar XNU build
    o  Known delta from __DATA.__const start
    o  Tune address with +/- delta
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24

    View full-size slide

  21. July 27-30, 2017
    Getting vtable - known offset
    o  Get vtable offset from similar XNU build
    o  Known delta from __DATA.__const start
    o  Tune address with +/- delta
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24

    View full-size slide

  22. July 27-30, 2017
    Getting vtable – OSString layout

    OSObject::retain()

    vtable ptr + 0x8
    retain count
    flags
    length
    string ptr
    vtable ptr + 0x8
    retain count flags
    length
    string ptr
    OSObject::retain()
    0x0
    0x4
    0x8
    0xC
    0x10
    0x0
    0x8
    0x10
    0x18
    0x0
    0x4
    0x8
    0xC
    0x10
    0x0
    0x8
    0x10
    0x18
    0x20
    OSString 32 bit
    OSString 64 bit
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    size == 0x14
    size == 0x20


    0x20
    0x14




    0x28
    0x14

    View full-size slide

  23. July 27-30, 2017
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24

    View full-size slide

  24. July 27-30, 2017
    OSString layout
    OSString vtable pointer
    OSObject::retain() offset
    0x20
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    OSString object
    OSString object vtable
    Kernel code section
    … …

    View full-size slide

  25. July 27-30, 2017
    o  vtable ptr is first 4/8 bytes of a on object
    o  What if object is not reallocated ?
    o  Memory marked as free
    o  New node pointing to next node in freelist
    Getting vtable – next free node trick 25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36

    View full-size slide

  26. July 27-30, 2017
    Heap zone freelist
    Next node pointer
    Freelist head
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36

    View full-size slide

  27. July 27-30, 2017
    o  OSString memory marked as free
    o  Now it’s a node pointing to next node
    o  Next node ptr will be interpreted as vtable
    o  Call to retain() will branch out of node bounds
    o  What if OSString size == retain() offset ?
    o  We can branch out to the start of next node
    Getting vtable – next free node trick 25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36

    View full-size slide

  28. July 27-30, 2017
    Next node ptr as a vtable ptr
    Interpreted as OSString
    Interpreted as OSString vtable pointer
    Interpreted as retain()
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36

    View full-size slide

  29. July 27-30, 2017
    o  Heap spray OSString objects
    o  Free few OSString’s
    o  Next free chunk pointer dereferenced as vtable
    o  Free chunk is surrounded by OSStrings
    o  retain() -> OOB branch to next OSString
    Getting vtable – next free node trick 25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36

    View full-size slide

  30. July 27-30, 2017
    Heap spray and OOB branch to vtable 25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    Used memory chunks

    View full-size slide

  31. July 27-30, 2017
    Heap spray and OOB branch to vtable 25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    Allocated OSString objects
    Used memory chunks

    View full-size slide

  32. July 27-30, 2017
    Heap spray and OOB branch to vtable
    Allocated OSString objects
    Used memory chunks
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    Deallocated OSString objects

    View full-size slide

  33. July 27-30, 2017
    Heap spray and OOB branch to vtable
    Allocated OSString objects
    Used memory chunks
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    Deallocated OSString objects
    Out of bounds branch to
    next OSString vtable

    View full-size slide

  34. July 27-30, 2017
    o  Heap spray OSString objects
    o  Make few OSDictionary with OSString
    o  Trigger OSDictionary deallocation
    o  retain() -> deref next free chunk pointer
    o  Free chunk is surrounded by OSStrings
    o  retain() -> OOB branch to next OSString node
    Getting vtable – next free node trick 25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36

    View full-size slide

  35. July 27-30, 2017
    Getting vtable – dump over panic
    o  OSString vtable reference in OSUnserializeBinary!
    o  OSUnserializeBinary reference in OSUnserializeXML
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36

    View full-size slide

  36. July 27-30, 2017
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36

    View full-size slide

  37. July 27-30, 2017
    Getting vtable – dump over panic
    o  Crash in OSUnserializeBinaryXML
    o  Copy panic log from a watch
    o  Get LR register value from panic
    o  We got OSUnserializeBinaryXML address
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48

    View full-size slide

  38. July 27-30, 2017
    Dumping kernel by panic logs
    o  retain() offset in vtable is 0x10
    o  Use address to leak as vtable_addr - 0x10
    o  vtable will be interpreted and branch to address
    o  Kernel will crash, but save panic log
    o  Address content appear in panic registers state
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48

    View full-size slide

  39. July 27-30, 2017
    Dumping kernel by 4 bytes
    o  Use address to leak as fake vtable address
    o  Watch will crash, wait until it restore
    o  ssh to a iPhone and run synchronization service
    o  Copy panic from Watch to iPhone and to Mac
    o  Parse panic, read 4 bytes and disassemble !
    o  Update address with 4 bytes delta and upload app
    o  Repeat
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48

    View full-size slide

  40. July 27-30, 2017
    It’s fun ! 37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48

    View full-size slide

  41. July 27-30, 2017
    OSString vtable in kernel
    OSString vtable offset
    OSUnserializeBinary address
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48

    View full-size slide

  42. July 27-30, 2017
    Getting vtable – final steps
    o  Crash in OSUnserializeXML
    o  Dump 4 bytes, disassemble, read opcode
    o  Leak opcode until ‘BL OSUnserializeBinary’
    o  Leak OSUnserializeBinary opcodes
    o  Finally leak OSString vtable offset
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48

    View full-size slide

  43. July 27-30, 2017
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48

    View full-size slide

  44. July 27-30, 2017
    Getting vtable – results
    o  5 minutes for recover watch after crash
    o  5 minutes to fetch panic from watch
    o  2 minutes to copy to Mac and parse
    o  No way to automate a process
    o  It takes me just 2 weeks to dump a vtable
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48

    View full-size slide

  45. July 27-30, 2017
    Next step – full kernel dump
    o  Now use fake OSString obj to read kernel
    o  Read data via IORegistryEntryGetProperty
    o  Leak kernel header, calculate kernel size
    o  Dump full kernel to userland by chunks
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48

    View full-size slide

  46. July 27-30, 2017
    Next step – kernel symbolication
    o  Find and list all kexts
    o  Find sysent and resolve syscalls
    o  Find and resolve mach traps
    o  Resolve IOKit objects vtable
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48

    View full-size slide

  47. July 27-30, 2017
    Next step – setting up primitives
    o  Scan kernel dump for gadgets
    o  Set up exec primitive
    o  Set up kernel read & write primitives
    STR R1, [R2]
    BX LR
    LDR R1, [R2]
    BX LR
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48

    View full-size slide

  48. July 27-30, 2017
    Next step – kernel structs layout
    o  Look for proc_* functions
    o  Restore proc structure layout
    o  Dump memory, check for known values
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48

    View full-size slide

  49. July 27-30, 2017
    Next step – patchfinder
    o  memmem string \ byte pattern
    o  + xref + instruction analysis
    o  Resolve syscalls table, mach traps table
    o  Simple instruction emulation
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60

    View full-size slide

  50. July 27-30, 2017
    Next step – kernel structs layout
    o  memmem string \ byte pattern
    o  + xref + instruction analysis
    o  Resolve syscalls table, mach traps table
    o  Simple instruction emulation
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60

    View full-size slide

  51. July 27-30, 2017
    Getting root and sandbox bypass
    o  Patch setreuid (no KPP)
    o  patch ucred in proc structure in kernel
    o  patch sandbox label value in ucred
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60

    View full-size slide

  52. July 27-30, 2017
    Getting kernel task
    o  Patch task_for_pid()
    o  Or save kernel sself in task bootstrap port
    o  Read it back via task_get_special_port()
    o  Restore original bootstrap port value
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60

    View full-size slide

  53. July 27-30, 2017
    Disable codesign checks
    o  Patch _debug to 1
    o  patch _nl_symbol_ptr (got) entries
    o  Patch amfi variables
    - cs_enforcement_disable
    - allow_invalid_signatures
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60

    View full-size slide

  54. July 27-30, 2017
    Remount rootfs
    o  Patch __mac_mount
    o  Change flags in rootfs vnode and mount RW
    o  Patch lwvm is_write_protected check
    o  Patch PE_i_can_has_debugger in lwvm
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60

    View full-size slide

  55. July 27-30, 2017
    Spawning ssh client
    o  Compile dropbear for ARMv7k
    o  Compile basic tools package for ARMv7k
    o  Problem: More sandbox restrictions
    o  Remove WatchOS specific sandbox ops
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60

    View full-size slide

  56. July 27-30, 2017
    ssh connection problem…
    "awdl0/ipv6" = "fe80::c837:8аff:fe60:90c2";
    "lo0/ipv4” = "127.0.0.1";
    "lo0/ipv6" = "fe80::1";
    "utun0/ipv6" = "fe80::face:5e30:271e:3cd3";
    o  WatchOS interfaces
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60

    View full-size slide

  57. July 27-30, 2017
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60

    View full-size slide

  58. July 27-30, 2017
    Watch <-> iPhone port forwarding
    NSDictionary *comm = @{!
    @"Command" :@"StartForwardingServicePort",
    @"ForwardedServiceName" :@"com.apple.syslog_relay",!
    @"GizmoRemotePortNumber" :[NSNumber numberWithUnsignedShort: pt],!
    @"IsServiceLowPriority" :@0,};!
    !
    AMDServiceConnectionSendMessage(serviceConnection,!
    (__bridge CFPropertyListRef)(comm),
    kCFPropertyListXMLFormat_v1_0);!
    !
    AMDServiceConnectionReceiveMessage(serviceConnection, &response,
    (CFPropertyListFormat*)&format);!
    !
    NSNumber *iphone_port = response[@"CompanionProxyServicePort"];!
    Thanks to Luca Todesco
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60

    View full-size slide

  59. July 27-30, 2017
    ssh connection over bluetooth 49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60

    View full-size slide

  60. July 27-30, 2017
    Black Hat Sound Bytes 49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60

    View full-size slide

  61. July 27-30, 2017
    Apple Watch usage
    o  Watch has access to SMS, Calls, Health
    o  Photos and emails synced to Watch
    o  Fetch GPS location from the phone
    o  Microphone usage
    o  Apple Pay
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72

    View full-size slide

  62. July 27-30, 2017
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72

    View full-size slide

  63. July 27-30, 2017
    Interesting findings
    o  Full access to jailbroken watch file system
    o  Including sqlite3 databases
    - Messages
    - Call history
    - Contacts
    - Emails
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72

    View full-size slide

  64. July 27-30, 2017
    What's next ?
    o  Interpose or trampoline system functions
    o  Catch data on sync with a iPhone
    o  Create tweaks for a watch
    o  Run frida and radare
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72

    View full-size slide

  65. July 27-30, 2017
    Takeaways
    o  WatchOS security is equal to iOS
    o  But new techniques required
    o  Easier data forensics on a Watch
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72

    View full-size slide

  66. July 27-30, 2017
    References
    o  Lookout - Technical Analysis of the Pegasus Exploits on iOS
    o  Luca Todesco - com.apple.companion_proxy client
    o  Siguza - tfp0 powered by Pegasus
    o  Stefan Esser - iOS 10 - Kernel Heap Revisited
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72

    View full-size slide

  67. July 27-30, 2017
    @mbazaliy
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72

    View full-size slide