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

Ultimate adventure

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

Спецвыпуск: Хакер, номер #058, стр. 058-028-7


push 300

lea eax, [ebp+var_34]

push eax

call _fgets

add esp, 0Ch

Сразу видно, что переменная var_34 используется для хранения введенной строки (значит, это все-таки буфер!) с предельно допустимой длинной в 300h байт, при длине самой локальной переменной в 10h байт. Не исключено, что var_34, var_24 и var_20 в действительности представляют собой "кусочки" одного буфера, однако в данном случае это ничего не меняет, поскольку их совокупный размер намного меньше 300h!

Если же среди локальных переменных обнаружить переполняющиеся буфера несмотря на все усилия так и не удастся, можно попытать счастья среди развалин динамической памяти, отслеживая все перекрестные ссылки на функции типа new и malloc и анализируя окрестности их вызова.

Как бы там ни было, обнаружив переполняющийся буфер в одной из глубоко вложенных функций, не спеши радоваться: возможно, он никак не связан с потоком пользовательских данных, или (не менее неприятно) одна из материнских функций ограничивает предельно допустимую длину ввода сверху и переполнения не происходит. Пользователи графической версии IDA (фууу!) могут воспользоваться инструментом CALL GRAPH для просмотра дерева вызовов, уродливо отображающего взаимоотношения между дочерними и материнскими функциями и позволяющего (во всяком случае теоретически) проследить маршрут передвижения введенных пользователем данных по программе. К сожалению, отсутствие каких бы то ни было средств навигации (нет даже простейшего поиска!) обесценивает все прелести CALL GRAPH'а, и сориентироваться в построенных им диаграммах просто нереально. Однако никто не запрещает разрабатывать адекватные средства визуализации самостоятельно.

Пока адекватный инструмент не готов, приходится иметь секс с отладчиком, причем не простой, а анальный. История начинается просто. Заполняем все доступные поля пользовательского ввода, устанавливаем точку останова на вызов считающей их функции (например recv), устанавливаем точки останова непосредственно на буфер, принимающий введенные нами данные, и затем ждем последующих обращений. Чаще всего данные обрабатываются не сразу после приема, а перегоняются через множество промежуточных буферов, каждый из которых может содержать ошибки переполнения. Чтобы удержать ситуацию под контролем, мы вынуждены устанавливать точки останова на каждый из промежуточных буферов, обязательно отслеживая их освобождение (после освобождения локального буфера принадлежащая ему область памяти может быть использована кем угодно, вызывая ложные всплытия отладчика, отнимающие время и сильно нервирующие нас). А ведь точек останова всего четыре… Как же мы будем отслеживать обращения к десяткам локальных буферов с помощью всего четырех точек?

А вот как! Версия Soft-ice для Windows 9x поддерживает установку точки останова на регион, причем количество таких точек практически не ограничено. К сожалению, в Soft-ice для Windows NT эта вкусность отсутствует, и ее приходится эмулировать путем хитроумных манипуляций с атрибутами страниц. Переводя страницу в состояние NO_ACCESS, мы будем отлавливать все обращения к ней (в том числе и подопытному буферу). Естественно, если размер буфера много меньше размера страницы (как известно, он составляет 4 Кб), нам придется каждый раз разбираться, к какой именно переменной произошло обращение. При желании этот процесс можно полностью или частично автоматизировать (имеется множество примочек к Soft-ice, поддерживающих развитые скриптовые языки).

Назад на стр. 058-028-6  Содержание  Вперед на стр. 058-028-8