Исследование CoinEx: Введение в распространенные уязвимости и атаки в смарт-контрактах

Исследование CoinEx В Ethereum есть два распространенных типа учетных записей: учетные записи, находящиеся во внешнем владении (EOA), и учетные записи смарт-контрактов (SCA). EOA очень похожи на...
Часто задаваемые вопросы

Исследование CoinEx: Введение в распространенные уязвимости и атаки в смарт-контрактах

Поделиться:
Исследование CoinEx

В Ethereum есть два распространенных типа учетных записей: учетные записи, находящиеся во внешнем владении (EOA), и учетные записи смарт-контрактов (SCA).
EOA очень похожи на электронные финансовые счета, которые мы обычно используем для хранения средств и взаимодействия с приложениями. Например, пользователи вносят фиатную валюту через PayPal и взаимодействуют с различными веб-сайтами, магазинами и приложениями для осуществления платежей. Майнеры DeFi обычно хранят криптографические данные в своих EOA, взаимодействуют с DeFi dApps и вносят средства в dApps для получения прибыли. Тем не менее, у EOA есть функция, которой нет у электронных финансовых счетов: пользователи должны подтвердить свой контроль над EOA посредством владения приватными ключами — не вашими ключами, не вашими монетами.
SCA также являются типом учетной записи, которая, по сути, связана с сегментом исполняемого байт-кода (также известного как смарт-контракт). Смарт-контракт описывает различную бизнес-логику и служит основой для dApps. Однако, несмотря на наличие большего количества ограничений по сравнению с традиционными языками разработки Turing complete, квази-полные смарт-контракты Turing по-прежнему уязвимы для многочисленных атак, нанося бесчисленные удары по блокчейн-индустрии.

Распространенные атаки на смарт-контракты



1. Атака повторного входа
Наиболее распространенной и печально известной атакой является атака повторного входа, которая была ответственна за форк Ethereum, приведший к созданию Ethereum Classic. В 2016 году хакеры осуществили повторную атаку на контракт DAO, похитив 3 600 000 ETH на сумму более 150 миллионов долларов на тот момент. Эта атака, произошедшая на ранних стадиях развития Ethereum, разрушила экосистему и подорвала доверие инвесторов, что в конечном итоге привело к форку.
Специфическая логика
Вот пример, который поможет вам лучше понять принцип повторной атаки. Банк B ранее одолжил некоторую сумму банку A. Однажды Банк B инициирует перевод в Банк A, запрашивая перевод всех денег обратно в банк B. Обычный путь следующий:
Шаг 1: Банк B запрашивает вывод средств
Шаг 2: Банк A переводит средства в Банк B
Шаг 3: Банк A подтверждает успешный перевод в Банк B
Шаг 4: Банк A обновляет баланс счета Банка B.


Однако, если Банк B создаст лазейку после шага 2 и продолжит запрашивать все деньги из Банка A без подтверждения на шаге 3, то баланс счета Банка A в Банке B останется неизменным. Этот рекурсивный вызов опустошит все активы Банка A.



Связанные смарт-контракты

Контракт банка A включает в себя две функции:
deposit(): Функция пополнения счета, которая вносит деньги в банк A и обновляет баланс пользователя;
withdraw(): Функция вывода средств, которая позволяет пользователям выводить все свои средства из банка A.



Контракт на атаку банка B в основном включает цикл, который запускает функцию обратного вызова receive(), которая, в свою очередь, вызывает функцию withdraw() банковского контракта для истощения активов Банка A посредством последовательности из 1 пополнения, 1 снятия и вызовов функции обратного вызова receive() и, наконец, обновляет Баланс B в A. Он включает в себя две функции:
receive(): Функция обратного вызова, запускаемая при получении ETH, которая рекурсивно вызывает функцию withdraw() банковского контракта для осуществления снятия средств.
attack(): сначала вызывается функция deposit() банковского контракта для обновления баланса, а затем функция withdraw() для инициирования первого вывода средств и запускает функцию обратного вызова receive() для рекурсивного вызова withdraw() для истощения активов банковского контракта.



Решение

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



Как им пользоваться



2. Неправильное использование tx.origin



Основная функция tx.origin в смарт-контракте заключается в получении исходной учетной записи, которая инициировала транзакцию. Здесь мы обсудим две общие переменные в смарт-контрактах: msg.sender и tx.origin. msg.sender извлекает учетную запись, непосредственно вызывая смарт-контракт, в то время как в мире блокчейна, из-за вложенных и взаимных вызовов различных смарт-контрактов (таких как DeFi Lego), tx.origin является необходимо для получения исходной учетной записи, которая инициировала транзакцию. Уязвимость возникает, когда разработчики DApp проверяют безопасность tx.origin только в коде, пренебрегая проверкой безопасности злоумышленников, развертывающих промежуточные контракты для обхода tx.origin и запуска атак.

Специфическая логика



Вот пример, который поможет вам разобраться в распространенном сценарии атаки. У Билла есть смарт-кошелек, который проверяет, является ли Билл инициатором перевода. Однажды Билл отчеканил NFT на фишинговом веб-сайте. Это позволило веб-сайту получить идентификационные данные Билла и инициировать перевод с его смарт-кошелька, используя его идентификационные данные, что привело к потере активов. При обычных обстоятельствах пользователи с меньшей вероятностью попадут в эту ловушку, но при взаимодействии с dApps с использованием кошелька они часто забывают проверить подсказки о взаимодействии. Например, если в обоих случаях задействована функция Mint(), неосторожные пользователи могут легко попасть в фишинговую ловушку. Бизнес-логика фишингового веб-сайта изобилует ловушками, поэтому важно проверять приглашения к взаимодействию на наличие ошибок во время обычных взаимодействий.

Следите за нашей группой TELEGRAM

Контракт смарт-кошелька



Контракт на смарт-кошелек включает в себя одну функцию:
● transfer(): Функция вывода средств, которая может быть инициирована только владельцем кошелька, которым в данном случае является Билл.



Контракт на фишинговую атаку


В контракте на фишинговую атаку Mint() побуждает пользователей переводить средства на адрес хакера. Он включает в себя одну функцию:
● Mint(): После вызова фишинговая функция внутренне выполняет transfer() контракта кошелька. Поскольку первоначальным инициатором является сам пользователь (в данном примере Билл), требование проверки (tx.origin == владелец, "Не владелец"); не будет проблемой. Однако целевой адрес для перевода уже был изменен на адрес хакера, что привело к краже средств.



Решения

1. Используйте msg.sender вместо tx.origin
Независимо от того, сколько вызовов контракта задействовано (Контракт A → Контракт B →...→ целевой контракт), проверяйте только msg.sender, т.е. прямого вызывающего абонента, чтобы избежать атак, вызванных вредоносными промежуточными контрактами.



2. Проверьте tx.origin == msg.sender
Этот метод может предотвратить вредоносные контракты, но разработчикам необходимо учитывать свои собственные бизнес-реалии, поскольку он эффективно изолирует все другие вызовы внешних контрактов.



3. Атака генератором случайных чисел (RNG)


Это восходит к тренду приложений для азартных игр или ставок в 2018 и 2019 годах. Как правило, разработчики используют определенные исходные данные в смарт-контрактах для генерации случайных чисел для выбора победителей во время розыгрышей. Распространенные исходные данные включают block.number, block.timestamp, хэш блока и keccak 256. Однако майнеры могут полностью контролировать эти исходные данные, поэтому в некоторых случаях злоумышленники могут манипулировать переменными, чтобы извлечь выгоду.

Распространенные контракты Dice



Контракт Dice включает в себя одну функцию:
Bet(): Функция ставок, при которой пользователи вводят номер ставки и выплачивают ETH. Генерируется случайное число с несколькими начальными значениями, и если номер ставки совпадает со случайным числом, пользователь выигрывает весь призовой фонд.



Контракт на атаку майнера
Майнеры могут выигрывать до тех пор, пока они предварительно вычисляют выигрышное случайное число и выполняют его в том же блоке. Это включает в себя одну функцию:
● attack(): функция атаки на ставки, при которой майнер предварительно вычисляет выигрышное случайное число. Поскольку он выполняется в одном и том же блоке, blockhash(block.number - 1) и block.timestamp в одном и том же блоке совпадают. Затем майнер вызывает Bet() контракта Dice для завершения атаки.



Решение



Используйте случайные числа вне цепочки, предоставляемые oracle projects
Благодаря сервисам, предоставляемым oracle projects, таким как Chainlink, случайные числа внутри цепочки вводятся в контракты внутри цепочки для обеспечения случайности и безопасности. Однако проекты oracle также сопряжены с рисками централизации, что требует более зрелых сервисов oracle.

4. Повторная атака



Повторная атака предполагает повторную инициализацию транзакции с использованием ранее использованной подписи для кражи средств. Одной из самых известных повторных атак за последние годы была кража токенов OP на 20 миллионов долларов у маркетмейкера Wintermute на Optimism, которая представляла собой перекрестную атаку с повторным использованием цепочки. Поскольку учетная запись кошелька Wintermute с несколькими подписями была временно развернута только в основной сети Ethereum, хакер использовал подпись транзакции для развертывания Wintermute адреса с несколькими подписями в Ethereum, чтобы повторно выполнить ту же транзакцию в цепочке Optimism, тем самым получив контроль над учетной записью кошелька с несколькими подписями в Ethereum. Оптимизм. Учетная запись кошелька с несколькими подписями - это, по сути, учетная запись смарт-контракта, которая также демонстрирует существенную разницу между SCA и EOA. Для EOA обычному пользователю нужен только один закрытый ключ для управления всеми адресами в цепочках, совместимых с Ethereum и EVM (строки адресов в точности совпадают), в то время как SCA действует только в одной цепочке после развертывания.

Специфическая логика


Здесь мы приводим пример типичной повторной атаки (same-chain replay attack). У Билла есть смарт-кошелек, который требует, чтобы он вводил свою электронную подпись перед выполнением каждой транзакции. Теперь, когда хакер Люси украла электронную подпись Билла, она может инициировать неограниченное количество транзакций, чтобы опустошить смарт-кошелек Билла.

Пример



Контракт с уязвимостями состоит из трех функций:
checkSig(): функция проверки ECDSA, гарантирующая, что результатом проверки является изначально установленный подписавший.
getMsgHash(): Функция для генерации хэша, которая объединяет to и amount для формирования хэша.
transfer(): функция перевода, позволяющая пользователям выводить средства из пула ликвидности. Из-за отсутствия ограничений на подпись, одна и та же подпись может использоваться повторно, что позволяет хакерам постоянно красть средства.



Решение



Включите одноразовый номер (nonce) в комбинацию сигнатур, чтобы предотвратить повторные атаки. Принцип действия параметра таков, как показано ниже:
● nonce: описывает переменную количества транзакций EOA в сети блокчейн. Она имеет порядок и уникальность. С каждой дополнительной транзакцией значение одноразового номера будет увеличиваться на 1. Блокчейн-сеть проверит, соответствует ли одноразовый номер транзакции текущему одноразовому номеру учетной записи. Следовательно, хакер потерпит неудачу, если он использует использованную подпись, потому что значение nonce в комбинации подписей меньше текущего одноразового значения EOA.



5. Атака типа "Отказ в обслуживании" (DoS)



Атака типа "Отказ в обслуживании" (DoS) не является чем-то новым в традиционном мире Web2. Это относится к любому вмешательству в работу сервера, такому как отправка большого количества нежелательной или деструктивной информации, затрудняющей или полностью уничтожающей доступность. Аналогичным образом, смарт-контракты страдают от подобных атак, которые, по сути, направлены на то, чтобы заставить смарт-контракт работать неправильно.

Специфическая логика


Давайте посмотрим пример. Проект A проводит публичное размещение токена протокола, в ходе которого все пользователи могут вносить средства в пул ликвидности (смарт-контракт) для покупки квот в порядке живой очереди, а избыточные средства будут возвращены участникам. Хакер Alice использует контракт на атаку для участия в публичном размещении. Как только пул ликвидности попытается вернуть средства в контракт на атаку Alice, будет запущена DoS-атака, что предотвратит реализацию действия по возврату. В результате в смарт-контракте заблокирована большая сумма средств.

Пример


Контракт о публичном размещении включает в себя две функции:
● deposit(): функция внесения депозита, записывающая адрес вкладчика и внесенную сумму.
● refund(): функция возврата средств, с помощью которой команда проекта возвращает средства инвесторам.



Контракт на DoS-атаку



Контракт на DoS-атаку включает в себя одну функцию:
attack(): Несмотря на то, что это функция атаки, у нее нет никаких проблем. Основная проблема заключается в функции обратного вызова платежа receive(), встроенной в контракт хакера, которая включает в себя оценку исключений. Любой внешний контракт, переводящий средства в хакерский контракт, вызовет исключение через функцию revert(), тем самым препятствуя завершению операции.



Решения


1. Избегайте зависания критической функциональности при вызове внешних контрактов
Удалите require(успех, "Возврат невозможен!"); из вышеупомянутой функции refund() контракта публичной продажи, гарантируя, что операция возврата может продолжаться, даже если возврат на один адрес завершится неудачей.

2. Развязка


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

6. разрешение Attack


При Attack с разрешением учетная запись A заранее предоставляет подпись для указанной стороны, а затем учетная запись B, получив подпись, может осуществлять авторизованные переводы токенов, чтобы украсть определенное количество токенов. Здесь мы в первую очередь обсудим две распространенные функции авторизации токенов в смарт-контрактах: approve() и permit().
В обычном контракте ERC20 учетная запись A может вызвать approve(), чтобы авторизовать определенное количество токенов для учетной записи B, позволяя последней перевести эти токены с первой. Кроме того, permit() был введен в контракты ERC20 в EIP-2612, а Uniswap выпустила новый стандарт авторизации токенов, Permit2, в ноябре 2022 года.

Специфическая логика


Вот пример. Однажды Билл просматривал новостной веб-сайт о блокчейне, когда внезапно появилось всплывающее окно подписи Metamask. Поскольку многие веб-сайты или приложения о блокчейне используют подписи для проверки логинов пользователей, Билл не придал этому особого значения и выполнил подпись напрямую. Пять минут спустя его активы Metamask были истощены. Затем Билл обнаружил в blockchain explorer, что неизвестный адрес инициировал транзакцию permit(), за которой последовала транзакция transferFrom(), которая опустошила его кошелек.

Пример


Эти две функции приведены ниже:
● одобрить(): Стандартная функция авторизации, при которой учетная запись A санкционирует перевод определенной суммы средств на учетную запись B.
● разрешить(): Функция авторизации подписи, при которой учетная запись B отправляет и завершает проверку подписи для получения разрешенной суммы со счета A. Параметры включают в себя владельца, предоставляющего разрешение, авторизованного расходователя, разрешенную сумму, крайний срок подписи и данные подписи владельца v, r и s.




Решения


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

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

7. Атака Honeypot


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

Специфическая логика


Вот пример. В объявлении в Telegram Project A информирует пользователей о том, что токен был развернут в основной сети и доступен для торговли. Поскольку токен можно только купить и не может быть продан, цена сначала продолжала расти, и пользователи, которые боятся что-то упустить, продолжают покупать. Через некоторое время, когда пользователи обнаруживают, что их невозможно продать, команда проекта использует эту возможность и сбрасывает токены, в результате чего цена резко падает.

Пример


Основная функция:
● _beforeTokenTransfer(): Внутренняя функция, вызываемая во время передачи токенов, которая может быть успешной только при вызове владельцем; вызовы из других учетных записей завершатся неудачей.



Решение


Используйте инструменты сканирования безопасности

a. Token Sniffer для токенов Ethereum
b. Ave Проверяйте наличие токенов в других цепочках
c. Веб-сайты Market со встроенными инструментами обнаружения, такими как Dextools
Избегайте торговли токенами с низкими баллами.

8. Фронтальная атака


Фронт-менеджмент изначально возник на традиционных финансовых рынках, где информационная асимметрия позволяла финансовым посредникам получать прибыль, предпринимая быстрые действия, основанные на конкретной отраслевой информации. В блокчейн-индустрии фронт-раннинг в основном связан с фронт-раннингом внутри цепочки, который включает в себя манипулирование майнерами, чтобы расставить приоритеты при размещении собственных транзакций в цепочке для получения прибыли.
В области блокчейна майнеры могут получать прибыль, манипулируя транзакциями, которые они объединяют в блоки, например, исключая определенные транзакции и переупорядочивая транзакции. Такая прибыль может быть измерена с помощью извлекаемого майнером значения (MEV). Прежде чем транзакция пользователя будет добавлена в основную сеть Ethereum, большинство транзакций агрегируются в mempool. Майнеры ищут транзакции с более высокими ценами на газ в этом mempool и расставляют приоритеты для их упаковки, чтобы максимизировать свою прибыль. Как правило, майнерам легче заключать сделки с более высокими ценами на газ. Между тем, некоторые боты MEV также просматривают mempool в поисках прибыльных транзакций.

Специфическая логика


Ниже приведен пример. Билл обнаруживает новый популярный токен со значительными колебаниями цены. Чтобы обеспечить успех транзакций с токенами в Uniswap, Билл устанавливает исключительно широкий диапазон проскальзывания. К сожалению, MEV-бот Алисы обнаруживает эту транзакцию в mempool и быстро увеличивает плату за газ, инициируя транзакцию покупки перед транзакцией Билла и вставляя транзакцию продажи после транзакции Билла в пределах того же блока. После подтверждения блокировки это приводит к значительным потерям при проскальзывании для Билла, в то время как Алиса получает прибыль от арбитражной операции покупки по низкой цене и продажи по высокой.

Пример


Функция выглядит следующим образом:
solve(): Функция угадывания, в которой любой желающий может отправить ответ, и если отправленный ответ совпадает с целевым ответом, отправитель может получить 10 эфиров.



Процесс:
1. Билл находит правильный ответ.
2. Алиса отслеживает mempool, ожидая, пока кто-нибудь отправит правильный ответ.
3. Билл вызывает solve(), чтобы отправить ответ, и устанавливает цену на газ в 100 Гвей.
4. Алиса видит транзакцию, отправленную Биллом, и узнает ответ. Она устанавливает цену на газ выше, чем 200 Гвей Билла, и вызывает solve().
5. Транзакция Алисы упаковывается майнером раньше, чем транзакция Билла.
6. Алиса выигрывает награду в размере 10 эфиров.

Решение


Ниже приведены три основные функции:
commitSolution(): Функция для отправки результатов, помещающая отправленный пользователем ответ solutionHash, время отправки commitTime и выявленное состояние в структуру фиксации.
getMySolution(): Функция для получения результатов, позволяющая пользователям просматривать отправленные ими ответы и связанную с ними информацию, включая хэш решения отправленного пользователем ответа, время отправки, время фиксации и выявленное состояние.
revealSolution(): Функция получения вознаграждения за отгадывание головоломки, позволяющая пользователям получать вознаграждение после предоставления ответа и установленного ими пароля.





Процесс:
1. Билл находит правильный ответ.
2. Билл вызывает commitSolution(), чтобы отправить правильный ответ.
3. В следующем блоке Билл вызывает revealSolution(), предоставляя ответ и пароль, который он установил, чтобы получить вознаграждение.
В commitSolution() Билл отправляет зашифрованную строку, сохраняя данные открытого текста, отправленные только ему. На этом шаге также записывается время отправки блока commitTime. Далее, в revealSolution() проверяется время блока, чтобы предотвратить повторный запуск в пределах одного и того же блока. Поскольку вызов revealSolution() требует отправки ответа в виде открытого текста, этот шаг направлен на то, чтобы помешать другим пользователям обойти commitSolution() и напрямую вызвать revealSolution(). После успешной проверки вознаграждение будет распределено, если ответ будет проверен правильно.

Вывод


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

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

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

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

Рекомендации:
Надежность на примере
https://solidity-by-example.org/
Блокчейн-ноу-хау SlowMist
https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzU4ODQ3NTM2OA==&action=getalbum&album_id=1378673890158936067&scene=173&from_msgid=2247498135&from_itemidx=1&count=3&nolastread=1#wechat_redirect
Chainlink - Топ-10 лучших практик обеспечения безопасности DeFi
https://blog.chain.link/defi-security-best-practices/#post-title
WTF - Надежность 104 Безопасность контрактов

https://www.wtf.academy/solidity-104/
Уязвимости в смарт-контрактах DeFi в 4 категориях с 38 сценариями
https://www.weiyangx.com/381670.html
OpenZeppelin
https://github.com/OpenZeppelin/

  • Смайлы и люди
    Животные и природа
    Еда и напитки
    Активность
    Путешествия и места
    Предметы
    Символы
    Флаги