Анализ уязвимостей компилятора Solidity и меры противодействия
Компилятор является одной из основных компонентов современных компьютерных систем, его функция заключается в преобразовании исходного кода на высокоуровневом языке программирования в исполняемые командные коды для компьютера. Хотя разработчики и специалисты по безопасности обычно сосредоточены на безопасности прикладного кода программ, сам компилятор как компьютерная программа также может содержать уязвимости безопасности, что в некоторых случаях может привести к серьезным рискам для безопасности.
Например, при компиляции и выполнении кода JavaScript браузер может подвергнуться удаленному выполнению кода из-за уязвимости в парсере, что позволяет злоумышленнику получить контроль над браузером жертвы или даже над операционной системой. Также исследования показывают, что ошибки компилятора C++ могут привести к серьезным последствиям, таким как удаленное выполнение кода.
В компиляторе Solidity также существуют уязвимости. Согласно предупреждениям безопасности от команды разработчиков, в нескольких версиях компилятора Solidity были обнаружены проблемы с безопасностью.
Компилятор Solidity предназначен для преобразования кода смарт-контрактов в код инструкций Ethereum Virtual Machine (EVM). Необходимо различать уязвимости компилятора Solidity и уязвимости самой EVM. Уязвимости EVM относятся к проблемам безопасности при выполнении инструкций виртуальной машиной, которые могут повлиять на всю сеть Ethereum. Уязвимости компилятора Solidity связаны с проблемами при преобразовании Solidity в код EVM, которые не оказывают непосредственного влияния на сеть Ethereum, но могут привести к несоответствию сгенерированного кода EVM ожиданиям разработчика.
Поскольку смарт-контракты обычно связаны с криптовалютными активами пользователей, любые ошибки, вызванные компилятором, могут иметь серьезные последствия. Просто проверка исходного кода контракта затрудняет обнаружение уязвимостей компилятора, необходимо проводить анализ с учетом конкретной версии и кодовых шаблонов.
Ниже представлены несколько реальных примеров, демонстрирующих конкретные формы, причины и последствия уязвимостей компилятора Solidity.
SOL-2016-9 HighOrderByteCleanStorage
Уязвимость существует в более ранних версиях компилятора Solidity (>=0.1.6 <0.4.4).
Рассмотрите следующий код:
солидность
контракт C {
uint32 a = 0x1234;
uint32 b = 0;
функция f() публичная {
a += 1;
}
функция run() публичный вид вернуть (uint) {
вернуть b;
}
}
Переменная b не была изменена, функция run() должна возвращать значение по умолчанию 0. Но в коде, сгенерированном уязвимым компилятором, run() вернет 1.
Это связано с тем, что EVM использует элементы стека размером 32 байта, в то время как Solidity поддерживает типы, такие как uint32, меньшие 32 байт. Компилятору необходимо очищать старшие биты, чтобы гарантировать корректность данных. При переполнении сложения компилятор неправильно очистил старшие биты, что привело к тому, что переполненный 1 бит был записан в хранилище и перезаписал переменную b.
SOL-2022-4 Влияние побочных эффектов памяти в InlineAssembly
Уязвимость существует в компиляторах версий >=0.8.13 <0.8.15.
Рассмотрим следующий код:
солидность
контракт C {
функция f() публичная чистая возвращает (uint) {
сборка {
mstore(0, 0x42)
}
uint x;
сборка {
x := mload(0)
}
вернуть x;
}
}
Компилятор в процессе оптимизации анализирует управляющий поток и поток данных, чтобы уменьшить объем кода и оптимизировать расход газа. Однако такая оптимизация может легко привести к ошибкам.
В этом примере компилятор ошибочно считает, что запись в память 0 в первом блоке сборки является избыточной, и удаляет ее, что приводит к возврату функции f() значения 0 вместо правильного 0x42.
Уязвимость затрагивает компиляторы версий >= 0.5.8 < 0.8.16.
Рассмотрите следующий код:
солидность
контракт C {
function f(string[1] calldata a) public pure возвращает (string memory) {
вернуть abi.decode(abi.encode(a), (строка[1]))[0];
}
}
В нормальных условиях этот код должен вернуть значение переменной a "aaaa". Но в уязвимой версии он вернет пустую строку "".
Это связано с тем, что при выполнении операции abi.encode с массивами типа calldata в Solidity неверно очищаются некоторые данные, что приводит к изменению соседних данных и вызывает несоответствие между закодированными и декодированными данными.
Стоит отметить, что при внешних вызовах и вызове событий происходит неявное применение abi.encode, что увеличивает вероятность возникновения таких уязвимостей.
Рекомендации по безопасности
Для разработчиков:
Используйте более новую версию компилятора Solidity, в которой обычно меньше известных проблем с безопасностью.
Улучшение тестовых случаев модулей, повышение покрытия кода поможет выявить проблемы, вызванные компилятором.
Избегайте использования встроенной сборки, сложной ABI кодировки и декодировки и других операций, не используйте новые функции и экспериментальные возможности без разбора.
Для сотрудников безопасности:
Не игнорируйте риски, которые могут быть вызваны компилятором во время аудита, в соответствии с пунктом проверки SWC-102.
В процессе SDL продвигайте обновление версии компилятора, рассмотрите возможность внедрения автоматической проверки.
Оцените реальное влияние уязвимости компилятора, не следует сильно паниковать.
Некоторые полезные ресурсы:
Официальный блог безопасности Solidity
Список ошибок в репозитории Solidity
Список ошибок компилятора для всех версий
Уведомление о уязвимости компилятора на странице контракта Etherscan
В общем, уязвимости компилятора Solidity могут привести к тому, что фактическое поведение смарт-контрактов не будет соответствовать ожиданиям, поэтому разработчики и специалисты по безопасности должны сохранять бдительность и принимать соответствующие меры для снижения рисков.
На этой странице может содержаться сторонний контент, который предоставляется исключительно в информационных целях (не в качестве заявлений/гарантий) и не должен рассматриваться как поддержка взглядов компании Gate или как финансовый или профессиональный совет. Подробности смотрите в разделе «Отказ от ответственности» .
16 Лайков
Награда
16
5
Репост
Поделиться
комментарий
0/400
ColdWalletGuardian
· 08-06 10:09
Все еще осмеливаются использовать старую версию компилятора, железные идиоты.
Посмотреть ОригиналОтветить0
LayerZeroHero
· 08-06 02:28
Компилятор тоже не очень стабилен.
Посмотреть ОригиналОтветить0
RektRecorder
· 08-03 12:34
这么危险 离谱了семья
Посмотреть ОригиналОтветить0
BearMarketGardener
· 08-03 12:30
Компиляторы тоже полны уязвимостей, за время, пока я спал, активы пропали.
Анализ уязвимостей компилятора Solidity: незаметные риски смарт-контрактов
Анализ уязвимостей компилятора Solidity и меры противодействия
Компилятор является одной из основных компонентов современных компьютерных систем, его функция заключается в преобразовании исходного кода на высокоуровневом языке программирования в исполняемые командные коды для компьютера. Хотя разработчики и специалисты по безопасности обычно сосредоточены на безопасности прикладного кода программ, сам компилятор как компьютерная программа также может содержать уязвимости безопасности, что в некоторых случаях может привести к серьезным рискам для безопасности.
Например, при компиляции и выполнении кода JavaScript браузер может подвергнуться удаленному выполнению кода из-за уязвимости в парсере, что позволяет злоумышленнику получить контроль над браузером жертвы или даже над операционной системой. Также исследования показывают, что ошибки компилятора C++ могут привести к серьезным последствиям, таким как удаленное выполнение кода.
В компиляторе Solidity также существуют уязвимости. Согласно предупреждениям безопасности от команды разработчиков, в нескольких версиях компилятора Solidity были обнаружены проблемы с безопасностью.
Компилятор Solidity предназначен для преобразования кода смарт-контрактов в код инструкций Ethereum Virtual Machine (EVM). Необходимо различать уязвимости компилятора Solidity и уязвимости самой EVM. Уязвимости EVM относятся к проблемам безопасности при выполнении инструкций виртуальной машиной, которые могут повлиять на всю сеть Ethereum. Уязвимости компилятора Solidity связаны с проблемами при преобразовании Solidity в код EVM, которые не оказывают непосредственного влияния на сеть Ethereum, но могут привести к несоответствию сгенерированного кода EVM ожиданиям разработчика.
Поскольку смарт-контракты обычно связаны с криптовалютными активами пользователей, любые ошибки, вызванные компилятором, могут иметь серьезные последствия. Просто проверка исходного кода контракта затрудняет обнаружение уязвимостей компилятора, необходимо проводить анализ с учетом конкретной версии и кодовых шаблонов.
Ниже представлены несколько реальных примеров, демонстрирующих конкретные формы, причины и последствия уязвимостей компилятора Solidity.
SOL-2016-9 HighOrderByteCleanStorage
Уязвимость существует в более ранних версиях компилятора Solidity (>=0.1.6 <0.4.4).
Рассмотрите следующий код:
солидность контракт C { uint32 a = 0x1234; uint32 b = 0; функция f() публичная { a += 1; } функция run() публичный вид вернуть (uint) { вернуть b; } }
Переменная b не была изменена, функция run() должна возвращать значение по умолчанию 0. Но в коде, сгенерированном уязвимым компилятором, run() вернет 1.
Это связано с тем, что EVM использует элементы стека размером 32 байта, в то время как Solidity поддерживает типы, такие как uint32, меньшие 32 байт. Компилятору необходимо очищать старшие биты, чтобы гарантировать корректность данных. При переполнении сложения компилятор неправильно очистил старшие биты, что привело к тому, что переполненный 1 бит был записан в хранилище и перезаписал переменную b.
SOL-2022-4 Влияние побочных эффектов памяти в InlineAssembly
Уязвимость существует в компиляторах версий >=0.8.13 <0.8.15.
Рассмотрим следующий код:
солидность контракт C { функция f() публичная чистая возвращает (uint) { сборка { mstore(0, 0x42) } uint x; сборка { x := mload(0) } вернуть x; } }
Компилятор в процессе оптимизации анализирует управляющий поток и поток данных, чтобы уменьшить объем кода и оптимизировать расход газа. Однако такая оптимизация может легко привести к ошибкам.
В этом примере компилятор ошибочно считает, что запись в память 0 в первом блоке сборки является избыточной, и удаляет ее, что приводит к возврату функции f() значения 0 вместо правильного 0x42.
SOL-2022-6 AbiReencodingHeadOverflowWithStaticArrayCleanup
Уязвимость затрагивает компиляторы версий >= 0.5.8 < 0.8.16.
Рассмотрите следующий код:
солидность контракт C { function f(string[1] calldata a) public pure возвращает (string memory) { вернуть abi.decode(abi.encode(a), (строка[1]))[0]; } }
В нормальных условиях этот код должен вернуть значение переменной a "aaaa". Но в уязвимой версии он вернет пустую строку "".
Это связано с тем, что при выполнении операции abi.encode с массивами типа calldata в Solidity неверно очищаются некоторые данные, что приводит к изменению соседних данных и вызывает несоответствие между закодированными и декодированными данными.
Стоит отметить, что при внешних вызовах и вызове событий происходит неявное применение abi.encode, что увеличивает вероятность возникновения таких уязвимостей.
Рекомендации по безопасности
Для разработчиков:
Для сотрудников безопасности:
Некоторые полезные ресурсы:
В общем, уязвимости компилятора Solidity могут привести к тому, что фактическое поведение смарт-контрактов не будет соответствовать ожиданиям, поэтому разработчики и специалисты по безопасности должны сохранять бдительность и принимать соответствующие меры для снижения рисков.