Объяснение пародийной библиотеки

Итак, сегодня уязвимость, обнаруженная в библиотеке паритета Parity, которая привела к замораживанию потенциально сотен миллионов долларов из кошельков с использованием паритета multi-sig. Может ли кто-то технически объяснить, как это злоупотребляли?

Вот ссылка на уязвимый код

16 голосов | спросил NowsyMe 7 22017vEurope/Moscow11bEurope/MoscowTue, 07 Nov 2017 22:10:53 +0300 2017, 22:10:53

2 ответа


6

Библиотеки на Ethereum

Во-первых, есть три способа вызова функции в контракте. CALL, CALLCODE, и DELEGATECALL .

Библиотеки на Ethereum в основном реализованы с помощью DELEGATECALL. Смысл, вы развертываете контракт, который служит библиотекой - у него есть некоторые функции, которые любой может вызвать, и могут даже изменить хранилище вызывающего контракта.

У Solidity есть синтаксический сахар, который позволяет вам объявить библиотеку library, которая делает все DELEGATECALL для вас, если вы используете библиотеку в своем контракте. Но на уровне EVM это то же самое, что развернуть их как contract s.

Контракт библиотеки четности

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

Тогда все остальные мультисайговые кошельки имеют это в своем коде:

address constant _walletLibrary = 0x863df6bfa4469f3ead0be8f9f2aae51c91a907b4

Поскольку он является константой, он заполняется во время компиляции, то есть он постоянно хранится в «коде», а не «в хранилище». Значение будет адресом библиотеки для DELEGATECALL on. Если вы запустите eth.getCode(walletAddress) на одном из поврежденных кошельков, вы должны увидеть адрес теперь мертвой библиотеки в индексе 422.

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

Убивание договора библиотеки

Поскольку сама библиотека является рабочим кошельком, , и она осталась неинициализированной , любой пользователь мог бы вызвать initWallet в контракте библиотеки. «Хакер» сделал это в этой транзакции . Звонок совершенно легален, нулевые трюки, так как он просто инициализирует кошелек, который не был инициализирован.

Теперь, когда он является владельцем библиотечного контракта, он может назвать любую привилегированную функцию, которую он хочет. Поэтому он вызвал kill в этой транзакции . Функция kill в основном вызывает suicide (которое теперь заменяется на selfdestruct), они делают то же самое). suicide уничтожает контракт, очищает хранилище и код , отправляя оставшиеся средства владельцу. (Который равен нулю, поскольку в библиотечном контракте нет средств)

Код становится нулевым

Теперь каждый вызов функции в теперь мертвой библиотеке просто возвращает false или 0.

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

Многосходные кошельки по существу заперты. Большинство функций (включая функцию kill-switch) полагаются на библиотеку, которая теперь возвращает ноль для каждого вызова функции.

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


Можете ли вы статически связывать библиотеки?

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

ответил libertylocked 13 12017vEurope/Moscow11bEurope/MoscowMon, 13 Nov 2017 07:51:50 +0300 2017, 07:51:50
21

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

Невольно пользователь взял на себя управление этим контрактом библиотеки, вызвав функцию initWallet в контракте с библиотекой, что дало ему право на участие в библиотечном контракте, поскольку оно не было инициализировано (поскольку это был контракт с библиотекой ) и переменная only_uninitialized не была установлена. UPDATE: Этого можно было избежать, если после того, как Parity развернул контракт с библиотекой, он вызвал initWallet один раз, чтобы потребовать контракт и установить инициализированную переменную. Источник

Затем пользователь самоубийства самоуничтожился , стирая функциональность для ~ 500 кошельков с несколькими сигами и эффективно, необратимо замораживая ~ 150 миллионов долларов. Требуется жесткая вилка для восстановления контракта и /или возврата средств .

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

Тем не менее, Паритет не ожидал, что сценарий этого договора библиотеки будет суицидом.

Здесь - отличная статья из Арагона по библиотеке -раздельная разработка интеллектуальных контрактов.

Буклеты, развернутые до 19 июля, использовали другой контракт библиотеки с аналогичной ошибкой initWallet, но контракт Library не мог быть принят таким же образом, как он уже был инициализирован разработчиков в Parity.

Update:

При дальнейшей проверке появляется, что контракт WalletLibrary был инициализирован с использованием contract вместо library, с фактическими кошельками, делающими простой DELEGATECALL к этому тонко связанному интеллектуальному контракту, вместо использования рекомендуемой практики реализации library и using it. Это делает библиотеку более похожей на Синглтон , чем Библиотека .

ответил valkn0t 7 22017vEurope/Moscow11bEurope/MoscowTue, 07 Nov 2017 22:35:50 +0300 2017, 22:35:50

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132