Анализ уязвимостей компилятора Solidity и стратегии безопасности для разработчиков

Анализ уязвимостей компилятора Solidity и стратегии реагирования

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

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

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

Уязвимость компилятора Solidity

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

Необходимо различать уязвимости компилятора Solidity и уязвимости самого EVM. Уязвимости EVM относятся к проблемам безопасности, возникающим при выполнении инструкций виртуальной машины. Поскольку злоумышленники могут загружать произвольный код в Ethereum, этот код в конечном итоге будет выполняться в каждой программе клиентского P2P Ethereum, если в EVM есть уязвимость безопасности, это повлияет на всю сеть Ethereum, что может привести к отказу в обслуживании всего сети (DoS) или даже к полному контролю злоумышленников. Однако, поскольку EVM имеет относительно простую архитектуру и основной код не обновляется часто, вероятность возникновения вышеупомянутых проблем невелика.

Уязвимость компилятора Solidity относится к проблемам, возникающим при преобразовании Solidity в код EVM. В отличие от сценариев, когда браузеры компилируют и выполняют JavaScript на компьютере пользователя, процесс компиляции Solidity происходит только на компьютере разработчика смарт-контрактов и не выполняется в сети Ethereum. Поэтому уязвимости компилятора Solidity не влияют на саму сеть Ethereum.

Основной опасностью уязвимости компилятора Solidity является то, что она может привести к несоответствию сгенерированного EVM-кода ожиданиям разработчиков смарт-контрактов. Поскольку смарт-контракты на Ethereum обычно связаны с криптоактивами пользователей, любые ошибки смарт-контракта, вызванные компилятором, могут привести к потере активов пользователей и серьезным последствиям.

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

Анализ уязвимости компилятора Solidity и меры по ее устранению

Пример уязвимости компилятора Solidity

Следующие реальные примеры уязвимостей компиляторов Solidity демонстрируют их конкретные формы, причины и последствия.

SOL-2016-9 HighOrderByteCleanStorage

Уязвимость существует в ранних версиях компилятора Solidity (>=0.1.6 <0.4.4).

Рассмотрите следующий код:

солидность контракт C { uint32 a = 0x1234; uint32 b = 0; функция f() публичная { a += 1; } функция run() публичный просмотр возвращает (uint32) { вернуть b; } }

Переменная хранения b не была изменена, поэтому функция run() должна возвращать значение по умолчанию 0. Но в коде, сгенерированном уязвимой версией компилятора, функция run() вернет 1.

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

Причина этого странного явления заключается в том, что EVM использует стековую виртуальную машину, где каждый элемент стека имеет размер 32 байта (, что соответствует размеру переменной uint256 ). С другой стороны, каждый слот в базовом хранилище (storage) также имеет размер 32 байта. На уровне языка Solidity поддерживаются различные типы данных, меньшие 32 байт, такие как uint32, и компилятор, обрабатывая такие переменные, должен выполнять соответствующие операции очистки высоких битов (clean up) для обеспечения корректности данных. В приведенной ситуации, когда сложение приводит к целочисленному переполнению, компилятор не выполнил правильную очистку высоких битов результата, что привело к тому, что высокие биты 1 были записаны в хранилище, в конечном итоге перезаписав переменную a, изменив значение переменной b на 1.

SOL-2022-4 ВстроенныеАссемблерныеПобочныеЭффектыПамяти

Рассмотрим следующий код:

солидность контракт C { функция f() публичная чистая возвращает (uint) { сборка { mstore(0, 0x42) } uint x; сборка { x := mload(0) } вернуть x; } }

Уязвимость существует в компиляторах версий >=0.8.13 <0.8.15. Компилятор Solidity в процессе преобразования языка Solidity в код EVM не просто выполняет простую трансляцию. Он также проводит глубокий анализ управления потоком и данных, реализует различные процессы оптимизации компиляции для уменьшения объема генерируемого кода и оптимизации расхода газа в процессе выполнения. Такие операции оптимизации встречаются во многих компиляторах высокоуровневых языков, но из-за сложности рассматриваемых ситуаций они также могут привести к появлению ошибок или уязвимостей безопасности.

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

Эта стратегия оптимизации сама по себе не имеет проблем, но в конкретной реализации кода компилятора Solidity такая оптимизация применяется только к отдельному блоку assembly. В приведенном выше коде PoC запись и доступ к памяти 0 находятся в двух разных блоках assembly, тогда как компилятор анализирует и оптимизирует только отдельный блок assembly. Поскольку в первом блоке assembly после записи в память 0 нет никаких операций чтения, это приводит к тому, что данная команда записи считается избыточной и будет удалена, что вызовет ошибку. В уязвимой версии функция f() вернет значение 0, в то время как на самом деле данный код должен вернуть правильное значение 0x42.

SOL-2022-6 AbiReencodingHeadOverflowWithStaticArrayCleanup

Рассмотрите следующий код:

солидность контракт C { function f(string[1] calldata a) внешних возвращает (string memory) { вернуть abi.decode(abi.encode(a), (строка)); } }

Уязвимость затрагивает компиляторы версий >= 0.5.8 < 0.8.16. Обычно переменная a, возвращаемая вышеуказанным кодом, должна быть "aaaa". Однако в уязвимой версии она возвращает пустую строку "".

Причиной уязвимости является ошибка в Solidity, которая при выполнении операции abi.encode над массивами типа calldata неправильно очищает некоторые данные, что приводит к изменению соседних данных и вызывает несоответствие между закодированными и декодированными данными.

Стоит отметить, что при выполнении внешних вызовов и эмитировании событий в Solidity параметры неявно кодируются с помощью abi.encode, поэтому вероятность появления указанной уязвимости выше, чем может показаться на первый взгляд.

Анализ уязвимостей компилятора Solidity и меры по их устранению

Рекомендации по безопасности

Команда по безопасности блокчейна Cobo, проанализировав модель угроз уязвимостей компилятора Solidity и изучив исторические уязвимости, предлагает следующие рекомендации для разработчиков и специалистов по безопасности.

Для разработчиков:

  • Используйте более новую версию компилятора Solidity. Хотя новая версия может также вводить новые проблемы безопасности, но известных проблем безопасности обычно меньше, чем в старой версии.

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

  • Старайтесь избегать использования встроенного ассемблера, сложных операций с многомерными массивами и структурой ABI, если нет явной необходимости; избегайте слепого использования новых языковых функций и экспериментальных возможностей ради демонстрации мастерства. Согласно анализу команды безопасности Cobo по историческим уязвимостям Solidity, большинство уязвимостей связано с встроенным ассемблером и операциями с кодировщиком ABI. Компилятор действительно может чаще выдавать ошибки при обработке сложных языковых особенностей. С другой стороны, разработчики также могут легко допустить ошибки при использовании новых функций, что может привести к проблемам с безопасностью.

Для охранных служб:

  • При проведении безопасности аудита кода Solidity не игнорируйте потенциальные риски безопасности, которые могут быть связаны с компилятором Solidity. Соответствующий пункт проверки в Smart Contract Weakness Classification(SWC) - это SWC-102: Устаревшая версия компилятора.

  • В процессе внутренней разработки SDL настоятельно призываю команду разработчиков обновить версию компилятора Solidity и рассмотреть возможность введения автоматической проверки версии компилятора в процесс CI/CD.

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

Практические ресурсы:

  • Публикации о Security Alerts от команды Solidity, выпускаемые регулярно:

  • Официальный репозиторий Solidity регулярно обновляет список ошибок:

  • Список ошибок компилятора для всех версий:

  • На странице Code контракта на Etherscan в правом верхнем углу треугольный восклицательный знак может указать на существующие уязвимости в компиляторе текущей версии.

Итог

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

Анализ уязвимости компилятора Solidity и меры по ее устранению

ETH2.9%
Посмотреть Оригинал
На этой странице может содержаться сторонний контент, который предоставляется исключительно в информационных целях (не в качестве заявлений/гарантий) и не должен рассматриваться как поддержка взглядов компании Gate или как финансовый или профессиональный совет. Подробности смотрите в разделе «Отказ от ответственности» .
  • Награда
  • 5
  • Поделиться
комментарий
0/400
staking_grampsvip
· 16ч назад
Куда больше уязвимостей, кто теперь осмелится разрабатывать?
Посмотреть ОригиналОтветить0
JustHereForMemesvip
· 07-23 05:15
У компилятора тоже большие проблемы, я ухожу, ухожу.
Посмотреть ОригиналОтветить0
BakedCatFanboyvip
· 07-22 21:56
Уязвимости только подбирать, да?
Посмотреть ОригиналОтветить0
OldLeekNewSicklevip
· 07-22 21:56
Высококлассные неудачники ищут дыры, низшие неудачники следят за Книгой ордеров
Посмотреть ОригиналОтветить0
RektCoastervip
· 07-22 21:52
Компилятор тоже выдает ошибки? Это действительно заставляет меня вспыхнуть и взорваться.
Посмотреть ОригиналОтветить0
  • Закрепить