25 декабря 2023 года наша система мониторинга обнаружила серию вредоносных действий в отношении Telcoin. Мы помогли команде Telcoin определить первопричину, которой оказалась некорректная инициализация контрактов кошелька, возникшая из-за несоответствия между фактической реализацией кошелька и его соответствующим прокси. Цель данного отчета — предоставить тщательный анализ для полного понимания инцидента.
0x0: Базовая архитектура
Прежде чем рассматривать уязвимость, важно сначала понять взаимосвязи между задействованными смарт-контрактами. По сути, их можно представить как комбинацию трех шаблонов проектирования: CloneFactory, Cloneable Proxy и Beacon Proxy, которые изображены на следующей схеме.

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

В частности, внутри функции CloneableProxy:Proxy.initialize() происходит delegatecall, который вызывает функцию Wallet.initialize(). Этот вызов осуществляется через delegatecall к функции CloneableProxy:Implementation.initialize(). В результате любые изменения в хранилище, внесенные функцией Wallet.initialize(), отражаются в хранилище контракта CloneableProxy:Proxy.
Чтобы полностью понять последствия, необходимо изучить структуру хранилища контракта CloneableProxy:Proxy. Определение этого контракта выглядит следующим образом:

Учитывая, что ни контракты Proxy, ни ERC1967Upgrade не имеют переменных хранилища, ячейка 0 используется двумя переменными хранилища — _initialized и _initializing, — обе из которых унаследованы от контракта Initializable.

Теперь давайте рассмотрим контракт Wallet. Внутри функции Wallet.initialize() видно, что ячейка 0xaa служит флагом инициализации. Это подчеркивается следующим фрагментом кода в строках 3–4 и 11–12:

Обратите внимание, что ячейка 0 выделена для _state, которая хранит следующие 32 байта из calldata после селектора функции, как указано в строке 21. Для получения дополнительной детальной информации обратитесь к комментариям в начале контракта Wallet:

Наблюдается явное несоответствие в использовании ячейки 0: контракт CloneableProxy:Proxy интерпретирует ее как флаг инициализации, тогда как функция Wallet:initialize() рассматривает ее как состояние кошелька.
Следовательно, после процесса инициализации два младших байта ячейки 0 будут сброшены до нуля. Это фактически устанавливает значения _initialized и _initializing в ноль. В результате контракт CloneableProxy:Proxy становится уязвимым для повторной инициализации через функцию initialize(), поскольку защита модификатора initializer может быть обойдена.

Очевидно, что возможность эксплуатации зависит от состояния кошелька. После обновления до ненулевого значения состояние кошелька предотвращает любую дальнейшую повторную инициализацию этого контракта. После инициализации, по мере того как состояние кошелька обновляется с каждой транзакцией, вероятность того, что два младших байта ячейки 0 станут ненулевыми, возрастает, что эффективно защищает кошелек от повторной инициализации. Это объясняет, почему большинство уязвимых кошельков имели мало или вообще не имели истории транзакций, что делало их открытыми для атаки.
0x2: Анализ атаки
Злоумышленник начал с повторной инициализации уязвимого контракта CloneableProxy:Proxy, чтобы изменить адрес контракта Beacon. Впоследствии злоумышленник перешел к выводу активов, содержащихся в контракте CloneableProxy:Proxy, как подробно описано ниже:

Примечательно, что несколько уязвимых контрактов были скомпрометированы в рамках одной транзакции, и злоумышленник неоднократно применял эту стратегию.
0x3: Сводка атак
Мы зафиксировали в общей сложности 4 958 атак, выполненных с шести отдельных учетных записей, следующим образом:

0x4: Исправление и рекомендации
Наше расследование показало, что основная проблема заключается в несогласованном использовании ячейки хранилища 0, что привело к возможности повторной инициализации уязвимых контрактов. Очевидно, что исправление требует тщательного управления распределением хранилища.
Из этого инцидента мы извлекли несколько важных уроков:
-
Соблюдайте предельную осторожность при работе с ячейками хранилища с помощью встроенного ассемблера, так как ошибки могут привести к серьезным уязвимостям.
-
Поддерживайте бдительный мониторинг состояния контрактов. Способность быстро реагировать зависит от получения своевременных уведомлений.
-
Внедрите механизм приостановки (pause) в контракты, чтобы обеспечить немедленную остановку операций в случае обнаружения взлома.
Более того, тот факт, что этот инцидент включал множество транзакций атаки, нацеленных на разные контракты кошельков, подчеркивает острую необходимость в решениях для мониторинга угроз и блокировки атак, таких как Phalcon. Такие инструменты необходимы для минимизации будущих рисков и защиты от потенциальных потерь.
0x5: Хронология событий
09:23 PST, 25 декабря: Наша система обнаружила первую вредоносную транзакцию в сети Polygon:

10:28 PST, 25 декабря: Служба поддержки Telcoin сообщила об инциденте во внутреннем канале связи.
10:32 — 10:37 PST, 25 декабря: Участники команды Telcoin уведомили сообщество Telcoin в Discord и организовали экстренный звонок со всеми ключевыми членами команды.
10:45 PST, 25 декабря: Было внедрено правило Web Application Firewall для ограничения доступа к инфраструктуре Telcoin.
11:02 PST, 25 декабря: Команда Telcoin начала переговоры с Seal 911.
11:11 PST, 25 декабря: Командой Telcoin и другими специалистами по безопасности был создан оперативный штаб для выяснения первопричины проблемы и обсуждения возможных решений для блокировки атаки.
13:14 PST, 25 декабря: Команда Telcoin публично выпустила предупреждение для пользователей через X (Twitter):
15:39 PST, 25 декабря: Telcoin связался с Chainalysis и Slowmist для помощи в расследовании кражи средств, в ходе которого они пометили украденные кошельки и адреса и поделились этой информацией с биржами.

22:35 PST, 25 декабря: По приглашению команды Telcoin мы присоединились к оперативному штабу и поделились нашим анализом для определения первопричины.
С 23:00 PST 25 декабря до 02:06 PST 26 декабря: После определения первопричины команда Telcoin успешно разработала стратегию смягчения последствий, воспроизведя эксплойт в безопасной и контролируемой среде. Этот процесс включал повторную инициализацию прокси-кошельков для согласования с новым, безопасно реализованным beacon-контрактом. Учитывая, что этот эксплойт был одноразовой возможностью, Telcoin смог заранее обновить конфигурации кошельков, тем самым лишив злоумышленника возможности дальнейшей эксплуатации этих уязвимостей.
С 02:07 PST 26 декабря до 02:14 PST 26 декабря: Команда Telcoin внедрила процесс исправления для всех ранее не скомпрометированных кошельков для обеспечения полного покрытия. Для быстрого и эффективного развертывания процесс выполнялся пакетами в строго определенный промежуток времени. Затем Telcoin начал процесс подготовки и внутреннего тестирования плана восстановления для полного восстановления всех пострадавших кошельков и окончательного исправления для всех кошельков.
16:52 PST, 26 декабря: Telcoin и наша команда начали обсуждение следующих тем:
-
Обзор инцидента
-
Хронология событий: описание того, как развивался инцидент.
-
Анализ первопричин: глубокий анализ основных причин инцидента.
-
Рекомендации по улучшению
-
Аудит кода
12:27 PST, 29 декабря: После нескольких раундов обсуждений мы начали сотрудничать с командой Telcoin для подготовки пост-мортем отчета и аудита исправлений.
3 января 2024: Был предоставлен черновик пост-мортем отчета.
4 января 2024: Были представлены результаты нашего аудита, включая выявленные проблемы и рекомендации.
С 4 по 10 января 2024: Мы работали с командой Telcoin над завершением пост-мортем отчета и проверкой исправлений.
Также стоит отметить, что с 25 декабря по настоящее время Telcoin активно сотрудничает с фирмами по расследованию блокчейн-инцидентов и правоохранительными органами по поводу данного происшествия.
О компании BlockSec
BlockSec — это передовая компания в области безопасности блокчейнов, основанная в 2021 году группой всемирно известных экспертов по безопасности. Компания стремится повышать безопасность и удобство использования для развивающегося мира Web3, чтобы способствовать его массовому внедрению. Для достижения этой цели BlockSec предоставляет услуги по аудиту безопасности смарт-контрактов и EVM-сетей, платформу Phalcon для разработки безопасности и проактивной блокировки угроз, платформу MetaSleuth для отслеживания и расследования транзакций, а также расширение MetaDock для продуктивной работы разработчиков Web3 в криптомире.
На сегодняшний день компания обслужила более 300 уважаемых клиентов, таких как MetaMask, Uniswap Foundation, Compound, Forta и PancakeSwap, и получила десятки миллионов долларов США в двух раундах финансирования от выдающихся инвесторов, включая Matrix Partners, Vitalbridge Capital и Fenbushi Capital.
Веб-сайт: https://blocksec.com/



