| RSS



Меню

Bookmark and Share


Статистика
Ваш IP: 3.15.10.104
Вы используете: v





Сейчас на сайте:

Тех поддержка ->

Облако тэгов
ОС видио Tor Обратная сторона антенна 4.6 PHP Эксплоит Windows Server 2008 qip Virtual chroot kernel proc sysctl tune FreeBSD bridge Boot Disk Bluetooth GEO game directx Emulator Python Shell DDoS червь Conficker вирус троян Лаборатория Касперского пиратство apple iPhone ИТ-отрасль Щеголев Microsoft экономический кризис Twitter социальная сеть анонимность Лицензия Open Source ASP.NET MVC уязвимость MySQL база данных файлообмен закон франция пират Skype мобильный Deutsche Telekom Хакер киберпреступник Trend Micro кибератака Германия робот утечка данных персональные данные ноутбук интернет Китай цензура ядро Linux Торвальдс Windows Vista Acer Linux патент браузер Firefox Internet Explorer Opera Net Applications Safari Intel Linux Foundation Moblin Oracle патч банкомат кардер HSM IBM X-Force Cofee сша кибервойна Эстония Dell ИТ-специалист хакерские атаки Pirate Bay контроль кибербезопасность язык программирования The Pirate Bay Пиратская партия утечка информации приговор Mozilla Chrome безопасность Госдума СМИ Windows 8 Баллмер взлом Пентагон ботнет Украина Facebook Cisco cloud Windows XP нетбук торрент музыка биометрический nokia ФБР IP-адрес CIPAV Comcast sms RSA java Google CAPTCHA Symantec спам конфиденциальная информация инсайдер Perimetrix антивирус тест Anti-Malware Windows 7 операционная система Windows провайдер авторское право RapidShare UNIX свиной грипп шантаж дети EFF BluWiki копирайт экстремизм Panda Security cloud computing McAfee Cybercrime Response Unit Bottle Domains HTTPS ICANN студент шпионское ПО Норвегия школьник New York Times XSS YouTube Warner Music кибершпионаж КНДР Ubuntu свободное ПО AMD ATI касперский Россия РФ сервер хостинг фальшивый антивирус Comodo CA Wi-Fi D-Link суд пароль блог фишинг Одноклассники медведев контрафакт мошенник штраф Sony GPS по Gumblar JAVASCRIPT хакеры вредоносное ПО Yahoo ФАС компьютер Софт MPAA кибероружие PandaLabs Red Hat Минкомсвязи сбой ASUSTeK Computer мошенничество Доктор Веб ВКонтакте Cyber-Arc исходный код PCI DSS МВД фильтр порнография BREIN свобода слова Казахстан GEMA Autodesk сисадмин Gmail кредитная карта кибермошенник LiveJournal шифрование криптография Deep Purple банк нанотехнологии Wikipedia zero-day ColdFusion выборы кража данных DNS BIND Android BASIC атака Black Hat Mac OS X Click Forensics Clampi домен фсб Прокуратура Уголовное дело icq Barrelfish киберпреступность Sophos AT&T ошибка Electa Gamma Knife OpenBSD DARPA военные Сайт Visual Studio 2010 .NET Framework 4 Chrome OS электронная почта турция конференция спамер FTC полиция российская ОС Koobface Великобритания БЕЛОРУССИЯ грузия BSA Bittorrent облачные вычисления Azure Европа Dr.Web Билл Гейтс спецслужбы Cryzip Живой Журнал Royal Bank of Scotland смартфон Canonical Pwn2Own F-Secure Symbian Hotmail фильм

Главная » Статьи » Общие Статьи

Эксплойт уязвимости Xen Hypervisor Sysret VM Escape

Привет всем! В этом блоге мы поделимся техническим анализом и эксплуатацией критической уязвимости (CVE-2012-0217), которой подвержен гипервизор Xen.

Автор: Jordan Gruskovnjak

Привет всем! В этом блоге мы поделимся техническим анализом и эксплуатацией критической уязвимости (CVE-2012-0217), которой подвержен гипервизор Xen. Уязвимость совсем недавно была обнаружена Рафалом Вайджуком (Rafal Wojtczuk) и Яном Бейлихом (Jan Beulich).

Уязвимости подвержены системы, работающие на интеловском аппаратном обеспечении. Благодаря уязвимости, нарушитель, находящийся внутри гостевой операционной системы, может обойти ограничения виртуальной среды и выполнить произвольный код на системе хоста с правами самого привилегированного домена ("dom0”). Обладая правами dom0 можно напрямую управлять аппаратным обеспечением и непривилегированными доменами ("domU”).

Если ваша виртуальная или облачная инфраструктура работает на гипервизоре Xen, то вам настоятельно рекомендуется обновиться до версии 4.1.3, в которой критическая уязвимость устранена.

1. Технический анализ уязвимости

Инструкции SYSCALL/SYSRET позволяют быстро переключить контекст между режимом пользователя и режимом ядра. Согласно спецификации Intel, SYSCALL осуществляет переход по адресу, указанному в регистре MSR_IA32_LSTAR. В Xen способ обработки системных вызовов зависит от того, является ли гостевая машина полностью виртуализируемой (Hardware Virtual Machine - HVM) или только паравиртуализироваемой (ParaVirtualized Machine- PVM):

Если мы имеем дело с HVM, то у гостевой системы есть собственная таблица прерываний IDT и MSR регистры, поэтому гостевая машина не нуждается в помощи гипервизора при обработке прерываний и системных вызовов.

С PVM дело обстоит немного по-другому, поскольку гостевая система знает, что ею управляет гипервизор. Чтобы паравиртуализируемая машина функционировала нормально, необходимо модифицировать ядро так, чтобы оно работало не в ring0, а в ring1.

Ядро обращается к ключевым структурам (GDT, IDT, и.т.п.) в Xen посредством гипервызовов. Гипервызовы идентичны системным вызовам, но производятся они не из пользовательского режима в режим ядра, а из режима ядра в режим гипервизора.

Системный вызов из пользовательского процесса напрямую обращается в ring0 к диспетчеру гипервизора, а диспетчер уже затем решает, из какого режима (пользовательского или режима ядра) производился вызов. Код процедуры выбора находится в файле "xen/x86/x86-64/entry.S”:


/* 
* When entering SYSCALL from kernel mode: 
* %rax = hypercall vector 
* %rdi, %rsi, %rdx, %r10, %r8, %9 = hypercall arguments 
* %rcx = SYSCALL-saved %rip 
* NB. We must move %r10 to %rcx for C function-calling ABI. 

* When entering SYSCALL from user mode: 
* Vector directly to the registered arch.syscall_addr. 

* Initial work is done by per-CPU stack trampolines. At this point %rsp 
* has been initialised to point at the correct Xen stack, and %rsp, %rflags 
* and %cs have been saved. All other registers are still to be saved onto 
* the stack, starting with %rip, and an appropriate %ss must be saved into 
* the space left by the trampoline. 
*/ 
ALIGN 
ENTRY(syscall_enter) 
sti 
movl $FLAT_KERNEL_SS,24(%rsp) 
pushq %rcx 
pushq $0 
movl $TRAP_syscall,4(%rsp) 
movq 24(%rsp),%r11 /* Re-load user RFLAGS into %r11 before SAVE_ALL */ 
SAVE_ALL 
GET_CURRENT(%rbx) 
movq VCPU_domain(%rbx),%rcx 
testb $1,DOMAIN_is_32bit_pv(%rcx) 
jnz compat_syscall 
testb $TF_kernel_mode,VCPU_thread_flags(%rbx) 
jz switch_to_kernel 

Если вызов исходил из пользовательского процесса, то Xen передает вызов в ядро, и затем для обработки вызова используется таблица IDT ядра. Если же системный вызов производился из режима ядра (гипервызов), то Xen использует свою таблицу IDT, чтобы обработать системный вызов. Снова код из "xen/x86/x86-64/entry.S”:

ENTRY(syscall_enter) 
sti 
movl $FLAT_KERNEL_SS,24(%rsp) 
pushq %rcx 
pushq $0 
movl $TRAP_syscall,4(%rsp) 
movq 24(%rsp),%r11 /* Re-load user RFLAGS into %r11 before SAVE_ALL */ 
SAVE_ALL 
GET_CURRENT(%rbx) 
movq VCPU_domain(%rbx),%rcx 
testb $1,DOMAIN_is_32bit_pv(%rcx) 
jnz compat_syscall 
testb $TF_kernel_mode,VCPU_thread_flags(%rbx) 
jz switch_to_kernel 
... 

/*hypercall:*/ 
movq %r10,%rcx 
cmpq $NR_hypercalls,%rax 
jae bad_hypercall ; exit in case of wrong hypercall number 
... 
leaq hypercall_table(%rip),%r10 
PERFC_INCR(hypercalls, %rax, %rbx) 
callq *(%r10,%rax,8) ; jump on hypercall handler 

При возврате из гипервызова в режиме ядра выполняется следующий код:


/* %rbx: struct vcpu, interrupts disabled */ 
restore_all_guest: 
ASSERT_INTERRUPTS_DISABLED 
RESTORE_ALL 
testw $TRAP_syscall,4(%rsp) 
jz iret_exit_to_guest 

addq $8,%rsp 
popq %rcx ; RIP 
popq %r11 ; CS 
cmpw $FLAT_USER_CS32,%r11 
popq %r11 ; RFLAGS 
popq %rsp ; RSP 
je 1f 
sysretq ; 64 bits kernel 
1: sysretl ; 32 bits kernel 

В мануалах Intel утверждается, что существует особый случай, когда выполнение инструкции SYSRET может вызвать исключение. Действительно, если регистр RCX (из которого загружается значение RIP при переходе в режим пользователя) содержит неканонический адрес, то процессор вызовет исключение #GP (General Protection fault).

Канонический адрес – это адрес, располагающийся в одном из следующих диапазонов:

  • 0x0000000000000000 - 0x00007FFFFFFFFFFF
  • 0xFFFF800000000000 - 0xFFFFFFFFFFFFFFFF

Канонические адреса требуются для того, чтобы ограничить виртуальное адресное пространство 48ю битами вместо полных 64 бит.

В интеловской архитектуре процессор при вызове исключения #GP работает в ring0, в то время как значения всех регистров общего назначения уже восстановлены до значений режима ядра.

Управляя регистрами общего назначения, можно повлиять на работу гипервизора, обойти ограничения виртуальной среды и выполнить произвольный код в контексте гипервизора.

2. Вызов бага в Xen и CitrixXenServer

Тот факт, что инструкция SYSRET выполняется только в контексте гипервызова, подразумевает, что инструкция SYSCALL должна выполняться в режиме ядра. Первое, что приходит на ум: для вызова бага использовать модуль ядра.

Чтобы баг сработал, нам нужно отобразить страницу памяти где-нибудь рядом с неканоническими адресами и вызвать SYSCALL так, чтобы адрес инструкции следующей за SYSCALL указывал бы на неканониченский адрес.

Обычно Linux не позволяет отображать память (с помощью функции mmap()) рядом с каноническим адресом 0x7FFFFFFFF000. Поэтому в первую очередь нам нужно как-то обойти такое ограничение.

В Linux после проверки всех параметров функция mmap() вызывает функцию "mmap_region()”, описанную в файле "mm/mmap.c”. Вызов непосредственно функции с необходимыми параметрами позволит нам отобразить страницу на адрес 0x7FFFFFFFF000:

void *mapping; 
unsigned int vm_flags; 
vm_flags = VM_READ | VM_WRITE | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC; 

mapping = p_mmap_region(NULL, 0x7ffffffff000, 0x1000, 
MAP_ANON|MAP_PRIVATE|MAP_FIXED|MAP_POPULATE, vm_flags, 0);

В мануале по mmap утверждается, что благодаря флагу MAP_POPULATE обновление таблицы страниц произойдет еще до возникновения ошибки, если таковая будет иметь место. В контексте модуля ядра, доступ к отображенной странице без флага MAP_POPULATE приведет к ошибке.

Таким образом, после вызова mmap_region с адресом 0x7FFFFFFFF000 в качестве параметра, ядро выделит страницу размером 0x1000 байт, начинающуюся с адреса 0x7FFFFFFFF000. Поскольку размер страницы 0x1000 байт, диапазон выделенных адресов будет начинаться адресом 0x7FFFFFFFF000 и заканчиваться адресом 0x7FFFFFFFFFFF.

Код инструкции SYSCALL – 0F 05. Разместив инструкцию по адресу 0x7FFFFFFFFFFE, мы заставим баг сработать:


Address 
7FFFFFFFF000 
... 
7FFFFFFFFFFE SYSCALL 
800000000000 Non-canonical address 

После вызова инструкции SYSCALL адресом возврата будет неканонический адрес 0x800000000000. Следовательно, в результате выполнения инструкции SYSRET, мы вызовем исключение #GP с привилегиями ringи подконтрольными нам регистрами.

3. Эксплуатация уязвимости в Xen и CitrixXenServer

При эксплуатации использовались 64битная паравиртуализируемая Linux-машина, Citrix XenServer версии 6.0.0 и гипервизор Xen версии 4.1.1. Описываемый метод работает также и в других средах.

3.1 Изменение адреса возврата

Так как гостевая система не является полностью виртуализируемой, инструкция "sidt” в действительности вернет адрес таблицы IDT гипервизора Xen. Поэтому перезапись таблицы IDT гипервизора позволит выполнить произвольный код. Локальная атака на IDT схожа с удаленной атакой в том плане, что неизвестно, как восстановить исходное состояние таблицы IDT ее модификации. Даже если мы попытаемся последовательно восстановить таблицу, используя сохраненные записи, такие как DivideError, у нас, скорее всего, ничего не получится. Поэтому описываемый эксплойт прекрасно работает на одних версиях гипервизора Xen, но оказывается полностью бесполезным на других версиях.

Необходим более надежный способ, не требующий внедрения в адресное пространство Xen.

После конференции BlackHat мне выпал шанс поговорить с Рафалом Вайджуком, человеком, который и обнаружил уязвимость. Ему пришла в голову хитрая идея, как использовать уязвимость, полагаясь не на аппаратные адреса, а на некоторые особенности обработки гипервизором исключений.

В основе эксплойта лежит способ обработки переменной "current ”. Переменная является указателем на структуру vCPU (Virtual CPU). vCPU содержит информацию о состоянии виртуальной машины (регистры общего назначения, виртуальная IDT, таблицы страниц и.т.п.)

Xen получает указатель current_vcpu из низа стека с помощью макроса "get_current”:


struct cpu_info { 
struct cpu_user_regs guest_cpu_user_regs; 
unsigned int processor_id; 
struct vcpu *current_vcpu; 
unsigned long per_cpu_offset; 
#ifdef __x86_64__ /* get_stack_bottom() must be 16-byte aligned */ 
unsigned long __pad_for_stack_bottom; 
#endif 
}; 

static inline struct cpu_info *get_cpu_info(void) 

struct cpu_info *cpu_info; 
__asm__ ( "and %%"__OP"sp,%0; or %2,%0" 
: "=r" (cpu_info) 
: "0" (~(STACK_SIZE-1)), "i" (STACK_SIZE-sizeof(struct cpu_info)) 
); 
return cpu_info; 


#define get_current() (get_cpu_info()->current_vcpu) 
#define set_current(vcpu) (get_cpu_info()->current_vcpu = (vcpu)) 
#define current (get_current()) 

При диспетчеризации исключения #GP выполняется следующий код из "arch/x86/x86-64/entry.S”:


/* No special register assumptions. */ 
ENTRY(handle_exception) 
SAVE_ALL 
handle_exception_saved: 
testb $X86_EFLAGS_IF>>8,UREGS_eflags+1(%rsp) 
jz exception_with_ints_disabled 
sti 
1: movq %rsp,%rdi 
movl UREGS_entry_vector(%rsp),%eax 
leaq exception_table(%rip),%rdx 
GET_CURRENT(%rbx) ; Retrieve guest_cpu_user_regs 
; of cpu_info structure 
PERFC_INCR(exceptions, %rax, %rbx) 
callq *(%rdx,%rax,8) ; call exception handler 

При входе в функцию "do_general_protection()” из "arch/x86/traps.с” выполняется несколько проверок:


asmlinkage void do_general_protection(struct cpu_user_regs *regs) 

struct vcpu *v = current; 
unsigned long fixup; 

DEBUGGER_trap_entry(TRAP_gp_fault, regs); 

if ( regs->error_code & 1 ) 
goto hardware_gp; 

if ( !guest_mode(regs) ) 
goto gp_in_kernel; 
... 

gp_in_kernel: 

... 
DEBUGGER_trap_fatal(TRAP_gp_fault, regs); 

hardware_gp: 
show_execution_state(regs); 
panic("GENERAL PROTECTION FAULT\n[error_code=%04x]\n", regs->error_code); 

Как правило, #GP приводит к панике ядра, чего нам не надо. Макрос guest_mode можно "обмануть” и заставить его думать, что исключение #GP на самом деле было вызвано из ring3:


#define guest_mode(r) \ 
({ \ 
unsigned long diff = (char *)guest_cpu_user_regs() - (char *)(r); \ 
/* Frame pointer must point into current CPU stack. */ \ 
ASSERT(diff < STACK_SIZE); \ 
/* If not a guest frame, it must be a hypervisor frame. */ \ 
ASSERT((diff == 0) || (!vm86_mode(r) && (r->cs == __HYPERVISOR_CS))); \ 
/* Return TRUE if it's a guest frame. */ \ 
(diff == 0); \ 
}) 

Макрос "guest_cpu_user_regs()” определен в "xen/include/asm-x86/current.h” следующим образом:

#define guest_cpu_user_regs() (&get_cpu_info()->guest_cpu_user_regs)

Если удастся присвоить переменной diff значение NULL, то проверка вернет true, и макрос будет считать, что исключение было вызвано изring3.

Ассемблерный код макросов GET_CURRENT и "guest_cpu_user_regs()” соответственно:

mov RBX, 0xFFFFFFFFFFF8000 
and RBX, RSP 
or RBX, 0x7FE8 
mov RBX, [RBX]

and: 

mov RAX, 0xFFFFFFFFFFFF8000 
and RAX, RSP 
or RAX, 0x7F18 

Установить значения для RAX и RBX достаточно легко, так как можно просто закинуть в RSP необходимый нам адрес.

Если исключение вызвано из ring3, то выполняется следующий код:


if ( (regs->error_code & 3) == 2 ) 

... 

else if ( is_pv_32on64_vcpu(v) && regs->error_code ) 

... 


/* Emulate some simple privileged and I/O instructions. */ 
if ( (regs->error_code == 0) && 
emulate_privileged_op(regs) 

trace_trap_one_addr(TRC_PV_EMULATE_PRIVOP, regs->eip); 
return; 

Наконец, вызывается функция "emulate_priveleged_op()” из "xen/x86/traps.c”; но в следующем участке кода подфункция "read_descriptor()” вызовет исключение #PF:

static int read_descriptor(unsigned int sel, 
const struct vcpu *v, 
const struct cpu_user_regs * regs, 
unsigned long *base, 
unsigned long *limit, 
unsigned int *ar, 
unsigned int vm86attr) 

struct desc_struct desc; 

if ( !vm86_mode(regs) ) 

if ( sel < 4) 
desc.b = desc.a = 0; 
else if ( __get_user(desc, 
(const struct desc_struct *)(!(sel & 4) 
? GDT_VIRT_START(v) 
: LDT_VIRT_START(v)) 
+ (sel >> 3)) ) 
return 0;

Исключение #PF в действительности вызвано ошибкой чтения из таблиц GDT/IDT. Дело в том, что макрос "__get_user()” использует текущий селектор сегмента в качестве индекса в таблицах ядра GDT/IDT.

Затем срабатывает обработчик исключения "do_page_fault” из "xen/x86/traps.c”:

asmlinkage void do_page_fault(struct cpu_user_regs *regs) 

unsigned long addr, fixup; 
unsigned int error_code; 

addr = read_cr2(); 

/* fixup_page_fault() might change regs->error_code, so cache it here. */ 
error_code = regs->error_code; 

DEBUGGER_trap_entry(TRAP_page_fault, regs); 

perfc_incr(page_faults); 

if ( unlikely(fixup_page_fault(addr, regs) != 0) ) 
return; 

if ( unlikely(!guest_mode(regs)) ) 

if ( spurious_page_fault(addr, error_code) ) 
return;

Из-за того, что в стеке теперь лежат аргументы вложенного исключения, значение адреса в регистре RSP модифицировалось. Следовательно, проверка guest_modeвозвращает false, что приводит к вызову функции "spurious_page_fault()”:

static int __spurious_page_fault(unsigned long addr, unsigned int error_code) 

unsigned long mfn, cr3 = read_cr3(); 
#if CONFIG_PAGING_LEVELS >= 4 
l4_pgentry_t l4e, *l4t; 
#endif 
#if CONFIG_PAGING_LEVELS >= 3 
l3_pgentry_t l3e, *l3t; 
#endif 
l2_pgentry_t l2e, *l2t; 
l1_pgentry_t l1e, *l1t; 
unsigned int required_flags, disallowed_flags; 

/* 
* We do not take spurious page faults in IRQ handlers as we do not 
* modify page tables in IRQ context. We therefore bail here because 
* map_domain_page() is not IRQ-safe. 
*/ 
if ( in_irq() ) 
return 0; 
... 
return 1;

Проверка "in_irq()” должна возвратить false, так как в противном случае, функция "spurious_page_fault()” вернет 0, и произойдет паника ядра. К счастью, поведением макроса "in_irq()” можно управлять, ассемблерный код макроса приведен ниже:

0xffff82c4801fe2bc <+4> : mov rax,0xffffffffffff8000 
0xffff82c4801fe2c3 <+11>: lea rcx,[rip+0x921b6] # 0xffff82c480290480 <irq_stat> 
0xffff82c4801fe2ca <+18>: and rax,rsp 
0xffff82c4801fe2cd <+21>: or rax,0x7f18 
0xffff82c4801fe2d3 <+27>: movedx,DWORDPTR [rax+0xc8] 
0xffff82c4801fe2d9 <+33>: xor eax,eax 
0xffff82c4801fe2db <+35>: shl rdx,0x7 
0xffff82c4801fe2df <+39> : cmpDWORDPTR [rcx+rdx*1+0x8],0x0

Переменная "current” содержится в регистре RAX. Смещение из структуры "current” (DWORD PTR [rax+0xc8]) используется в качестве индекса в массиве irq_array. Если значение по индексу равно 0, "in_irq” вернет false, функция "spurious_page_fault()” вернет 1, и мы покинем обработчик исключения "do_page_fault()”.

Затем выполнение кода перейдет к той инструкции, которая следует непосредственно за инструкцией, вызвавшей исключение #PF в "read_descriptor()”. В результате функция "read_descriptor()” вернет 0.

Значение, возвращаемое "read_descriptor()” затем проверяется в "emulate_privileged_code()”:

if ( !read_descriptor(regs->cs, v, regs, 
&code_base, &code_limit, &ar, 
_SEGMENT_CODE|_SEGMENT_S|_SEGMENT_DPL|_SEGMENT_P) ) 
goto fail
... 

fail
return 0;

Функция "emulate_privileged_code()” возвращает 0, условие "if” мы перепрыгиваем и затем достигаем функции "go_guest_trap()”. И вот тут все становится намного интереснее:

/* Emulate some simple privileged and I/O instructions. */ 
if ( (regs->error_code == 0) && 
emulate_privileged_op(regs) ) 

trace_trap_one_addr(TRC_PV_EMULATE_PRIVOP, regs->eip); 
return; 


/* Pass on GPF as is. */ 
do_guest_trap(TRAP_gp_fault, regs, 1);

Функция "go_guest_trap()” ответственна за то, чтобы передать информацию об #GP в обработчик исключения ядра. Поскольку мы обманули гипервизор, и теперь он думает, что исключение произошло в ring3, логичным было бы передать обработку исключения в ядро:

static void do_guest_trap(int trapnr, const struct cpu_user_regs *regs, int use_error_code) 

struct vcpu *v = current; 
struct trap_bounce *tb; 
const struct trap_info *ti; 

trace_pv_trap(trapnr, regs->eip, use_error_code, regs->error_code); 

tb = &v->arch.trap_bounce; 
ti = &v->arch.guest_context.trap_ctxt[trapnr]; 

tb->flags = TBF_EXCEPTION; 
tb->cs = ti->cs; 
tb->eip = ti->address;
 

if ( use_error_code ) 

tb->flags |= TBF_EXCEPTION_ERRCODE; 
tb->error_code = regs->error_code; 


if ( TI_GET_IF(ti) ) 
tb->flags |= TBF_INTERRUPT; 

if ( unlikely(null_trap_bounce(v, tb)) ) 
gdprintk(XENLOG_WARNING, "Unhandled %s fault/trap [#%d] " 
"on VCPU %d [ec=%04x]\n", 
trapstr(trapnr), trapnr, v->vcpu_id, regs->error_code); 
}

Указатель "current” используется для инициализации структуры trap_bounce. Адреса двух структур (tb, ti) представляют собой смещения от указателя arch. Arch, в свою очередь, это одно из полей в указателе "current”. Можно легко передать необходимый нам указатель arch, и перезаписать старые значения tb->cs и tb->eip. Соответственно, после выполнения инструкции SYSRET значения регистров CS и RIP также изменятся.

Затем производится возврат из функции "do_general_protection()” и выполняется следующий код:

/* %rbx: struct vcpu, interrupts disabled */ 
restore_all_guest: 
ASSERT_INTERRUPTS_DISABLED 
RESTORE_ALL 
testw $TRAP_syscall,4(%rsp) 
jz iret_exit_to_guest 
... 
/* No special register assumptions. */ 
iret_exit_to_guest: 
addq $8,%rsp 
.Lft0: iretq

После достижения инструкции IRETQ, из стека достается новый селектор сегмента и осуществляется дальний переход на измененный адрес возврата.

Как уже утверждалось ранее, все структуры располагаются в пользовательских участках адресного пространства, причем никакие аппаратные адреса не задействованы. Благодаря вышеописанным манипуляциям, нам удастся выполнить произвольный код с правами ring0.

3.2. Выполнение кода в контексте "dom0”

Поскольку эксплойт работает в режиме ядра, то подразумевается, что нарушитель уже обладает (на законных основаниях или повысив свои привилегии с помощью другого эксплойта) правами rootна гостевой машине. С помощью описываемого в статье эксплойта можно получить права самого привилегированного домена "dom0”, домена, который по умолчанию имеет прямой доступ к аппаратному обеспечению. Из "dom0” можно управлять самим гипервизором, а также запускать другие непривилегированные домены (domU).

В Citrix XenServer dom0 представляет собой 32битную виртуальную машину. 32битная конфигурация была выбрана из соображений производительности.

Наша тактика будет следующей: внедриться в dom0 и получить права root c помощью bindshell или reverse shell.

Будет использоваться такая же идея, как и при удаленной эксплуатации уязвимости ядра: модифицировать обработчик исключения 0x80 и дождаться, когда случится прерывание в dom0. После исключения необходимо убедиться, что виртуальные страницы dom0 отображены в памяти.

Страницы памяти Xen отображаются в одно и то же адресное пространство во всех виртуализируемых ядрах, точно так же, как адрес 0xc0000000 отображается во всех 32битных пользовательских процессах.

Так как память Xen отображается с правами RWX, то нам нужно только записать в неиспользуемое адресное пространство новый обработчик исключения 0x80 и переписать соответствующую запись в таблице IDT.

В обработчике первого уровня производятся следующие действия:

Если пользовательский процесс произвел системный вызов из домена dom0, то нам нужно сохранить контекст процесса; изменить аргументы системного вызова, так чтобы осуществить системный вызов mmap() с правами RWX; установить указатель EIP процесса на инструкцию "int 0x80” и вызвать исходный обработчик исключения 0x80.

После удачного выполнения системного вызова процесс возвратится к инструкции "int 0x80” и выполнит системный вызов, причем значение регистра EAX должно быть больше 0x1000 (для вызова mmap()). Затем выполняется обработчик "int 0x80” второго уровня:


Шеллкод создаст копию исходного процесса с помощью fork(); установит EIP родительского процесса на инструкцию "int 0x80” на сей раз уже с оригинальными параметрами, так чтобы родительский процесс смог продолжать работать дальше без ошибок. Процесс-потомок в это время выполняет классический ring3-шеллкод и дарит нам ключ от нулевого королевства 
Категория: Общие Статьи | Добавил: aka_kludge (18.12.2012)
Просмотров: 2960 | Рейтинг: 0.0/0
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
    Главная      
...
На службе : дней

21:49
Обновить


Пользователи
aka_kludge
qwerty
LeadyTOR
aka_Atlantis
AdHErENt
mAss
Sissutr
hiss
DrBio
tHick

Поиск


Copyright tHR - TeAM 2024 г. admin: aka_kludge (ICQ:334449009) Moderator's: LeadyTOR, ... Яндекс.Метрика