coolstar / electra

Electra iOS 11.0 - 11.1.2 jailbreak toolkit based on async_awake
GNU General Public License v3.0
656 stars 163 forks source link

su-like binary #53

Closed stek29 closed 6 years ago

stek29 commented 6 years ago
coolstar commented 6 years ago

We should also have jailbreakd setuid the binary while we're at it, since setuid() doesn't work

stek29 commented 6 years ago

Yup, that's what I've meant by "Add su command to jailbreakd" :)

stek29 commented 6 years ago
#include <spawn.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

#include "common.h"

int main(int argc, char *argv[], char *envp[]) {
    if (argc < 2) {
        fprintf(stderr, "usage: %s program args...\n", argv[0]);
        return EXIT_FAILURE;
    }
    posix_spawnattr_t attr;
    posix_spawnattr_init(&attr);
    posix_spawnattr_setflags(&attr, POSIX_SPAWN_START_SUSPENDED|POSIX_SPAWN_SETEXEC);

    calljailbreakd(getpid(), JAILBREAKD_COMMAND_ENTITLE_AND_SIGCONT_AFTER_DELAY);

    int ret = posix_spawnp(NULL, argv[1], NULL, &attr, &argv[1], envp);

    fprintf(stderr, "Failed: %d (%s)\n", ret, strerror(ret));
    return ret;
}
littlelailo commented 6 years ago

If we have something like a su command for jailbreakd we could use it in posix_spawn: We have a list of setuid binaries on the system and if the binary which gets spawned is in that list we elevate privileges.

coolstar commented 6 years ago

@littlelailo hardcoding a a list of binaries isn't really a good idea. A better solution would be to get the path of the PID that's to get setuid, and check if the file on disk has the setuid flag set

littlelailo commented 6 years ago

@coolstar Oh, I thought that some MACF policy would deny the execution of setuid binaries, but if they just start without higher privileges, this is of course the better solution. So we could do something like this to check if the binary is a setuid binary:

#include <sys/stat.h>
#include <stdbool.h>

bool is_setuid(char* path) {
    struct stat sb; 
    if (stat(path, &sb) == -1) {
        return false; 
    }   
    if (sb.st_mode & S_ISUID) {
        return true;
    }   
    return false;
}

The code is of course vulnerable to a race condition (basic TOCTOU), but I don't think this is a big problem.

kirb commented 6 years ago

Does it seem like a bad idea to let /Developer/usr/bin/debugserver always get elevated, without needing to use su? So that it can be spawned for non-get-task-allow entitled processes via the Xcode/Instruments/etc UI. Of course I’d be concerned about an app reading data from another app via spawning debugserver. CFUserNotification could be used to display a prompt and block till there's a response (or it times out). Would make something similar to SuperSU possible without needing to inject a tweak into SpringBoard.

littlelailo commented 6 years ago

Current state of implementation:

OTTO:/bootstrap mobile$ ps aux | grep "\-sh"
mobile           301   0.0  0.1  1584208   1216 s000  R+    3:33PM   0:00.01 grep \-sh
mobile           299   0.0  0.1  1594464   2304 s000  Ss    3:32PM   0:00.03 -sh
OTTO:/bootstrap mobile$ ./jailbreakd_client 
Usage: 
jailbreakd_client <pid> <1 | 2 | 5>
        1 = entitle+platformize the target PID
        2 = entitle+platformize the target PID and subsequently sent SIGCONT
        5 = rootify the pid (su/sudo/setuid(0))
OTTO:/bootstrap mobile$ ./jailbreakd_client 299 5
OTTO:/bootstrap mobile$ ps aux | grep "\-sh"
root             305   0.0  0.1  1584208   1392 s000  R+    3:33PM   0:00.01 grep \-sh
root             299   0.0  0.1  1594464   2304 s000  Ss    3:32PM   0:00.04 -sh
OTTO:/bootstrap mobile$

Now I will try to implement the setuid check in posix_spawn.

littlelailo commented 6 years ago

This took way longer then I thought it would take. Anyway now everything works (App was restarted manual after each kill):

OTTO:~ root# ps aux | grep "test"
root             711   0.0  0.1  1584208   1392 s000  R+    1:02PM   0:00.01 grep test
mobile           709   0.0  1.0  1640672  20240   ??  Ss    1:02PM   0:00.22 /var/containers/Bundle/Application/<uid>/test_posix_spawn.app/test_posix_spawn
OTTO:~ root# chmod +s /var/containers/Bundle/Application/<uid>/test_posix_spawn.app/test_posix_spawn
OTTO:~ root# kill -9 709
OTTO:~ root# ps aux | grep "test"
root             713   0.0  1.1  1641120  22208   ??  Ss    1:02PM   0:00.24 /var/containers/Bundle/Application/<uid>/test_posix_spawn.app/test_posix_spawn
root             715   0.0  0.1  1584288   1424 s000  R+    1:02PM   0:00.01 grep test
OTTO:~ root# chmod -s /var/containers/Bundle/Application/<uid>/test_posix_spawn.app/test_posix_spawn
OTTO:~ root# kill -9 713
OTTO:~ root# ps aux | grep "test"
mobile           717   0.0  1.0  1641776  20128   ??  Ss    1:03PM   0:00.21 /var/containers/Bundle/Application/<uid>/test_posix_spawn.app/test_posix_spawn
root             719   0.0  0.1  1584288   1408 s000  R+    1:03PM   0:00.01 grep test
OTTO:~ root#

Of course this does not work for anything which isn't going through launchd or xpc_proxy. So when you run a setuid binary over ssh (logged in as mobile) it won't elevate, there you need to elevate using jailbreakd_client's rootify command.

I will now test everything and removed my debug code. Pull request: #81

nullpixel commented 6 years ago

Added in https://github.com/coolstar/electra/commit/a1bc56384df29b36bf4bc09c9e3c890b339c385a

stek29 commented 6 years ago

Nah, there's still no su binary.

nullpixel commented 6 years ago

oh lol

nullpixel commented 6 years ago

thought that added it for some reason

littlelailo commented 6 years ago

So the su binary should do the following(?):

Because I would like to implement this, but I want to make sure, that you're ok with my idea on how to implement it.

stek29 commented 6 years ago

Yup, I think that's ok.

littlelailo commented 6 years ago

Update: the su binary is now working:

OTTO:~ root# ls -la /bootstrap/                                                                                                                                                                                                               
total 348                                                  
drwxr-xr-x 17 root   admin   544 Jan 31 21:25 .            
drwxrwxr-t 19 root   admin   608 Jan 31 21:25 ..           
drwxr-xr-x  8 mobile staff   256 Jan 31 21:25 Library      
-rwxr-xr-x  1 mobile staff   896 Dec 23 19:21 README       
-rwxr-xr-x  1 mobile staff 52176 Jan 31 21:25 amfid_payload.dylib                                                      
drwxr-xr-x 53 mobile staff  1696 Jan 16 21:36 bin          
-rw-r--r--  1 mobile staff   453 Dec 22 04:09 buildlist.sh 
drwxr-xr-x  4 mobile staff   128 Dec 20 02:42 etc          
-rwxr-xr-x  1 mobile staff 53088 Jan 31 21:25 inject_criticald                                                         
-rwxr-xr-x  1 mobile staff 77216 Jan 31 21:25 jailbreakd   
-rwxr-xr-x  1 mobile staff 50672 Jan 31 21:25 jailbreakd_client                                                        
-rwxr-xr-x  1 mobile staff 52976 Jan 31 21:25 pspawn_payload.dylib                                                     
drwxr-xr-x  9 mobile staff   288 Dec 25 00:39 sbin         
-rwsr-xr-x  1 root   wheel 51376 Jan 31 21:25 su           
drwxr-xr-x  4 root   admin   128 Jan 27 10:52 test         
-rw-r--r--  1 root   admin   810 Jan 31 21:25 unjailbreak.sh                                                           
drwxr-xr-x  9 mobile staff   288 Jan 25 21:55 usr   
====== (started process in other terminal)
OTTO:~ root# ps aux | grep "/3"                        
root             278   0.0  0.1  1584208   1216 s000  S+    9:27PM   0:00.01 grep /3
root             274   0.0  0.1  1583968   1232 s001  S+    9:27PM   0:00.00 ./test/3
root             273   0.0  0.1  1584992   1856 s001  S+    9:27PM   0:00.02 ./su ./test/3
OTTO:~ root#

Other terminal:

OTTO:/bootstrap mobile$ ./su ./test/3                      
Call up to jbd. This may take some time...                 
Spawn process now...

But I was not able to get my head around the UserNotification thing. So looking into this is the next step and after that I will make a PR.

nullpixel commented 6 years ago

Looks good!

stek29 commented 6 years ago

@littlelailo btw, @summertriangle-dev was working with XPC jailbreakd on his fork. you might want to check it out.

littlelailo commented 6 years ago

img_0026 Works 🎉 One question @stek29 I need the value kCFBooleanTrue, but I wasn't able to find the right header file. Could you help? And one more question: how long should I wait till I let the request time out? Now I need to port this to the jbd lib and then I will open a pr.

stek29 commented 6 years ago

@littlelailo

❯ rg kCFBooleanTrue /System/Library/Frameworks/CoreFoundation.framework
/System/Library/Frameworks/CoreFoundation.framework/Versions/A/Headers/CFNumber.h
21:const CFBooleanRef kCFBooleanTrue;
coolstar commented 6 years ago

http://git.savannah.gnu.org/gitweb/?p=coreutils.git;a=blob;f=src/su.c;h=bb54cc33a3b5ac18efeb06c4898718d0b70450ef;hb=7b6ce030cc54b34c7fc8a87a0c89137fb5c78a50

We can use su from GNU coreutils 8.18 (its been removed from coreutils after that version, but we should be fine with just su being older source)

littlelailo commented 6 years ago

@coolstar So we won't go for the CFUserNotification approach?

stek29 commented 6 years ago

@littlelailo I think whole CFUserNotification thing should have it's own issue with discussion: about tweak/sandbox injection skipping, about SU notification, about safe mode (which IMO should show a notification which can be opened from status bar and not the app activating on each unlock)