фузинг частина 1

Фаззинг Частина 1: Теорія

Нестримне

Перш за все, що саме таке фаззінг? Коли ми перевіряємо програму або функцію, яка отримує вхідні дані (будь-який тип), ми пробуємо різні комбінації вхідних даних, поки не отримаємо краш або інший бажаний результат (часто витік пам’яті). Якщо програма не очищає вхідні дані належним чином, користувач може ввести некоректні або неправильні дані, що може спричинити збої та дивну чи невизначену поведінку. Гарний приклад фаззингу, про який ви, напевно, чули раніше dirbusting, коли ми пробуємо різні URL-адреси, спочатку починаючи зі звичайних, доки не знаходимо законні каталоги на веб-сайті. Такі інструменти, як пуф зробити це на відмінно.

Фаззинг особливо корисний у програмах, написаних на низькорівневих або старих мовах, таких як Basic, Assembly, C/C++ тощо, які не заважають програмісту писати помилки, такі як неправильне приведення типів, використання після вільного [вказівника], або переповнення пам’яті (буфер, стек, ціле число), які зазвичай не обов’язково призводять до збоїв під час виконання чи помилок під час компіляції та можуть бути використані спритним зловмисником. Зазвичай, коли згадується термін «фаззинг», він стосується цього типу фаззингу.

Види фаззингу

Є три підходи до фаззингу, які ми повинні перерахувати.

Фаззинг Whitebox

Під «фаззингом білого ящика» ми маємо на увазі тип фаззингу, при якому фаззер намагається проаналізувати внутрішню структуру програми, щоб відстежити та максимізувати покриття коду. Покриття коду стосується частки гілок, яких ми досягли в нашому коді; щоразу умовний оператор типу if or в той час як код розбивається на одну гілку, де твердження є істинним, і іншу, де воно хибне. Обґрунтування полягає в тому, що якщо в якійсь гілці ховається помилка, ми спочатку повинні переконатися, що ми досягли цієї гілки в першу чергу. Щоб виконати цей вид аналізу, програма має бути обладнана під час компіляції.

Інструменти працюють, викликаючи спеціальну функцію кожного разу, коли запускається гілка, яка реєструє її як запущену, іноді навіть з роздільною здатністю рядка, щоб можна було відслідковувати покриття. Інструменти також можуть допомогти знайти помилки. Наприклад, Address Sanitation (ASan) допомагає знайти витоки пам’яті, які зазвичай не викликають збоїв. Оскільки повний структурний аналіз потребує багато ресурсів, фаззінг білого вікна є повільним, але набагато ефективнішим у пошуку помилок і вразливостей, особливо тих, які приховані глибоко в програмі. Звичайно, для того, щоб виконувати широкі інструменти, потрібно мати доступ до вихідного коду, який не завжди доступний, особливо як зловмисник.

Blackbox Fuzzing

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

Фаззінг сірого ящика

Цей підхід намагається знайти баланс між відповідними плюсами та мінусами вищезгаданих підходів; він використовує легкі інструменти під час компіляції замість повного аналізу, щоб обчислити покриття коду та відстежувати стан програми. Найпопулярніші фаззери сьогодні, такі як AFL, HongFuzz і LibFuzzer, є сірими фазерами. Щоб виконати такий фаззинг, зазвичай потрібен вихідний код, але є обхідні шляхи, якщо доступний лише виконуваний файл, але вони серйозно погіршують продуктивність. У цій статті я не буду торкатися цих прийомів.

Прийоми фаззингу

Як і в dirbusting, фаззинг не потрібно виконувати грубою силою, тобто спробою випадкового введення. Дійсно, груба сила не є хорошою технікою для фаззингу, і це рідко використовується. На щастя, існує ряд розумніших методів, які дають кращі результати за розумні витрати часу та ресурсів. Тут я обговорю два з них:

Фаззинг на основі мутацій

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

Найвідомішим інструментом (і, можливо, найвідомішим фаззером взагалі) є AFL, або American Fuzzy Lop.

AFL використовує три типи основних мутацій:

  • Видалення випадкового біта.
  • Вставка випадкового біта.
  • Перевертання випадкового біта (від 0 до 1 або навпаки)

AFL не працює лише з однією мутацією в будь-який момент часу, а розподіляє свої ресурси між кількома з них і віддає перевагу тим, які мають найбільшу кількість енергія. Енергія кожної мутації залежить від того, які гілки в коді вона запускає – рідкісні гілки, через які проходить більшість вхідних даних, призначають більше енергії. Кожна гілка має унікальний хеш, що дозволяє відстежувати кількість виконань. Важливо зазначити, що початкові дані в цій техніці можуть надходити зі словника, який містить більше одного варіанту.

Граматичний фаззинг

Ви, напевно, знаєте, що багато програм не можуть отримувати неструктуровані вхідні дані, але мають певні правила формування вхідних даних. Ці правила називаються синтаксисом введення, оскільки вони схожі на синтаксичні правила розмовних мов. Для тестування таких програм у спосіб, який охоплює більшість синтаксичних параметрів, фаззер повинен знати синтаксис, інакше вхідні дані, створені за допомогою простих мутацій, будуть відфільтровані та відкинуті. Такі фазери вже існують, і вони можуть змішувати JavaScript, WASM, URL та інші. але на момент написання цієї статті більшість із них є експериментальними та повільними, і, наскільки мені відомо, усі вони написані на Python, який чудово підходить для створення прототипів і демонстрацій, але не настільки для оптимізованих фаззерів виробничого рівня. Тому вони використовуються рідко.

Далі – Частина 2

У наступному розділі "Фузінг з AFL“, я демонструю, як розкрити просту програму за допомогою AFL, щоб знайти збої, які можуть бути небезпечними в реальному світі.

Перейти до вмісту