JIT SPRAY ÃÂÃÂÃÂÛØ× TDSS - Xakep Online
JIT SPRAY ÃÂÃÂÃÂÛØ× TDSS - Xakep Online
JIT SPRAY ÃÂÃÂÃÂÛØ× TDSS - Xakep Online
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