Издательский дом ООО "Гейм Лэнд"СПЕЦВЫПУСК ЖУРНАЛА ХАКЕР #45, АВГУСТ 2004 г.

Зоопарк переполняющихся буферов 

Крис Касперски aka мыщъх

Спецвыпуск Xakep, номер #045, стр. 045-008-6


Анализировать следует, в первую очередь, те буфера, на которые можно так или иначе воздействовать. Обычно это буфера, связанные с сетевыми сервисами, так как локальный взлом гораздо менее интересен.

Переполнение на практике

Теперь, слегка ознакомившись с теоретической частью, мы попрактикуемся – уроним буфер. Откомпилируем следующий демонстрационный пример (а еще лучше, возьмем готовый исполняемый файл с диска) и запустим его на выполнение:

Код #9. Наш тестовый стенд

#include >stdio.h<

root()

{

printf("your have a root!\n");

}

main()

{

char passwd[16]; char login[16];

printf("login :"); gets(login);

printf("passwd:"); gets(passwd);

if (!strcmp(login, "bob") && ~strcmp(passwd,"god"))

printf("hello, bob!\n");

}

Программа спрашивает у нас логин и пароль. Раз спрашивает, значит копирует в буфер, а тут и до переполнения недалеко. Вводим "AAAA" (много букв «A») в качестве имени и "BBBBB" в качестве пароля. Программа немедленно падает, реагируя на это критической ошибкой приложения. Ага, значит, переполнение все-таки есть! Присмотримся к нему внимательнее: Windows говорит, что "инструкция по адресу 0x41414141 обратилась к памяти по адресу 0x41414141". Откуда она взяла 0x41414141? Постойте, да ведь 0x41 – это шестнадцатеричный ASCII-код буквицы "A". Значит, во-первых, переполнение произошло в буфере логина, а во-вторых, данный тип переполнения допускает передачу управления на произвольный код, поскольку регистр – указатель команд переметнулся на содержащийся в хвосте буфера адрес. Случайным образом по адресу 0x41414141 оказался расположен бессмысленный мусор, возбуждающий процессор вплоть до исключения, но этому горю легко помочь!

Для начала нам предстоит выяснить, какие по счету символы логина попадают в адрес возврата. В этом нам поможет последовательность в стиле "qwerty...zxcvbnm", вводим ее и... система сообщает, что "инструкция по адресу 0x7a6c6b6a обратилась к памяти". Запускаем HIEW и набиваем эти "7A 6C 6B 6A" на клавиатуре. Получается "zlkj". Значит, в адрес возврата попали 17-й, 18-й, 19-й и 20-й символы логина (на архитектуре x86 младший байт записывается по меньшему адресу, то есть машинное слово, образно выражаясь, становится к лесу передом, а к нам задом).

Наскоро дизассемблировав программу (смотрим disasm.htm на диске), мы обнаруживаем в ней прелюбопытную функцию root, с помощью которой можно творить чудеса. Да вот беда: при нормальном развитии событий она никогда не получает управления. Если, конечно, не подсунуть адрес ее начала вместо адреса возврата. А какой у root'а адрес? Смотрим – 00401150h. Перетягиваем младшие байты на меньшие адреса и получаем 50 11 40 00. Именно в таком виде адрес возврата хранится в памяти. Хорошо, что ноль в нем встретился лишь однажды, аккурат оказавшись на его конце. Пусть он и будет тем нулем, что служит завершителем всякой ASIIZ-строки. Символам с кодами 50h и 40h соответствуют буквицы "P" и "@". Символу с кодом 11h соответствует комбинация >Ctrl-Q< или >Alt<+>0, 1, 7< (нажмите Alt, введите на цифровой клавиатуре 0, 1 и 7, отпустите Alt).

Назад на стр. 045-008-5  Содержание  Вперед на стр. 045-008-7