From $600

Smart contract audit

Смарт-контракты.

Смарт-контракты — это специализированные программы, хранящиеся в блокчейне, которые обычно используются для автоматизации выполнения соглашения, чтобы все контрагенты могли быть уверены в результате без необходимости доверять друг другу или каким-либо посредникам. Смарт-контракт гарантирует, что его исполнение будет точно соответствовать той логике, которая в нем изначально прописана. И после выполнения указанной предопределенной логики конечное состояние в сети останется неизменным.

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

Блокчейн Ethereum является первой и на данный момент наиболее используемой платформой для реализации смарт-контрактов. Будучи программируемой, платформа позволяет пользователям реализовывать процессы различной сложности. Код этих контрактов хранится в распределенном реестре и выполняется виртуальной машиной Ethereum (EVM) — ядром этой блокчейн-платформы.

Уязвимости смарт-контрактов.

Проблемы безопасности в смарт-контрактах достаточно серьезны по нескольким причинам:

  • Большинство смарт-контрактов имеют дело с финансовыми активами;
  • Ошибки в смарт-контрактах после публикации не могут быть исправлены из-за неизменной природы блокчейна;
  • Изменения в состоянии блокчейна, вызванные транзакциями ошибочных или мошеннических контрактов, не могут быть отменены.

Косвенное выполнение неизвестного кода.

Возможность непрямого исполнения существует из-за наличия в смарт-контрактах функции fallback. Есть несколько причин, по которым эта функция может быть вызвана:

  • Вызов функции другого контракта с помощью ABI: если в строке подписи, переданной для кодирования, опечатка, или функции с такой подписью не существует, то будет вызвана fallback функция;
  • Депозит на другой контракт генерирует вызов его fallback функции;
  • Вызов функции другого контракта с помощью API: если разработчик ошибся при объявлении интерфейса вызываемого контракта (например, перепутал тип параметра), то будет вызвана fallback функция.

Повторный вход.

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

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

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

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

Неверный расчет суммы выходного токена.

Большинство современных смарт-контрактов DeFi имеют дело с огромными суммами денег, выраженными в токенах или стоимости ETH. Таким образом, многие операции в контрактной логике связаны с переводом токенов в контракт и из контракта.

Это создает широкое поле для различных ошибок, связанных с правильным расчетом процентов, сборов и прибыли. Топ таких ошибок:

  • Некорректная работа с десятичными знаками, особенно в случае с таким токеном, как USDT;
  • Неправильный порядок действий при расчете комиссий, что приводит к значительной потере точности;
  • Отсутствие константы точности в математических операцияx.

Проблемы с интерфейсом / названием.

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

Следует отметить, что в версиях Solidity до 0.4.22 конструкторы определялись как функции с тем же именем, что и имя контракта. В какой-то момент контракт был переименован с Dynamic Pyramid на Rubixi, но разработчик забыл изменить имя конструктора, поэтому любой, кто вызвал функцию Dynamic Pyramid, мог стать владельцем контракта и украсть накопленные средства.

Зависимость от порядка исполнения.

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

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

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

Также становится особенно опасно взаимодействовать с контрактами, написанными таким образом, что их поведение может быть изменено с течением времени.

Временные компоненты.

Иногда логика смарт-контрактов может зависеть от времени. Время для контракта доступно только в контексте транзакции. Временная метка транзакции, в свою очередь, равна метке блока, в который она включена. Таким образом достигается согласованность с состоянием смарт-контракта.

Однако это также создает возможность для майнера злоупотреблять своим положением из-за некоторой свободы в установке метки времени для блока. Таким образом, у майнера есть некоторое преимущество перед другими сторонами контракта, которое он может использовать в своих интересах.

Использование хэш-функции.

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

Неправильно обработанные исключения.

Есть много ситуаций, когда в Solidity может быть выдано исключение, но способ обработки этих исключений не всегда одинаков. Обработка исключений основана на взаимодействии между контрактами. Таким образом, контракты уязвимы для атак со стороны злонамеренных пользователей. Если эти исключения не обрабатываются должным образом, транзакции будут откатываться.

Некорректная работа с токеном ERC20.

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

Хотя есть место для пользовательских реализаций стандарта токена. Таким образом, это создает место для расхождений между вновь созданным токеном и фактическим стандартом ERC20 — небольшие несоответствия, такие как отсутствующее возвращаемое значение в функции transfer().

Однако такое небольшое изменение может привести к неработоспособности метода контракта, так как он не сможет распознать интерфейс. Это очень маленькая ошибка, почти незаметная при тестировании, но в продакшене она приводит к зависанию средств и блокировке контрактов.

Итоги и выводы.

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

Контакты

0/50000