Контракт-кидала: как 5 строк Solidity укрывают ваш бизнес после оплаты
💀 «TIME-LOCK RUG»: Как украсть бизнес после escrow и подписания договора Расследование, декомпиляция, и почему даже KYC не спасает. Плюс: шаблон «анти-кидала» для Hardhat.
📉 Кейс: $1.2M за DeFi-агрегатор → 72 часа — и всё gone Актив: DeFi-бот с TVL $4.3M, 12K пользователей, интеграция с 7 DEX. Сделка: $1.2M в USDC (через Gnosis Safe escrow, 2/3 multi-sig, включая гаранта). Этапы: День 0: средства разблокированы → передача GitHub, админок, VPS, и контракта. День 1: всё работает. Проверили withdraw — проходит. День 2: логи чистые. Обновили front-end — без ошибок. День 3, 04:17 UTC: Все вызовы swap() → 0.0001% execution. Админка GitHub — «404». Контракт обновил owner → адрес 0xdead...beef. Деньги на пуле — исчезли в 4 hop-транзакциях через Tornado Cash. 🔍 Что нашли при аудите: Контракт выглядел «честно» — OpenZeppelin-based, verified в Etherscan, даже CertiK-аудит («low risk»). Но в initialize() был скрытый патч:
solidity
1 2 3 4 5 6 7 8 9 10 // ⚠️ ОТРЫВОК ИЗ РЕАЛЬНОГО КОНТРАКТА (адрес: 0x8a3...d1f2) function initialize(address _newOwner) public initializer { __Ownable_init(); _transferOwnership(_newOwner);
// 👇 ВОТ ОН — «КИДАЛ-ТРИГГЕР» if (block.timestamp > 1742102400) { // 15 марта 2025, 12:00 UTC _setEmergencyAdmin(0x7a2...c9e1); // скрытый owner } } → Через 72 часа после initialize() (вызывается при передаче) — автоматическая смена админа на кошелёк мошенника. И это не баг — это заложенная фича, прошедшая все стандартные аудиты.
👉 Это не rug-pull. Это time-bomb escrow. И таких контрактов в 2025 — уже 147, по данным BlockSec.
🔍 Топ-5 «тихих» уязвимостей в контрактах digital-активов (Не ловятся DappRadar, CertiK, даже ручным ревью без специфического чек-листа)
УЯЗВИМОСТЬ КАК РАБОТАЕТ КАК ВЫГЛЯДИТ «ЧЕСТНО» КРАСНЫЙ ФЛАГ 1. Time-Trigger Owner Swap block.timestamp > X → _setOwner(скрытый) Инициализация выглядит стандартно Дата в будущем в коде / странное условие в initialize 2. Proxy-Admin Hijack Upgradeable контракт: admin() → transferAdmin() в fallback() Используется UUPS — «современно» fallback() меняет не только storage, но и права 3. Backdoor в permit() Подпись с v=27 → даёт owner-права Совместимость с EIP-2612 Необычные значения v в логах 4. Гибридный Rug via Events emit Transfer(...) — но _balances не меняются Front-end показывает «успешно» Расхождение между событиями и storage 5. NFT-Submarine transferFrom() → передаёт view-only NFT (не актив) «Вы получили NFT-доступ» В метаданных — access_level: "demo"
📌 Статистика: 68% мошенников используют ≥2 из этих методов одновременно.
🛡️ Чек-лист Due Diligence для контрактов (скачать PDF) Проверяйте ДО разблокировки escrow — даже если «всё verified».
✅ Шаг 1: Проверка инициализации Есть ли initializer modifier? Вызывается ли initialize() только один раз? Есть ли в нём условия с block.timestamp, block.number, address(this).balance? ✅ Шаг 2: Поиск скрытых админов bash
transferOwnership() вне onlyOwner _setAdmin(), _grantRole() с хардкод-адресами DELEGATECALL в fallback() ✅ Шаг 3: Тест «после 72 часов» Запустите fork-сеть (через Anvil) Промотайте время на +72 часа Проверьте: js
1 2 await contract.owner() === ваш_адрес await contract.hasRole(DEFAULT_ADMIN_ROLE, ваш_адрес) ✅ Шаг 4: Проверка upgradeability Если UUPS или Transparent: Кто admin прокси? Можно ли обновить логику без multi-sig? Используйте: slither-check-upgradeability ✅ Шаг 5: NFT/DID-аутентификация Если актив передаётся как NFT: Проверьте tokenURI() → JSON → access_scope Убедитесь, что transferFrom() даёт полную собственность, а не «лицензию». 📥 Скачать чек-лист PDF + Hardhat-плагин
🧩 Open-Source: Шаблон «Anti-Kidala» для Hardhat Готовый контракт-обёртка, который блокирует time-bomb атаки и добавляет escrow-триггеры:
72h-лок на смену владельца Обязательное подтверждение гарантом (адрес задаётся в .env) Авто-пауза при аномалиях Совместим с Gnosis Safe, TON Connect, Telegram Web Apps 📥 GitHub: anti-kidala-template → npx create-anti-kidala@latest — и у вас готовый контракт за 90 сек.
🔮 Прогноз-2025: Контрактный скам нового поколения AI-генерированные backdoors: LLM пишет «чистый» контракт с уязвимостью, которую не видит Slither. Rug-pull через governance: DAO голосует за «апгрейд» → в нём — скрытый delegatecall на кидал-контракт. Кросс-чейн time-bomb: инициализация на Arbitrum → триггер на Base через CCIP. 💡 Решение: Escrow 2.0 с on-chain триггерами. Пример:
Пока safetyFlags[0] && safetyFlags[1] == true → средства в escrow. Если emergencyLock() → возврат 100% покупателю. Все действия — логируются в The Graph → доступны в Telegram-боте. 🎯 Совет от «Гаранта Сделок №1» «Не бойтесь сложных контрактов. Бойтесь простых, где нет:
time-lock’ов, подтверждения гарантом, флагов безопасности, и открытого кода. Потому что простота — это не удобство. Это ловушка». 🔗 Ресурсы 🛠️ anti-kidala-template — защитный контракт 📊 Contract Scam Dashboard (BlockSec) 🤖 @DealGuarantorBot → команда /audit_contract 0x... → полный отчёт за 2 минуты 📚 Чек-лист «10 строк, убивающих сделку» 📌 Итог: 3 правила для безопасной сделки с контрактом Escrow ≠ безопасность. Без time-lock и гаранта — это лишь задержка кидалова. Verified ≠ безопасно. Проверяйте логику, а не только байткод. «Работает» ≠ «навсегда». Протестируйте состояние через 72 часа — в fork-сети.