Мутаційне тестування для Solidity зі Slither (slither-mutate)
Reading time: 5 minutes
tip
Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Вивчайте та практикуйте Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.
Мутаційне тестування "перевіряє ваші тести", систематично вносячи невеликі зміни (мутанти) у ваш Solidity-код і повторно запускаючи набір тестів. Якщо тест не проходить — мутант вбито. Якщо тести все ще проходять — мутант виживає, виявляючи сліпу пляму у вашому наборі тестів, яку line/branch coverage не може виявити.
Ключова ідея: Coverage показує, що код був виконаний; мутаційне тестування показує, чи поведінка фактично перевірена.
Чому coverage може вводити в оману
Розглянемо цю просту перевірку порогу:
function verifyMinimumDeposit(uint256 deposit) public returns (bool) {
if (deposit >= 1 ether) {
return true;
} else {
return false;
}
}
Модульні тести, які перевіряють лише значення нижче та вище порогу, можуть досягти 100% покриття рядків/гілок, водночас не перевіряючи граничну рівність (==). Рефакторинг до deposit >= 2 ether
все ще пройде такі тести, тихо порушивши логіку протоколу.
Mutation testing виявляє цю прогалину — мутує умову й перевіряє, що тести не проходять.
Поширені оператори мутації для Solidity
Slither’s mutation engine applies many small, semantics-changing edits, such as:
- Заміна операторів:
+
↔-
,*
↔/
, тощо. - Заміна присвоєння:
+=
→=
,-=
→=
- Заміна констант: ненульове →
0
,true
↔false
- Заперечення/заміна умов всередині
if
/циклів - Коментування цілих рядків (CR: Comment Replacement)
- Замінити рядок на
revert()
- Заміна типів даних: наприклад,
int128
→int64
Мета: знищити 100% згенерованих мутантів, або обґрунтувати тих, що вижили, зрозумілими аргументами.
Запуск mutation testing за допомогою slither-mutate
Вимоги: Slither v0.10.2+.
- Перелічити опції та мутатори:
slither-mutate --help
slither-mutate --list-mutators
- Foundry приклад (захопити результати та зберегти повний log):
slither-mutate ./src/contracts --test-cmd="forge test" &> >(tee mutation.results)
- Якщо ви не використовуєте Foundry, замініть
--test-cmd
на те, як ви запускаєте тести (наприклад,npx hardhat test
,npm test
).
Артефакти та звіти зберігаються в ./mutation_campaign
за замовчуванням. Невиловлені (вцілілі) мутанти копіюються туди для перевірки.
Розуміння виводу
Рядки звіту виглядають так:
INFO:Slither-Mutate:Mutating contract ContractName
INFO:Slither-Mutate:[CR] Line 123: 'original line' ==> '//original line' --> UNCAUGHT
- Тег у дужках — псевдонім мутатора (наприклад,
CR
= Comment Replacement). UNCAUGHT
означає, що тести пройшли під мутованою поведінкою → відсутнє твердження.
Зменшення часу виконання: пріоритезуйте впливові мутанти
Мутаційні кампанії можуть тривати години або дні. Поради для зменшення витрат:
- Обсяг: Почніть лише з критичних контрактів/директорій, потім розширюйте.
- Пріоритезуйте мутатори: Якщо мутант з високим пріоритетом на рядку виживає (наприклад, увесь рядок закоментовано), ви можете пропустити варіанти з нижчим пріоритетом для цього рядка.
- Паралелізуйте тести, якщо ваш runner дозволяє; кешуйте залежності/збірки.
- Fail-fast: зупиняйтеся раніше, коли зміна чітко демонструє прогалину в твердженнях.
Робочий процес тріажу для вцілілих мутантів
- Перевірте мутований рядок та його поведінку.
- Відтворіть локально, застосувавши мутований рядок і запустивши цілеспрямований тест.
- Посиліть тести так, щоб вони перевіряли стан, а не лише значення повернення.
- Додайте перевірки меж рівності (наприклад, тест порогу
==
). - Перевіряйте постумови: баланси, total supply, ефекти авторизації та згенеровані події.
- Замініть надмірно дозволяючі моки на реалістичну поведінку.
- Переконайтеся, що моки примушують виконувати трансфери, шляхи відмови та емісію подій, які відбуваються on-chain.
- Додайте інваріанти для fuzz-тестів.
- Наприклад: збереження вартості, невід'ємні баланси, інваріанти авторизації, монотонна загальна пропозиція там, де це застосовно.
- Повторно запустіть slither-mutate, поки вцілілі мутанти не будуть усунуті або явно виправдані.
Case study: revealing missing state assertions (Arkis protocol)
Під час аудиту протоколу Arkis DeFi мутаційна кампанія виявила такі вцілілі мутанти:
INFO:Slither-Mutate:[CR] Line 33: 'cmdsToExecute.last().value = _cmd.value' ==> '//cmdsToExecute.last().value = _cmd.value' --> UNCAUGHT
Коментування присвоєння не зламало тести, що підтверджує відсутність перевірок стану після виконання. Причина: код покладався на керований користувачем _cmd.value
замість перевірки фактичних переказів токенів. Атакувальник міг розсинхронізувати очікувані та фактичні перекази, щоб вивести кошти. Наслідок: високий ризик для платоспроможності протоколу.
Рекомендація: вважайте виживші мутанти, які впливають на перекази вартості, облік або контроль доступу, високоризиковими, доки їх не знищено.
Практичний чекліст
- Run a targeted campaign:
slither-mutate ./src/contracts --test-cmd="forge test"
- Проаналізуйте виживші мутанти та напишіть тести/інваріанти, які проваляться при мутованій поведінці.
- Перевірте баланси, загальну емісію, авторизації та події.
- Додайте граничні тести (
==
, overflows/underflows, zero-address, zero-amount, empty arrays). - Замініть нереалістичні mocks; змоделюйте режими відмов.
- Ітеруйте, поки всі мутанти не будуть знищені або виправдані коментарями та обґрунтуванням.
References
- Use mutation testing to find the bugs your tests don't catch (Trail of Bits)
- Arkis DeFi Prime Brokerage Security Review (Appendix C)
- Slither (GitHub)
tip
Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Вивчайте та практикуйте Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.