- •5.1. Передумови виникнення вразливостей у комп'ютерних системах
- •5.2. Класифікація вад захисту
- •5.2.1. Класифікація вад захисту за причиною їх появи
- •5.2.2. Класифікація вад захисту за їх розміщенням у системі
- •5.2.3. Класифікація вад захисту за етапами їх появи
- •5.3. Класифікація помилок, що виникають у процесі програмної реалізації системи
- •5.4. Помилки переповнення буфера
- •5.4.1. Переповнення буфера у стеку
- •5.4.2. Переповнення буфера у статичній або динамічній пам'яті
- •5.4.3. Помилка переповнення в один байт
- •5.5. Помилки оброблення текстових рядків
- •5.5.1. Використання конвеєра
- •5.5.2. Переспрямування введення-виведення
- •5.5.3. Спеціальні символи
- •5.6. Люки
- •5.6.1. Режим debug у програмі sendmail
5.4.1. Переповнення буфера у стеку
Переповнення буфера у стеку, або «зривання стека», є найвідомішою техкшкшєю використання переповнення буфера, яка, незважаючи на складність її реалізації, становить цілком реальну загрозу. Саме помилку перепрвнеііця буфЩа^5й^Щ^Й існувала в демоні fingerd, успішно використовував мережний хробак, відомий як вірус Морріса (докладніше про нього йтиметься в розділі 6). Якщо у програмі виявляють помилку переповнення буфера у стеку, її оголошують як критичну.
Локальні змінні, оголошені у процедурі (функції), компілятор, як ^правило, розміщує у стеку. Тому розміщення у стеку буфера — явище типове. Розглянемо структуру стека. Як відомо, на багатьох апаратних платформах, зокрема на персональних комп'ютерах, стек зростає «зверху вниз», тобто в бік молодших (менших) адрес пам'яті. Після занесення даних у стек, його покажчик автоматично (апаратно) зміщується в бік молодших адрес, а в разі видалення даних зі стеку — в бік старших. Якщо у функції оголошено кілька локальних змінних, вони розміщуються (або для них резервується місце) у стеку послідовної неперервно. Порядок розміщення залежить від компілятора, тобто першою у стек може потрапити або перша, або остання змінна. Якщо, наприклад, у функції є такий фрапдент [60]:
test_function ()
і <ЩТО
char а;
char buff[5];
char b;
}
то стан стека після виклику функції test_f unction () може бути таким, як на рис. 5.4. Різним може бути порядок розміщення змінних, тобто а і Ь можуть помінятися місцями.

Рис. 5.4. Стан стека після виклику функції testJunQBpn()
З наведеної схеми стають очевидними кілька важливих особливостей. По-перше, оскільки стек зростає в бік молодших адрес, а зміннЬйаповнюють пам'ять у напрямку зростання адрес, то переповнення буфера призведе до того, що будуть змінені ті дані, які були занесені у стек раніше. У нашому випадку це змінна Ьу службова інформація, а далі — адреса повернення з функції, тобто адреса інструкції, що розташована за командою виклику функції. У багатьох архітектурах комп'ютерів адреса повернення розміщується саме у стеку. У таких архітектурах шляхом переповнення буфера у стеку можна не лише модифікувати значення окремих змінних, але й передати керування у довільне місце.
Тепер розглянемо, за яких умов порушники матимуть можливість використати переповнення буфера. Атака може бути здійснена за таких умов:
локальні змінні розміщені у стеку;
стек зростає «вниз»;
існують програми, в яких є вразливий код на кшталт наведеної вище функції
test_function() .
Атака матиме сенс, якщо:
функція приймає рядок символів від користувача (з клавіатури, зі стандартного вводу, через мережу, від іншої програми);
функція виконується з більшими привілеями чи повноваженнями, ніж має користувач, від якого вона приймає дані.
За цих умов користувач-порушник має можливість змінити у стеку значення деякої змінної. Це може мати сенс, оскільки цілком імовірно, що така змінна матиме критичне для безпеки системи значення (наприклад, логічна змінна, яка визначає результат перевірки прав доступу).
Порушник може передати керування іншій функції за таких додаткових умов:
адресу повернення також розміщено у стеку;
дані у стеку можуть бути інтерпретовані як команди.
Порушника, що хоче лише передати керування певній системній функції, адреса якої в пам'яті йому відома, вдовольнить виконання першої умови. Виконання другої умови надає порушнику унікальну можливість — вставити програмний код, який потрібно виконати, безпосередньо в рядок, що порушник передає у буфер, і на нього ж передати керування через адресу повернення. Хоча апаратні засоби, зокрема процесори Intel х86 (про них ітиметься в розділі 10), розрізняють сегменти коду і стека та підтримують заборону виконання інструкцій, розміщених у стеку, моделі пам'яті поширених ОС ці заборони скасовують за допомогою повного перекриття сегментів. Підсумовуючи всі викладені вище умови здійснення атак, можна дійти висновку, що більшість поширених ОС, зокрема UNIX і Windows, надають порушникам чимало можливостей щодо «зривання стека».
Ще раз переглянемо принципову схему атаки. Перед початком атаки в системі функціонує певна вразлива програма, що виконується з високими привілеями. Вона приймає дані (наприклад, текстовий рядок) від непривілейованих користувачів (або від будь-кого з мережі). Порушник передає програмі спеціально підготовлений текстовий рядок. У результаті модифікуються важливі дані, до яких порушник із його повноваженнями доступу не мав, або виконується певний програмний код порушника з повноваженнями вразливої програми. Певний інтерес для порушників становлять програми зі встановленим атрибутом SUID і майже всі демони в UNIX, сервіси (служби) Windows, а також багато прикладних програм, які так чи інакше здійснюють виклик привілейованого коду. Детальніше технології переповнення буфера у стеку роаглянуто в [15, 60].
