18.11.2014 Views

JIT SPRAY АНАЛИЗ TDSS - Xakep Online

JIT SPRAY АНАЛИЗ TDSS - Xakep Online

JIT SPRAY АНАЛИЗ TDSS - Xakep Online

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

ASLR влияет только на первый блок. Красным<br />

помечены <strong>JIT</strong> <strong>SPRAY</strong> блоки. Цветным — системные<br />

модули<br />

RWX страницы повсюду<br />

что компилятор для ActionScript (скриптовый язык для Flash-приложений)<br />

сохраняет значения в памяти как есть. Мне же удалось обнаружить аналогичную<br />

ситуацию в компиляторе JavaScript в браузере Safari для Windows.<br />

Напишем простейший код на JavaScript, выполняющий операцию XOR:<br />

<br />

function jit_() {<br />

var y=( 0x11111111^<br />

0x22222222^<br />

0x33333333^<br />

0x44444444^<br />

0x55555555^<br />

0x66666666^<br />

0x77777777^<br />

0x88888888);<br />

return y;<br />

}<br />

<br />

Чтобы высчитать значение Y, движок JavaScript в браузере должен<br />

посчитать XOR, поэтому в памяти процесса создается страница, и туда<br />

заносится скомпилированный <strong>JIT</strong>-код, которому, в свою очередь, передается<br />

управление при вызове функции jit_():<br />

. . .<br />

04450432 81F033333333 XOR EAX, 33333333<br />

04450438 894708 MOV [EDI+8], EAX<br />

0445043B 8B4708 MOV EAX, [EDI+8]<br />

0445043E 8B570C MOV EDX, [EDI+C]<br />

04450441 83FAFF CMP EDX, -1<br />

04450444 0F8529010000 JNZ 04450573<br />

0445044A 81F044444444 XOR EAX, 44444444<br />

. . .<br />

Данный код в памяти появляется сразу после вызова jit_(). Первая<br />

колонка — адрес, вторая — машинные коды, третья — код на ассемблере<br />

(все значения в HEX’ах). Как видно, аргументы оператора XOR<br />

передаются в память как есть, сама память помечена как доступная<br />

для чтения, записи и исполнения — RWX (в Flash было только RX). Но<br />

главное разочарование — аргументы в памяти находятся далеко друг<br />

от друга, на расстоянии 20 байт. В Flash-плеере же разница в один<br />

байт. Итак, как это можно использовать для обхода DEP и ASLR? Для<br />

начала выберем уязвимость, на которой будем проводить опыты.<br />

ÓßÇÂÈÌÎÑÒÜ<br />

Повторное использование освобожденной памяти в Safari 4.0.5. Эту<br />

уязвимость я уже описывал в одном из прошлых обзорах, суть ее<br />

проста — удаляем родительский объект, при этом сохраняя указатель<br />

на него, потом вызываем метод, используя сохраненный указатель.<br />

В итоге берется значение из поврежденной памяти (которая освободилась).<br />

При этом значение указателя из таблицы vtable оказывается<br />

переписанным аргументом метода. Так мы захватываем контроль, а<br />

именно — регистр EIP:<br />

var a = parent; // Óêàçàòåëü íà ðîäèòåëüñêèé ýëåìåíò<br />

var buf = make_buf(unescape('%u0101%u0101'), 63000);<br />

a.prompt(alert);<br />

// çàïîëíÿåì ïàìÿòü çíà÷åíèåì 0x01010101<br />

a.prompt(buf);<br />

a.close(); // óäàëÿåì ðîäèòåëüñêèé îáúåêò<br />

// óêàçàòåëü íà ôóíêöèþ promt() òåïåðü = 0x01010101<br />

a.prompt(alert);<br />

<strong>JIT</strong> <strong>SPRAY</strong><br />

Ну вот, мы имеем уязвимость и можем передавать управление<br />

по любому адресу. Обычно управление передают туда, где лежит<br />

шеллкод. Для этого раньше память заполняли большими блоками<br />

в памяти (в куче) с шеллкодом. Если таких кусков очень много, то<br />

угадать адрес было легко. Только вот с появлением DEP все это<br />

бесполезно, так как шеллкод из кучи не будет исполняться. Методика<br />

обратно-ориентированного программирования также неприменима,<br />

потому что все модули поддерживают ASLR, и адреса нужных<br />

инструкций нам неизвестны. Для таких безвыходных ситуаций применим<br />

возможности <strong>JIT</strong>-компилятора, которые мы описали выше.<br />

Если написать несколько сотен функций jit_() и выполнить<br />

их, то память процесса заполнится блоками памяти с <strong>JIT</strong>-кодом.<br />

Память эта исполняема, но как угадать ее адрес? Если XOR-строка<br />

будет достаточно большой, память для каждого <strong>JIT</strong>-блока будет<br />

выделяться по адресу с предсказуемыми младшими разрядами в<br />

адресе — 0x0000. Это значит, что по адресу 0xXXYY0000 будет начинаться<br />

скомпилированный <strong>JIT</strong>-блок с нашими аргументами. Если<br />

таких блоков будет достаточно много, то 0xXXYY мы можем легко угадать,<br />

как в аналогии с Heap Spray. Но почему же не работает ASLR?<br />

Почему 0xXXYY не такие случайные? На самом деле ASLR работает,<br />

но только когда Safari пытается выделить первый блок для самой<br />

первой jit_() функции. Все последующие выделения памяти<br />

идут последовательно друг за другом. Это позволяет нам заполнить<br />

с вероятностью 99% середину памяти процесса, скажем, адреса<br />

0x0606000, 0x07070000 и т.д. (см. рисунок). Если каждый <strong>JIT</strong>-блок<br />

будет размером меньше чем 0x010000, тогда память будет расти<br />

равномерно, то есть, к примеру, адрес блока N есть 0x06060000, тогда<br />

адрес блока N+1 будет 0x06070000 и т.д. Осталось только определить<br />

младшие разряды адреса, чтобы указывать в аккурат на наш<br />

аргумент. Тут тоже все просто, так как смещение от начала блока<br />

XÀÊÅÐ 09 /140/ 10 071

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!