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

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

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

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

Компилятор Solidity не является исключением, в нескольких версиях существуют уязвимости. Роль компилятора Solidity заключается в преобразовании кода смарт-контракта в байт-код команд Ethereum Virtual Machine (EVM), который в конечном итоге выполняется в EVM. Стоит отметить, что уязвимости компилятора Solidity отличаются от уязвимостей самой EVM. Уязвимости EVM относятся к проблемам безопасности при выполнении инструкций виртуальной машины, которые могут повлиять на всю сеть Ethereum. В то время как уязвимости компилятора Solidity возникают при преобразовании Solidity в код EVM.

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

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

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

SOL-2016-9 HighOrderByteCleanStorage

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

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

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

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

Это несоответствие трудно выявить простым кодовым ревью. Хотя пример кода имеет ограниченное влияние, если переменная b используется для проверки прав или учета активов, последствия будут весьма серьезными.

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

SOL-2022-4 ВлиятельныеПобочныеЭффектыInlineAssemblyMemory

Уязвимость существует в компиляторах версий от 0.8.13 до 0.8.15. Рассмотрим следующий код:

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

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

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

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

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

SOL-2022-6 AbiReencodingHeadOverflowWithStaticArrayCleanup

Этот уязвимость затрагивает версии компилятора с 0.5.8 по 0.8.16. Рассмотрим следующий код:

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

В нормальных условиях данный код должен возвращать значение переменной a "aaaa". Однако в уязвимой версии он будет возвращать пустую строку "".

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

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

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

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

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

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

К безопасности персонала:

  • Не игнорируйте потенциальные риски безопасности, которые могут быть вызваны компилятором во время аудита. Соответствующий пункт проверки в Smart Contract Weakness Classification(SWC) - это SWC-102: Устаревшая версия компилятора.
  • В процессе разработки SDL необходимо побуждать команду разработчиков обновлять версию компилятора и рассмотреть возможность внедрения автоматической проверки версии компилятора в CI/CD.
  • Не стоит чрезмерно беспокоиться о уязвимостях компилятора. Большинство уязвимостей срабатывают только при определенных кодовых паттернах, и использование контрактов, скомпилированных с уязвимой версией, не обязательно связано с риском, необходимо оценивать ситуацию в каждом конкретном случае.

Некоторые полезные ресурсы:

  • Регулярные уведомления о безопасности от команды Solidity
  • Регулярно обновляемый список ошибок в официальном репозитории Solidity
  • Список ошибок компилятора для различных версий, который можно использовать для автоматической проверки в CI/CD.
  • Знак предупреждения в правом верхнем углу страницы кода контракта Etherscan может сигнализировать о существующих уязвимостях в текущей версии компилятора.

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

Резюме

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

ETH2.9%
SOL5.09%
Посмотреть Оригинал
На этой странице может содержаться сторонний контент, который предоставляется исключительно в информационных целях (не в качестве заявлений/гарантий) и не должен рассматриваться как поддержка взглядов компании Gate или как финансовый или профессиональный совет. Подробности смотрите в разделе «Отказ от ответственности» .
  • Награда
  • 5
  • Поделиться
комментарий
0/400
0xInsomniavip
· 07-24 15:11
Уязвимость на нижнем уровне, верхний уровень не спасает.
Посмотреть ОригиналОтветить0
0xSunnyDayvip
· 07-24 06:35
Кто еще смеет говорить, что компиляторы безопасны?
Посмотреть ОригиналОтветить0
BankruptcyArtistvip
· 07-24 06:29
Каждый день ищу уязвимости, каждый день на грани банкротства.
Посмотреть ОригиналОтветить0
bridge_anxietyvip
· 07-24 06:23
Сложность эксплуатации уязвимости ударила по всем фронтам.
Посмотреть ОригиналОтветить0
TokenDustCollectorvip
· 07-24 06:13
Уязвимость безопасности — это начало того, как неудачники теряют деньги.
Посмотреть ОригиналОтветить0
  • Закрепить