Ответ 1
Прочитайте отличную статью от Aleph One: Разрушение стека для удовольствия и прибыли.
Я прочитал много статей о небезопасных функциях, таких как strcpy, memcpy и т.д., что может привести к проблемам безопасности при обработке внешних данных, таких как содержимое файла или данные, поступающие из сокетов. Это может показаться глупым, но я написал уязвимую программу, но мне не удалось "взломать" ее.
Я понимаю проблему переполнения буфера. Возьмите этот пример кода:
int main() {
char buffer[1];
int var = 0;
scan("%s", &buffer);
printf("var = 0x%x\n", var);
return 0;
}
Когда я запускаю программу и набираю "abcde", программа выводит 0x65646362, который является "edcb" в шестнадцатеричном + мало-endian. Однако я прочитал, что вы можете изменить значение eip, которое было нажато в стек, чтобы программа выполняла какой-то нежелательный код (например, прямо перед вызовом функции system()).
Однако сборка функции начинается следующим образом:
push %ebp
mov %ebp, %esp
and $0xfffffff0, %esp
sub $0x20, %esp
Так как значение% esp является случайным в начале функции, и из-за этого "и", похоже, нет надежного способа записать точное значение в значение push-значения.
Кроме того, я читал, что можно было выполнить код, который вы написали в буфере (здесь буфер длиной всего 1 байт, но на самом деле он был бы достаточно большим, чтобы хранить некоторый код), но какое значение вы бы дали eip для этого (учитывая, что местоположение буфера является случайным)?
Итак, почему разработчики так беспокоятся о проблемах безопасности (за исключением того, что программа может потерпеть крах)? У вас есть пример уязвимой программы и как "взломать" ее для выполнения нежелательного кода? Я пробовал это на Linux, Windows менее безопасна?
Прочитайте отличную статью от Aleph One: Разрушение стека для удовольствия и прибыли.
Ну, во-первых, не оценивайте опасности, связанные с возможностью неоправданно размещать ценность внутри EIP. Если эксплойт работает один раз в 16 раз, а служба, на которую он атакует, автоматически перезапускается, как и многие веб-приложения, тогда злоумышленник, который терпит неудачу при попытке получить доступ, всегда может попробовать, попробуйте еще раз.
Также во многих случаях значение ESP менее случайное, чем вы думаете. Для начала в 32-битной системе почти всегда кратно четыре. Это означает, что дополнительное дополнение, предлагаемое командой and $0xfffffff0, %esp
, будет либо 0, 4, 8, либо 12 байтов. Это означает, что можно просто повторить значение, которое должно быть записано в EIP возврата четыре раза, чтобы охватить все возможные смещения к адресу возврата EIP.
На самом деле существуют гораздо более агрессивные механизмы защита стека/переполнение буфера. Тем не менее, есть способы и средства даже для них.
Кроме того, для примера, где это может быть опасно, подумайте, важно ли значение var
для вас логично, как в следующем примере игрушек.
int main() {
char buffer[1];
int var = 0;
var = SecurityCheck();
scan("%s", &buffer);
if (var != 0)
GrantAccess();
else
DenyAccess()
}
Кроме того, вам не нужно перезаписывать EIP указателем на что-то в вашей строке. Например, вы можете переписать его указателем на system()
и переписать следующее слово указателем на /bin/sh
в фиксированном месте в образе программы.
Изменить: обратите внимание, что system
использует PATH
(на самом деле он запускает команду через оболочку), поэтому "sh"
будет таким же хорошим; таким образом, любое английское слово, заканчивающееся на "sh" в конце строки, предоставляет необходимый вам аргумент.
Классическим примером фактического эксплойта, основанного на переполнении буфера, является Morris Worm 1988 года.
Как упоминалось в других ответах, абсолютная надежность не всегда необходима для успеха атаки. Примером могут служить приложения, которые перезапускаются автоматически. Локально эксплуатируемые переполнения буфера для suid-программ будут другими. И там техника санки NOP, чтобы увеличить шансы на успешную эксплуатацию, поставил много NOP перед вашим шеллкодеком, чтобы у вас был гораздо лучший шанс правильно угадать "начало" вашего шеллкода.
Существует много методов повышения надежности атак. В Windows, в тот же день, многие эксплойты переписывали обратный адрес с адресом "jmp% esp", расположенным где-то в программе (батут).
"Небезопасное программирование на примере" имело хороший трюк для Linux. Очистите среду и поместите свой шелл-код в переменную среды. В тот же день это приведет к предсказуемому адресу рядом с верхней частью стека.
И есть также варианты, такие как return-in-libc и обратное ориентированное программирование.
Была даже статья о Phrack о том, как использовать однобайтовые (что означает, что буфер был переполнен только одним байтом) (бит-кет, переполнение кучи в 1 байт также можно использовать в подавляющем большинстве случаев, запрещая защиту).
Подводя итог, это не то, что разработчики параноидны, есть много способов использовать даже самые странные случаи и помнить:
Вот версия и учебник Windows:
http://www.codeproject.com/KB/winsdk/CodeInject.aspx
Общий случай, о котором я всегда предупреждал, был:
printf( string );
Поскольку пользователь может предоставить "%n"
там, где вы можете вставлять все, что хотите в память. Все, что вам нужно сделать, это найти смещение памяти для системного вызова, передать несколько "%n"
и нежелательных символов и, таким образом, вставить адрес памяти в стек, где обычно будет обратный вектор. Voila - вставьте любой код, который вам нравится.