logo
Методические указания для АЗ-ИБ

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

Язык Си даёт программисту большие возможности для контроля над программой, но то же обстоятельство может привести к появлению программ, подверженных переполнению буфера или утечкам памяти, если программист будет недостаточно внимателен. Имеется в виду, что если переменной выделена память, то никакие встроенные механизмы защиты не будут обеспечивать соответствие размеров помещаемых в переменную данных и отведённого для неё пространства памяти. Если возложить ответственность за целостность данных на компилятор, то в результате будут получаться исполняемые файлы, которые станут работать значительно медленнее из-за проверок целостности, осуществляемых для каждой переменной. Если программист захочет записать десять байт данных в буфер, которому выделено только восемь байт памяти, ничто не запретит ему это сделать, даже если в результате почти наверняка последует крах программы. Такое действие называют переполнением буфера, поскольку два лишних байта переполнят буфер и разместятся за концом отведённой памяти, разрушив то, что находилось дальше. Если будет изменён важный участок данных, это вызовет крах программы. Соответствующий пример даёт следующий код.

void overflow_func(char *str)

{

char buf[20];

strcpy(buf, str); // Функция, копирующая str в buf

}

 

int main()

{

char big_string[128];

int i;

 

for(i=0; i < 128; i++) // Повторить цикл 128 раз

{

big_string[i] = 'A'; // Заполнить big_string символами 'A'

}

overflow_func(big_string);

 

return 0;

}

Функция overflow_func попытается втиснуть 128 байт данных в буфер, которому выделено всего 20 байт. Оставшиеся 108 байт данных просто покроют всё, что находится в памяти за буфером.

$ gcc -o overflow overflow.c

$ ./overflow

Segmentation fault

$

Программа аварийно завершилась в результате переполнения. программист часто встречается с такими ошибками, которые легко исправить, если только известно, какой длины будут входные данные. Часто программист рассчитывает, что вводимые пользователем данные всегда будут иметь определённую длину, и основывает на этом свои действия. Но поиск уязвимостей в том и заклдючается, чтобы представить себе ситуацию, на которую не рассчитывали, и тогда программа, прекрасно работавшая годами, может внезапно рухнуть, если кто-нибудь решит ввести тысячу символов в поле, которое обычно принимает несколько десятков символов, например имя пользователя. Итак, можно вызвать крах программы, введя неожиданные значения, которые вызовут переполнение буфера, но можно ещё и получить контроль над программой. Для этого нужно разобраться, какие именно данные оказываются затёртыми.