Старый 13.06.2012, 09:06   #1
SynQ
 
Регистрация: 11.07.2010
Сообщений: 953
Репутация: 352
По умолчанию CVE-2012-0217 FreeBSD 7.x - 9.0 amd64 privesc @ Intel CPUs

FreeBSD-SA-12:04.sysret


UPDATE: эксплойт от overxor в 12-ом посте этой темы!
UPDATE2: более поздний эксплойт от iZsh с меньшим количеством зависимостей 17-ом посте
UPDATE3:
BlackHat US 12: Rafal Wojtczuk - A Stitch in Time Saves Nine: A Case of Multiple Operating System Vulnerability Whitepaper
BlackHat US 12: Rafal Wojtczuk - A Stitch in Time Saves Nine: A Case of Multiple Operating System Vulnerability Slides
UPDATE4:
VUPEN - Advanced Exploitation of Windows Kernel Intel 64-Bit Mode Sysret Vulnerability
UPDATE5:
Видео + исходники эксплуатации уязвимости под Windows
UPDATE6:
VUPEN - Advanced Exploitation of Xen Hypervisor Sysret VM Escape Vulnerability
UPDATE7(2015):
Adventures in Xen exploitation

Рафау Войчук (Rafal Wojtczuk), который работал в фирме Джоанны Рутковской, выложил багу под гипервизор Xen, которая также нашлась в 64-битных версиях ядра FreeBSD, работающих на процессорах Intel.

Заключается она в возможности выполнения своего кода в ring0.

При установке пользователем указателя инструкций RIP неканонического вида процессор вызовет обработчик ошибки, который, будучи еще в ring0, запустится с выбранными пользователем значениями регистров %gs и %rsp.

Уязвимости подвержены все поддерживаемые версии FreeBSD (о более ранних молчат).

Исправлено:
Цитата:
Corrected: 2012-06-12 12:10:10 UTC (RELENG_7, 7.4-STABLE)
2012-06-12 12:10:10 UTC (RELENG_7_4, 7.4-RELEASE-p9)
2012-06-12 12:10:10 UTC (RELENG_8, 8.3-STABLE)
2012-06-12 12:10:10 UTC (RELENG_8_3, 8.3-RELEASE-p3)
2012-06-12 12:10:10 UTC (RELENG_8_2, 8.2-RELEASE-p9)
2012-06-12 12:10:10 UTC (RELENG_8_1, 8.1-RELEASE-p11)
2012-06-12 12:10:10 UTC (RELENG_9, 9.0-STABLE)
2012-06-12 12:10:10 UTC (RELENG_9_0, 9.0-RELEASE-p3)
Патч:
Код:
Index: sys/amd64/amd64/trap.c
===================================================================
--- sys/amd64/amd64/trap.c.orig
+++ sys/amd64/amd64/trap.c	(working copy)
@@ -972,4 +972,21 @@
 	     syscallname(td->td_proc, sa.code)));
 
 	syscallret(td, error, &sa);
+
+	/*
+	 * If the user-supplied value of %rip is not a canonical
+	 * address, then some CPUs will trigger a ring 0 #GP during
+	 * the sysret instruction.  However, the fault handler would
+	 * execute with the user's %gs and %rsp in ring 0 which would
+	 * not be safe.  Instead, preemptively kill the thread with a
+	 * SIGBUS.
+	 */
+	if (td->td_frame->tf_rip >= VM_MAXUSER_ADDRESS) {
+		ksiginfo_init_trap(&ksi);
+		ksi.ksi_signo = SIGBUS;
+		ksi.ksi_code = BUS_OBJERR;
+		ksi.ksi_trapno = T_PROTFLT;
+		ksi.ksi_addr = (void *)td->td_frame->tf_rip;
+		trapsignal(td, &ksi);
+	}
 }
Посмотреть тип процессора во FreeBSD можно так:
Код:
sysctl -a|grep "hw."
@argp уже пишет poc, так что думаю эксплойт не за горами.

Линки:
баг в Xen – https://bugzilla.redhat.com/show_bug.cgi?id=813428
Патч – http://security.freebsd.org/patches/SA-12:04/sysret.patch
В ядре Linux это исправили в 2006-м году – http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;...

PS Интересно, в Open- и NetBSD такой баги нет?

Последний раз редактировалось SynQ; 27.02.2015 в 14:17..
SynQ вне форума   Ответить с цитированием
Старый 14.06.2012, 16:32   #2
SynQ
 
Регистрация: 11.07.2010
Сообщений: 953
Репутация: 352
По умолчанию

В NetBSD тоже нашлась И в Win7.

Хороший пост о баге: http://blog.xen.org/index.php/2012/0...ge-escalation/

Кто не знает английского, кратко сюда перепишу.
Неканонический - указатель, который лежит за пределами диапазонов:
Цитата:
0x0000000000000000-0x00007fffffffffff
0xffff800000000000-0xffffffffffffffff
После SYSRET в RIP восстанавливается значение, которое было сохранено в RCX. И тогда срабатывает general protection fault, в котором ядро пытается записать fault frame по адресу в rsp (который может быть указан юзером перед выполнением syscall).

Последний раз редактировалось SynQ; 20.06.2012 в 13:08..
SynQ вне форума   Ответить с цитированием
Старый 14.06.2012, 18:19   #3
tipsy
 
Аватар для tipsy
 
Регистрация: 10.07.2010
Сообщений: 415
Репутация: 311
По умолчанию

В OpenBSD нет
tipsy вне форума   Ответить с цитированием
Старый 19.06.2012, 10:05   #4
SynQ
 
Регистрация: 11.07.2010
Сообщений: 953
Репутация: 352
По умолчанию

Еще порция инфы. На блэкхэте Рафау будет выступать с предентацией, там же наверняка будет эксплойт.

Пока Immunity CANVAS выложили видео работы эксплойта в своем фреймворке (не особо интересно): http://partners.immunityinc.com/movies/SYSRET-v2.mov

Как оказалось, во фре изначально неправильно запатчили этот баг в версии 8.1 (случайно вставили проверку внутри другого условия if):
http://marc.info/?l=freebsd-security...6981130813&w=2
http://marc.info/?l=freebsd-security...5680621707&w=2
http://svnweb.freebsd.org/base/relen...ew=markup#l965
SynQ вне форума   Ответить с цитированием
Старый 20.06.2012, 17:00   #5
SynQ
 
Регистрация: 11.07.2010
Сообщений: 953
Репутация: 352
По умолчанию

У кого какие идеи, как сделать в rip неканонический адрес при сисколле?
Через ptrace() никак наверно. Сделать mmap в зоне неканонических адресов естественно не разрешает.

Пришла идея, что можно заммапить последнюю страницу 0x7ffffffff000 в юзерленде, занопить ее, а в самый конец поставить вызов сисколла, тогда по идее при его вызове rip выйдет за зону канонических адресов и станет 0x800000000000.
У меня на фре 9.0 в виртуалке подобный ход конем завешивает ее, в /var/crash пусто.

Какие мысли, это оно?

Код:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>

char sc[]=
"\x90\x48\xb8\xb7\x00\x00\x00\x00\x00\x00\x00" // mov 123, rax
"\x48\x31\xff" // xor rdi, rdi
"\x0f\x05";  // syscall

void main(){
void (*addr)();
addr = mmap(0x00007ffffffff000, 4096, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0);

if (addr == MAP_FAILED) {
        printf("mmap fault\n");
        exit(1);
        }

memset(addr, 0x90,4096);
memcpy(addr+4080, sc, 16);
addr();
// 0x0000000000000000-0x00007fffffffffff        0xffff800000000000-0xffffffffffffffff
}
SynQ вне форума   Ответить с цитированием
Старый 21.06.2012, 21:24   #6
Specialist
 
Регистрация: 13.06.2012
Сообщений: 25
Репутация: 20
По умолчанию

Такого рода вещи лучше на реальном железе тестить, а не в виртуалке, они вполне могли всё эмулировать в соответствии со стандартами. Во фре есть неплохой DDB, посмотри в нём, что в RCX перед SYSRET.
Идея твоя классная, должно сработать
Дыра вообще интересная, был бы x64, поковырял бы.
Specialist вне форума   Ответить с цитированием
Старый 22.06.2012, 11:35   #7
SynQ
 
Регистрация: 11.07.2010
Сообщений: 953
Репутация: 352
По умолчанию

Не, выше видео есть от immunity, там тоже в виртуалке, все работает через VT-d проца.
В моем случае еще лучше: я эту freebsd amd64 запускаю в 32-битной хост ОСи

ddb лень ставить/разбираться, хотя может и посмотрю. Через месяц на blackhat уверен готовый эксплойт зарелизят.
SynQ вне форума   Ответить с цитированием
Старый 23.06.2012, 13:47   #8
overxor
 
Регистрация: 14.10.2011
Сообщений: 73
Репутация: 90
По умолчанию

SynQ, отличная идея!
В сискол входит с rip равным 0x800000000000
Единственная сложность отлаживать неудобно. ddb через раз ловит панику.
И перед sysret значение rsp, которое я задал еще в юзер моде, почему-то не восстанавливается.
__________________
[IO]
overxor вне форума   Ответить с цитированием
Старый 25.06.2012, 14:00   #9
SynQ
 
Регистрация: 11.07.2010
Сообщений: 953
Репутация: 352
По умолчанию

Выложу немного наработок.
я ставил бряк на amd64_syscall и последовательно проверял имя процесса (в файле поставил перез запуском sleep(10)):
(kgdb) print td->td_name
если не мой запущенный файл, то continue "c" и снова смотрел имя, пока не найдешь, обычно раз 5-6 хватало, чтобы найти.
Затем снимал бряк "clear amd64_syscall".
Бектрейс показал, что amd64_syscall вызывается из Xfast_syscall(): http://fxr.watson.org/fxr/source/amd...ception.S#L387
На след. строку можно поставить бряк b /usr/src/sys/amd64/amd64/exception.S:388
Поскольку у меня переходило на третью метку и уходило куда-то далеко, я руками сменил rip на тот, что в 398-ой строке, тогда далее $rsp и $rcx (в котором $rip) восстанавливались, как и должно быть, но увидеть запись ошибки по выбранному $rsp не довелось - вмварь на sysret ребутала вм.
Вероятно такие вещи надо отлаживать на реальной машине с серийным портом.

В логах вмвари увидел, что рестарт идет из-за triple fault процессора

Последний раз редактировалось SynQ; 25.06.2012 в 14:28..
SynQ вне форума   Ответить с цитированием
Старый 25.06.2012, 22:15   #10
12309
 
Регистрация: 25.12.2011
Сообщений: 265
Репутация: 33
По умолчанию

https://www.youtube.com/watch?v=1UeJXokbja0
видео со сплоентом, не от immunity canvas
12309 вне форума   Ответить с цитированием
Ответ

Метки
freebsd, kernel, privilege escalation

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

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

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

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

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



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