Разница между - переполнением буфера и возвратом к атаке libc - PullRequest
10 голосов
/ 05 сентября 2011

Я хочу понять точную разницу между этими двумя типами атак. Из того, что я прочитал:

Переполнение буфера: перезаписывает адрес ret в стеке, чтобы указать на другой раздел кода, в который вставлен вредоносный код. Так эффективно - здесь нам нужно изменить исходный код программы, чтобы фактически осуществить атаку.

Возврат к Libc. Здесь вместо изменения исходного кода используются вызовы функций времени выполнения, предоставляемые библиотекой C (например, открытие оболочки). Здесь параметры, используемые для вызова функции, также передаются в перезаписывающем буфере, заканчиваясь после ret части стека.

Выше приведено точное описание?

И еще один связанный с этим вопрос - возможно ли провести атаку переполнения буфера без фактического изменения исходного кода исходной программы? Вероятно, если мы напишем новую программу и позволим ей изменять определенные разделы памяти (что является новым адресом возврата в поврежденном стеке исходной программы). Опять же, я думаю, что это может быть невозможно из-за защиты памяти, предлагаемой между процессами в ядре.

Ответы [ 4 ]

12 голосов
/ 05 сентября 2011

В классическом эксплойте с переполнением буфера переполняемый буфер стека заполнялся как машинным кодом, который должен быть выполнен (так называемый шелл-код, потому что он обычно вызывал процесс оболочки), так и новым адресом возврата.Новый адрес возврата будет создан так, чтобы указывать обратно в переполненный буфер стека.Очевидно, что для этого требуется знать или угадывать адрес этого стекового буфера в атакуемом процессе.

В те дни расположение процессов в памяти обычно было очень детерминированным - расположение буфера стека обычно можно было предсказать достаточно хорошо.злоумышленником (особенно если они точно знали, какая версия целевого программного обеспечения подверглась атаке).Чтобы повысить шансы на успех, когда были какие-то догадки, активному шелл-коду часто предшествовало бы большое количество исполняемого машинного кода, который не выполнял никакой полезной операции - называемой «NOP sled» или «NOP slide», где «NOP»Типичное имя для инструкции машинного кода, которая выполняет «Нет операции».Возврат к точке где-нибудь в салазках NOP будет иметь желаемый эффект.

С другой стороны, эксплойт "return-to-libc" не приводит к тому, что угнанный процесс возвращается непосредственно к шелл-коду.Вместо этого он поочередно возвращает процесс к началу цепочки библиотечных функций.Эти библиотечные функции могут напрямую выполнять операции, которые хочет атакующий, но чаще они используются для косвенного выполнения шелл-кода атакующего.

4 голосов
/ 05 сентября 2011

Я бы сказал, переполнение буфера - это класс программной ошибки, а возврат в libc - метод эксплуатации.Лучше не смешивать понятия вместе.

Например, вы можете использовать return to libc , чтобы использовать уязвимость переполнения буфера .Или вы можете использовать другие методы, такие как возврат к .text или возврат к шеллкоду .И наоборот, вы также можете использовать return to libc для использования других ошибок, таких как строка формата тоже.

4 голосов
/ 05 сентября 2011

Часть перезаписи ret-адреса распределяется между обеими атаками. Как видно из приведенного выше ответа, вы просто возвращались в код сборки, который вы написали. Этот ассемблерный код, скажем, порождает оболочку пользователя root.

Ни в одной из этих атак вы не перезапишете исходный код. Рассматривая его с точки зрения сборки, исходный код находится в сегменте .text и всегда был (или, по крайней мере, все, что я знаю) защищен от записи. Чтобы воспользоваться этим преимуществом, нужно было написать код, который вы предварительно собрали в сегменты памяти, а затем перейти к этому коду. Код, как правило, находился в «сегменте стека» или рядом с ним, и, переполнив все, что вы выбрали для перекрытия, вы перенаправили бы трафик с (скажем) ретрансляционного адреса туда. Другие места атаки включали переменную среды, которую вы предварительно создали и заполнили своим шеллкодом; или куча, или указатели функций, или PLT. Вставленный таким образом код обычно использует вызов system () для выполнения желаемого, но для этого вам необходимо иметь возможность «выполнять» в областях памяти (или иметь записи перемещения, которые вы намереваетесь использовать, объявленные как доступные для записи).

Разница между этими двумя атаками заключается в том, что после того, как память стала практически неисполнимой, тип атаки a (переполнение стека) был в значительной степени облажан. Попытка обойти этот тип атаки была тогда, когда вы пишете, вместо этого получить прямой доступ к функциям совместно используемой библиотеки - иначе вам больше не нужно было сначала записывать свой код в сегмент стека или в другое место и выполнять его там. Тем не менее, я считаю, что атаки типа libc также в значительной степени исправлены; У меня нет подробностей под рукой; и возможно я ошибаюсь.

Если вы хотите узнать, как в наши дни предотвращается любая из этих атак, или хотя бы прочитать о некоторых ключевых идеях, начните с Google 'Smashing the Stack в 2011' (или 2010).

0 голосов
/ 05 сентября 2011

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

Например:

char* str[5];<br> cin << str;

ЭтоКод, который может быть использован, если пользователь вставит строку размером более 5 символов, все последующее в стеке будет перезаписано.И из-за того, что ret-ptr «ниже» в стеке, вы можете переопределить его, если вы правильно выберете расстояние.Ваше намерение при переопределении состоит в том, чтобы он указывал на начало вашего ввода, в которое вы вставили вредоносный (ассемблерный) код, который будет выполнен, как только будет вызван ret-ptr и выполнен «переход».

...