Переповнення буфера
У галузі комп'ютерної безпеки і програмування, переповнення буфера (англ. buffer overflow або англ. buffer overrun), це явище, при якому програма, під час запису даних в буфер, перезаписує дані за межами буфера. Це може викликати несподівану поведінку, включно з помилками доступу до даних, хибними результатами, збоєм програми або дірою в системі безпеки.
Переповнення буфера може бути викликане недостатньою перевіркою вхідних даних. Воно є базою для багатьох уразливостей в програмних продуктах і може бути використане зі злим наміром. Додаткова перевірка може запобігти переповненню буфера, хоча така перевірка вплине на швидкодію програми.
Мови програмування, зазвичай згадувані у зв'язку з переповненням буфера, це здебільшого C та C++. Вони не мають вбудованого механізму проти доступу або перезаписування даних у будь-якій частині пам'яті й не провадять автоматичної перевірки даних, які записують в масив, на вихід за межі масиву.
Переповнення буфера відбувається тоді, коли дані, що записуються в буфер, через недостатню перевірку, пошкоджують дані, розташовані за сусідніми до буфера адресами. Часто це відбувається, коли копіюється рядок з одного буфера в інший.
В наступному прикладі програма визначила два суміжні об'єкти в пам'яті: рядок 8 байтів завдовжки, A, і двобайтове ціле, B. Початково А містить нульові байти, а В містить число 1979. Символи мають розмір один байт.
ім'я змінної | A | B | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
значення | [порожній рядок] | 1979 | ||||||||
шістнадцяткове значення | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 07 | BB |
Тепер, програма намагається зберегти нуль-термінований рядок excessive в буфер A. Через відсутність перевірки на допустиму довжину рядка, він затирає значення B:
ім'я змінної | A | B | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
значення | 'e' | 'x' | 'c' | 'e' | 's' | 's' | 'i' | 'v' | 25856 | |
шістнадцяткове значення | 65 | 78 | 63 | 65 | 73 | 73 | 69 | 76 | 65 | 00 |
Хоча програміст не збирався змінювати значення B, це значення було перезаписане і тепер містить число, утворене частиною рядка. В цьому випадку, на big-endian системі, що використовує ASCII, "e" і нульовий байт сформують число 25856. Якщо за B слідує недоступна для запису ділянка пам'яті, запис ще довшого рядка може призвести до помилки сегментації, що перерве процес.
Техніки використання уразливості через переповнення буфера залежать від архітектури, операційної системи і ділянки пам'яті. Наприклад, використання купи різниться від використання стека викликів.
Технічно освідомлений і злонамірений користувач може використати стекове переповнення буфера так:
- Для перезапису локальної змінної, змінивши тим самим перебіг програми на вигідніший для нападника.
- Для перезапису адреси повернення в стековому кадрі. Коли буде виконане повернення з функції, виконання програми відновиться за адресою, вказаною нападником (зазвичай це адреса буфера поля вводу). Такий спосіб найбільш розповсюджений в архітектурах, де стек росте донизу (наприклад в архітектурі x86).
- Для перезаписів вказівника на функцію,[1] або обробника винятків, що будуть виконані згодом.
З методом «трамполайнінга» (англ. trampolining, буквально «стрибки на батуті»), якщо адреса даних, яку ввів користувач, невідома, але їх місцеперебування зберігається в реєстрі, тоді адреса повернення може бути перезаписана на адресу опкоду, який виконає перехід до даних, введених користувачем. Якщо їх месцезнаходження зберігається в реєстрі R, тоді потрібен стрибок до опкоду для стрибка R, це викличе виконання користувацьких даних. Розташування необхідних опкодів або байтів в пам'яті може бути знайдено в динамічних бібліотеках або самій програмі. Адреси опкодів можуть змінюватися між застосунками й версіями ОС. Metasploit Project - одна з баз даних потрібних опкодів для Windows.[2]
Не варто плутати стекове переповнення буфера з переповненням стека.
Також зауважимо, що наявність таких вразливостей зазвичай перевіряється за допомогою фаззінга.[3]
Переповнення буфера в купі використовується відмінно від переповнення в стеку. Пам'ять в купі динамічно розподіляється застосунком під час виконання і, зазвичай, містить дані програми. Використання відбувається через пошкодження даних особливим чином, що призводить до перезапису внутрішніх структур даних, таких як зв'язний список вказівників.
Уразливість Microsoft GDI+ при обробці JPEGів, приклад наскільки небезпечною може бути переповнення в купі.[4]
Для зменшення імовірності переповнення буфера, використовуються наступні заходи.
За допомогою систем виявлення вторгнення (СВВ) можна виявити й запобігти спробам віддаленого використання переповнення буфера. Через те, що в більшості випадків дані, призначені для переповнення буфера містять довгі масиви інструкцій No Operation (NOP
або NOOP
), СВВ просто блокує всі вхідні пакети, що містять велику кількість послідовних NOP-ів. Цей спосіб, загалом, не ефективний, бо такі масиви можуть бути записані за допомогою великого різноманіття інструкцій мови асемблера. Останнім часом зламувачі для оминання СВВ почали використовувати коди оболонки (шел-коди) з шифруванням, кодом, що змінює себе сам, поліморфним кодом і абетково-цифровим кодом, а також атаку з поверненням в бібліотеку libc.
Захист від пошкодження стека використовується для виявлення найбільш поширених помилок переповнення буфера. При цьому перевіряється, що стек викликів не був змінений перед виходом з функції. Якщо він був змінений, тоді програма завершує своє виконання з помилкою сегментації.
Існують три такі системи: Libsafe і StackGuard з Stack-Smashing Protector (стара назва — ProPolice), дві останні є розширеннями компілятора gcc. Починаючи з gcc-4.1-stage2, SSP був інтегрований в основний дистрибутив компілятора. Gentoo Linux і OpenBSD мають SSP в складі розповсюджуваного з ними gcc.
Майкрософтівська функція безпеки з запобігання виконанню даних не дозволяє виконувати код з області пам'яті з позначкою «тільки для даних»
Захист простору машинного коду може пом'якшити наслідки переповнення буфера, унеможливлюючи більшість дій зловмисника. Це досягається рандомізацією адресного простору (ASLR — англ. Address space layout randomization) і/або забороною одночасного доступу до пам'яті на запис і виконання. Стек без виконання запобігає більшості вразливостей коду оболонки.
Існує два виправлення для ядра Linux, які забезпечують цей захист — PaX і exec-shield. Жоден з них не є частиною основного дистрибутиву ядра. OpenBSD починаючи з версії 3.3 включає систему під назвою W^X, котра також забезпечує контроль простору виконання[джерело?].
Зауважимо, що такий спосіб захисту не запобігає пошкодженню стека. З усім тим він часто запобігає успішне виконання «корисного вантажу» експлойта. Програма не в змозі вставити код оболонки в захищену від запису пам'ять, таку як існуючі сегменти коду виконання. Також буде неможливо виконання інструкцій в пам'яті не для виконання, наприклад в стеку або в купі.
ASLR утруднює для зламника визначення адрес функцій в коді програми, за допомогою яких він міг би здійснити успішну атаку, і робить атаки типу ret2libc дуже складним завданням, хоча вони все ще можливі в контрольованому середовищі, якщо нападник вгадає правильну адресу[джерело?].
Деякі процесори, як от Sparc від Sun, Efficeon від Transmeta, найновіші 64-розрядні x86 процесори фірм AMD (починаючи з Opteron) та Intel (починаючи з версій Pentium 4 Prescott) запобігають виконанню коду, розташованого в областях пам'яті, які позначені особливим бітом NX. AMD називає своє рішення NX (від англ. No eXecute), а Intel своє — XD (від англ. eXecute Disabled).
Зараз існує декілька різних рішень, призначених для захисту виконуваного коду в системах Windows, які пропонує компанія Майкрософт і сторонні компанії.
Майкрософт запропонувала своє рішення під назвою DEP (від англ. Data Execution Prevention — «запобігання виконанню даних»), включила його в пакети оновлень для Windows XP та Windows Server 2003. DEP використовує додаткові можливості нових процесорів Intel і AMD, для подолання обмеження в 4 ГіБ на можливість адресації пам'яті, розмір пам'яті, притаманне 32-розрядним процесорам. Для цих цілей службові структури були збільшені. Ці структури тепер містять зарезервований біт NX. DEP використовує цей біт для запобігання атакам, пов'язаним зі зміною адреси обробника винятків (так званий SEH-експлойт). DEP забезпечує тільки захист від SEH-експлойта, він не захищає сторінки пам'яті з виконуваним кодом.
До того, Майкрософт розробила механізм захисту стека, призначений для Windows Server 2003. Стек позначається за допомогою позначок (англ. canary), цілісність яких перевіряється. Якщо така позначка була змінена, значить, стек пошкоджено.
Існують також рішення від інших компаній, які запобігають виконанню кода, розташованого в областях пам'яті, призначених для даних або реалізуючих механізм ASLR.
Проблема переповнення буфера характерна для мов програмування С та C++, бо вони не приховують деталі низькорівневого представлення буферів як контейнерів для типів даних. Таким чином, задля уникнення переповнення буфера, потрібно забезпечити високий рівень контролю за створенням і зміною програмного коду, який здійснює керування буферами. Використання бібліотек абстрактних типів даних, які виконують централізоване автоматичне керування буферами й містять в собі перевірку на переповнення — один з підходів для запобігання переповнення буфера.
Два основних типи даних, які дозволяють здійснити переповнення буфера в цих мовах — рядки і масиви. Таким чином, використання бібліотек для рядків і спискових структур даних, які були розроблені для запобігання і/або виявлення переповнень буфера, дозволить уникнути багатьох уразливостей.
- ↑ CORE-2007-0219: OpenBSD's IPv6 mbufs remote kernel buffer overflow. Архів оригіналу за 8 липня 2013. Процитовано 15 травня 2007.
- ↑ The Metasploit Opcode Database. Архів оригіналу за 12 травня 2007. Процитовано 15 травня 2007.
- ↑ The Exploitant - Security info and tutorials. Архів оригіналу за 8 липня 2013. Процитовано 29 листопада 2009.
- ↑ Microsoft Technet Security Bulletin MS04-028. Архів оригіналу за 8 липня 2013. Процитовано 15 травня 2007.
Це незавершена стаття про програмування. Ви можете допомогти проєкту, виправивши або дописавши її. |