aboutsummaryrefslogtreecommitdiff
path: root/interpose/src/envbypass.c
diff options
context:
space:
mode:
authorspv <spv@spv.sh>2023-03-19 17:56:17 -0400
committerspv <spv@spv.sh>2023-03-19 17:56:17 -0400
commit7001c2a2a18bee2537946f4d490be1c7eef6a138 (patch)
treeeec15413f8bd6f95e1435542a709a1e675ccff59 /interpose/src/envbypass.c
Diffstat (limited to 'interpose/src/envbypass.c')
-rwxr-xr-xinterpose/src/envbypass.c431
1 files changed, 431 insertions, 0 deletions
diff --git a/interpose/src/envbypass.c b/interpose/src/envbypass.c
new file mode 100755
index 0000000..db0355e
--- /dev/null
+++ b/interpose/src/envbypass.c
@@ -0,0 +1,431 @@
+#include <time.h>
+#include <stdio.h>
+#include <spawn.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <mach/mach.h>
+#include "envbypass.h"
+
+task_t tfp1;
+
+uint32_t lread_uint32(uint32_t addr) {
+ vm_size_t bytesRead=0;
+ uint32_t ret = 0;
+ vm_read_overwrite(tfp1, addr, 4, (vm_address_t)&ret, &bytesRead);
+ return ret;
+}
+
+int lwrite_uint32(uint32_t addr, uint32_t value) {
+ return vm_write(tfp1, addr, (vm_offset_t)&value, 4);
+}
+
+bool page_allocated(uint32_t addr) {
+ vm_size_t bytesRead=0;
+ uint32_t ret = 0;
+ return vm_read_overwrite(tfp1, addr, 4, (vm_address_t)&ret, &bytesRead) == 0;
+}
+
+extern char **environ;
+
+#include <mach/mach_time.h>
+#include <mach/mach.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <stdio.h>
+#include <errno.h>
+
+/* kernel HACKED */
+task_t tfp0;
+
+/* KASLR shit */
+#define LC_SIZE 0x0000000f
+#define UNSLID_BASE 0x80001000
+
+/* fuck you apple let me use syscall(...) */
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+
+#ifndef USLEEP_TIME_IN_US
+#define USLEEP_TIME_IN_US 250
+#endif
+
+/* slip-n-slide into bullshit :tm: */
+uint32_t slide;
+
+uint32_t kread_uint32(uint32_t addr) {
+ vm_size_t bytesRead=0;
+ uint32_t ret = 0;
+ vm_read_overwrite(tfp0, addr, 4, (vm_address_t)&ret, &bytesRead);
+ return ret;
+}
+
+void kwrite_uint32(uint32_t addr, uint32_t value) {
+ vm_write(tfp0, addr, (vm_offset_t)&value, 4);
+}
+
+void kwrite_uint16(uint32_t addr, uint16_t value) {
+ vm_write(tfp0, addr, (vm_offset_t)&value, 2);
+}
+
+uint32_t get_kernel_slide(){
+ uint32_t slide;
+ uint32_t base = 0x80001000;
+ uint32_t slid_base;
+
+ /*
+ * slide = 0x1000000 + (0x200000 * random byte)
+ * start at 256 so we don't get the kernel mad at us for reading unmapped memory
+ * or something idk
+ */
+
+ for (int slide_byte = 256; slide_byte >= 1; slide_byte--) {
+ slide = 0x01000000 + 0x00200000 * slide_byte;
+ slid_base = base + slide;
+
+ if (kread_uint32(slid_base) == 0xfeedface) {
+ /*
+ * this looks like a kernel base
+ */
+
+ if (kread_uint32(slid_base + 0x10) == LC_SIZE) {
+ /*
+ * we found it bae
+ */
+
+ return slide;
+ }
+ }
+ }
+ return -1;
+}
+
+uint8_t* dump_kernel(uint8_t* kdata, uint32_t len) {
+ vm_size_t segment = 4;
+
+ /*
+ * this code is stolen from jailbreak.m in p0laris,
+ * which was stolen from internal Athenus Dev Team tools :P
+ */
+
+ printf("[*] finding acceptable segment size...\n");
+
+ for (int i = 0; i < 16384; i++) {
+ /*
+ * basically, continuously increment `segment` we're reading by by 4.
+ * re-read from the kernel base until vm_read_overwrite fails.
+ *
+ * now, technically, there's probably a better way to get this value,
+ * and also likely and a better way to check that won't run into issues
+ * if vm_read_overwrite fails for other reasons, but i CBA. :P
+ */
+
+ int ret = vm_read_overwrite(tfp0,
+ UNSLID_BASE + slide,
+ segment,
+ (vm_address_t)kdata + (i * segment),
+ &segment);
+
+ if (ret == 0) {
+ /*
+ * no fail, increase by 4.
+ */
+
+ segment += 4;
+ } else {
+ /*
+ * it failed at a length of `segment`, and we increase by 4 in the loop.
+ * so, subtracting 4 will give us the last value we used that succeeded.
+ */
+
+ printf("[*] mach_vm_read_overwrite returned %d at segment %d\n",
+ ret,
+ segment);
+ segment -= 4;
+ break;
+ }
+ }
+
+ /*
+ * we found the max segment size!
+ */
+
+ printf("[*] acceptable segment size: %d\n", segment);
+
+ for (int i = 0; i < len / segment; i++) {
+ /*
+ * DUMP DUMP DUMP
+ */
+
+ vm_read_overwrite(tfp0,
+ UNSLID_BASE + slide + (i * segment),
+ segment,
+ (vm_address_t)kdata + (i * segment),
+ &segment);
+ }
+
+ return kdata;
+}
+
+uint32_t find_syscall0(uint32_t region, uint8_t* kdata, size_t ksize) {
+ uint32_t addy = -1;
+ char* hfs_private_directory_data = memmem(kdata,
+ ksize,
+ ".HFS+ Private Directory Data\r",
+ strlen(".HFS+ Private Directory Data\r"));
+ printf("[*] hfs_private_directory_data = %p\n",
+ hfs_private_directory_data);
+ uint32_t hfs_private_directory_data_addy = (uintptr_t)hfs_private_directory_data
+ - (uintptr_t)kdata
+ + region;
+ char* hfs_private_directory_data_addy_ptr = memmem(kdata,
+ ksize,
+ (char*)&hfs_private_directory_data_addy,
+ sizeof(hfs_private_directory_data_addy));
+ printf("[*] hfs_private_directory_data_addy_ptr = %p\n",
+ hfs_private_directory_data_addy_ptr);
+ uint32_t hfs_private_directory_data_ptr_addy = (uintptr_t)hfs_private_directory_data_addy_ptr
+ - (uintptr_t)kdata;
+ addy = hfs_private_directory_data_ptr_addy + 0x4;
+
+ return addy;
+}
+
+uint32_t syscall0_addr = -1;
+#define DEBUG_SYSCALLS 0
+
+uint32_t function_addr(int syscall_id, uint32_t slide) {
+ uint32_t function_entry_addr = syscall0_addr + (syscall_id * 0xc);
+ uint32_t function_addr = kread_uint32(function_entry_addr);
+ printf("[*] function_entry_addr = 0x08%x, function_addr = 0x%08x\n", function_entry_addr, function_addr);
+ return function_addr;
+}
+
+void replace_syscall_with_addr(int syscall_id, uint32_t addr, uint32_t slide, uint16_t num_args, uint32_t arg_bytes) {
+ uint32_t function_entry_addr = syscall0_addr + (syscall_id * 0xc);
+#if DEBUG_SYSCALLS
+ printf("[*] function_entry_addr = 0x%08x, function_addr = 0x%08x\n", function_entry_addr, kread_uint32(function_entry_addr));
+#endif
+ kwrite_uint32(function_entry_addr, addr | 1);
+ kwrite_uint16(function_entry_addr + 0x8, num_args);
+ kwrite_uint32(function_entry_addr + 0xa, arg_bytes);
+#if DEBUG_SYSCALLS
+ printf("[*] function_entry_addr = 0x%08x, function_addr = 0x%08x\n", function_entry_addr, kread_uint32(function_entry_addr));
+#endif
+}
+
+void replace_syscall(int syscall_id, uint8_t* code, uint32_t length, uint32_t slide, uint16_t num_args, uint32_t arg_bytes) {
+ uint32_t where = slide + 0x80001b00;
+ vm_write(tfp0, where, (vm_offset_t)code, length);
+ replace_syscall_with_addr(syscall_id, where, slide, num_args, arg_bytes);
+}
+
+#define ownage_syscall 379
+
+void csbypass(int offset_) {
+ uint32_t* comm_page_time;
+ kern_return_t ret;
+ uint8_t* kdata;
+
+ uint8_t payload420[] = {
+ 0x08, 0x68, // ldr r0, [r1]
+ 0x44, 0xf2, 0x44, 0x44, // movw r4, #0x4048
+ 0xcf, 0xf6, 0xff, 0x74, // movt r4, #0xffff
+ 0x20, 0x60, // str r0, [r4]
+ 0x4f, 0xf0, 0x00, 0x00, // mov r0, #0x0
+ 0x70, 0x47 // bx lr
+ };
+
+ int syscall_ret = 0;
+ uint32_t sret = 0;
+
+ printf("[*] offset=%d\n", offset_);
+
+ ret = task_for_pid(mach_task_self(), 0, &tfp0);
+ printf("[*] ret=%d, tfp0=%x\n", ret, tfp0);
+
+ slide = get_kernel_slide();
+ printf("[*] slide=0x%08x\n", slide);
+
+ kdata = (uint8_t*)malloc(32 * 1024 * 1024);
+ printf("[*] kdata=%p\n", kdata);
+
+ dump_kernel(kdata, 32 * 1024 * 1024);
+ syscall0_addr = find_syscall0(slide + 0x80001000,
+ kdata,
+ 32 * 1024 * 1024)
+ + 0x80001000
+ + slide;
+
+ free(kdata);
+ kdata = NULL;
+
+ printf("[*] 0x%08x\n", syscall0_addr);
+
+ printf("[*] 0x%08x\n", function_addr(ownage_syscall, slide));
+
+ replace_syscall(ownage_syscall, payload420, sizeof(payload420), slide, 1, 4);
+
+ printf("[*] 0x%08x\n", function_addr(ownage_syscall, slide));
+
+ syscall_ret = syscall(ownage_syscall, offset_);
+ sret = errno;
+
+ printf("[*] syscall(%d); = %d. errno(dec) = %d, errno(hex) = 0x%x. \n", ownage_syscall, syscall_ret, sret, sret);
+}
+
+char swaggang[] = "swaggang";
+
+bool _0wn(char* global_inject_dylib) {
+ task_for_pid(mach_task_self(), 1, &tfp1);
+ printf("[*] launchd DYLD env bypass by @__spv\n");
+ printf("[*] tfp1=0x%x\n", tfp1);
+ vm_size_t size;
+ uint32_t addy;
+ uint8_t* page = malloc(0x1000);
+ uint32_t address_of_string = 0;
+
+ char* replace_me = "SMOKETREESCSBYSPV1337";
+
+ for (int i = 0; i < 10; i++) {
+ printf("[*] setting %s=%s\n", replace_me, global_inject_dylib);
+ pid_t pid;
+ char *argv[] = {"/bin/launchctl", "setenv", replace_me, global_inject_dylib, NULL};
+
+ int status;
+ status = posix_spawn(&pid, "/bin/launchctl", NULL, NULL, argv, environ);
+ if (status == 0) {
+ do {
+ if (waitpid(pid, &status, 0) != -1) {
+ //
+ } else {
+ perror("waitpid");
+ goto out;
+ }
+ } while (!WIFEXITED(status) && !WIFSIGNALED(status));
+ }
+ else {
+ printf("posix_spawn: %s\n", strerror(status));
+ }
+ }
+
+ char* hax = "DYLD_INSERT_LIBRARIES";
+
+ printf("[*] searching teh pages\n");
+
+ bool found_one = false;
+ uint32_t num_found = 0;
+
+ char* read_data;
+
+ for (uint32_t pagen = 0x0; pagen < (0xffffffff >> 12); pagen++) {
+
+ if (pagen % ((0xffffffff >> 12) / 100) == 0) {
+ //printf("%d\n", pagen / ((0xffffffff >> 12) / 100));
+ }
+
+ uint32_t page_start = pagen << 12;
+ if (vm_read_overwrite(tfp1, page_start, 0x1000, (vm_address_t)page, &size))
+ continue; // page isn't allocated
+
+ ;
+
+ uint8_t* find = (uint8_t*)memmem(page, 0x1000, replace_me, 21);
+
+ if (!find)
+ continue; // not in this page
+
+ /* if we reach here, we have found a page that is allocated in launchd, containing our string. */
+ uint32_t offset = (uint32_t)(find - page);
+ address_of_string = page_start + offset;
+
+ printf("[*] found an addy 0x%08x\n", address_of_string);
+ printf("[*] lread_uint32(addy) = 0x%08x\n", lread_uint32(address_of_string));
+ printf("[*] vm_write(0x%08x) = 0x%x\n", addy, vm_write(tfp1, (vm_address_t)address_of_string, (vm_offset_t)hax, 21));
+ printf("[*] lread_uint32(addy) = 0x%08x\n", lread_uint32(address_of_string));
+
+ num_found++;
+ found_one = true;
+
+ pid_t pid;
+ char *argv[] = {"/bin/sh", "-c", "launchctl getenv DYLD_INSERT_LIBRARIES 2>&1 > /tmp/env", NULL};
+
+ int status;
+ status = posix_spawn(&pid, "/bin/sh", NULL, NULL, argv, environ);
+ if (status == 0) {
+ do {
+ if (waitpid(pid, &status, 0) != -1) {
+ //
+ } else {
+ perror("waitpid");
+ goto out;
+ }
+ } while (!WIFEXITED(status) && !WIFSIGNALED(status));
+ }
+ else {
+ printf("posix_spawn: %s\n", strerror(status));
+ }
+
+ FILE* fp = fopen("/tmp/env", "r");
+
+ if (!fp) continue;
+
+ fseek(fp, 0, SEEK_END);
+ size_t len = ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+
+ read_data = (char*)malloc(len);
+ fread(read_data, len, 1, fp);
+ fclose(fp);
+
+ if (strstr(read_data, "dylib")) {
+ // prolly good, right?
+ break;
+ }
+
+ }
+
+ unlink("/tmp/env");
+
+ free(page);
+ if (read_data)
+ free(read_data);
+
+out:
+ if (found_one) {
+ printf("[*] done\n");
+ return true;
+ }
+ else {
+ printf("[*] didn't find any. whatever, let's try again\n");
+ return _0wn();
+ }
+}
+
+int main(int argc, char* argv[]) {
+ _0wn();
+
+ uint32_t offset = 0;
+ time_t val;
+ FILE* fp;
+ syslog(LOG_SYSLOG, "game over");
+
+ if (argc >= 2) {
+ offset = atoi(argv[1]);
+ goto do_it;
+ }
+
+ fp = fopen("/untether/offset", "rb");
+ if (fp) {
+ fread(&val, sizeof(val), 1, fp);
+ fclose(fp);
+ offset = val;
+ }
+
+do_it:
+ csbypass(offset);
+
+ return 0;
+}