Back to Blog

Систематический подход к обеспечению совместимости с EVM и безопасности

Code Auditing
March 27, 2023
7 min read

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

Чтобы решить эту проблему, BlockSec разработала внутреннюю систему, которая способна систематически находить ошибки и уязвимости безопасности внутри реализации EVM. Эта система доказала свою эффективность. С ее помощью было выявлено четыре ошибки в Aurora Engine и четыре ошибки в Moonbeam. Все они были зарегистрированы и исправлены. Отметим, что эта методология тестирования в прошлом году также использовалась для обнаружения двух критических уязвимостей (CVE-2021–46102, CVE-2022–23066) в реализации Solana rbpf.

1. Контекст

В настоящее время предлагается множество различных блокчейнов с оптимизацией низкой комиссии за газ, высокой пропускной способностью и отличной производительностью. В связи с этим создаются новые виртуальные машины или языки разработки, что повышает порог перехода для существующих Solidity-разработчиков. В подобных случаях предлагается множество решений, совместимых с EVM, которые позволяют пользователям развертывать свои децентрализованные приложения (DApps), разработанные на Solidity, в этих новых сетях. Aurora и Moonbeam являются представителями таких решений, совместимых с EVM. Однако надежность, точность и корректность этих реализаций EVM неизвестны и заслуживают нашего внимания. С этой целью мы используем технику дифференциального фаззинга, чтобы проверить наличие каких-либо изъянов в данных реализациях.

2. Дифференциальный фаззинг

Основная идея заключается в том, чтобы подавать идентичные входные данные этим реализациям EVM (например, Aurora, Moonbeam) и современному клиенту Ethereum (т.е. geth), чтобы проверить, будет ли результат одинаковым. В частности, мы собираем исторические транзакции в Ethereum и мутируем коды контрактов и состояния транзакций с помощью различных стратегий для генерации тестовых примеров. Наши результаты показывают, что Aurora Engine и Moonbeam в некоторых случаях не соответствуют спецификации. К счастью, обо всех выявленных проблемах было сообщено, и теперь мы поделимся подробностями.

3. Найденные ошибки

Большинство из этих ошибок содержатся в предварительно скомпилированных контрактах (precompiled contracts), а их первопричины и последствия различны. Например, некоторые ошибки могут влиять на расчет значения nonce (одноразового номера), другие — на расчет газа, что в дальнейшем может привести к DoS-атаке. Все найденные ошибки нарушают установленную логику выполнения согласно спецификации EVM и могут привести к непредсказуемому поведению в конкретных случаях. Подробное описание найденных ошибок приведено ниже.

3.1 Некорректная валидация

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

Aurora Engine: ecPairing

Эта ошибка найдена в предварительно скомпилированном контракте ecPairing.

Входные данные ecPairing состоят из нескольких точек на двух эллиптических кривых. Согласно спецификации, точка (0, 0) находится на обеих кривых и должна быть допустимым входным значением:

Однако Aurora Engine (версия 2.7.0) делает откат (revert), если точка (0,0) включена во входные данные.

Соответствующий PR доступен здесь.

Moonbeam: ecMul

Эта ошибка содержится в предварительно скомпилированном контракте ecMul. В отличие от Aurora Engine, Moonbeam делает откат транзакции, когда входные данные верны. Согласно спецификации, предварительно скомпилированный контракт ecMul должен дополнять входные данные нулями, если длина ввода меньше 64 байт. Однако Moonbeam делает откат вместо выполнения операции дополнения.

Мы также обнаружили, что предварительно скомпилированные контракты ecAdd и modexp имеют ту же проблему.

Moonbeam: ecRecover

Эта ошибка содержится в предварительно скомпилированном контракте ecRecover, который используется для восстановления адреса Ethereum.

Согласно спецификации, input[32..63] v представляет собой идентификатор U256, и ожидается, что он будет равен либо 27, либо 28, в противном случае ecRecover не должен ничего возвращать (но вся транзакция не должна завершаться откатом).

Однако Moonbeam здесь допускает две ошибки:

  • Проверяется только input[63], вместо конвертации input[32..63] в тип U256 и последующей проверки значения.
  • Входные данные считаются допустимыми, если идентификатор равен 0 или 1 (должен быть только 27 или 28).

Moonbeam: ecPairing

Эта ошибка содержится в предварительно скомпилированном контракте ecPairing. Moonbeam не делает откат транзакции при получении некорректных входных данных. Согласно спецификации, входные данные для ecPairing должны быть кратны 192. В противном случае транзакция должна завершиться откатом.

Однако Moonbeam не делает откат транзакции, когда вышеупомянутые требования не соблюдаются.

3.2 Некорректный расчет газа

Каждый предварительно скомпилированный контракт имеет алгоритм для определения расхода газа. Некорректный расчет газа может привести к DoS-атаке.

Тем не менее, мы обнаружили две ошибки в Aurora Engine и Moonbeam, связанные с неправильным расчетом газа.

Aurora Engine: modexp

Ошибка содержится в предварительно скомпилированном контракте modexp. Алгоритм расчета расхода газа определен в EIP-2565. Расход газа зависит от количества итераций.

Алгоритм расчета количества итераций выглядит следующим образом:

def calculate_iteration_count(exponent_length, exponent):
   iteration_count = 0
   if exponent_length <= 32 and exponent == 0: iteration_count = 0
   elif exponent_length <= 32: iteration_count = exponent.bit_length() - 1
   elif exponent_length > 32: iteration_count = (8 * (exponent_length - 32)) + ((exponent & (2**256 - 1)).bit_length() - 1)
   return max(iteration_count, 1)

Согласно алгоритму выше, количество итераций должно быть не менее одной. Однако Aurora Engine возвращает значение iteration_count напрямую, вместо использования max(iteration_count, 1). В этом случае возвращаемое значение (т.е. iteration_count) может быть равно 0, что означает, что в определенных случаях Aurora будет списывать значительно меньше газа, чем ожидалось.

Ссылка на соответствующую проблему здесь.

Moonbeam: modexp

Эта ошибка также связана с функцией calculate_iteration_count в предварительно скомпилированном контракте modexp, но была обнаружена в Moonbeam.

Когда exponent_length больше 32, iteration_count рассчитывается по алгоритму ниже:

(8 * (exponent_length - 32)) + ((exponent & (2**256 - 1)).bit_length() - 1)

Заметьте, что используется exponent & (2**256 - 1), что берет младшие 32 байта exponent, и реализация Moonbeam следует этому алгоритму.

Однако, согласно спецификации, в формуле расчета газа должны использоваться старшие 32 байта exponent:

3.3 Ошибка инкремента nonce

Nonce внешнего аккаунта (EOA) указывает на количество успешно отправленных транзакций с этого адреса. Однако мы заметили, что в Aurora Engine значение nonce может увеличиться при отправке некорректных транзакций.

Согласно EIP-1559, перед выполнением транзакции EVM должна убедиться, что у отправителя достаточно баланса для покрытия переводимого нативного токена (например, ETH) и необходимого газа. В противном случае транзакция должна быть отброшена, а nonce отправителя не должен увеличиваться.

Хотя Aurora Engine отбрасывает транзакцию в этой ситуации, она все равно увеличивает nonce отправителя.

Соответствующий PR доступен здесь.

3.4 Некорректная реализация опкода

Эта ошибка касается реализации конкретного опкода (т.е. PUSH). Когда байты, следующие за опкодом PUSH, неполны, они должны быть выровнены по правому краю. Например, байт-код 0x64ffff может быть декодирован как:

PUSH5 0xffff

Так как операнд должен быть выровнен по правому краю, в стек должно быть помещено значение 0xffff000000. Однако реализации EVM как в Aurora Engine, так и в Moonbeam помещают в стек 0xffff, что неверно.

Соответствующий PR доступен здесь.

4. Наши услуги

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

Наша внутренняя система доказала свою высокую эффективность в поиске багов и уязвимостей. Она успешно выявила и помогла устранить четыре ошибки в Aurora Engine и четыре в Moonbeam. Кроме того, наша методология тестирования использовалась для обнаружения двух критических уязвимостей (CVE-2021–46102, CVE-2022–23066) в реализации Solana rbpf в прошлом году, что подчеркивает эффективность нашего подхода.

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

О компании BlockSec

Команда BlockSec фокусируется на безопасности экосистемы блокчейна и сотрудничает с ведущими DeFi-проектами для защиты их продуктов. Команда основана первоклассными исследователями в области безопасности и опытными экспертами из академических кругов и индустрии. Они опубликовали множество работ по безопасности блокчейна на престижных конференциях, сообщили о нескольких атаках «нулевого дня» на DeFi-приложения и выпустили подробные аналитические отчеты об инцидентах безопасности с большим влиянием.

Официальный сайт | Twitter | Medium

Best Security Auditor for Web3

Validate design, code, and business logic before launch. Aligned with the highest industry security standards.

BlockSec Audit