Повторный вход (Re-entrancy) – это распространенная уязвимость смарт-контрактов. Хотя он может существовать в смарт-контрактах на различных блокчейн-платформах, чаще всего он ассоциируется с блокчейном Ethereum.
Атаки Re-entrancy – на повторный вход, наиболее известны благодаря знаменитому взлому DAO в 2016 году на блокчейне Ethereum. Однако, эти уязвимости также обнаружились при многочисленных взломах смарт-контрактов, включая несколько протоколов DeFi.
Передача эфира и резервные функции
Потенциал для повторных атак в смарт-контрактах Ethereum возникает из-за того, как в Ethereum обрабатываются переводы стоимости. Ethereum одинаково относится к учетным записям пользователей и смарт-контрактов, поэтому оба могут проводить операции по смарт-контракту или получить перевод эфира.
Если эфир передается на адрес, содержащий код смарт-контракта, то этому смарт-контракту предоставляется возможность запустить некоторый код. Эта “резервная функция” может использоваться для обновления внутреннего состояния на основе перевода или выполнения других действий, вызванных депозитом (например, выдача некоторого токена в ответ).
Как работает атака повторного входа Re-entrancy?
По логике вещей, функции смарт-контрактов, такие как функции вывода средств, будут следовать шаблону проверки-взаимодействия-эффектов (check-interaction-effects pattern). Это означает, что они проверят правильность вывода средств, выполнят перевод, запрошенный при выводе средств, а затем обновят свое внутреннее состояние на основе вывода средств (то есть, сообщат, что сумма была списана со счета пользователя).
Однако, этот шаблон кода создает уязвимость для повторного входа из-за существования резервных функций Ethereum. На этапе взаимодействия процесса, смарт-контракт, который вызвал уязвимую функцию, имеет возможность запускать код в своей резервной функции.
Если этот код снова вызовет уязвимую функцию, вторая итерация кода произойдет до того, как функция выполнит свое внутреннее обновление.
Например, рассмотрим следующую последовательность событий:
- Вредоносный контракт M вызывает уязвимую функцию F, пытающуюся вывести 4 ETH со счета, содержащего 5 ETH
- F проверяет, что отзыв действителен, и, поскольку 5 > 4, одобряет его
- F переводит запрошенные 4 ETH на M
- Этот перевод запускает резервную функцию M, которая снова вызывает F с запросом на вывод 4 ETH
- F проверяет, что вывод средств действителен, и, поскольку баланс счета M по-прежнему равен 5, а 5 > 4, одобряет его
- F переводит запрошенные 4 ETH на M
- Резервная функция M возвращается без выполнения каких-либо действий
- F обновляет свое состояние, чтобы отразить вывод средств на шаге 6, уменьшая баланс счета M до 1 ETH
- Возвращает F, который передает управление резервной функции M с шага 4
- Резервная функция M возвращается без выполнения каких-либо действий
- F обновляет свое состояние, чтобы отразить вывод средств на шаге 3, уменьшая баланс счета M до -2 ETH
- F возвращает управление M, что завершает транзакцию
Между шагами 3 и 6 уязвимая функция переводит 8 ETH на вредоносный смарт-контракт, несмотря на то, что учетная запись вредоносного контракта содержала только 5 ETH. Это возможно, потому что уязвимая функция выполняет обновление своего состояния только после того, как передача была произведена, и вредоносный контракт имеет возможность запустить код, содержащийся в его резервной функции.
Уязвимости при повторном входе и взломы DE-FI
Взлом DAO – самый известный пример взлома при повторном входе, и он произошел в июне 2016 года. Однако, уязвимости при повторном входе по-прежнему приводят к крупным взломам почти шесть лет спустя.
Некоторые примеры недавних взломов DeFi, связанных с уязвимостями при повторном входе, включают:
Протокол Fei: В апреле 2022 года протокол Fei стал жертвой взлома стоимостью ~ 80 миллионов долларов, который стал возможным благодаря использованию стороннего кода, содержащего уязвимости для повторного входа.
Paraluni: Взлом смарт-контракта Paraluni в марте 2022 года использовал уязвимость повторного входа и плохую проверку ненадежных пользовательских данных, чтобы украсть токены на сумму ~ 1,7 миллиона долларов.
Grim Finance: В декабре 2021 года уязвимость повторного входа в функцию Grim Finance safeTransferFrom была использована для получения токенов на сумму ~ 30 миллионов долларов.
Протокол SIREN: Уязвимость повторного входа в смарт-контракты пула AMM протокола SIREN была использована в сентябре 2021 года за токены на сумму ~ 3,5 миллиона долларов.
CREAM Finance: В августе 2021 года злоумышленник воспользовался уязвимостью повторного входа в систему интеграции токенов AMP CREAM Finance, чтобы украсть токены на сумму около 18,8 миллионов долларов.
Это далеко не единственные примеры взломов DeFi, которые использовали уязвимости при повторном входе. Несмотря на то, что это старый и широко разрекламированный риск, уязвимости при повторном входе все еще появляются в новых смарт-контрактах сегодня.
Защита от атак повторного входа
Атаки с повторным входом становятся возможными благодаря использованию логичного, но небезопасного шаблона кода при выполнении переводов в рамках смарт-контрактов Ethereum. Шаблон кода check-interaction-effects позволяет вредоносному смарт-контракту выполнить код в своей резервной функции и повторно ввести уязвимую функцию, прежде чем у него появится возможность обновить свое внутреннее состояние.
Уязвимостей повторного входа можно избежать, используя шаблон кода check-effects-interaction, в котором обновления состояния выполняются перед передачей значения, которое они записывают. Если бы это произошло в приведенном выше примере, проверка в строке 5 завершилась бы неудачей, поскольку баланс счета злоумышленника уже был бы обновлен до значения 1.