ИнцидентыSmartAlert7 мин чтения

Взлом Orbit Bridge, декабрь 2023: $81,5 млн ушли из хранилища пятью выводами за 17 минут

Как шёл взлом Orbit Bridge в декабре 2023: $81,5 млн пятью выводами, когда пришёл бы алерт по порогу в $ и сколько ещё лежало в хранилище.

Вечером 31 декабря 2023 года (UTC) атакующий опустошил хранилище Orbit Bridge в Ethereum: около $81,5 млн в DAI, WBTC, ETH, USDC и USDT12. Orbit подтвердила инцидент той же ночью13.

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

Как устроено хранилище Orbit Bridge

Orbit Bridge, который ведёт корейская компания Ozys, переносит токены между Orbit Chain и другими сетями. В Ethereum все перенесённые токены лежат в одном контракте — хранилище 0x1Bf6…489a2.

  • Депозит. Пользователь отправляет токены в хранилище в Ethereum и получает обёрнутые токены в Orbit Chain.
  • Вывод. Пользователь сжигает обёрнутые токены в Orbit Chain. Валидаторы моста видят сжигание, и каждый подписывает сообщение о выводе.
  • Выдача. Затем кто угодно может вызвать withdraw у хранилища с этими подписями. Хранилище проверяет, что подписало достаточно его владельцев, помечает сообщение использованным, чтобы его нельзя было повторить, и отправляет токены.

Хранилище — мультисиг. До атаки у него было 10 владельцев и нужно было 7 подписей: мы прочитали getOwners() и required() на блоке 18907899, за один блок до первой транзакции атакующего4. Десять ключей и порог 70% звучат надёжно. Надёжны они, только пока никто в одиночку не может получить семь из них.

Хранилище не отличает настоящее сжигание в Orbit Chain от выдуманного. Оно видит только подписи. Есть семь верных подписей — токены уходят.

Атака по шагам

Время — UTC, время блоков Ethereum. Каждую транзакцию ниже мы прочитали в сети сами4. Каждый вывод вызывал withdraw у хранилища минимум с семью подписями его владельцев, и хранилище приняло их все.

20:40:35 — проба на 0,012 WBTC

С адреса 0xdc54…c522 атакующий вывел 0,0120879 WBTC на 0x9ca5…4049 (0x9e51…b589). Через полчаса тот же адрес получил 230 WBTC. Несколько сотен долларов — это проба: атакующий проверил, что подписи работают.

20:52:47 — 30 ETH

Основной адрес атакующего 0x9263…6AfF вывел 30,095 ETH на 0x27E2…5710 (0x958a…5f16). Нативный ETH уходит из хранилища внутренним переводом, без события Transfer. По данным Rekt, именно 20:52 Orbit называет временем первого несанкционированного доступа2.

С 21:07:59 до 21:25:35 — хранилище пустеет

21:07:59
Что ушло из хранилища10 000 000 DAI
Транзакция0xafdc…07ca
21:10:59
Что ушло из хранилища230,88 WBTC (~$9,8 млн)
Транзакция0xe0ba…71f9
21:16:59
Что ушло из хранилища9 500 ETH (~$21,5 млн)
Транзакция0x639d…ae0a
21:25:11
Что ушло из хранилища10 000 000 USDC
Транзакция0x64a6…3f0e
21:25:35
Что ушло из хранилища30 000 000 USDT
Транзакция0xd8ca…0ac8

Суммы в долларах — по данным Orbit и Rekt на момент инцидента12. WBTC ушёл на адрес пробы, остальное — каждый раз на новый адрес.

Здесь порог по сумме работает. $10 млн в DAI из хранилища моста одной транзакцией — это не обычный трафик пользователей.

То же правило на WBTC, USDC и USDT и правило «Общий баланс адреса в $ ниже порога» на хранилище с порогом около $75 млн сработали бы примерно тогда же — от DAI и WBTC. Ещё один алерт в ту же минуту не добавляет времени. Он подтверждает, что это не ошибка.

22:21:35 — хранилище выключено

В 22:21:35 адрес 0x4C35…4d05 вызвал changeActivate(false) у хранилища (0xedfc…13f4). С этого блока хранилище отказывало в выводе. withdraw на 300 000 USDC в 22:26:23 откатился (0x0958…705b)4.

Это было через 74 минуты после вывода DAI и через 56 минут после последнего вывода. Хранилище к тому времени почти опустело.

После хранилища — куда ушли деньги

Атакующий начал выводить средства дальше в течение получаса: USDC с 21:50, USDT с 22:13, WBTC с 22:444. По данным Rekt, стейблкоины и WBTC обменяли на ETH, а адреса атакующего изначально пополнили через Tornado Cash2. В июне 2024 года атакующий отправил в Tornado Cash 8 671 ETH, около $32 млн6.

Сообщений о заморозке этих адресов эмитентами USDT и USDC мы не нашли.

Что Orbit сказала о причине

Ozys заявила, что ошибки в контрактах не было7. В январе 2024 года она подала в суд на своего бывшего директора по информационной безопасности. По её словам, он ослабил правила файрвола в ноябре 2023 года и ушёл из компании в начале декабря, за три недели до атаки7. Как атакующий получил семь верных подписей, публично не объяснено. Мы не гадаем.

Что не изменило бы ни одно правило

Как поставить такие правила в SmartAlert

  1. Добавьте каждый токен, который хранит хранилище. Для Orbit это DAI, WBTC, USDC и USDT.
  2. На каждом создайте правило перевод больше суммы в $ с from = ваше хранилище. Порог берите из своего трафика: выше самого крупного обычного вывода пользователя и сильно ниже суммы в хранилище. Сумма считается по цене на блоке перевода, поэтому порог не плывёт вместе с ценой. Тариф Pro и выше.
  3. Проверьте порог до включения. Правило в $ читает цены только с момента создания, поэтому на прошлых переводах его не проверить. Подберите порог правилом крупный перевод в токенах: оно показывает на прошлых данных, как часто сработало бы. Если каждый день — поднимите порог.
  4. Добавьте и нативный ETH. ETH не выпускает Transfer. Добавьте хранилище в «Адреса» и создайте правило «Общий баланс адреса в $ ниже порога» с порогом чуть ниже обычной суммы.
  5. Отправляйте эти алерты тем, кто может выключить хранилище. Telegram бесплатный. Держатель этого ключа должен получать их напрямую, а не через общий канал, который читают утром.

Все рецепты алертов.

Переезжаете с OpenZeppelin Defender? Как каждый монитор Defender переносится в правило SmartAlert — в руководстве по переезду, а сравнение с Defender — отдельной страницей.

Источники

  1. 1.Orbit Chain, Official statement regarding Orbit Bridge exploit: суммы и украденные токены. ↩
  2. 2.Rekt, Orbit Bridge — Rekt: хронология, 20:52 как первый несанкционированный доступ, обмен в ETH, пополнение атакующего через Tornado Cash. ↩
  3. 3.Orbit Chain в X, сообщение об инциденте. ↩
  4. 4.Проверено SmartAlert в сети: required() = 7 и getOwners() = 10 адресов у хранилища на блоке 18907899 (архивный eth_call); каждая транзакция в посте — время блока, отправитель, получатель и сумма — через Blockscout API; откатившийся вывод в 22:26:23. ↩
  5. 5.SmartAlert, задержка алерта в Ethereum: 12 подтверждений (около 144 с), опрос головы сети до 12 с, запись до 15 с (P95), проверка правила раз в 60 с на Pro. ↩
  6. 6.Forklog, Orbit hacker funnels $32 million into Tornado Cash. ↩
  7. 7.The Block, материал об Ozys и её бывшем директоре по безопасности: ошибки в контрактах нет, изменение файрвола в ноябре 2023 года, уход в декабре, иск. ↩
  8. 8.CertiK, Bybit incident technical analysis. ↩
  9. 9.KiloEx, Security incident root cause analysis. ↩

Попробуйте бесплатно

Достаточно адреса. Первые 14 дней действуют лимиты Pro, а правила проверяются на истории до включения.

Ещё статьи