Back to Blog

№10: Инцидент с ThirdWeb: несовместимость доверенных модулей привела к обнаружению уязвимости

Code AuditingPhalcon Security
February 22, 2024
7 min read
Key Insights

5 декабря 2023 года известная платформа для разработки Web3-приложений Thirdweb сообщила о критических уязвимостях в безопасности своих готовых смарт-контрактов. Этот серьезный изъян затронул все токены стандартов ERC-20, ERC-721 и ERC-1155, развернутые с использованием этих конкретных уязвимых контрактов. В дни, последовавшие за раскрытием информации, токены, развернутые с помощью данных контрактов, стали подвергаться серии атак, что подчеркнуло всю серьезность имеющейся несовместимости.

Понимание уязвимости смарт-контрактов ThirdWeb

Первопричина инцидента ThirdWeb кроется в непредвиденном взаимодействии двух фундаментальных компонентов разработки смарт-контрактов: ERC-2771 и реализации Multicall от OpenZeppelin. Чтобы полностью осознать суть уязвимости, важно сначала понять каждый компонент по отдельности, а затем проследить, как их взаимодействие создало вектор для атаки.

ERC-2771: Метатранзакции и доверенные ретрансляторы

EIP-2771 определяет протокол на уровне контракта, который позволяет контрактам-получателям (Recipient) принимать метатранзакции через доверенные контракты-ретрансляторы (Forwarder). Этот стандарт крайне важен для улучшения пользовательского опыта, поскольку он позволяет третьим сторонам (ретрансляторам) оплачивать комиссию за газ от имени пользователей, избавляя их от необходимости владеть нативными токенами блокчейна.

На практике широкое распространение получила реализация ERC2771Context от OpenZeppelin. Её основная функциональность заключается в том, что последние 20 байт calldata от доверенного ретранслятора интерпретируются как фактический _msgSender(). Для разработчиков, использующих эту библиотеку, общепринятой практикой является замена всех прямых обращений к msg.sender на _msgSender(), чтобы обеспечить совместимость с метатранзакциями. Аналогично, _msgData() используется для получения исходных данных транзакции без учета добавленной информации об отправителе.

function _msgSender() internal view virtual override returns (address) {
    uint256 calldataLength = msg.data.length;
    uint256 contextSuffixLength = _contextSuffixLength();
    if (isTrustedForwarder(msg.sender) && calldataLength >= contextSuffixLength) {
        return address(bytes20(msg.data[calldataLength - contextSuffixLength:]));
    } else {
        return super._msgSender();
    }
}

function _msgData() internal view virtual override returns (bytes calldata) {
    uint256 calldataLength = msg.data.length;
    uint256 contextSuffixLength = _contextSuffixLength();
    if (isTrustedForwarder(msg.sender) && calldataLength >= contextSuffixLength) {
        return msg.data[:calldataLength - contextSuffixLength];
    } else {
        return super._msgData();
    }
}

Multicall: Пакетная обработка транзакций для повышения эффективности

Функциональность Multicall позволяет пользователям объединять несколько вызовов функций в одну транзакцию, что значительно снижает затраты на газ и повышает эффективность транзакций. MulticallUpgradeable от OpenZeppelin — популярная реализация для этих целей. Она принимает массив байтов данных (calldata) и выполняет delegatecall для каждого элемента, запуская их в контексте вызывающего контракта.

function multicall(bytes[] calldata data) external virtual returns (bytes[] memory results) {
    results = new bytes[](data.length);
    for (uint256 i = 0; i < data.length; i++) {
        results[i] = _functionDelegateCall(address(this), data[i]);
    }
    return results;
}

(Примечание: Описанная здесь ошибка была исправлена в более поздних версиях Multicall от OpenZeppelin.)

Несовместимость: Конфликт ERC-2771 и Multicall

Суть уязвимости смарт-контрактов в инциденте с ThirdWeb проистекает из критического несоответствия в том, как данные вызовов (calldata) обрабатываются стандартами ERC-2771 и Multicall. ERC-2771 ожидает, что доверенный ретранслятор упакует данные сообщения и информацию об отправителе вместе. Затем контракт-получатель использует _msgData() и _msgSender(), чтобы правильно распаковать эту информацию.

Однако функция Multicall в своей уязвимой версии не была рассчитана на совместимость с тем, как ERC-2771 упаковывает данные для метатранзакций. В частности, когда Multicall обрабатывает пакет вызовов, он должен был корректно извлечь _msgSender() из первоначальной метатранзакции, а затем добавлять эту информацию об отправителе к данным каждого отдельного вызова перед их исполнением. Этот важный шаг отсутствовал.

Поскольку информация об отправителе не добавлялась должным образом к данным каждого подвызова, обрабатываемого Multicall, контекст ERC-2771 в целевом контракте пытался распаковать информацию об отправителе из последних 20 байт _msgData() самого подвызова. Важно отметить, что злоумышленник мог контролировать эти последние 20 байт. Это позволяло атакующему создать специфические данные вызовов, которые при обработке функцией Multicall и последующей интерпретации контрактом с поддержкой ERC-2771 выполняли произвольную логику с подделанным значением _msgSender() (например, адрес, контролируемый злоумышленником, или даже адрес пула самого протокола). Это фактически обходило предназначенные проверки безопасности и нарушало ожидания, установленные обеими спецификациями, что приводило к несанкционированным действиям.

Инцидент с ThirdWeb: Анализ атаки и эксплуатации

Давайте рассмотрим пример из реальной жизни, связанный с использованием данной уязвимости в смарт-контрактах ThirdWeb, с помощью транзакции атаки, проанализированной платформой Phalcon от BlockSec.

Стратегия злоумышленника заключалась в манипуляции _msgSender() для выдачи себя за пул Uniswap, что позволило истощить его баланс токенов.

  • Шаг 1: Первичное получение токенов. Атакующий начал с обмена 5 WETH на 3 455 399 346 токенов TIME на децентрализованной бирже. Это дало необходимые токены для последующей манипуляции.

  • Шаг 2: Исполнение вредоносного Multicall. Это суть эксплойта. Злоумышленник обратился к доверенному ретранслятору со специально подготовленными байтами данных, предназначенными для использования несовместимости ERC-2771 и Multicall. Когда эти данные были обработаны функцией Multicall, была вызвана функция burn контракта токена TIME. Важно отметить, что из-за уязвимости _msgSender() был неверно интерпретирован как адрес пула Uniswap. Это позволило злоумышленнику фактически сжечь значительную часть токенов TIME, хранившихся в пуле Uniswap, без реального разрешения. Платформа BlockSec Phalcon предоставляет детальное отслеживание транзакций для визуализации этого процесса.

    Трассировка транзакции, демонстрирующая вредоносный multicall
    Трассировка транзакции, демонстрирующая вредоносный multicall

    На изображении выше показано, как обрабатывается вызов Forwarder.execute от злоумышленника. Функция multicall получает массив байтов, что затем приводит к вызову функции burn с подделанным _msgSender().

    Детальный вид разбора multicall и вызова функции burn
    Детальный вид разбора multicall и вызова функции burn

    Этот детальный вид из Phalcon показывает bytes[] длиной 1, используемый в качестве данных для вызова контракта, что приводит к выполнению функции burn под ложным _msgSender().

  • Шаг 3: Манипуляция ценой. Сжигая большое количество токенов TIME из пула Uniswap, злоумышленник радикально снизил ликвидность пула для TIME. Это искусственное сокращение предложения привело к резкому росту цены TIME по отношению к WETH внутри пула.

  • Шаг 4: Прибыльный арбитраж. При искусственно завышенной цене TIME злоумышленник обменял свои оставшиеся 3 455 399 346 токенов TIME обратно на 94 WETH, получив существенную прибыль на манипуляции ценой.

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

Обеспечьте безопасность ваших смарт-контрактов с BlockSec

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

Лучший аудитор безопасности для Web3

Проверка дизайна, кода и бизнес-логики перед запуском

Основные выводы и уроки инцидента с ThirdWeb

Инцидент с ThirdWeb служит тревожным напоминанием о сложности, присущей безопасности Web3, особенно в отношении взаимодействия сторонних библиотек.

  • Риски взаимодействия: В стремительно развивающемся DeFi-пространстве проекты сильно зависят от набора сторонних библиотек и модулей. Хотя эти компоненты ускоряют разработку, их взаимодействие может приводить к неожиданным и скрытым уязвимостям. Инцидент с ThirdWeb наглядно демонстрирует, что даже широко используемые и кажущиеся надежными компоненты, такие как ERC2771Context и MulticallUpgradeable от OpenZeppelin, могут создавать критические бреши в безопасности, если их интеграция не проработана досконально.
  • Глубокий технический аудит обязателен: Этот тип уязвимости смарт-контрактов непросто обнаружить поверхностными проверками. Требуется глубокая техническая экспертиза для анализа того, как разные модули обрабатывают и интерпретируют данные, особенно calldata, и для выявления возможных несоответствий. Тщательный аудит смарт-контрактов с акцентом на взаимодействия между модулями и пограничные случаи имеет первостепенное значение.
  • Непрерывный мониторинг и реагирование на инциденты: Даже при наличии надежного аудита могут появляться новые векторы атак. Постоянный мониторинг безопасности блокчейна, подобный тому, что предоставляет Phalcon от BlockSec, критически важен для обнаружения подозрительной активности в режиме реального времени и быстрого реагирования на инциденты для минимизации ущерба.
  • Выход за рамки безопасности отдельных модулей: Разработчики должны мыслить шире, чем просто безопасность отдельных компонентов, и учитывать целостную систему безопасности всего стека смарт-контрактов. Как потоки данных проходят между модулями, как сохраняются или изменяются контексты и как обрабатываются внешние вызовы — всё это критически важные аспекты.

Инцидент с ThirdWeb подчеркивает важность проактивного и комплексного подхода к безопасности блокчейна. Полагаться только на репутацию отдельных библиотек недостаточно; взаимодействия между ними должны подвергаться строгой проверке.

Расследуйте ончейн-инциденты с помощью Phalcon

Phalcon от BlockSec — это ведущая платформа безопасности Web3 для мониторинга в режиме реального времени, реагирования на инциденты и углубленного анализа транзакций. Разбирайтесь в сложных взломах, подобных инциденту с ThirdWeb, с непревзойденной ясностью.

Начните работу с Phalcon Security

Обнаруживайте все угрозы, получайте оповещения о важном и блокируйте атаки.

Попробовать бесплатно

Читайте другие статьи из этой серии:

Best Security Auditor for Web3

Validate design, code, and business logic before launch. Aligned with the highest industry security standards.

BlockSec Audit

Get Real-Time Protection with Phalcon Security

Audits alone are not enough. Phalcon Security detects attacks in real time and blocks threats mid-flight.

phalcon security