Evasi0n7

evasi0n7 is a jailbreak program from the evad3rs. It performs an untethered jailbreak for all devices on iOS 7.0 through 7.1 beta 3, except the Apple TV. It was initially released on 2013, and became subject to controversy and criticism. On 2013, the Cydia package went live to saurik's repo.

Controversy
The release of evasi0n7 was met with sharp criticism. It came without advance notice, much to the dismay of jailbreak developers, including saurik. It is believed that this was done in response to Geohot trying to sell the jailbreak, a claim which Geohot later brushed off. In addition, if the user's language was set to Chinese, a different app store, the TaiG app store would be installed by default. This store contained cracked versions of App Store apps and Cydia apps. The evad3rs were reportedly unaware of the included piracy when they formed the deal, and remotely disabled that store's installation several hours later. The evad3rs put out letters to the community during this - Part 1 and Part 2.

Supported Devices
The only unsupported devices are those of the Apple TV family. All other devices capable of running iOS 7 are supported.

Apple TVs
evasi0n7 is not capable of jailbreaking the Apple TVs. According to nitoTV, in his "Why isn't the Apple TV 3 jailbroken?" WWJC 2014 talk (video), evasi0n7 would have been able to jailbreak the Apple TV (2nd generation) but was never updated to properly support it.

Version History
Note: evasi0n7 1.0.8 is known to cause boot loops. 1.0.8 has since been taken down from the evad3rs' website, and users are advised to use 1.0.7 unless you have an iPhone 5s/iPhone 5c running iOS 7.0 (build 11A466).

Mach-O (macOS binary)
evasi0n7 is a single architecture (i386) unsigned binary. The app is self-contained, meaning it packages all of its resources into the Mach-O. Using jtool to inspect the Mach-O header of the binary shows that there is some added sections in the  segment.

bash$ jtool -l ./evasi0n\ 7.app/Contents/MacOS/evasi0n7 ... LC 02: LC_SEGMENT           	Mem: 0x00170000-0x01d09000 __DATA Mem: 0x00170000-0x00170008		__DATA.__dyld Mem: 0x00170008-0x00170060		__DATA.__nl_symbol_ptr    (Non-Lazy Symbol Ptrs) Mem: 0x00170060-0x001703d4		__DATA.__la_symbol_ptr    (Lazy Symbol Ptrs) Mem: 0x001703d4-0x001703d8		__DATA.__mod_init_func    (Module Init Function Ptrs) Mem: 0x001703d8-0x001705d0		__DATA.__const Mem: 0x001705d0-0x00171c14		__DATA.__data Mem: 0x00171c14-0x00171c64		__DATA.__cfstring 	Mem: 0x00171c64-0x001a942d		__DATA.data_3 Mem: 0x001a942d-0x0087b92c		__DATA.data_4 Mem: 0x0087b92c-0x0087be18		__DATA.data_5 Mem: 0x0087be18-0x0087c2f8		__DATA.data_6 Mem: 0x0087c2f8-0x008fb944		__DATA.data_7 Mem: 0x008fb944-0x008fba7f		__DATA.data_8 Mem: 0x008fba7f-0x008fbeac		__DATA.data_9 Mem: 0x008fbeac-0x0160f3a1		__DATA.data_10 Mem: 0x0160f3a1-0x016101ac		__DATA.data_11 Mem: 0x016101ac-0x01d083dd		__DATA.data_12         Mem: 0x01d08400-0x01d084cc		__DATA.__common           (Zero Fill) Mem: 0x01d084cc-0x01d0866c		__DATA.__bss              (Zero Fill) ...

The Mach-O ABI describes the __DATA segment as: "The __DATA segment contains writable data. The static linker sets the virtual memory permissions of this segment to allow both reading and writing. Because it is writable, the __DATA segment of a framework or other shared library is logically copied for each process linking with the library. When memory pages such as those making up the __DATA segment are readable and writable, the kernel marks them copy-on-write; therefore when a process writes to one of these pages, that process receives its own private copy of the page." This means additional sections can be added using compiler flags, and these will be treated as raw data and added to the header and binary contents. Specifically they were called data_3 through data_12, and this is where the payloads used for jailbreak process are stored. At runtime, the evasi0n app was loading these data segments into memory to prepare to use them when jailbreaking.

Payload Extraction
The locations of the payloads have been identified, and they can be extracted and examined. To extract the payloads from the binary and dump the data into a file that can be examined: bash$ jtool -e __DATA.data_3 ./evasi0n\ 7.app/Contents/MacOS/evasi0n7 Requested section found at Offset 1510500 Extracting __DATA.data_3 at 1510500, 227273 (377c9) bytes into evasi0n7.__DATA.data_3

Payload Format
Before examining the dumped payload files, some information can be gathered from other parts of the Mach-O binary. By dumping the symbol table from the binary, it is possible to see the names of functions used in the binary that are linked to in external libraries. Something that stands out in the evasi0n binary is the usage of the gzip library.

bash $ dsymutil -s ./evasi0n\ 7.app/Contents/MacOS/evasi0n7 -- Symbol table for: './evasi0n 7.app/Contents/MacOS/evasi0n7' (i386) -- Index   n_strx   n_type             n_sect n_desc n_value ======== -- -- --  ... [   164] 00000ab1 01 (     UNDF EXT) 00     0a00   0000000000000000 '_getcwd' [  165] 00000ab9 01 (     UNDF EXT) 00     0a00   0000000000000000 '_getsectdata'

"_getsectdata" Suggests it is used to get the data from a particular data section from the Mach-O header

[  166] 00000ac6 01 (     UNDF EXT) 00     0100   0000000000000000 '_gzclose' [  167] 00000acf 01 (     UNDF EXT) 00     0100   0000000000000000 '_gzopen' [  168] 00000ad7 01 (     UNDF EXT) 00     0100   0000000000000000 '_gzread' [  169] 00000adf 01 (     UNDF EXT) 00     0100   0000000000000000 '_gzseek' [  170] 00000ae7 01 (     UNDF EXT) 00     0100   0000000000000000 '_inflate' [  171] 00000af0 01 (     UNDF EXT) 00     0100   0000000000000000 '_inflateEnd' [  172] 00000afc 01 (     UNDF EXT) 00     0100   0000000000000000 '_inflateInit2_' ...

From that, it can be deduced that the payloads that were extracted are compressed using gzip. This can be verified by running the command  on the extracted payloads.

bash $ file ./evasi0n7.__DATA.data_3  evasi0n7.__DATA.data_3: gzip compressed data, from Unix, last modified: Sun Dec 22 05:54:11 2013

After decompressing the gzip file there is a new file, again test that with.

bash $ mv ./evasi0n7.__DATA.data_3 ./evasi0n7.__DATA.data_3.gz bash $ gunzip ./evasi0n7.__DATA.data_3.gz bash $ file ./evasi0n7.__DATA.data_3 evasi0n7.__DATA.data_3: POSIX tar archive

Seems that the payloads were stored as simply  files dumped directly into the Mach-O header of the binary.

Payload Contents
Now having an understanding of how the payloads were supposed to be used and packaged, their contents can be examined in detail to see what they are used for.

bash $ tar ztvf ./evasi0n7.__DATA.data_3  drwxr-xr-x 0 planetbeing staff       0 Dec 22 00:20 ./ drwxr-xr-x 0 planetbeing staff       0 Dec 17 18:27 ./Applications/ drwxr-xr-x 0 planetbeing staff       0 Dec 21 07:25 ./etc/ drwxr-xr-x 0 planetbeing staff       0 Dec 18 18:34 ./private/ drwxr-xr-x 0 planetbeing staff       0 Dec 18 18:57 ./usr/ drwxr-xr-x 0 planetbeing staff       0 Dec 19 04:18 ./usr/bin/ drwxr-xr-x 0 planetbeing staff       0 Oct 31 23:14 ./usr/libexec/ drwxr-xr-x 0 planetbeing staff       0 Dec 18 19:11 ./usr/libexec/cydia/ -rwxr-xr-x 0 planetbeing staff    3363 Dec 18 23:59 ./usr/libexec/cydia/firmware.sh -rwxr-xr-x  0 planetbeing staff     228 Dec 17 20:43 ./usr/libexec/cydia/free.sh -rwxr-xr-x  0 planetbeing staff  132848 Dec 18 18:57 ./usr/bin/gssc -rwxr-xr-x 0 planetbeing staff  200352 Dec 19 04:18 ./usr/bin/uicache drwxr-xr-x 0 planetbeing staff       0 Dec 18 18:34 ./private/var/ drwxr-xr-x 0 planetbeing staff       0 Dec 18 18:34 ./private/var/lib/ drwxr-xr-x 0 planetbeing staff       0 Dec 18 18:34 ./private/var/lib/dpkg/ drwxr-xr-x 0 planetbeing staff       0 Dec 22 00:12 ./private/var/lib/dpkg/info/ -rw-r--r-- 0 planetbeing staff     393 Dec 18 18:40 ./private/var/lib/dpkg/info/com.evad3rs.evasi0n7.list -rwxr-xr-x 0 planetbeing staff     678 Dec 18 18:52 ./private/var/lib/dpkg/info/com.evad3rs.evasi0n7.prerm -rw-r--r-- 0 planetbeing staff    5137 Dec 22 00:12 ./private/var/lib/dpkg/info/cydia.list drwxr-xr-x 0 planetbeing staff       0 Dec 21 23:31 ./Applications/Cydia.app/ -rwxr-xr-x 0 planetbeing staff     211 Dec 21 22:52 ./Applications/Cydia.app/Cydia -rwsr-sr-x 0 planetbeing staff  131824 Dec 22 00:00 ./Applications/Cydia.app/CydiaWrapper -rwsr-sr-x 0 planetbeing staff  382608 Dec 17 20:50 ./Applications/Cydia.app/MobileCydia -rwxr-xr-x 0 planetbeing staff   66960 Dec 22 00:04 ./Applications/Cydia.app/udidfix.dylib


 * __data3 contains Cydia.
 * __data4 contains Cydia subsystems (/bin, /usr/bin) and their supported libraries (/usr/lib)
 * __data5 contains a Mach-O universal binary (ARMv7/ARMv7s,ARMv8) which is installed in the root file system
 * __data6 contains a dylib (likely game over.dyliib) which exports the same symbols as libmis.dylib (used by amfid for code signature verification), but overrides them to return true
 * __data7 contains another Mach-O binary (ARMv7/ARMv8), likely evasi0n7, which is installed in the root filesystem during the jailbreak
 * __data8 contains the plist (property list) file used by evasion to register as a launchDaemon
 * __data9 contains a dylib which overrides the sandbox dylib (similar to __data6, but to enable evasion to avoid the sandbox)
 * __data10 contained the TaiG app and subsystems (similar to Cydia) - removed in 1.01 due to negative backlash
 * __data11 contains a binary plist of strings used by the evasion binary
 * __data12 contains the Cydia repo list

Network Access
Noteably, when attempting to run the evasi0n.app without an active or accessible network connection, it will display a prompt that says it requires a network connection to be used. This is very true, as it needs to download the WWDC app as part of the exploit. However the app doesn't exhibit any of the typical commands for network access via Cocoa or CF APIs. Examining the symbol table we do see that there are references to "send", "recv", and other C-socket calls, however they appear to be used exclusively for the unix socket to communicate directly with the iOS device.

Examining the list of libraries linked to the binary gives some insight to how it was checking for a network connection.

bash $ otool -L ./evasi0n\ 7.app/Contents/MacOS/evasi0n7  ./evasi0n 7.app/Contents/MacOS/evasi0n7: /usr/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.5) /usr/lib/libxml2.2.dylib (compatibility version 10.0.0, current version 10.9.0) /usr/lib/libssl.0.9.8.dylib (compatibility version 0.9.8, current version 50.0.0) /usr/lib/libcrypto.0.9.8.dylib (compatibility version 0.9.8, current version 50.0.0) /usr/lib/libcurl.4.dylib (compatibility version 7.0.0, current version 8.0.0) /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 855.11.0) /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0) /System/Library/Frameworks/IOKit.framework/Versions/A/IOKit (compatibility version 1.0.0, current version 275.0.0) /System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa (compatibility version 1.0.0, current version 20.0.0) /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.1.1) /usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 60.0.0) /usr/lib/libgcc_s.1.dylib (compatibility version 1.0.0, current version 2577.0.0) /System/Library/Frameworks/AppKit.framework/Versions/C/AppKit (compatibility version 45.0.0, current version 1265.0.0) /System/Library/Frameworks/Foundation.framework/Versions/C/Foundation (compatibility version 300.0.0, current version 1056.0.0)

This stands out due to the compatibility version listed being higher than the version Mac OS X 10.6.8, which was oldest version of macOS that evasi0n.app claimed to support. Checking the symbol table again evidence of how  can be seen.

bash $ dsymutil -s ./evasi0n\ 7.app/Contents/MacOS/evasi0n7  -- Symbol table for: './evasi0n 7.app/Contents/MacOS/evasi0n7' (i386) -- Index   n_strx   n_type             n_sect n_desc n_value ======== -- -- --  ... [   133] 00000938 01 (     UNDF EXT) 00     0500   0000000000000000 '_curl_easy_cleanup' [  134] 0000094b 01 (     UNDF EXT) 00     0500   0000000000000000 '_curl_easy_getinfo' [  135] 0000095e 01 (     UNDF EXT) 00     0500   0000000000000000 '_curl_easy_init' [  136] 0000096e 01 (     UNDF EXT) 00     0500   0000000000000000 '_curl_easy_perform' [  137] 00000981 01 (     UNDF EXT) 00     0500   0000000000000000 '_curl_easy_setopt' [  138] 00000993 01 (     UNDF EXT) 00     0500   0000000000000000 '_curl_easy_strerror' [  139] 000009a7 01 (     UNDF EXT) 00     0500   0000000000000000 '_curl_global_cleanup' [  140] 000009bc 01 (     UNDF EXT) 00     0500   0000000000000000 '_curl_global_init' [  141] 000009ce 01 (     UNDF EXT) 00     0500   0000000000000000 '_curl_slist_append' [  142] 000009e1 01 (     UNDF EXT) 00     0500   0000000000000000 '_curl_slist_free_all' ...

Digging into the code in the binary, it appears as these commands are used to do a check against the address. This appears to be a binary file that dictates the internal operation of the evasi0n7.app. Specifically it is known to be able to enable and disable ability to install the TaiG payloads.

Language Checks
The major controversy surrounding this release was that the evasi0n7.app would do a check against the locale and language settings of the computer being run on to see if it was set to Chinese. If this check was successful, it would install the TaiG app store by default instead of Cydia, and present Cydia as a secondary option. This was quickly discovered and patched to remove this functionally by both TaiG and @Dirk_Gently.

Write-up by Braden Thomas
Originally posted on Pastebin


 * WWDC.app is downloaded from app store and uploaded over AFC to ~/Media/Downloads
 * An IPA containing WWDC.app is uploaded and installed using MobileInstall, but first, the Info.plist in the WWDC app in the IPA is changed so that CFBundleExecutable points to the untouched copy of the app in Downloads
 * when MobileInstall installs the app, it signature checks the copy in Downloads, signature check passes and app is installed
 * WWDC.app/WWDC is overwritten using AFC with a #! script to point to afcd the command line in #! will expose the entire / over afc port 8888
 * a dylib (gameover) is uploaded which uses a CS bypass (vmsize 0) to neuter sandboxing in afcd using LINKEDIT section (afcd starts its sandbox at runtime using sandbox_init*)
 * a LaunchServices bug is used to make that app load that library when it runs the device reboots and the user is instructed to run the app
 * when the app runs, afcd runs exposing /, and the sandbox is neutered, allowing access everywhere however, iOS 7 kernel still prevents remapping / as writable so it's still just readonly
 * at this point, /var/mobile/Library/Logs/AppleSupport is symlinked to /dev/rdisk0s1 the device is rebooted, and something early in boot (i believe ReportCrash) will chown that path to mobile which chowns rdisk
 * they have an HFS library that has an AFC backend, so they're able to virtually mount the entire system partition via AFC by seeking around on the rdisk using AFC commands. so using that, they modify the system partition the changes to the system partition are adding an executable which is signed with a self-signed cert at /evasi0n7 and a launchd plist to run it at boot
 * they use the same CS bypass used before to modify libmis.dylib which is loaded by amfid (which checks code signatures) to neuter the amfi checks and always return true (i.e. to MISValidateSignature)
 * so evasi0n will run fine, and at that point it does the kernel portion
 * they also have to do this trick involving another codeless library containing this xpcd_cache blob to bypass a change in iOS 7 (or was it 6) where launchctl will only load plists from signed libraries

See followups at @drspringfield.

Write-up by geohot
geohot presented an evasi0n7 writeup on his website here.

Write-up by p0sixninja
The vulnerability is an out of bounds array in the  array by specifying an overly large minor device node number. By placing data in a known location past the array it's possible to hijack the tty structure and special read and write data from ioctl calls, and control function pointers to control execution.

The exploit is actually quite simple to trigger. I discovered this with a simple fuzzing script to test out every single device node. Here's a small sample script that should crash the latest maverick update. please run this as root.

The 16 major device node actually is mapped to the ptmx/ptsd pseudo terminal system. It seems that only 16 spaces are allocated for these terminals and if you make a device node with major 16 and minor larger that 16 you start getting out of bounds of the array. The maximum size of device nodes are about 0x600000 giving to the ability to offset your pointer into a crafted structure very large. The only hard part is finding which zones are ahead of your array you can index into. The exploit itself is in the bsd/kernel/tty_ptmx.c file in XNU kernel. The crash happens in…

The problem is they lack the check to see if the minor number is higher than the number of spots allocated. The problem comes down to this, I'll try to comment code as I go through it...

First notice the, if this is not true a lot of code will be skipped. on the ptmx devices, this isn't set so all this is complete skipped and we can skip to the end of the the code since there is no all catching else clause to handle most connections. It just automatically returns this array indexed with a user controllable value. Crash but true, let's look more into this structure we can control if we create a large minor number.

This just contains a pointer vector of ptmx_ioctl structures, let's look at the structure which should be contained in the minor number offset.

The first pointer in this structure is a pointer to a tty structure. This structure is easily readable and writable using using user land APIS. It also includes some function pointers in there which can be triggered to gain

You can imagine all the power you could do if you can control all these structures carefully. That will be the difficulty when trying to exploit. You need to find a kernel zone past this array and allocate your data into it in a way you always know the offset. shouldn't be too hard.

Here's what the crash looks like once triggered.

in gdb remote kernel debugger…

it was trying to read in the value of _state.pis_ioctl_list[10].

It crashes here before dereferenceing the tty structure at the beginning of the ptmx_ioctl structure. We must know it's an address, but we also leak a bit near the address if it is an address. We should also be able to retrieve the value of all these state variables it sets from variable bits wherever the pointer is at to see if it's the correct pointer or not.

Examine the read, write, and select apis for these terminals to learn all you can do. ioctl calls might also be interesting. Also since it uses the tty zone for allocating this devices, it might be a very predictable zone if we can control all the pseudo terminals. Also checking out return values based on flags in structs can be a good way to feel around in memory.

New in iOS 7.0 security protections, you are now no longer allowed to remount the root partition as readable/writeable. Before we just change the /etc/fstab file to remount the filesystems, but now there is a special kernel check preventing root filesystem from being remounted. Also the user filesystem containing all the data is mounted to disallow super user files, and device nodes. Luckily, if we can remount the user filesystem to reallow superuser and device node files we can create this device node and launch the kernel exploit on iOS7.