Издательский дом ООО "Гейм Лэнд"ЖУРНАЛ ХАКЕР 120, ДЕКАБРЬ 2008 г.

Обзор эксплойтов

Крис Касперски




В конце октября в Малайзии состоялась конференция HITB (Hack In The Box), где я зачитал доклад об ошибках ЦП, допускающих локальные и удаленные атаки на систему. Это вызвало огромный общественный интерес, и потому сегодняшний обзор я решил посвятить процессорным багам, продемонстрировав технику вторжения в чужие компьютеры.

Intel Core – еще одна ошибка когерентности L1 кэша

Brief

В середине октября (непосредственно перед конференцией HIBT) Intel обнаружила еще один дефект кэш-контролера первого уровня, который и описала в errata под номером AZ73. Приведенной информации оказалось достаточно для воспроизведения ошибки на ноутбуке, но отладить exploit в условиях гостиничного номера за оставшееся перед выступлением время не получилось. Тем не менее, модификация ядерной памяти операционной системы с прикладного уровня проходила стабильно и вполне успешно. А значит, есть все основания ожидать, что техника будет взята на вооружение malware-писателями. Для этого достаточно заставить несколько процессорных ядер обрабатывать разделяемые данные, находящиеся в кэш-памяти первого уровня между двумя кэш-линейками. Согласно errata, при этом происходит нарушение очередности последовательности записей/чтения, что не совсем соответствует действительности. Intel не удосужилась упомянуть «удар по памяти» — кэш-контроллер «забывает» подлинный адрес скэшированных ячеек памяти и выгружает модифицированные данные совершенно в другое место.

Выгрузка проводится уже после проверки атрибутов защиты страниц, за счет чего становится возможным атаковать код операционной системы с прикладного уровня. Атаковать можно очень большое количество приложений, в том числе и операционную систему, – даже если сами по себе они и не содержат ошибок. Атакующему нужно, чтобы целевой код обрабатывал разделяемые данные в двух или более потоках, причем, один поток записывал, а другой — читал. Драйвер TCP/IP-стека представляет собой отличную мишень для атаки, поскольку в момент прихода очередного IP-пакета сетевая карта генерирует прерывание, подхватываемое свободным процессором. И если в этот момент упадет еще один пакет, операционная система автоматически отправит его на второй процессор, вынужденный взаимодействовать с первым (а как иначе собирать TCP-пакеты из IP?).

Направленный шторм TCP/IP-пакетов — «пробивает» любую операционную систему (естественно, из тех, что поддерживают многопроцессорность; Windows 9x не поддерживает, и потому ее никак не сломаешь). Shell-код, разумеется, привязан к конкретной операционной системе и должен проектироваться с учетом специфики ее архитектуры, однако это уже вторая фаза атаки, которая не так интересна, как принципиальная возможность удаленного «впрыскивания» кода в память ядра. О том, как это сделать, можно прочитать в Specification Update: download.intel.com/design/mobile/specupdt/320121.pdf (AZ73 - Memory Ordering Violation With Stores/Loads Crossing a Cacheline Boundary).

Targets

Intel Core 2 Extreme Quad-Core Mobile, Intel Core 2 Quad Mobile, Intel Core 2 Extreme Mobile, Intel Core 2 Duo Mobile Processor, Intel Core 2 Solo Mobile и Intel Celeron 45-nm.

Exploit

Ниже приводится ключевой фрагмент proof-of-concept exploit'а разработанного хакером Zen Lee с целью завешивания целевой системы. Циклы CORE1/CORE2 должны выполняться в раздельных потоках, «закрепленных» за своими ядрами. Регистр EDX указывает на заранее выделенный блок памяти размером 64Кбайт, общий для всех потоков:

Ключевой фрагмент боевого exploit'а от Zen'а Lee, демонстрирующий дефект кэш-контролера (внимание: exploit работает только с 32-битными операционными системами!)

CORE1:
moveax, dword_405030
imuleax, 343FDh
addeax, 269EC3h
movdword_405030, eax
sareax, 10h
andeax, 7FFFh
cdq
movecx, 1FFh
idivecx
movedx, dword_4054C2[edx]
movdword_405438, edx
JMP CORR1

CORE2:
moveax, dword_405030
imuleax, 343FDh
addeax, 269EC3h
movdword_405030, eax
sareax, 10h
andeax, 7FFFh
cdq
movecx, 1FFh
idivecx
moveax, dword_405438
movdword_4054C2[edx], eax
jmpshort _main
JMP CORR2

Solution

Intel работает над исправлением микрокода, который после выхода в свет будет доступен разработчикам BIOS. Однако далеко не все из них включают последние версии микрокода в очередную версию своей прошивки, да и обновления BIOS'а на ноутбуке – операция не из штатных, а потому ситуация – ласты. Кто не спрятался, тот сам себя и наказал.

Intel Core – множественные ошибки XRSTOR/XSAVE

Brief

Команда XRSTOR, восстанавливающая состояние процессора, сохраненное командой XSAVE, оказалась жутко багистной — только за последний месяц в ней обнаружилось три новых ошибки, ведущих к краху системного программного обеспечения, использующего ее в своих целях. Ошибка, проходящая в errata (смотри http://download.intel.com/design/mobile/specupdt/320121.pdf) под кодовым номером AZ74 (The XRSTOR Instruction May Fail to Cause a General-Protection) позволяет процессору взводить зарезервированные биты 63:9 регистра XFEATURE_ENABLED_MASK (XCR0) без генерации исключения общей защиты, как это следует из документации. Само по себе это не опасно, но позволяет создать код, работающий только на багистных процессорах. В малвари, отловленной в дикой природе, сей баг использовался для детекции уязвимых процессоров, а, быть может, и для чего-то еще. Две других ошибки относятся к инструкции XSAVE. Согласно errata, AZ71 (The XSAVE Instruction May Erroneously Set Reserved Bits in the XSTATE_BV Field), как и следует из ее названия, при определенных обстоятельствах взводит зарезервированные биты регистра XCR0, что ведет к непредсказуемому поведению программного обеспечения, уверенного, что эти биты равны нулю (как утверждает документация). Ошибка AZ72 (Store Ordering Violation When Using XSAVE) намного более коварна: если программист использует XSAVE для сохранения одного лишь SSE-контекста, то происходит переупорядочивание операций записи — инструкции отгружают данные в память совсем не в том порядке, в котором ожидает программист. Что и ведет к непредсказуемому поведению приложения и зачастую сопровождается крахом.

Targets

Intel Core2 Extreme Quad-Core Mobile, Intel Core 2 Quad Mobile, Intel Core 2 Extreme Mobile, Intel Core 2 Duo Mobile Processor, Intel Core 2 Solo Mobile и Intel Celeron 45-nm.

Exploit

Отсутствует.

Solution

Intel исправила ошибку в процессорах со степпингом E-0, а также выпустила обновленный микрокод. Ввиду того, что ошибки реализации XRSTOR/XSAVE невозможно использовать ни для удаленных атак, ни для локального повышения привилегий, смысла накладывать заплатки на процессор нет.

Intel Core – разрушение регистра CS при переходе в PM

Brief

Наконец-то Intel обнародовала информацию, объясняющую логику работы антиотладочных приемов, встречающихся в некоторых rootkit'ах. Впрочем, «обнародовала» – это сильно сказано! Всего лишь приоткрыла дверь в потайную комнату, и в образовавшуюся щель просочился крошечный лучик света, позволяющий (не без мата, конечно) разобраться в ситуации. На первый взгляд, сообщение об ошибке AZ70 (Corruption of CS Segment Register During RSM While Transitioning From Real Mode to Protected Mode) носит невменяемый характер. Если при переходе из реального в защищенный режим неожиданно придет прерывание от «Системного Менеджера Прерываний» (System Management Interrupt или, сокращенно, SMI), случившееся после того, как бит PE (Protection Enable) регистра CR0 уже взведен, но JMP FAR еще не выполняется, – процессор угробит два младших бита регистра CS, однако все будет работать. Во всяком случае, если программист не попытается прочитать содержимое CS инструкцией MOV или каким-то другим способом. Ситуация, прямо скажем, немыслимая. Вероятность возникновения прерывания на столь узком временном промежутке близка к нулю. К тому же, с угробленным CS можно какое-то время работать – пока не начали читать его содержимое. И в чем здесь соль? А в том, что регистр CS, как и другие сегментные регистры, является лишь «надстройкой» над механизмом трансляции адресов и внутри процессора явным образом не используется. Именно потому с испорченным CS система продолжает работать, а испортить регистр можно множеством способов (связанных с ошибками реализации команд гипервизора, например). Прикладная программа после порчи регистра CS продолжает работать нормально, а вот отладчики выбрасывают исключение, ругаясь на неправильный селектор. Хакер смотрит — и офигивает: селектор, действительно, неправильный! Попытки разобраться, откуда берется неправильный селектор в таблице дескрипторов и куда исчезает — обречены на провал, поскольку на самом деле, селектор ни откуда не берется и никуда не девается, это всего лишь следствие разрушения регистра CS. Вот такой антиотладочный прием. Перезагрузка CS валидным значением позволяет продолжить отладку.

Targets

Intel Core2 Extreme Quad-Core Mobile, Intel Core 2 Quad Mobile, Intel Core 2 Extreme Mobile, Intel Core 2 Duo Mobile Processor, Intel Core 2 Solo Mobile и Intel Celeron 45-nm.

Exploit

Отсутствует.

Solution

Intel исправила ошибку в процессорах со степпингом E-0, а также выпустила обновленный микрокод.

Cross-Modifying Code Attacks

Первое (в жизни!) мое выступление закончилось провалом. Только взошел на подиум — тут же забыл половину из того, что хотел сказать. В результате, вместо запланированных 60 минут говорил только полчаса с ужасным русским акцентом. Народ обречено втыкал в слайды, набранные мелким шрифтом, а качество мультимедийного проектора было, скажем так, далеко не на высоте. Чувство уверенности, что это действительно провал, укрепилось на заключительной вечеринке, где ко мне подходили симпатичные японки и, дружески толкая плечом, говорили: все было круто, типа, не переживай. Ага, понятно. Если бы все было действительно круто, они бы не подходили. Впрочем, я и не думал переживать. В конце концов, надо же с чего-то начинать.

Презентация подняла намного больше вопросов, чем решила и, обсуждая с хакерами сложившиеся перспективы, я обогатил себя свежими идеями, открывающими двери в мир новых атак. Скромные рамки журнальной статьи не позволяют рассказать обо всех атаках целиком, поэтому приходится выбирать что-то одно. Наибольший интерес вызвал класс атак, официально обозначенный Intel'ом как Cross-Modifying Code Bug или, сокращенно, XMC.

Как известно, Pentium-процессоры используют раздельный кэш первого уровня. Один для кода, другой — для данных, причем, внутри кристалла реализован специальный механизм, отслеживающий модификацию ячеек памяти, уже загруженных в кодовый кэш и вызывающий его перезагрузку. Вплоть до Pentium-III (включительно) детект самомодифицирующего кода не представлял большой проблемы, поскольку кэш был устроен предельно просто. Но начиная с Pentium-4, кодовый кэш хранит не оригинальное содержимое оперативной памяти, а декодированные микроинструкции, – что существенно затрудняет проверку их принадлежности к модифицированным ячейкам. Механизм распознавания самомодифицирующего кода резко усложнился, и в нем появились ошибки. При определенных ситуациях (о которых мы еще поговорим) процессор продолжает исполнять старый код, игнорируя факт его модификации на другом ядре (реже — на том же самом ядре). В результате, мы получаем в свое распоряжение превосходный антиотладочный прием, используемый еще во времена древних XT/AT. При «живом» прогоне программы модификация идет лесом, то есть не воспринимается процессором, поскольку модифицируемые команды уже находятся на конвейере, а сбросить конвейер некому — детектор самомодифицирующего кода ловит муху.

Вот отладчик — совсем другое дело. При пошаговой трассировке между соседними командами процессор выполняет сотни и даже тысячи других команд, а потому самомодифицирующийся код исполняется как положено, без ошибок. Аналогично обстоят дела с дизассемблерами и эмуляторами, которые очень легко зациклить. В самом деле, пусть самомодифицирующийся код вырубает команду безусловного (условного) перехода L1: jmp L1, тогда программа будет выполняться только на живом процессоре, но не под отладчиком. Это, разумеется, дебильный прием, который нетрудно обнаружить, но, если модифицировать расшифровщик основного тела программы, ситуация окажется весьма неоднозначной. Чтобы разобраться, в каких случаях процессор игнорирует модификацию кода, а в каких нет, уйдет туева хуча времени.

Но это еще что! Существует возможность модифицировать код, загруженный в кэш первого уровня так, чтобы содержимое кэша данных первого уровня второго ядра осталось неизменным. Замечательное средство для обхода защит, контролирующих целостность кода. Поскольку напрямую прочитать содержимое кодового кэша невозможно, приходится довольствоваться содержимым кэша данных, надеясь на то, что процессор поддерживает их в согласованном состоянии. Ага, разбежались! Дефекты кэш-контроллера ведут к нарушению когерентности и потому в кодовом кэше записано одно, а в кэше данных — совсем другое, причем модифицированные ячейки кэша данных вытесняются в кэш второго уровня (кодовый кэш не вытесняется никогда), а оттуда уже попадают в оперативную память.

Комбинирование двух типов ошибок поддержки когерентности позволяет создать весьма устойчивый «голландский гибрид», переживающий вытеснение модифицированных ячеек из кэша данных в оперативную память. Алгоритм атаки выглядит так:

  1. Ядро L1 модифицирует содержимое кэш-памяти первого уровня D2 таким образом, чтобы ядро L2 об этом ничего не знало.
  2. Ядро L1 передает на модифицированный код выполнение, загружая его в кодовый кэш C1, при этом кэш D1 находится в согласованном состоянии с кэшем C1.
  3. Ядро L2 по-прежнему ничего не знает о факте модификации и потому попытка проверки целостности кода показывает, что все нормально. Лучшего способа для маскировки зловредного кода, пожалуй, и не придумать. Вот только у злоумышленника нет никаких гарантий, что проверка будет выполняться именно на ядре L2, а не L1, поэтому необходимо предпринять дополнительные действия.
  4. ОК, у нас имеется: модифицированный код и данные в C1 и D1, а также немодифицированные данные в D2 — выполняя модификацию модифицированных ячеек памяти в D1, хакер возвращает их в исходный вид. C1 об этом ничего не знает и не перезагружает кэш. А вот в кэш второго уровня будут вытеснены именно дважды модифицированные данные, то есть, фактически не модифицированные, с тщательно вычищенными следами порчи. Как следствие, — факт вторжения становится очень трудно обнаружить!

Естественно, после перезагрузки C1 кэша все придется начинать сначала. То есть, перехватить системную функцию получится только на очень короткое время, хотя и вполне достаточное для большинства задач, стоящих перед вирусами и червями. Ключевой фрагмент proof-of-concept exploit'а, демонстрирующий технику XMC-атак приведен ниже, ну а над законченным оружием возмездия еще предстоит поработать. Кстати говоря, идея использовать XMC-атаки для «ослепления» механизмов проверки целостности кода/данных возникла в ходе разговора с Александром Терешкиным — ведущим исследователем (principal researcher) из фирмы Invisible Things Lab. Да-да! Той самой, в которой трудится Жанна Рутковская, поклявшаяся убить любого, кто снова спутает атаку на файл подкачки Windows с Голубой Пилюлей, последняя версия которой поддерживает вложенную виртуализацию (исправно работает под запущенным аппаратным эмулятором типа XEN'а, что делает ее обнаружение очень проблематичным, если вообще возможным). Попутно — Жанна, которую все почему-то называют Джоанной, оказывается никакая не Жанна и не Джоанна, а Юанна.

К сожалению, сама Юанна на конференции не обозначилась, и мы с Александром тусовались в «гордом одиночестве» на тридцатом этаже отела Crown Plaza Malaysia. Других русскоязычных хакеров на HIBT замечено не было. И вот пока мы с ним так тусовались, к нам подходили разные люди, чтобы обсудить проблемы виртуализации и атак на процессоры. Одним из них оказался Анатолий Зборальски, работающий в индонезийской конторе Bellua Asia Pacific. Идея обхода Patch Guard'а посредством багистных процессоров — его. Ну а сейчас самое время продемонстрировать код, с помощью которого это можно сделать. Кстати, код тоже не мой и его происхождение весьма любопытно. Изначально он задумывался как головоломка в стиле: «угадай, что эта программа делает?», заброшенная на форум WASM'а хакером PROFi (смотри пост http://www.wasm.ru/forum/viewtopic.php?id=28983#8). Однако, в результате неправильно выбранного смещения регистра ESP вместо того, чтобы затирать саму себя (как задумывалось), инструкция POP перезаписывала команду, следующую за командой, вызывающей исключение. В итоге, на процессорах Intel Core 2 мы поимели XMC. Способ модификации команды может быть любым. Необязательно использовать именно POP — MOV или STOS сработают ничуть не хуже. Исключение – необязательно нарушение доступа. Сгодится и «инвалидная команда» (скажем, UD2). Главное — чтобы модифицируемая команда располагалась после команды, вызывающей исключение, а модифицирующая команда находилась в пределах досягаемости конвейера и между ними отсутствовали ошибочно предсказанные ветвления, инструкции сериализации типа CPUID и прочий stuff.

Ключевой фрагмент кода, демонстрирующий XMC-атаку (только для 32-битных систем!)

.00403854:BC59384000movesp, 000403859
.00403859:8F442404popd, [esp] [04]
.0040385D:33C0xoreax, eax
.0040385F:8B00moveax, [eax]

При одновременном выполнении обозначенного кода на двух ядрах одно ядро «почувствует» модификацию, а другое – нет. Разумеется, при условии, что в процессоре присутствует неисправленный баг. Небольшое расследование показало, что среди мобильных ЦП багистные встречаются намного чаще, в то время как в последних партиях десктопных процессоров ошибки уже исправлены.

Содержание
загрузка...
Журнал Хакер #151Журнал Хакер #150Журнал Хакер #149Журнал Хакер #148Журнал Хакер #147Журнал Хакер #146Журнал Хакер #145Журнал Хакер #144Журнал Хакер #143Журнал Хакер #142Журнал Хакер #141Журнал Хакер #140Журнал Хакер #139Журнал Хакер #138Журнал Хакер #137Журнал Хакер #136Журнал Хакер #135Журнал Хакер #134Журнал Хакер #133Журнал Хакер #132Журнал Хакер #131Журнал Хакер #130Журнал Хакер #129Журнал Хакер #128Журнал Хакер #127Журнал Хакер #126Журнал Хакер #125Журнал Хакер #124Журнал Хакер #123Журнал Хакер #122Журнал Хакер #121Журнал Хакер #120Журнал Хакер #119Журнал Хакер #118Журнал Хакер #117Журнал Хакер #116Журнал Хакер #115Журнал Хакер #114Журнал Хакер #113Журнал Хакер #112Журнал Хакер #111Журнал Хакер #110Журнал Хакер #109Журнал Хакер #108Журнал Хакер #107Журнал Хакер #106Журнал Хакер #105Журнал Хакер #104Журнал Хакер #103Журнал Хакер #102Журнал Хакер #101Журнал Хакер #100Журнал Хакер #099Журнал Хакер #098Журнал Хакер #097Журнал Хакер #096Журнал Хакер #095Журнал Хакер #094Журнал Хакер #093Журнал Хакер #092Журнал Хакер #091Журнал Хакер #090Журнал Хакер #089Журнал Хакер #088Журнал Хакер #087Журнал Хакер #086Журнал Хакер #085Журнал Хакер #084Журнал Хакер #083Журнал Хакер #082Журнал Хакер #081Журнал Хакер #080Журнал Хакер #079Журнал Хакер #078Журнал Хакер #077Журнал Хакер #076Журнал Хакер #075Журнал Хакер #074Журнал Хакер #073Журнал Хакер #072Журнал Хакер #071Журнал Хакер #070Журнал Хакер #069Журнал Хакер #068Журнал Хакер #067Журнал Хакер #066Журнал Хакер #065Журнал Хакер #064Журнал Хакер #063Журнал Хакер #062Журнал Хакер #061Журнал Хакер #060Журнал Хакер #059Журнал Хакер #058Журнал Хакер #057Журнал Хакер #056Журнал Хакер #055Журнал Хакер #054Журнал Хакер #053Журнал Хакер #052Журнал Хакер #051Журнал Хакер #050Журнал Хакер #049Журнал Хакер #048Журнал Хакер #047Журнал Хакер #046Журнал Хакер #045Журнал Хакер #044Журнал Хакер #043Журнал Хакер #042Журнал Хакер #041Журнал Хакер #040Журнал Хакер #039Журнал Хакер #038Журнал Хакер #037Журнал Хакер #036Журнал Хакер #035Журнал Хакер #034Журнал Хакер #033Журнал Хакер #032Журнал Хакер #031Журнал Хакер #030Журнал Хакер #029Журнал Хакер #028Журнал Хакер #027Журнал Хакер #026Журнал Хакер #025Журнал Хакер #024Журнал Хакер #023Журнал Хакер #022Журнал Хакер #021Журнал Хакер #020Журнал Хакер #019Журнал Хакер #018Журнал Хакер #017Журнал Хакер #016Журнал Хакер #015Журнал Хакер #014Журнал Хакер #013Журнал Хакер #012Журнал Хакер #011Журнал Хакер #010Журнал Хакер #009Журнал Хакер #008Журнал Хакер #007Журнал Хакер #006Журнал Хакер #005Журнал Хакер #004Журнал Хакер #003Журнал Хакер #002Журнал Хакер #001