Skip to content

Commit

Permalink
First successful untether boot
Browse files Browse the repository at this point in the history
  • Loading branch information
UInt2048 committed May 19, 2024
1 parent 4369dcb commit 83b9b44
Show file tree
Hide file tree
Showing 11 changed files with 84 additions and 16 deletions.
39 changes: 30 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Important notes

If you have an A7-A9(X) device on iOS 11, this repo is extremely close to providing an untethered userland iOS 11 jailbreak.
If you have an A7-A9(X) device on iOS 11, congratulations! This repo can now provide your device an untethered userland iOS 11 jailbreak.

This should be blatantly obvious, but Spice will NOT magically untether your device that you [tethered downgraded to iOS 11.x](https://github.com/y08wilm/Semaphorin), even if you have blobs unless you've actually used them.

Expand All @@ -15,12 +15,14 @@ Spice can't help until you can run the vulnerable iOS 11 code (`/usr/sbin/racoon

## Device support

At present, the repo is configured to build for the **iPhone 6S Plus (iPhone8,2) on 11.3.1**.
At present, the repo is configured to build for the **iPhone 6S Plus (iPhone8,2) on 11.3.1**. The binaries in /docs are ONLY built for this device + iOS.

The **iPad mini 4 (Wi-Fi) (iPad5,1) on iOS 11.1.2**, **iPad mini 4 (Wi-Fi) (iPad5,1) on iOS 11.3.1**, **iPhone SE (1st gen) (iPhone8,4), iOS 11.3**, and **iPhone SE (1st gen) (iPhone8,4), iOS 11.4** already have offsets and probably build fine if the appropriate support is turned on in offsets.h.
The **iPad mini 4 (Wi-Fi) (iPad5,1) on iOS 11.1.2**, **iPad mini 4 (Wi-Fi) (iPad5,1) on iOS 11.3.1**, **iPhone SE (1st gen) (iPhone8,4), iOS 11.3**, and **iPhone SE (1st gen) (iPhone8,4), iOS 11.4** already have offsets and may build fine if the appropriate support is turned on in offsets.h.

Any other device will require offsets to be added. PRs are welcomed to speed this up, but an actual device will be needed to provide the final offset (`DYLD_CACHE_FD`) if you desire support.

Binaries are added to the repo by copying the DEB file in /generated and the Spice-DEV.ipa file to the /docs folder and running `dpkg-scanpackages -m ./docs > docs/Packages && bzip2 docs/Packages -k -f`

## Installation

Obviously, just run `make` to create all generated files (the makefile requires macOS, use a VM or something if you need it).
Expand All @@ -32,7 +34,7 @@ If you have an issue upgrading essential packages, run `apt --fix-broken install

To install the untether payload (these files are located in ./src/untether/generated):
1. Install the DEB file (use `make payload` if you can't find it) or manually copy the stage 1-2 install script to `/private/etc/racoon/install_stage1_2`, stage 3 to `/usr/sbin/racoon.dylib`, and stage 4 to `/mystuff/stage4`.
2. If installing manually, type `/private/etc/racoon/install_stage1_2` in a terminal or SSH connection. This will create the folder `/var/run/racoon` if it does not yet exist.
2. If installing manually, type `/private/etc/racoon/install_stage1_2; mv /var/run/racoon/test.conf /private/etc/racoon/spice.conf` in a terminal or SSH connection. This will create the folder `/var/run/racoon` if it does not yet exist.
There will be a lot of output. If successful, the end looks something like:
```
0x1f0214e60: 0x00000000 (NOP)
Expand All @@ -45,6 +47,8 @@ There will be a lot of output. If successful, the end looks something like:

If you're running the DEB in Zebra, the last two lines might be replaced with "Finished!".

You now want to replace `/private/etc/racoon/racoon.conf` with the racoon.conf in this folder. This is just to make sure that if `/var/run/racoon` gets deleted, that the exploit doesn't.

3. Then execute racoon (the real one in PATH, should be `/usr/sbin/racoon`) till it doesn't kernel panic anymore to make sure you got the right offsets.
If you get a segfault, and the crash report shows the beast gadget offset listed in your output, you likely need to set `STAGE1FD_SCREAM_TEST` to find the right stage 1 fd in the crash log.
If successful, the end looks something like:
Expand Down Expand Up @@ -73,14 +77,31 @@ Pressing enter after this will restore control of the SSH connection.

4. Now enable the killswitch with `nvram boot-args="__spice_untether_disable"` then replace one of the launch daemons and check if the system keeps running stable even with racoon (this tests the killswitch).

TODO: How do you replace the daemon?
To replace the daemon, you first need to edit your jetsam configuration to ensure the daemon has enough memory to run the exploit without being killed.

I've edited the override configuration in `/System/Library/LaunchDaemons/com.apple.jetsamproperties.N66.plist` (replace N66 with your board config) for both `com.apple.prdaily` and `com.apple.racoon` to be:

```
<dict>
<key>ActiveSoftMemoryLimit</key>
<integer>80</integer>
<key>InactiveHardMemoryLimit</key>
<integer>80</integer>
<key>JetsamPriority</key>
<integer>11</integer>
</dict>
```

I've attempted to replace `/System/Library/LaunchDaemons/com.apple.prdaily.plist` with the prdaily.plist in this folder and `/private/etc/racoon/racoon.conf` with the racoon.conf in this folder, then `mv /var/run/racoon/test.conf /private/etc/racoon/spice.conf`.
(The reason for the latter half is that for me, /var/run/racoon has been getting deleted for some reason...)
After doing this (and rebooting for the change to take effect), I then ran the following to actually perform the replacement:

However, the command still seems not to work for some undiagnosable reason. I suspect that due to being triggered by launchd, it is being passed the -D argument automatically which causes it not to do anything.
```
mv /System/Library/CoreServices/prdaily /System/Library/CoreServices/prdaily.bak
cp /usr/sbin/racoon /System/Library/CoreServices/prdaily
/bin/launchctl unload /System/Library/LaunchDaemons/com.apple.prdaily.plist
/bin/launchctl load /System/Library/LaunchDaemons/com.apple.prdaily.plist
```

5. If you did you can then go for the real untether by changing the boot-args back to anything else, e.g. `nvram boot-args="__developer_mode_enabled"`
5. If you did you can then go for the real untether by changing the boot-args back to anything else, e.g. `nvram boot-args="__spice_untether_enabled"`

There, you need to watch out for three things:
- the launch daemon isn't used by anything important (namely springboard) (otherwise you will softbrick when it fails to run)
Expand Down
15 changes: 15 additions & 0 deletions docs/Packages
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Package: lol.spyware.spiceuntether
Version: 1.0.165
Architecture: iphoneos-arm
Maintainer: UInt2048
Depends: firmware (>= 11.0), firmware (<= 11.4.1)
Filename: ./docs/lol.spyware.spiceuntether_1.0.165_iphoneos-arm.deb
Size: 130232
MD5sum: 6a7b1ef1fc5f6335dd4a684af9eb8272
SHA1: b2f1037fbdd4a24f5863cf34892bb3ee41985216
SHA256: 353b9d2c6e67471e4a71bcc4c53264f9825b067ed035550425cd68832f2cfa63
Section: System
Description: Upgrades the Spice jailbreak to untethered
Author: JakeBlair420
Name: Spice Untether Payload

Binary file added docs/Packages.bz2
Binary file not shown.
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Welcome to the UInt2048/Spice repo :)
Binary file added docs/Spice-DEV.ipa
Binary file not shown.
Binary file not shown.
32 changes: 30 additions & 2 deletions src/shared/jailbreak.m
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,30 @@
kptr_t kernel_slide;
kptr_t kernproc;

#include <time.h>
#include <errno.h>
#include <sys/sysctl.h>

// Shamelessly stolen from https://stackoverflow.com/a/11676260/
time_t bootsec()
{
struct timeval boottime;
size_t len = sizeof(boottime);
int mib[2] = { CTL_KERN, KERN_BOOTTIME };
if( sysctl(mib, 2, &boottime, &len, NULL, 0) < 0 )
{
return -1.0;
}
return boottime.tv_sec;
}

kern_return_t jailbreak(uint32_t opt, void* controller, void (*sendLog)(void*, NSString*))
{
kern_return_t ret = 0;
task_t self = mach_task_self();
kptr_t kbase = 0;
NSFileManager *fileMgr = [NSFileManager defaultManager];
#define PWN_LOG(...) do { sendLog(controller, [NSString stringWithFormat:@__VA_ARGS__]); LOG(__VA_ARGS__); } while(0)

if(opt & JBOPT_POST_ONLY)
{
Expand Down Expand Up @@ -244,6 +262,15 @@ kern_return_t jailbreak(uint32_t opt, void* controller, void (*sendLog)(void*, N
CFURLGetFileSystemRepresentation(resourcesUrl, TRUE, (UInt8 *)bundle_path, len);
LOG("bundle path: %s", bundle_path);

// make sure this only gets run once per boot
char *doublebootcheck = [[NSString stringWithFormat:@"/tmp/spice.%lu", (unsigned long)bootsec()] UTF8String];
if (access(doublebootcheck, F_OK) == 0) {
PWN_LOG("We're already jailbroken silly");
// spin for now
while (1) {}
}
fclose(fopen(doublebootcheck, "w"));

// TODO: hash checks on binaries
#define COPY_RESOURCE(name, to_path)\
do\
Expand Down Expand Up @@ -580,7 +607,8 @@ kern_return_t jailbreak(uint32_t opt, void* controller, void (*sendLog)(void*, N
{
LOG("finished post exploitation");

LOG("unloading prdaily...");
// Removed because the double boot check should make it safe
/*LOG("unloading prdaily...");
ret = execprog("/bin/launchctl", (const char **)&(const char *[])
{
Expand All @@ -596,7 +624,7 @@ kern_return_t jailbreak(uint32_t opt, void* controller, void (*sendLog)(void*, N
goto out;
}
LOG("prdaily unloaded\n");
LOG("prdaily unloaded\n");*/

/* hope substrate is running by this point? */

Expand Down
2 changes: 1 addition & 1 deletion src/untether/control
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: lol.spyware.spiceuntether
Name: Spice Untether Payload
Version: 1.0.160
Version: 1.0.165
Architecture: iphoneos-arm
Description: Upgrades the Spice jailbreak to untethered
Maintainer: UInt2048
Expand Down
2 changes: 1 addition & 1 deletion src/untether/postinst
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
#!/bin/sh
/private/etc/racoon/install_stage1_2
/private/etc/racoon/install_stage1_2; mv /var/run/racoon/test.conf /private/etc/racoon/spice.conf
7 changes: 5 additions & 2 deletions src/untether/stage1.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,14 @@
// IF YOU CHANGE THESE VALUES HERE AND THEN USE IT IN A KEEP ALIVE DAEMON IT WILL CRASH OVER AND OVER AGAIN CAUSE A SOFTBRICK OF THE SYSTEM SO REALLY WATCH OUT WHEN YOU CHANGE THEM/MAKE SURE THEY ARE SET RIGHT WHEN YOU TEST THIS ON A NEW/DIFFERENT IOS VERSION
// see stage1.c on when and how they are used (I think STAGE2_FD will always be DYLD_CACHE_FD + 1)

// When you test directly with racoon, versus testing through a launch daemon, this descriptor may change.
// In my testing on N69AP 11.3, the fd was 5 when testing after the semi-untether and 6 when replacing prdaily right after boot.

#if STAGE1FD_SCREAM_TEST
#define DYLD_CACHE_FD 3
#elif (N69AP & IOS_11_3) || (N69AP & IOS_11_4) || (N66AP & IOS_11_3_1)
#elif (N69AP & IOS_11_3) || (N69AP & IOS_11_4)
#define DYLD_CACHE_FD 5
#elif (J96AP & IOS_11_1_2) || (J96AP & IOS_11_3_1)
#elif (N66AP & IOS_11_3_1) || (J96AP & IOS_11_1_2) || (J96AP & IOS_11_3_1)
#define DYLD_CACHE_FD 6
#else
// If you're doing a scream test, it shouldn't matter too much what you set this to, but you have to set it. You can also use 6 if you want.
Expand Down
2 changes: 1 addition & 1 deletion src/untether/stage2.m
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ void build_chain_DBG(offset_struct_t * offsets,rop_var_t * ropvars) {
int pos = 0;
char * pos_buf = NULL;
#if STAGE1FD_SCREAM_TEST
LOG("Stage 1 fd scream test is active\n\n")
LOG("Stage 1 fd scream test is active\n\n");
#endif
LOG("STAGE 2 DBG\nWe start with our chain here, x0 is pointing to that location (%llx) and we are in longjmp atm",offsets->stage2_base);
while (next != NULL) {
Expand Down

0 comments on commit 83b9b44

Please sign in to comment.