Переполняющиеся буфера - активные средства защиты

         

состояние стека функции


После защиты StackGuard'ом перед адресом возврата располагается константа 000AFF0Dh (в терминологии StackGuard'а — canary word), целостность которой проверяется перед выходом из функции. Суть в том, что комбинацию символов, слагающие canary word – \x00\x0A\xFF\x0D, очень трудно "воспроизвести" с помощью строковых функций, поскольку в языке Си символ нуля трактуется как "конец строки". Функция gets – одна из тех немногих, что обрабатывает ноль как обыкновенный символ, поскольку в качестве завершителя строки использует символ "возврата каретки".

При работе с ASCIIZ-строками "подделать" canary word невозможно! Адрес возврата можно считать надежно защищенным. Ведь, чтобы "дотянуться" до него, переполняющемуся буферу необходимо пересечь (и затереть) canary word! Разработчики торжествуют, а хакеры рвут себе вены и вешаются. Или… все-таки нет? Начнем с того, что на уникод все эти ограничения не распространяются и canary word подделывается без труда (кстати говоря, плотная версия Stack Guard'а в качестве сторожевого слова использовала 00000000h, что уникодом уже не воспроизводится, но может быть введено с помощью функции gets, которая сегодня практически никем и нигде не используется). К тому же, приложения, обрабатывающие двоичные данные функциями типа memcpy, так же остаются беззащитными.

Локальные переменные и указатель кадра стека вообще никак не защищены и могут быть беспрепятственно атакованы. Если среди этих переменных присутствует хотя бы один указатель на функцию, вызываемую после переполнения, хакер сможет подменить его адрес, передавая управление на свой shell-код. Конструкция типа "int *x; int a; … x = a;", которая к числу экзотических никак не относится, позволяет атакующему модифицировать любые указатели на функции, в том числе и адрес возврата (правда, в этом случае необходимо знать точное положение вершины стека на момент атаки, что не всегда возможно, поэтому хакеры предпочитают модифицировать таблицу импорта в Windows, а в UNIX – секцию got).


Рассмотрим самый сложный случай, когда никаких переменных в нашем распоряжении нет, а есть только сохраненный регистр кадра стека, который мы и будем атаковать. Фатальной ошибкой StackGuard'а явилось то, что он не учел "побочных эффектов" инструкции leave, которая работает так: mov esp, ebp/pop ebp, позволяя хакеру воздействовать на кадр материнской функции. Если в каком-то месте стека или кучи атакующему удастся "сложить" конструкцию 000AFF0Dh &shell-code, ему остается всего лишь подменить сохраненный EBP на адрес "своего" canary-word. Тогда при выходе из материнской функции управление будет передано на shell-код! Атаки этого типа называются ret2ret и давно описаны в хакерской литературе, однако, какого-либо практического приложения они так и не получили, поскольку, в оптимизированных эпилогах (ключ -O2) вместо инструкции leave компилятор использует более быстродействующую конструкцию add esp,x/pop ebp, и побочный эффект воздействия на ESP исчезает. В оптимизированном эпилоге, хакер может воздействовать только на стековый кадр материнской функции, "подсовывая" ей те значения локальных переменных, которые он захочет. Для успешной реализации атаки этого, обычно, оказывается вполне достаточно.

В версии 2.0 защита адреса возврата была как бы усилена — в нем появился случайный canary word, хранящийся в read-only памяти и "шифрующий" адрес возврата по XOR. Угадать 32-битный canary word — нереально, но это и не нужно! Достаточно подсунуть заведомо ложное значение. Тогда, убедившись, что стек переполнен и хакеры хакерствуют как крысы в амбаре, Stack-Guard передаст управление функции __canary_death_handler, которая завершает выполнение программы, устраивая настоящий DoS. Но лучше DoS, чем захват управления!

Весь фокус в том, что указатель на __canary_death_handler размещается в глобальной таблице смещений — GOT и может быть атакован путем воздействия на локальные переменные через уязвимый указатель кадра стека.Если такие переменные действительно есть (а куда бы они подевались?), хакер просто перенаправляет __canary_death_handler на свой shell-код!

В последующих версиях Stack-Guard'а canary world "переехал" на одну позицию вверх, взяв под свою защиту и указатель кадра, однако, дальнейшего развития проект не получил и постепенно сдулся.


Содержание раздела