Недавняя уязвимость пула Curve отличается от инцидентов взлома криптовалюты, которые мы видели раньше, поскольку на этот раз проблема напрямую связана не с уязвимостью самого смарт-контракта, а с базовым компилятором языка программирования, используемого Vyper.

Vyper — это интеллектуальный язык программирования, ориентированный на контракты, который использует стиль Python и специально разработан для взаимодействия с виртуальной машиной Ethereum (EVM).

Последствия этой уязвимости очень серьезны, и каждый день в новостях сообщается об огромных потерях. Ситуация, похоже, находится под контролем, но не раньше, чем хакеры украли более 70 миллионов долларов. Согласно последующей оценке LlamaRisk, некоторые пулы проектов DeFi также подверглись атакам хакеров, в том числе пул pETH/ETH PEGD, который потерял 11 миллионов долларов США, пул msETH/ETH Metronome, который потерял 3,4 миллиона долларов США, и пул alETH/ETH Alchemix, который потерял 11 миллионов долларов США. 22,6 миллиона долларов США, а пул Curve DAO потерял примерно 24,7 миллиона долларов США.

Эта уязвимость называется ошибкой повторного входа и в основном появляется в некоторых версиях языка программирования Vyper, в частности в v0.2.15, v0.2.16 и v0.3.0. Поэтому проекты, использующие именно эти версии Vyper, могут стать объектами атак.

Что такое реентерабельность?​

Чтобы понять, почему возникла эта уязвимость, давайте сначала разберемся, что такое повторный вход и как он работает.

Так называемая реентерабельность означает, что функция может быть прервана во время выполнения и безопасно вызвана снова до завершения предыдущего вызова. Этот механизм часто используется в таких приложениях, как обработка аппаратных прерываний и рекурсия.

Чтобы функция была реентерабельной, она должна соответствовать нескольким условиям:

Во-первых, он не может использовать глобальные и статические данные. Это соглашение, означающее, что при выполнении функции не полагайтесь на глобальные данные или статические переменные. Потому что, если функция прерывается во время выполнения, а затем вызывается снова, глобальные и статические данные могут быть повреждены или информация может быть потеряна.

Во-вторых, он не может изменять свой собственный код. Независимо от того, когда функция прерывается, она должна иметь возможность продолжить выполнение таким же образом. Если функция изменяет свой код во время выполнения, при повторном вызове может возникнуть ошибка.

Наконец, он не может вызывать другие функции, которые не являются реентерабельными. То есть внутри реентерабельной функции не следует вызывать другие функции, которые могут не быть реентерабельными. Потому что, если вы это сделаете, это может привести к непредсказуемым результатам, что приведет к сбою программы или ошибкам.

Это слишком сложно для понимания, поэтому не будем вдаваться в подробности.

Как это эксплуатировалось?

Давайте объясним, как повторные атаки привели к краже средств и потере 70 миллионов долларов в результате атаки Curve.

Прежде всего, мы знаем, что атака с повторным входом относится к методу, в котором вредоносный контракт неоднократно вызывает функцию в смарт-контракте. В атаке Curve эта функция используется для вывода ликвидности пользователя из пула. У этой функции есть недостаток: она не выполняет достаточных проверок перед обновлением суммы.

Давайте посмотрим на конкретный процесс атаки:

  1. Допустим, уязвимый смарт-контракт имеет 10 эфиров.

  2. Злоумышленник вызывает функцию депозита и вносит 1 Ethereum.

  3. Затем злоумышленник вызывает функцию вывода средств и готовится вывести 1 Ethereum. В этой функции проверяется, есть ли у злоумышленника на счету 1 Ethereum.

  4. Однако эта функция не обновляет баланс в контракте перед переводом 1 эфира на счет злоумышленника. Это означает, что контракт все еще считает, что внутри находится 10 эфиров.

  5. Злоумышленник снова вызывает функцию вывода (повторного входа) и готовится снова вывести 1 Ethereum.

  6. Поскольку контракт по-прежнему считает, что внутри находится 10 эфиров, он снова передаст злоумышленнику 1 эфир.

  7. Этот процесс повторяется до тех пор, пока в контракте не останется ликвидности.

Таким образом, злоумышленник может неоднократно вызывать функцию вывода и переводить почти всю ликвидность в контракте на свой счет, что приводит к краже средств в контракте.

Эта уязвимость очень выгодна злоумышленнику, поскольку сумма в контракте не обновляется в режиме реального времени, что позволяет злоумышленнику повторять атаку до тех пор, пока в контракте не закончатся средства для вывода. #Crv