Уязвимости децентрализованной биржи

За последний месяц потери в результате хакерских атак на криптосообщество выросли до 1.019 млрд долларов (24.10), превысив показатели прошлых месяцев (без учета инцидента с Terra Luna).

Присмотревшись повнимательнее, мы видим, что основные эксплойты были совершены на платформах DEX (децентрализованная биржа), что составило почти 15% от общих потерь только в октябре.

Имея это в виду, давайте углубимся в три случая эксплуатации DEX и попробуем ответить на следующие вопросы:

  • Каковы основные причины уязвимостей DEX?
  • Как мы можем избежать их в будущем?

Обмен бананами

28 августа состоялась биржа токенов $DDC, Обмен бананами, подвергся нападению. Злоумышленник успешно манипулировал ценой монеты, нарушив внутреннюю логику расчета цены, и в результате обменял 23 доллара DDC на 110,105 XNUMX долларов США.

Уязвимость была довольно простой, но ее воздействие имело огромный потенциал для получения прибыли:

  1. Атака началась с перевода 26 долларов DDC на счет злоумышленника.
  2. Затем был инициирован поиск кошелька жертвы, чтобы найти кошелек, содержащий большое количество токенов.
  3. [Эксплуатация] Когда подходящая учетная запись была найдена, злоумышленник позвонил handleDeductFee который выполнил списание почти всех токенов с баланса жертвы
  4. Для того, чтобы завершить манипулирование ценой, функция sync был вызван для обновления значения/цены $DDC

В результате баланс $DDC в пуле был уменьшен до 0.0003 $DDC, после обновления значения/цены цена $USD, соответствующая $DDC, значительно повысилась, и можно было обменять большое количество долларов США. через небольшую сумму $DDC. Хакер использовал 23 доллара DDC для обмена на 104,600 XNUMX долларов США.

Так как же злоумышленник мог манипулировать балансом аккаунта жертвы? В чем был handleDeductFee функция выполняется?

Давайте посмотрим на код:

function handleDeductFee (ActionType actionType, uint256 feeAmount, address from, address user) external override {
	distributeFee(actionType, feeAmount, from, user);
}
// deduct the config fee and transfer to handle fee address which config.
// parameter from
function distributeFee (ActionType actionType, uint feeAmount, address from, address user) internal { 
	_balances [from] = _balances[from].sub(feeAmount);
	...
}

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

Злоумышленник передал адрес жертвы как from параметр и feeAmount было несколько меньше, чем в результате balanceOf этого адреса.

Вот и все! Ни одной проверки входящих данных. Никакой сложной теории за этим нет вообще.

кибер Безопасность 101: Никогда не доверяйте данным, контролируемым пользователем.

Дополнительную информацию можно найти в сообщении Beosin Alert в Твиттере. здесь.

Далее мы рассмотрим более сложный протокол. Но, как мы уже видели, отсутствие одной строки кода может привести к поломке всей системы.

Транзитный обмен

Транзитный обмен — мультицепочная платформа-агрегатор DEX, работающая в цепочках Ethereum и Binance. 1 октября платформа стала жертвой атаки, в результате которой из кошельков пользователей протокола были выкачаны активы на сумму почти 29 миллионов долларов.

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

Упрощенная версия потока данных выглядит примерно так:

Как я упоминал ранее, каждый из контрактов вызывает следующий, передавая аргументы в качестве параметров, так почему же это так критично?

«Основная причина этой атаки заключается в том, что протокол Transit Swap не строго проверяет данные, переданные пользователем во время обмена токенами, что приводит к произвольному внешнему вызову». – Анализ SlowMist

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

Это еще один случай проверки данных с более масштабной уязвимостью. Давайте перейдем к одной из самых больших потерь в этом году:

Биржа Майар – Сеть Элронд

Третья по прибыльности DEX-атака за все время была проведена на Майар DEX. Хакеры воспользовались уязвимой функцией, недавно развернутой в основной сети. Они успешно опустошили резервы протокола, похитив активы на 113 миллионов долларов.

Эксплойт начался с функции executeOnDestByCaller это позволило контракту A выполнять действия над контрактом C через прокси-сервер B. Контракт A вызовет функцию внутри B, которая позволяет B выполнять действия над C от имени контракта A.

Чтобы проиллюстрировать это, мы проиллюстрируем контракты A, B и C. Контракт A вызывает foo то есть внутри Б. foo звонки executeOnDestByCaller что позволяет B выполнить функцию bar Контракта С как самозванца А.

На практике Contract B может выполнять любую функцию от имени A, если A сделал первый вызов B. Эта идея уже звучит немного подозрительно.

Чтобы создать эксплойт с использованием этой функции, нужно выяснить, как заставить жертву вызывать контракт, а затем можно делать с этим контрактом все, что они хотят, используя внешние функции, которые он предоставляет, например transferFrom.

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

Если вы хотите погрузиться глубже, см. Официальный отчет Элронда и Срыв атаки Арды.

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

Ответы на вопросы

Зная то, что мы знаем сейчас, мы можем ответить на эти вопросы.

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

  1. С открытым исходным кодом — как мы все знаем, буква «D» в DEX означает «децентрализованный», что означает, что продукт управляется пользователями, и это делает код доступным для всего мира. Это облегчает поиск уязвимостей.
  2. Сложность обновления. Стоимость поиска и обновления уязвимости намного выше, чем в автономном приложении. Поскольку контракты загружаются в цепочку, исправление уязвимости означает загрузку новой копии контракта и перенаправление всех адресов со старого на новый, если не используется прокси-контракт.

Поэтому второго шанса у нас не будет. Мы должны убедиться, что контракт не содержит ошибок и безопасен, прежде чем загружать его в цепочку.

Аудит безопасности перед загрузкой и постоянный мониторинг угроз безопасности являются важными мерами в мире децентрализованных приложений.

Заключение

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

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

Написано
Итай Чередман

Итай — исследователь безопасности в Sayfer. Он увлечен пониманием и исследованием векторов атаки и защиты, которые появляются в новых технологиях.

перейти к содержанию