Пример продвижения переполнения буфера к утечке безопасности

Я прочитал много статей о небезопасных функциях как strcpy, memcpy, и т.д. который может привести к проблемам безопасности при обработке внешних данных, как содержание файла или данных, прибывающих из сокетов. Это может звучать глупым, но я записал уязвимую программу, но мне не удалось "взломать" ее.

Я понимаю проблему переполнения буфера. Возьмите этот пример кода:

int main() {
   char buffer[1];
   int var = 0;

   scan("%s", &buffer);
   printf("var = 0x%x\n", var);
   return 0;
}

Когда я выполняю программу и ввожу "abcde", выводы программы 0x65646362, который является "edcb" в шестнадцатеричном + прямой порядок байтов. Однако я считал, что Вы могли изменить значение eip, которое было продвинуто на стеке, чтобы заставить программу выполнить некоторый нежелательный код (например, прямо перед вызовом к системе () функция).

Однако блок функции запускается как это:

push %ebp
mov %ebp, %esp
and $0xfffffff0, %esp
sub $0x20, %esp

Так как значение %esp случайно в начале функции и из-за этого "и", кажется, нет никакого надежного способа записать точное значение в продвинутое значение eip.

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

Итак, почему разработчики так волнуются по поводу проблем безопасности (за исключением того, что программа могла отказать)? У Вас есть пример уязвимой программы и как "взломать" его для выполнения нежелательного кода? Я попробовал это на Linux, действительно ли Windows менее безопасен?

15
задан Tomaka17 20 July 2010 в 15:59
поделиться

6 ответов

Прочитайте отличную статью от Aleph One: Smashing the Stack for Fun and Profit.

15
ответ дан 1 December 2019 в 02:54
поделиться

Ну, во-первых, не стоит недооценивать опасности, связанные с возможностью ненадежно поместить значение в EIP. Если эксплойт срабатывает один из 16 раз, а атакованная им служба автоматически перезагружается, как и многие веб-приложения, то злоумышленник, который не может получить доступ, всегда может попробовать, попробовать еще раз.

Также во многих случаях значение ESP менее случайное, чем вы думаете. Для начала, в 32-битной системе оно почти всегда кратно четырем. Это означает, что дополнительное заполнение, предлагаемое инструкциями и $ 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()
}
4
ответ дан 1 December 2019 в 02:54
поделиться

Кроме того, вам не нужно перезаписывать EIP указателем на что-то в строке. Например, вы можете перезаписать его указателем на system() и перезаписать следующее слово указателем на /bin/sh в фиксированном месте в образе программы.

Правка: Обратите внимание, что system использует PATH (на самом деле она запускает команду через оболочку), поэтому "sh" было бы так же хорошо; таким образом, любое английское слово, оканчивающееся на "sh" в конце строки, предоставляет нужный аргумент.

4
ответ дан 1 December 2019 в 02:54
поделиться

Классическим примером реального эксплойта, основанного на переполнении буфера, является червь Morris Worm 1988 года.

1
ответ дан 1 December 2019 в 02:54
поделиться

Как упоминалось в других ответах, абсолютная надежность не всегда важна для успеха атаки. Примером могут служить приложения, которые автоматически перезапускаются. Другое дело - локально эксплуатируемое переполнение буфера в suid-программах. И есть техника NOP, чтобы увеличить шансы на успешную эксплуатацию, поместите много NOP перед вашим шеллкодом, чтобы у вас было гораздо больше шансов правильно угадать «начало» вашего шеллкода.

Есть много других методов повышения надежности атак. В свое время в Windows многие эксплойты заменяли адрес возврата адресом "jmp% esp", расположенным где-то в программе (батут).

«Небезопасное программирование на примере» было хорошим приемом для Linux. Очистите свое окружение и поместите свой шелл-код в переменную окружения. Раньше это привело бы к предсказуемому адресу в верхней части стека.

Есть также варианты, такие как return-into-libc и возвратно-ориентированное программирование.

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

Подводя итог, можно сказать, что разработчики не параноики, существует множество способов использовать даже самые странные случаи, и помните:

  • Программа хорошего качества, когда она делает то, что должна делать.
  • Программа безопасна, когда делает то, что должна делать, и ничего более .
1
ответ дан 1 December 2019 в 02:54
поделиться

Вот версия для Windows и руководство:

http://www.codeproject.com /KB/winsdk/CodeInject.aspx

Общий случай, о котором меня всегда предупреждали:

printf( string );

Потому что пользователь может предоставить «% n» туда, что позволяет вам вставлять все, что вы хочу в память. Все, что вам нужно сделать, это найти смещение памяти для системного вызова, передать несколько "% n" символов и ненужных символов и, таким образом, вставить адрес памяти в стек, где обычно будет возвращаемый вектор. . Вуаля - вставьте любой понравившийся код.

0
ответ дан 1 December 2019 в 02:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: