На нашем сайте мы используем cookie для сбора информации технического характера и обрабатываем IP-адрес вашего местоположения. Продолжая использовать этот сайт, вы даете согласие на использование файлов cookies. Здесь вы можете узнать, как мы пользуемся файлами cookies.
Я согласен
логотип upread.ru

Переполнение буфера



Ошибки переполнения буфера характеризуются перезаписью фрагментов памяти процесса, которые никогда не должны были изменяться намеренно или непреднамеренно. Перезапись значений IP (указатель команд), BP (базовый указатель) и других регистров приводит к возникновению исключений, сбоев сегментации и других ошибок. Обычно эти ошибки заканчивают выполнение приложения неожиданным образом. Ошибки переполнения буфера возникают, когда мы работаем с буферами типа char.

Переполнение буфера может состоять из переполнения стека или переполнения кучи. Я не привожу различия между этими двумя в этой статье, чтобы избежать путаницы. Приведенные ниже примеры написаны на языке C в системе GNU/Linux на архитектуре x86.

Пример 1

#include <stdio.h>
int main(int argc, char **argv)
{
char buf[8]; // buffer for eight characters
gets(buf); // read from stdio (sensitive function!)
printf("%s\n", buf); // print out data stored in buf
return 0; // 0 as return value
}
Это очень простое приложение считывает из стандартного ввода массив символов и копирует его в буфер типа char. Размер этого буфера составляет восемь символов. После этого отображается содержимое буфера и приложение завершает работу.

Компиляция программы:

user@spin ~/inzyeria $ gcc bo-simple.c -o bo-simple
/tmp/cCXQAX.o: In function `main':
bo-simple.c:(.text+0x17): warning: the `gets' function is dangerous and
should not be used.
На этом этапе даже компилятор предупреждает, что функция gets() небезопасна. Пример использования:

user@spin ~/inzynieria $ ./bo-simple // program start
1234 // we eneter "1234" string from the keyboard
1234 // program prints out the conent of the buffer
user@spin ~/inzynieria $ ./bo-simple // start
123456789012 // we eneter "123456789012"
123456789012 // content of the buffer "buf" ?!?!
Segmentation fault // information about memory segmenatation fault
К счастью, нам удается (не) выполнить ошибочную операцию с помощью программы и спровоцировать ее аварийный выход.

Анализ проблемы:

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

Пример 2

#include <stdio.h>
#include <string.h>

void doit(void)
{
        char buf[8];

        gets(buf);
          printf("%s\n", buf);
}

int main(void)
{
        printf("So... The End...\n");
        doit();
        printf("or... maybe not?\n");

        return 0;
}
Этот пример аналогичен первому. Кроме того, до и после функции doit() у нас есть два вызова функции printf(). Программа между двумя определенными вызовами printf() отображает содержимое буфера, которое заполнено данными, введенными пользователем. Поскольку размер буфера был определен (char buf[8]) и он был заполнен тринадцатью символами типа char, буфер был переполнен.

Если наше двоичное приложение в формате ELF, то мы можем использовать программу objdump для его анализа и поиска необходимой информации для использования ошибки переполнения буфера.

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

Как возникают ошибки переполнения буфера?

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

  • gets() -\> fgets() - считывает символы
  • strcpy() -\> strncpy() - копирует содержимое буфера
  • strcat() -\> strncat() - объединение буферов
  • sprintf() -\> snprintf() - заполняет буфер данными разных типов
  • (f)scanf() - считывание из STDIN
  • getwd() - возвращает рабочий каталог
  • realpath() - возвращает абсолютный (полный) путь
Используйте безопасные эквивалентные функции, которые проверяют размер буфера, когда это возможно. Именно:

  • gets() -\> fgets()
  • strcpy() -\> strncpy()
  • strcat() -\> strncat()
  • sprintf() -\> snprintf()
Те функции, которые не имеют безопасных эквивалентов, должны быть переписаны с внедрением безопасных проверок. Время, потраченное на это, принесет пользу в будущем. Помните, что вы должны сделать это только один раз.

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



Автор этого материала - я - Пахолков Юрий. Я оказываю услуги по написанию программ на языках Java, C++, C# (а также консультирую по ним) и созданию сайтов. Работаю с сайтами на CMS OpenCart, WordPress, ModX и самописными. Кроме этого, работаю напрямую с JavaScript, PHP, CSS, HTML - то есть могу доработать ваш сайт или помочь с веб-программированием. Пишите сюда.



тегизаметки, си плюс плюс, ошибки





Отправляя сообщение я подтверждаю, что ознакомлен и согласен с политикой конфиденциальности данного сайта.




Реестр почти без программирования, или KISS
Урок по работе со строками (String) на C#


© upread.ru 2013-2022
При перепечатке активная ссылка на сайт обязательна.
Задать вопрос
письмо
Здравствуйте! Вы можете задать мне любой вопрос. Если не получается отправить сообщение через эту форму, то пишите на почу up777up@yandex.ru
Отправляя сообщение я подтверждаю, что ознакомлен и согласен с политикой конфиденциальности данного сайта.