Курс — Хакинг на Rust. #23 Инструменты хакера на Rust. Фаззинг и тестирование на устойчивость. Анализ крашей и отладка
Здравствуйте, дорогие друзья.
Что такое краш в контексте фаззинга?
Краш — аварийное завершение программы из-за критической ошибки, например:
- Сегментация памяти (SEGFAULT): Доступ к недопустимому адресу.
- Переполнение буфера: Запись за пределы выделенной памяти.
- Use-after-free: Использование освобождённой памяти.
- Арифметические ошибки: Деление на ноль, целочисленное переполнение.
Фаззеры (например, cargo-fuzz
, afl.rs
) сохраняют входные данные, вызвавшие краш, в виде файлов (артефактов).
Анализ краш-логов
Пример лога от AddressSanitizer
1 2 3 4 |
==12345==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000000010 READ of size 4 at 0x602000000010 thread T0 #0 0x55a5d43f113e in parse_packet /src/parser.rs:42 #1 0x55a5d43f0abc in main /src/main.rs:15 |
Ключевые элементы:
- Тип ошибки:
heap-buffer-overflow
(переполнение кучи). - Адрес памяти:
0x602000000010
. - Стек вызовов: Функция
parse_packet
в строке 42.
Шаги для анализа краша
1. Воспроизведение краша
Используйте артефакт из fuzz/artifacts
(для cargo-fuzz
) или out_dir/crashes
(для afl.rs
):
1 |
cargo run --bin my_app crash_input.bin |
2. Отладка с GDB/LLDB
Загрузите программу в отладчик:
1 |
gdb -ex "run" --args ./target/debug/my_app crash_input.bin |
Полезные команды GDB:
bt
: Показать трассировку стека.info registers
: Проверить значения регистров (RIP, RSP).x/20xw $rsp
: Просмотреть память вокруг стека.disassemble
: Вывести ассемблерный код текущей функции.
Пример вывода:
1 2 3 4 5 6 |
Program received signal SIGSEGV, Segmentation fault. 0x000055555555513e in parse_packet (data=0x555555559010) at src/parser.rs:42 42 let value = data[offset]; // Чтение за границей массива (gdb) bt #0 0x000055555555513e in parse_packet (data=0x555555559010) at src/parser.rs:42 #1 0x0000555555555abc in main () at src/main.rs:15 |
3. Минимизация тест-кейса
Краш-файл может быть слишком большим. Используйте:
1 2 |
cargo fuzz cmin crash_input.bin # Для cargo-fuzz afl-tmin -i crash_input.bin -o minimized.bin -- ./my_app # Для AFL |
4. Анализ кода
Найдите уязвимый участок. Пример ошибки:
1 2 3 4 |
fn parse_packet(data: &[u8]) { let offset = data[0] as usize; // offset может превысить длину data let value = data[offset]; // Краш при выходе за границы } |
Исправление:
1 2 3 4 5 6 7 8 9 10 |
fn parse_packet(data: &[u8]) -> Result<u8, &'static str> { if data.is_empty() { return Err("Empty data"); } let offset = data[0] as usize; if offset >= data.len() { return Err("Offset out of bounds"); } Ok(data[offset]) } |
5. Использование статических анализаторов
- Clippy: Находит антипаттерны:
1 |
cargo clippy -- -D warnings |
- Rust Analyzer: Интеграция с IDE для мгновенного выявления ошибок.
Автоматизация анализа
Создайте скрипт для массовой обработки крашей:
1 2 3 4 5 |
#!/bin/bash for crash in fuzz/artifacts/*; do echo "Анализ $crash" gdb -batch -ex "run" --args ./target/debug/my_app "$crash" > report.txt done |
Этический контекст
- Не эксплуатируйте уязвимости без разрешения.
- Сообщайте о проблемах разработчикам.
- Используйте знания для улучшения безопасности, а не для атак.
Задание для самостоятельной работы:
- Проанализируйте краш-лог из
cargo-fuzz
, найдите уязвимую строку кода. - Исправьте ошибку, используя проверки границ.
- Настройте автоматический отчёт об ошибках через CI/CD.
Итог:
Анализ крашей — не менее важен, чем их обнаружение. Rust предоставляет инструменты для точной диагностики и исправления ошибок, а фаззинг становится мощным союзником в борьбе с уязвимостями. Помните: каждая найденная ошибка — шаг к более безопасному коду.

На этом все. Всем хорошего дня!