Нажмите CTRL-D чтобы добавить нас в закладки
Внимание! Вы находитесь в незащищенном режиме (HTTP). Для перехода в защищенный режим SSL, нажмите здесь
HackZone.RU - Атаки на переполнение стека в Windows NT
Войти / Регистрация / Участники
-
Поиск по сайту
Форумы



Реклама

Поиск ТОП Добавить публикацию

Атаки на переполнение стека в Windows NT

16.06.2008

Обращаем внимание, что данная публикация взята из архива.
Возможно, что информация, изложенная здесь, частично устарела

На сегодняшний день уязвимости программного обеспечении, связанные с так называемым переполнением стека, являются одной из основных проблем системных администраторов. В списках рассылки и белютенях, посвященных брешам в защите программного обеспечения, уязвимости такого рода составляют около 2/3 от общего числа. Со времени первой атаки на переполнение буфера в черве Морриса в 1988 году, число "buffer-overflow exploits" постоянно увеличивается. Причем проблема давно вышла за рамки UNIX-систем. В этой статье мы рассмотрим переполнение буфера в Windows NT

Основа атак переполнения буфера - принцип функционирования операционных систем, где программа получает привилегии и права запустившего ее пользователя или процесса. Так менее привилегированный пользователь или процесс, который взаимодействует с данной программой может использовать ее права в своих целях и "переполнение буфера" делает это возможным. Использование данной уязвимости подразумевает изменение хода выполнения привилегированной программы, например, запуск командной оболочки с правами атакуемого приложения.

Чтобы представить себе, как это происходит, разберем простой пример уязвимости переполнения буфера и напишем для него эксплоит. Для этого рассмотрим следующую небольшую программу.

#include <stdio.h>
int test(char *big)
{
char buffer[100]; // переполняемый буфер
strcpy(buffer,big); // переполнение буфера
return 0;
}

int main (int argc, char *argv[])
{
char big[1024];

gets(big); // ввод строки
test(big); // вызов уязвимой функции
return 0;
}
Здесь, на первый взгляд, ничего особенного: вводится строка big, передается в качестве параметра функции test, где копируется в промежуточный буфер buffer. Главное здесь для нас то, что промежуточный буфер buffer имеет размер, который меньше потенциально возможного размера вводимой строки big. При передаче функции test строки длиной более 100 символов произойдет переполнение буфера buffer, которое можно использовать в своих целях. Теперь скомпилируем программу как консольное Win32 приложение (я использовал VC++ 6.0) и посмотрим, что произойдет при переполнении буфера. Программу я назвал so, соответственно запускаем so.exe:

D:\exploit>so

и вводим строку длиной более 100 символов
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

в результате чего получаем аварийное завершение программы и следующее сообщение об ошибке нарушения доступа по адресу 0x61616161:

Давайте разберемся, что же происходит. Как известно, при вызове подпрограммы в стек заносится адрес возврата, т. е. адрес оператора следующего за вызовом функции, в нашем примере: return 0. Также стек используется для локальных переменных функции. Таким образом, в точке переполнения буфера (строка strcpy(buffer,big) в листинге) имеем следующую структуру стека.

Очевидно, что выполнение strcpy(buffer,big) при big с длиной превышающей размер отведенный под buffer приводит к затиранию-подмене адреса возврата. Теперь понятно, почему в сообщении об ошибке фигурировал адрес 0x61616161, так как 0x61 - код символа 'a', из которого состояла наша строка.

Итак, при помощи переполнения буфера мы добились передачи управления по адресу, содержащемуся в определенных позициях нашей строки. Так можно сформировать строку для ввода, которая содержала бы небольшой код (инструкции процессора) по выполнению нужных нам действий и при помощи изменения адреса возврата передать ему выполнение. Таким образом, мы получим эксплоит.

Приступим.

Прежде всего необходимо определить, какие позиции буфера приходятся на адрес возврата. В общем случае, однозначно определить это из приведенного выше листинга нельзя, так как компилятор генерирует пролог функции, в котором может изменятся содержимое стека. Существует два пути. Первый - дизассемблирование программы, например, при помощи IDA, но при этом нужно точно знать, в какой подпрограмме происходит переполнение буфера. Второй - экспериментальный, который мы и будем использовать. Для чего подготовим строку с символами всех кодов от 32 до 255.

/*ascii.c*/
#include <stdio.h>

void main(void)
{
int i;
for (i=32;i<256;i++) printf("%c",i);
}
Здесь обращаю ваше внимание на один очень важный момент - строка эксплоита не должна содержать символов конца строки: NULL(0x00), LF(0x0a), CR(0x0c), EOF(0x1a), так как в этом случае функция strcpy скопирует в буфер лишь часть нашей строки до этих символов. В связи с чем я использовал коды символов от 32 до 255.

Компилируем и запускаем:

D:\exploit>ascii | so.exe

В результате чего получаем:

Адрес 0x8b8a8988 означает, что начиная с позиции 0x88 - 0x20(32) = 104-го символа (отсчет ведется с нуля) строка пересекается с адресом возврата (эта позиция может варьироваться в зависимости от компилятора и его опций). Значит строку нужно сформировать так, чтобы символы в позициях 104, 105, 106 и 107 содержали адрес, по которому нужно передать управление.

Теперь принимаем решение о том, каким образом будет формироваться код. Есть два решения: с начала строки до 104-й позиции, со 108-й позиции либо комбинация. Первый способ дает относительно мало "места" под исполнительный код эксплоита - 104 байта, поэтому выбираем второй. Строку до 104-й позиции просто заполним кодом инструкции 'NOP' 0x90.

Далее следует определить каким же адресом мы заменим адрес возврата, для чего выясним контекст программы, т.е. содержимое регистров и памяти, после выполнения инструкции выхода из подпрограммы 'RET'. С этой целью построим схему стека в этот момент.

Здесь слева отмечены позиции строки. Очевидно, что после выполнения инструкции 'RET' регистр вершины стека ESP будет указывать на 108-ю позицию введенной строки. Таким образом, если, как мы уже определили, наш код будет располагаться со 108-й позиции, то чтобы передать управление нашему коду достаточно выполнить инструкции: jmp esp либо call esp. Для этого необходимо отыскать в виртуальном адресном пространстве нашей программы комбинацию двух байт: 0xff 0xe4 (jmp esp) либо 0xff 0xd4 (call esp). Адрес найденной комбинации и будет адресом, которым мы заменим адрес возврата. Получится следующая последовательность выполнения:

RET -> JMP ESP -> исполнительный код эксплоита

Искомая комбинация может располагаться как в области памяти самой программы, так и в области динамически загружаемых библиотек DLL программы и системных. Причем идеальным вариантом будет первое либо DLL, относящиеся к программе, так как системные DLL Windows NT часто меняются от сервиспака к сервиспаку. К сожалению (или к счастью) такое маловероятно, так как программа обычно занимает относительно низкие адреса со старшим байтом равным нулю, который является признаком конца строки и его можно использовать лишь в случае, когда код располагается до адреса возврата (в нашем случае до позиции 104). Образ исполнимого файла программы и DLL располагается в памяти начиная с так называемого Image base, который легко можно выяснить при помощи любой утилиты, анализирующей содержимое PE заголовка. Но мы воспользуемся для этого утилитой LISTDLLS Марка Руссиновича (доступна на http:\\www.sysinternals.com):

D:\exploit>listdlls so
. . .
Base Size Version Path
0x00400000 0x27000 D:\exploit\so.exe
0x77f60000 0x5c000 4.00.1381.0130 E:\WINNT\System32\ntdll.dll
0x77f00000 0x5e000 4.00.1381.0133 E:\WINNT\system32\KERNEL32.dll

Здесь Base - это image base исполняемого файла. Итак, мы получили сведения о расположении программы и DLL в виртуальном адресном пространстве.

Далее отметим, что поиск комбинации 2х байт, образующих инструкцию jmp esp, можно выполнять как непосредственно в исполняемых файлах (1), так и в памяти (2). Последнее мне представляется более удобным, так как не нужно проводить пересчет смещения в файле в адрес памяти. Для этих целей используем отладчик, а именно: SoftIce версии для Windows NT. Запускаем сервис SoftIce, набираем so.exe и вызываем переполнение буфера, как показано ранее. После возникновения исключения попадаем в консоль SoftIce и набираем команду поиска: s 1000000 l ffffffff ff e4 -что означает, искать последовательность байт 0xff 0xe4 начиная с адреса 0x0100000 по 0xFFFFFFFF. В результате получаем:
Pattern found at 0023:77f327e5 (77f327e5) - последовательность найдена по адресу 0x77f327e5. Отлично, мы нашли то, что нужно.

Приведенный адрес не содержит кодов конца строки: 0x00, 0x0a и 0x0c, 0x1a, поэтому его можно смело использовать. Найденная инструкция находится в KERNEL32.DLL (диапазон 0x77f00000-0x77f5e000), которая зависит от установленного сервиспака и поэтому адрес инструкции у вас скорее всего будет отличным от моего. Отметим также, что адрес начала поиска 0x01000000 - соответствует наименьшему адресу, не содержащему нулевого старшего байта.

При поиске нужной инструкции в файле (1) наши рассуждения были бы следующими:
so.exe расположен в диапазоне 0x00400000 : 0x00427000, т.е. старший байт всегда ноль - не подходит;
KERNEL32.DLL в диапазоне 0x77f00000 : 0x77f5e000, значит берем любой hexviewer и ищем ff e4, далее к найденному смещению прибавляем Image base и получаем тот же результат - 0x77f327e5.

Приступим к написанию эксплоита. Для простоты реализации договоримся, что он будет запускать командную оболочку cmd.exe, что потребует вызова функции WinExec (выбрана для простоты), которая находятся в KERNEL32.DLL. На Си наш эксплоит должен выполнять следующее:

WinExec("start cmd.exe", SW_SHOW); // запуск cmd.exe в новой консоли
ExitProcess(0); // нормальное завершение программы без вывода сообщения об
// ошибке

Посмотрим теперь, какие динамические библиотеки и импортируемые функции используются нашей программой. С целью чего, воспользуемся утилитой dumpbin из пакета VC++ (можно также использовать и другие утилиты: tdump - среды Borland, pedump и пр.).

D:\exploit>dumpbin SO.EXE /imports
. . .
Section contains the following imports:

KERNEL32.dll
42513C Import Address Table
425028 Import Name Table
0 time date stamp
0 Index of first forwarder reference

19F HeapFree
174 GetVersion
7D ExitProcess
51 DebugBreak
152 GetStdHandle
2DF WriteFile
1AD InterlockedDecrement
1F5 OutputDebugStringA
13E GetProcAddress
1C2 LoadLibraryA
. . .

Как видно, нужная KERNEL32.DLL уже присутствует, но WinExec - нет в числе импортируемых функций. Поэтому будем использовать функцию загрузки динамической библиотеки - LoadLibraryA (так как GetModuleHandle не импортируется) и функцию получения адреса импортируемой процедуры GetProcAddress.

LoadLibraryA и GetProcAddres импортируются и их адреса находятся в таблице импорта (Import Address Table), которая настраивается в процессе загрузки программы на исполнение. Чтобы получить адрес, необходимо к смещению начала Import Address Table прибавить порядковый номер функции в таблице (начиная с нуля), умноженный на четыре. Из приведенного выше результата выполнения 'dumpbin SO.EXE /imports' получаем:
для GetProcAddress 0x42513C + 8*4 = 0x42515С,
для LoadLibraryA 0x42513C + 9*4 = 0x425160.

Эти адреса придется "жестко зашить" в эксплоит и они будут зависеть от уязвимой программы, в нашем случае, so.exe. Итак, с адресами мы определились, займемся следующей проблемой.

Функции LoadLibraryA, GetProcAddres, WinExec требуют в качестве своих параметров строки символов, оканчивающиеся нулевым байтом, который, как описано выше, нам нельзя использовать. Что же делать ? В данной ситуации, обычно, применяют некий механизм кодирования, например операцию xor. В результате, строки символов передаются в закодированном виде и не содержат байта 0x00.

Наконец, составим алгоритм исполнительного кода эксплоита:

  1. раскодирование строковых констант;
  2. циклы вызовов LoadLibraryA и GetProcAddres для подготовки необходимых функций;
  3. выполнение WinExec;
  4. выполнение ExitProcess.

За реализацией данного алгоритма отсылаю вас непосредственно к тексту исполняемого кода эксплоита с комментариями. В нем я постарался выделить все параметры, зависящие от уязвимой программы. Эти параметры потребуется откорректировать, чтобы получить рабочий эксплоит для вашей версии so.exe. В результате компиляции и сборки исполнительного кода эксплоита мы получим часть строки эксплоита со 108-й позиции.

Далее по технологической цепочке необходимо выполнить программу EXPL, формирующую полную строку эксплоита. Листинг программы с комментариями приведен здесь.

D:\exploit>expl runcode exploit

И в завершении:

D:\exploit>type exploit | so.exe

Наш эксплоит получился зависимым от версии KERNEL32.DLL, так как используется ссылка на инструкцию 'jmp esp' в данной DLL. Для примера это вполне подойдет, но реальный эксплоит должен работать с любыми сервиспаками и постфиксами. Реализация такой совместимости требует, чтобы инструкция, которой передается управление по команде 'RET', располагалась в самой программе, в поставляемых с ней DLL либо в системных динамических библиотеках, которые неизменны при любом установленном сервиспаке. Также более детальное изучение контекста после выполнения 'RET' позволит отыскать возможность применения инструкций перехода отличных от 'jmp esp' и 'call esp'.

Отсутствие импортируемых LoadLibrary и GetProcAddress тоже не будет помехой. В этом случае можно использовать алгоритм, предложенный Jeremy Kothe (hard-coded windows exploits. Bugtraq, 16 ноября, 1999). Его суть заключается в следующем: так как все процессы запускаются посредством kernel32.dll, то при вершине стека должен располагаться указатель на диапазон памяти kernel32.dll, а зная, что вершина стека хранится по fs:4, можно найти ее PE заголовок и далее адреса экспортируемых ей LoadLibrary и GetProcAddress.

По ходу разработки эксплоита сформировалось некое подобие инструментария в виде explcode.asm и expl.c, настраиваемые параметры которых позволят относительно быстро и с минимальными усилиями получить строку эксплоита для любой подобной уязвимости.

Вспомним теперь, что буфер переполнился при выполнении strcpy, которая не имеет параметра размера буфера. Существуют и другие такие функции, например gets, sprintf. Законно предположить, что программа, оперирующая этими функциями - потенциально уязвима. Но часто ли они используются в программах. Для выяснения этого напишем два крошечных пакетных файла:

 getvul.cmd@echo off
for %%f in (*.exe *.dll) do printvul.cmd %%f
printvul.cmd
@echo off
echo %1 >> vulinfo.txt
dumpbin %1 /imports | find "strcpy" >> vulinfo.txt
dumpbin %1 /imports | find "sprintf" >> vulinfo.txt
dumpbin %1 /imports | find "gets" >> vulinfo.txt
echo ----------------------------------------------------------- >> vulinfo.txt

скопируем их в %SystemRoot%\system32 и запустим getvul.cmd. Для тех, кто посмотрит содержимое vulinfo.txt, дополнительные комментарии будут излишни.

Итак, мы рассмотрели пример уязвимости переполнения буфера и разработали атаку для него в виде эксплоита. Однако, это всего лишь один из возможных вариантов атак на переполнение буфера, называемый "срыв стека" (stack smashing attack). Возможны атаки на указатели функций, данных и различные другие комбинации. Описание и классификация атак на переполнение буфера, а также известные методы защиты от них приведены в другой моей статье "Атаки на переполнение буфера".


Андрей Колищак

При копировании материалов ссылка на HackZone.RU обязательна

Добавить страницу в закладки

 Детали
Категория: Архив
Опубликовал: DiMan
Просмотров: 601088
Проголосовало через SMS: 0
  Разместить у себя на сайте
Прямая ссылка
HTML
BBCode ссылка
BBCode ссылка с текстом

 Комментарии (оставить свой комментарий можно здесь)
Tongue
19.03.2010 / 1DexteR1
Только зарегистрированные пользователи могут оставлять комментарии

Зарегистрироваться *** Авторизоваться


 Последние новости и статьи  Последние сообщения с форумов
  • В CMS Joomla обнаружена критическая 0-day уязвимость
  • ФБР не смогло взломать протокол шифрования переписки террористов ...
  • Полиция обыскала дом предполагаемого создателя платежной системы ...
  • Google: квантовый ПК будет в 100 млн раз быстрее стандартных чипо...
  • "Лаборатория Касперского" констатирует усиление атак кибергруппир...
  • Microsoft Edge откроет исходные коды ChakraCore
  • Anonymous объявили 11 декабря «днём троллинга» ИГИЛ
  • Миллионы телевизоров, смартфонов и маршрутизаторов оказались уязв...
  • Adobe прощается с Flash
  • У пользователей Viber наблюдаются проблемы

    Все новости... Все статьи... Прислать новость RSS
  • Разное / Ищу работу » Re: -=Мощный DDoS service/ДДоС сервис=-
  • Разное / Предложения работы » Re: Взлом Whatsapp.Viber.Instagram. facebook.Узнаем взломаем...
  • Разное / Ищу работу » Re: Взлом емейлов, вконтакте, одноклассники
  • Разное / Ищу работу » Re: Взлом ВКонтакте на заказ. Взлом почты на заказ.
  • Разное / Предложения работы » Взлом Вк, Viber и почты.
  • Разное / Предложения работы » &lt;&lt;Взлом акков ВК,viber по вменяемой цене&g...
  • Разное / Предложения работы » Взлом Вк, Viber и почты.
  • Разное / Ищу работу » Re: Качественный взлом почты (rambler.ru,yandex.ru,gmail.com...
  • Взлом и безопасность / WEB сайтов » Re: Как взломать сайт в котором нет авторизации и пользовате...
  • Разное / Предложения работы » Re: Взлом Удаленного доступа к телефонам и пк. Взлом Iphone

    Все форумы... RSS


  • Разместить рекламу
    © HackZone Ltd. 2007-2012. Все права зарегистрированы.
    Перепечатка материалов без согласования и указания источника будет преследоваться по Закону

    О проекте | История проекта | Размещение рекламы | Обратная связь | Правила поведения на портале
    Ya-Cyt службы мониторинга серверов

    #{title}

    #{text}

    x

    #{title}

    #{text}