
Большинство атак по переполнению буфера проводят простые «сценаристы», которые не понимают, как происходит атака.
Они просто сканируют определенную сеть с помощью автоматизированного инструмента, выявляют слабые места в системе, загружают код взлома, написанный кем-то другим, и направляют инструмент взлома против выбранной сети. Скорее всего, код взлома был разработан человеком, лучше разбирающимся в уязвимых программах и преуспевшим в создании успешных программ взлома.
Как же создатель программ по переполнению стековой памяти находит программы, уязвимые с данной точки зрения? Этот человек тщательно проанализирует программы, где содержатся функции, не проверяющие границы локальных переменных.
Если у атакующего есть исходный код программы, он может поискать часто применяемые функции, которые не проверяют локальные переменные. Рассмотренная ранее strcpy - как раз такая функция, которой программисты часто неправильно пользуются, в результате данная функция становится уязвимой при переполнении стековой памяти. К другим функциям языка С, которые также вызывают подобные проблемы, относятся:
fgets;
gets;
getws;
шегпсру;
memmove;
scant;
sprintf;
strcat;
strncpy.
Создатель программы взлома станет искать исходный код или воспользуется отладчиком, чтобы узнать, какие из этих функций применяются в выбранной программе. Если у атакующего будет исходный код, с помощью автоматизированных инструментов он без труда обнаружит недостатки программы.
При отсутствии исходного кода создатель программы взлома прибегнет к более грубому способу, чтобы выявить уязвимые программы. Он запустит программу в своей лаборатории и с помощью специального инструмента станет вводить туда огромные объемы информации. Пространство, отведенное для записи данных локальных пользователей, а также для ввода данных в сети, будет заполнено этой информацией. При загрузке большого объема информации в программу атакующий должен убедиться, что данные периодически повторяются, например символ «А» включен тысячи раз.
Хакер будет искать программу, которая в таких условиях откажется работать, причем стремится обнаружить подобные приложения не просто так, а для своей выгоды. Атакующие хотят, чтобы введенные данные (например, символ «А», шестнадцатеричный код которого 0x41) заменили указатель возврата, когда произойдет аварийный отказ сети от работы.
Рассмотрим пример знаменитой программы взлома переполнением буфера, которая широко рекламировалась командой еЕуе в середине 1999 года. Эта команда искала слабые места в Internet Information Server от Microsoft, отправляя ему огромный объем информации с помощью своего продукта Retina. После часа загрузки данных информационный сервер оказался в аварийном состоянии, а в журналах процессора остались следующие записи:
ЕАХ = 00F7FCC8 ЕВХ = 00F41130
ЕСХ - 41414141 EDX - 77F9485A
ESI - 00F7FCC0 EDI - 00F7FCC0
EIP - 41414141 ESP - 00F4106C
EBP = 00F4108C EFL = 00000246
Не смотрите на разные значения, обратите внимание на указатель команды (EIP). Атакующие просто обожают этот указатель. Введенные в программу данные (повторяющийся набор 0x41) каким-то образом заменили указатель команды. Скорее всего, вписанная пользователем информация переполнила буфер, заменила указатель возврата, а затем перешла и в указатель команды.
Основываясь на полученных результатах, команда еЕуе разработала программу взлома, которая позволяет атакующему получить доступ к системам Windows, где функционирует Internet Information Server.
Когда создатели программ взлома находят уязвимый вызов функции (либо исследуя исходный код, либо с помощью отладчика, либо путем ввода огромного объема информации), они тщательно анализируют, как функция получает данные от пользователя. Затем пишется специальный код, который введет подобные данные в программу, чтобы заменить указатель команды и указатель возврата. И опять же, правильное создание кода и присвоение указателю возврата правильного значения - трудоемкий процесс.
Кроме того, в командах, помещенных в стек, не должно быть таких символов, которые фильтруются программой. При нарушении работы уязвимой символьной функции в коде и указателе возврата нуль-символы, которые останавливают выполнение многих функций, должны отсутствовать.
Что такое переполнение буфера памяти?
Рассмотрим составляющие программы взлома посредством переполнения буфера подробнее. Какие действия в конечном итоге приводят к переполнению? Очевидно, что атакующий должен отправить машинный код, чтобы выполнились определенные команды, а также послать такую информацию, которая перезаписала бы указатель возврата, адресующий информацию стека, где располагается код атакующего.
Очень важно, чтобы указателю возврата было присвоено верное значение: указание на неверную область памяти может привести к аварийному отказу программы или неверному выполнению кода атакующего. Но что еще больше усложняет работу хакера, так это периодическая смена места расположения стека в памяти компьютера. Следовательно, атакующему часто приходится угадывать ту область памяти, куда должна перейти программа для выполнения нужного кода.
Для решения этой немаловажной задачи - добиться, чтобы указатель возврата представлял ту область памяти, которую нужно, - атакующие часто добавляют в начале своего кода несколько команд NOP.
Эти команды просто приказывают процессору ничего не делать. Когда процессор встречает такую команду, он приостанавливается, а затем загружает следующую команду. У каждого процессора есть один или более типов команд, реализующих N О Р, чтобы процессор выждал некоторое время, прежде чем переходить к выполнению следующей команды.
Атакующие перед своим кодом в стеке поместят несколько таких NOP. В зависимости от размера буфера будут включены сотни или даже тысячи команд NOP. В программе взлома по переполнению буфера набор подобных команд иногда называют выжиданием NOP. Следовательно, при переполнении буфера в стек отправляются данные, состоящие из выжидания NOP, машинного кода, содержащего те команды, которые атакующий хочет выполнить, и указателя возврата.
Таким образом, NOP увеличивают вероятность того, что указатель возврата покажет правильное место в памяти сети, чтобы реализовать код атакующего. Без применения NOP программа должна переместиться непосредственно к началу кода атакующего, то есть указателю возврата будет присвоено определенное значение. Если же использовать команды NOP, программа может перейти к любой из них.
Если атакующий задал такое значение указателя возврата, что программа обратилась к одной из команд NOP, процессор станет последовательно выполнять NOP, пока не дойдет до кода атакующего. Затем будет загружен и этот код, и атака по переполнению буфера завершится. Именно по данной причине в большинстве атак переполнения буфера задействуются команды NOP.
Системы обнаружения вторжений и переполнение стековой памяти
Многие IDS обнаруживают атаку переполнения стековой памяти, сравнивая сигнатуры. Эти системы ищут команды NOP, которые обычно используются в коде атакующего, либо указатели возврата, связанные с известными атаками переполнения буфера. Любой из названных элементов атаки переполнения буфера легко выявляется IDS.
Отслеживая поток информации, проходящий по сети, и выискивая группу NOP, обычный код взлома или типичные указатели возврата, IDS может вычислить атаку и предупредить администратора. Наиболее популярные сигнатуры IDS для определения атаки переполнения буфера учитывают посылку команд NOP.
Автор: pimka21
Еще советуем: