Анализ уязвимостей компилятора Solidity и стратегии реагирования
Компилятор является одним из основных компонентов современных компьютерных систем, его задача заключается в преобразовании исходного кода на высокоуровневом языке программирования в исполняемый код для компьютера. Большинство разработчиков и специалистов по безопасности обычно сосредотачиваются на безопасности приложений, но часто игнорируют безопасность самого компилятора. На самом деле, компилятор как программа также может иметь уязвимости, которые в определенных сценариях могут привести к серьезным рискам безопасности.
Например, когда браузер компилирует и выполняет код JavaScript, он может подвергнуться атаке из-за уязвимости движка JavaScript, что может привести к удаленному выполнению кода злоумышленником, когда пользователь посещает вредоносные веб-страницы, в конечном итоге контролируя браузер жертвы или даже операционную систему. Другое исследование также показало, что ошибка компилятора C++ может привести к серьезным последствиям, таким как удаленное выполнение кода.
Компилятор Solidity также имеет уязвимости в безопасности. Согласно предупреждениям о безопасности от команды разработчиков Solidity, несколько версий компилятора Solidity содержат уязвимости. Роль компилятора Solidity заключается в преобразовании кода смарт-контрактов в машинный код команд Ethereum виртуальной машины (EVM), который в конечном итоге будет загружен в Ethereum и выполнен EVM.
Необходимо различать уязвимости компилятора Solidity и уязвимости самой EVM. Уязвимости EVM относятся к проблемам безопасности, возникающим при выполнении инструкций виртуальной машины, которые могут повлиять на всю сеть Ethereum. Уязвимости компилятора Solidity касаются проблем, возникающих при преобразовании Solidity в код EVM, которые не влияют непосредственно на сеть Ethereum, но могут привести к тому, что сгенерированный код EVM будет отличаться от ожиданий разработчика.
Одна из опасностей уязвимости компилятора Solidity заключается в том, что она может привести к тому, что сгенерированный код EVM не будет соответствовать ожиданиям разработчиков смарт-контрактов. Поскольку смарт-контракты обычно связаны с криптовалютными активами пользователей, любая ошибка, вызванная компилятором, может привести к потере активов пользователей и серьезным последствиям.
Разработчики и аудиторы часто сосредотачиваются на логике контрактов и распространенных проблемах безопасности, в то время как уязвимости компилятора трудно обнаружить с помощью аудита кода. Необходимо совместно анализировать конкретную версию компилятора и шаблоны кода, чтобы определить, подвержен ли смарт-контракт уязвимостям компилятора.
Вот несколько примеров реальных уязвимостей компилятора 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. Это происходит потому, что EVM использует элементы стека размером 32 байта, в то время как Solidity поддерживает более мелкие типы данных, такие как uint32. Компилятор при обработке должен очищать старшие биты ( clean up ), но при переполнении сложения не обработал это правильно, что привело к записи старшего бита 1 в переменную b.
Уязвимость существует в компиляторах версий с 0.8.13 по 0.8.15. Рассмотрим следующий код:
солидность
контракт C {
функция f() публичная чистая возвращает (uint) {
сборка {
mstore(0, 0x42)
}
uint x;
сборка {
x := mload(0)
}
вернуть x;
}
}
Компилятор для оптимизации удаляет, казалось бы, бесполезные операции записи в память, но ошибочно также оптимизирует доступ к памяти, пересекающий блоки сборки. Это приводит к тому, что функция f() возвращает 0 вместо правильного 0x42.
Уязвимость затрагивает версии компилятора от 0.5.8 до 0.8.16. Рассмотрим следующий код:
солидность
контракт C {
function f(string[1] calldata a) внешних чистых возвращает (string memory) {
вернуть abi.decode(abi.encode(a), (строка[1]))[0];
}
}
В нормальных условиях эта функция должна возвращать входную строку. Однако в уязвимой версии она возвращает пустую строку. Это связано с тем, что компилятор неправильно очистил некоторые данные при ABI-кодировании массива calldata, что привело к несоответствию закодированных и декодированных данных.
В связи с уязвимостями компилятора Solidity, команда безопасности блокчейна Cobo предлагает следующие рекомендации:
Для разработчиков:
Используйте более новую версию компилятора Solidity, в которой обычно меньше известных проблем с безопасностью.
Улучшите тестовые случаи модулей. Большинство ошибок на уровне компилятора приводят к тому, что результаты выполнения кода не соответствуют ожиданиям; повышение покрытия тестами может помочь избежать подобных проблем.
Избегайте использования встроенного ассемблера, сложной компиляции и декодирования ABI и других операций, не используйте слепо новые функции и экспериментальные возможности. Большинство уязвимостей компилятора связано с этими сложными операциями.
К службе безопасности:
Не игнорируйте потенциальные риски безопасности, связанные с компилятором, во время аудита. Соответствующий пункт проверки: SWC-102: Устаревшая версия компилятора.
В процессе разработки необходимо побуждать команду разработчиков обновлять версию компилятора, можно внедрить автоматическую проверку версии в CI/CD.
Не нужно чрезмерно беспокоиться о уязвимостях компилятора. Большинство уязвимостей срабатывают только в определённых кодовых паттернах, необходимо оценить влияние на безопасность в зависимости от конкретного проекта.
Некоторые полезные ресурсы:
Официальное предупреждение о безопасности Solidity:
Официальный список ошибок Solidity:
Список ошибок компилятора для всех версий:
В правом верхнем углу страницы контракта Etherscan значок предупреждения может указывать на существующие уязвимости в текущей версии компилятора.
В целом, разработчики и специалисты по безопасности должны обратить внимание на потенциальные риски безопасности, связанные с уязвимостями компилятора Solidity, и принять соответствующие меры для снижения рисков, чтобы обеспечить безопасность смарт-контрактов.
Посмотреть Оригинал
This page may contain third-party content, which is provided for information purposes only (not representations/warranties) and should not be considered as an endorsement of its views by Gate, nor as financial or professional advice. See Disclaimer for details.
18 Лайков
Награда
18
6
Поделиться
комментарий
0/400
MetaverseLandlord
· 07-12 19:10
С компилятором что-то не так
Посмотреть ОригиналОтветить0
NFTHoarder
· 07-12 03:00
Компилятор тоже может ошибаться.
Посмотреть ОригиналОтветить0
0xOverleveraged
· 07-10 21:09
Компилятор — это предок.
Посмотреть ОригиналОтветить0
TestnetNomad
· 07-10 21:08
Класс по компиляторам очень хороший
Посмотреть ОригиналОтветить0
ParallelChainMaxi
· 07-10 21:06
Безопасность компилятора не должна игнорироваться
Посмотреть ОригиналОтветить0
DegenApeSurfer
· 07-10 20:55
Безопасность контрактов действительно непростая задача
Анализ уязвимостей компилятора Solidity и практические стратегии защиты безопасности смарт-контрактов
Анализ уязвимостей компилятора Solidity и стратегии реагирования
Компилятор является одним из основных компонентов современных компьютерных систем, его задача заключается в преобразовании исходного кода на высокоуровневом языке программирования в исполняемый код для компьютера. Большинство разработчиков и специалистов по безопасности обычно сосредотачиваются на безопасности приложений, но часто игнорируют безопасность самого компилятора. На самом деле, компилятор как программа также может иметь уязвимости, которые в определенных сценариях могут привести к серьезным рискам безопасности.
Например, когда браузер компилирует и выполняет код JavaScript, он может подвергнуться атаке из-за уязвимости движка JavaScript, что может привести к удаленному выполнению кода злоумышленником, когда пользователь посещает вредоносные веб-страницы, в конечном итоге контролируя браузер жертвы или даже операционную систему. Другое исследование также показало, что ошибка компилятора C++ может привести к серьезным последствиям, таким как удаленное выполнение кода.
Компилятор Solidity также имеет уязвимости в безопасности. Согласно предупреждениям о безопасности от команды разработчиков Solidity, несколько версий компилятора Solidity содержат уязвимости. Роль компилятора Solidity заключается в преобразовании кода смарт-контрактов в машинный код команд Ethereum виртуальной машины (EVM), который в конечном итоге будет загружен в Ethereum и выполнен EVM.
Необходимо различать уязвимости компилятора Solidity и уязвимости самой EVM. Уязвимости EVM относятся к проблемам безопасности, возникающим при выполнении инструкций виртуальной машины, которые могут повлиять на всю сеть Ethereum. Уязвимости компилятора Solidity касаются проблем, возникающих при преобразовании Solidity в код EVM, которые не влияют непосредственно на сеть Ethereum, но могут привести к тому, что сгенерированный код EVM будет отличаться от ожиданий разработчика.
Одна из опасностей уязвимости компилятора Solidity заключается в том, что она может привести к тому, что сгенерированный код EVM не будет соответствовать ожиданиям разработчиков смарт-контрактов. Поскольку смарт-контракты обычно связаны с криптовалютными активами пользователей, любая ошибка, вызванная компилятором, может привести к потере активов пользователей и серьезным последствиям.
Разработчики и аудиторы часто сосредотачиваются на логике контрактов и распространенных проблемах безопасности, в то время как уязвимости компилятора трудно обнаружить с помощью аудита кода. Необходимо совместно анализировать конкретную версию компилятора и шаблоны кода, чтобы определить, подвержен ли смарт-контракт уязвимостям компилятора.
Вот несколько примеров реальных уязвимостей компилятора Solidity:
Уязвимость существует в более ранних версиях компилятора 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. Это происходит потому, что EVM использует элементы стека размером 32 байта, в то время как Solidity поддерживает более мелкие типы данных, такие как uint32. Компилятор при обработке должен очищать старшие биты ( clean up ), но при переполнении сложения не обработал это правильно, что привело к записи старшего бита 1 в переменную b.
Уязвимость существует в компиляторах версий с 0.8.13 по 0.8.15. Рассмотрим следующий код:
солидность контракт C { функция f() публичная чистая возвращает (uint) { сборка { mstore(0, 0x42) } uint x; сборка { x := mload(0) } вернуть x; } }
Компилятор для оптимизации удаляет, казалось бы, бесполезные операции записи в память, но ошибочно также оптимизирует доступ к памяти, пересекающий блоки сборки. Это приводит к тому, что функция f() возвращает 0 вместо правильного 0x42.
Уязвимость затрагивает версии компилятора от 0.5.8 до 0.8.16. Рассмотрим следующий код:
солидность контракт C { function f(string[1] calldata a) внешних чистых возвращает (string memory) { вернуть abi.decode(abi.encode(a), (строка[1]))[0]; } }
В нормальных условиях эта функция должна возвращать входную строку. Однако в уязвимой версии она возвращает пустую строку. Это связано с тем, что компилятор неправильно очистил некоторые данные при ABI-кодировании массива calldata, что привело к несоответствию закодированных и декодированных данных.
В связи с уязвимостями компилятора Solidity, команда безопасности блокчейна Cobo предлагает следующие рекомендации:
Для разработчиков:
Используйте более новую версию компилятора Solidity, в которой обычно меньше известных проблем с безопасностью.
Улучшите тестовые случаи модулей. Большинство ошибок на уровне компилятора приводят к тому, что результаты выполнения кода не соответствуют ожиданиям; повышение покрытия тестами может помочь избежать подобных проблем.
Избегайте использования встроенного ассемблера, сложной компиляции и декодирования ABI и других операций, не используйте слепо новые функции и экспериментальные возможности. Большинство уязвимостей компилятора связано с этими сложными операциями.
К службе безопасности:
Не игнорируйте потенциальные риски безопасности, связанные с компилятором, во время аудита. Соответствующий пункт проверки: SWC-102: Устаревшая версия компилятора.
В процессе разработки необходимо побуждать команду разработчиков обновлять версию компилятора, можно внедрить автоматическую проверку версии в CI/CD.
Не нужно чрезмерно беспокоиться о уязвимостях компилятора. Большинство уязвимостей срабатывают только в определённых кодовых паттернах, необходимо оценить влияние на безопасность в зависимости от конкретного проекта.
Некоторые полезные ресурсы:
В целом, разработчики и специалисты по безопасности должны обратить внимание на потенциальные риски безопасности, связанные с уязвимостями компилятора Solidity, и принять соответствующие меры для снижения рисков, чтобы обеспечить безопасность смарт-контрактов.