✅✅✅
Как и обещал, пишу про уязвимости и ошибки в истории существования смарт-контрактов. Этот блок я сделаю в нескольких подчастях. Так как интересной и полезной информации довольно много.
Полетели🚀
Часть 3.1. Уязвимости и ошибки в истории смарт-контрактов
⬇️⬇️⬇️
Вот какие ошибки считаются самыми популярными и значимыми в истории смарт-контрактов:
1) The DAO 1.0
2) FirePonzi
3) Казино с публичным RNG-сидом
4) Зависли 1100 ETH из-за нехватки газа
5) Игра The King of the Ether
6) 5800 ETH вывели из токенов ERC-20
7) Rubixi
Самыми крупными хищениями стали 30 миллионов долларов из Parity и 53 миллиона долларов из DAO.
Я постараюсь кратко, но в то же время подробно описать эти уязвимости.
Надеюсь я правильно смог все описать, так как не являюсь кодером. Если вдруг я не прав и допустил ошибку, пожалуйста, напишите мне об, чтобы я не вводил в заблуждение своих читателей. Я пытался максимально упростить и объяснить на простом языке.😉
Начну по порядку.
1) Про уязвимость в DAO.
Атаку назвали
- "Повторный вход, Reentrancy"
- Race-To-Empty
- Recursive call vulnerability, (рекурсивный вызов)
- Call to the unknown (призыв к неизвестному).
Любое действие в блокчейне Ethereum выполняется с помощью транзакций: отправка ether с одного аккаунта на другой, создание контракта, обращение к функции контракта. Причем инициировать транзакции могут только внешние аккаунты, а контракты могут создавать транзакции только под действием полученных ими транзакций. За каждую транзакцию взимается комиссия, для этого введена специальная единица —
gas. Комиссия рассчитывается как произведение цены gas и количества gas.
Проблема кроется в том, что уязвимый контракт совершает вызов к другому контракту, при этом внешний контракт может делать ответный вызов функций уязвимого контракта внутри начального вызова.
Все дело в функции "withdraw".
Функция «withdraw» имеет модификатор «onlyOwner», т.е. может быть вызвана только владельцем смартконтракта. Единственное, что она делает – переводит весь баланс смартконтракта на адрес владельца смартконтракта.
Почему назвали повторный вход?
Контракт жертвы выполняет функцию для отправки ETH во вредоносный контракт до обновления баланса вредоносного контракта.
В мошенническом контракте есть функция возврата fallback(), которая принимает средства, а затем возвращает их обратно в функцию withdraw(). Эта функция необходима, если нужно, чтобы контракт получал эфир.
Это второе исполнение инициирует перевод средств, ведь баланс вредоносного контракта по-прежнему не обновлялся с момента первого вывода. В результате вредоносный контракт во второй раз успешно отменяет весь баланс.
Рекурсивный вызов удается выполнить только один раз; нужные нам балансы в итоге ставятся в 0, и на этом все заканчивается. Однако атакующий смог повторить эту операцию как минимум раз 50.
Если адрес является смарт-контрактом, платеж вызовет резервную функцию fallback () с тем, что осталось от транзакционного газа.
Таким образом, пользователь получит в два раза больше своего баланса из контракта.
Безопаснее было перевести токены при помощи функции transfer(), которое должно испускаться смартконтрактом при каждой операции перемещения токенов между держателями токенов. Но если все же необходимо использовать вызов аккаунта, то нужно было сначала обновить баланс аккаунта, а затем уже совершать вызов.
Самое интересное, что баг в коде был не один. Именно совокупность этих багов и помогла хакеру украсть так много. Ошибка стала результатом плохого программирования, и вероятно типографской ошибки в коде.