Переповнення буфера

Матеріал з Вікіпедії — вільної енциклопедії.
Перейти до: навігація, пошук

В галузі комп'ютерної безпеки і програмування, переповнення буфера (англ. 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.

Майкрософтівська функція безпеки по запобіганню виконанню даних не дозволяє виконувати код з області пам'яті з позначкою «тільки для даних»

Захист простору машинного коду для UNIX-подібних систем[ред.ред. код]

Захист простору машинного коду може пом'якшити наслідки переповнення буфера, унеможливюючи більшість дій зловмисника. Це досягається рандомізацією адресного простору (ASLR) і/або забороною одночасного доступу до пам'яті на запис і виконання. Стек без виконання запобігає більшості експлойтів коду оболонки.

Існує два виправлення для ядра Linux, які забезпучують цей захист — PaX і exec-shield. Жоден з них не є частиною основного дистрибутиву ядра. OpenBSD починаючи з версії 3.3 включає систему під назвою W^X, котра також забезпечує контроль простору виконання.

Зауважимо, що такий споіб захисту не запобігає пошкодженню стека. Тим не менш він часто запобігає успішне виконання «корисного вантажу» експлойта. Програма не взмозі вставити код оболонки в захищену від запису пам'ять, таку як існуючи сегменти коду виконання. Також буде неможливо виконання інструкцій в пам'яті не для виконання, наприклад в стеку або в купі.

ASLR утруднює для зламника визначення адрес функцій в коді програми, за допомогою яких він міг би здійснити успішну атаку, і робить атаки типу ret2libc дуже складним завданням, хоча вони все ще можливі в контрольованому середовищі, якщо нападник вгадає правильну адресу.

Деякі процесори, як от Sparc від Sun, Efficeon від Transmeta, і найновіші 64-біовіі процесори фірм AMD і Intel запобігають виконанню коду, розташованого в областях пам'яті, які позначені особливим бітом NX. AMD називає своє рішення NX (від англ. No eXecute), а Intel своє — XD (от англ. eXecute Disabled).

Захист простору машинного коду для Windows[ред.ред. код]

Зараз існує декілька різних рішень, призначених для захисту виконуваного коду в системах 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++, бо вони не приховують деталі низькорівневого представлення буферів як контейнерів для типів даних. Таким чином, задля уникнення переповнення буфера, потрібно забезпечити високий рівень контролю за створенням і зміною програмного коду, який здійснює керування буферами. Використання бібліотек абстрактних типів даних, які виконують централізоване автоматичне керування буферами і включають в себе перевірку на переповнення — один з підходів для запобігання переповнення буфера.

Два основних типи даних, які дозволяють здійснити переповнення буфера в цих мовах — рядки і масиви. Таким чином, використання бібліотек для рядків і спискових структур даних, які були розроблені для запобігання і/або виявлення переповнень буфера, дозволить уникнути багатьох уразливостей.

Примітки[ред.ред. код]

  1. «CORE-2007-0219: OpenBSD's IPv6 mbufs remote kernel buffer overflow». Архів оригіналу за 2013-07-08. Процитовано 2007-05-15. 
  2. «The Metasploit Opcode Database». Процитовано 2007-05-15. 
  3. «The Exploitant - Security info and tutorials». Архів оригіналу за 2013-07-08. Процитовано 2009-11-29. 
  4. «Microsoft Technet Security Bulletin MS04-028». Архів оригіналу за 2013-07-08. Процитовано 2007-05-15. 

Див. також[ред.ред. код]