Есть такие предприниматели — братья Уинклвосс; они известны, в частности, тем, что стояли у истоков социальной сети Facebook и даже получили в 2008 году компенсацию от Марка Цукерберга в размере 65 млн долларов. В 2013 году они крупно инвестировали в биткойны, купив около 1% всех существующих монет по цене в 120$ за штуку.
Чуть позже они открыли криптобиржу Gemini, а в 2018 году запустили стейблкойн Gemini dollar (GUSD). Стейблкойн — это криптовалюта с фиксированным курсом, один токен GUSD всегда стоит один USD. Стейблкойны удобны для того, чтобы «оцифровать» настоящие доллары. После этого блокчейн-доллары быстро и легко можно перемещать между биржами. Гарантом обратного обмена на доллары выступает фирма, их выпустившая и продавшая вам.
В рамках сервиса Kaspersky Smart Contract Source Code Review мы проанализировали смарт-контракт, который обеспечивает функционирование GUSD, и обнаружили существенный недостаток, о котором и хотим рассказать.
Работа смарт-контрактов простым языком описана здесь.
Принцип работы смарт-контракта Gemini Dollar
Как правило, когда кто-то хочет создать новые токены на базе блокчейна Ethereum, он пишет смарт-контракт (мини-программу), в которой описаны следующие моменты:
- Данные типа «у адреса такого-то столько-то токенов».
- Методы типа «прошу передать мои токены на такой-то адрес» и еще несколько других.
Но создатели системы Gemini Dollar дополнительно реализовали следующие улучшения:
- Они разделили контракт на три составляющие: Proxy (неизменный интерфейс, с которым держатели токенов могут взаимодействовать и проводить операции); Store (компонент, сопоставляющий держателей токенов их балансу); и Impl (собственно логика работы).
- Компонент, описывающий логику, спроектирован так, чтобы его можно было впоследствии обновлять, дополняя новыми функциями (возможностью замораживать средства и т. п.). При этом данные и интерфейс остаются неизменными, обновление происходит «прозрачно» для всех.
- Для обновления и управления используется отдельный смарт-контракт Custodian, которым для дополнительной защиты управляют несколько человек — так называемых «Попечителей». Один из них предлагает что-то сделать, другие соглашаются, и только после этого действие выполняется.
Надо признать, улучшения правильные и повышают общую защищенность, и одновременно дают гибкость.
Антиспам-платежи
Когда кто-то, кроме самого «Главного Попечителя», вносит предложение в контракт Custodian, он должен попутно внести залог в размере 1 ETH (на данный момент — порядка 200$). Как отмечено в комментариях к самому контракту, это своего рода защита от спама, чтобы участники не создавали слишком много заявок.
Любопытно, что все эти антиспам-платежи в итоге достаются одному лицу — тому, кто объявляет об одобрении конкретной заявки или предложения. Это достаточно спорная реализация, которая не выглядит справедливой, однако комментарии явно свидетельствуют, что так авторы и задумывали.
} else {
if (address(this).balance > 0) {
// reward sender with anti-spam payments
// ignore send success (assign to `success` but this will be overwritten)
success = msg.sender.send(address(this).balance);
Мы же со своей стороны рекомендуем использовать подход «Приди сам и забери свои деньги» (Solidity Withdrawal Pattern).
Атака Front-Running позволяет злоумышленнику украсть все антиспам-платежи
Итак, все антиспам-платежи в эфире получает тот, кто сообщает об одобрении заявки. Для этого он вызывает функцию смарт-контракта completeUnlock, а в параметрах передает подписи двух «Попечителей».
Проблема в том, что Ethereum, как любой другой блокчейн, не выполняет запросы мгновенно. Транзакция клиента (передача денег или вызов функции) какое-то время висит в очереди (обычно 15 секунд или дольше). В это время абсолютно любой может посмотреть планируемые переводы других пользователей Ethereum и увидеть суммы, получателей и параметры. При необходимости он может воспользоваться этой информацией, создать свою транзакцию и пропихнуть ее вперед всех подсмотренных, заплатив майнеру более высокую комиссию.
Если таким образом подсматривающий получил преимущество, то это считается атакой и называется фронтраннингом (Known Attacks: Front-Running).
Из финансового словаря investopedia.com:
Фронтраннинг — неэтичная и в некоторых случаях незаконная практика, когда брокер ставит свой собственный ордер перед крупным ордером клиента, который, по его мнению, приведет к движению рынка. Трейдеру от клиента поступает заказ на приобретение пакета ценных бумаг, однако он вначале покупает их для себя, а затем продает трейдеру или на рынке по более высокой цене.
В нашем случае совершенно посторонний человек может настроить робота, который будет внимательно следить за контрактом Custodian. Если он увидит, что кто-то вызывает функцию completeUnlock (то есть «Попечители» взаимодействуют с Gemini Dollar), он тут же скопирует все параметры и сам вызовет эту функцию, чтобы заполучить весь эфир, который там скопился.
Чтобы противостоять такой атаке, мы опять-таки рекомендуем использовать популярный подход «Приди сам и забери свои деньги» (Solidity Withdrawal Pattern).
Кроме того, мы рекомендуем запретить неизвестным лицам вызывать функцию, предназначенную для «Попечителей».
Практическая реализация атаки
Найденная уязвимость хоть и опасна в теории, на практике не так уж и страшна. И вот почему:
- Антиспам-платежи едва ли тревожат «Попечителей» такого серьезного проекта, как Gemini Dollar. Капитализация GUSD (общий объем выпущенных токенов) в свое время превосходила 100 млн долларов. Даже сейчас она составляет более 5 млн долларов.
- До сих пор антиспам-платежи еще не появлялись в этом контракте и могут так и не появиться, ведь «Главный Попечитель» вообще не обязан их вносить (все остальные обязаны).
- Зная об уязвимости, вполне можно не пользоваться уязвимой функцией; к тому же контракт можно обновить.
- В рамках обзора мы не обнаружили уязвимостей, подвергающих опасности сами токены GUSD, которые, по идее, и должны являться целью злоумышленников.
Вот заявление от самой Gemini: «Мы выбрали этот подход, потому что Gemini не намеревается осуществлять платежи в ETH при обычных условиях. Мы оценили риски и приняли решение не расширять и не усложнять нашу кодовую базу только ради реализации более надежного механизма восстановления существующего в теории и чисто номинального антиспам-платежа, так как практическая польза от этого несущественна. Приоритизация безопасного и простого кода остается наилучшим решением для системы Gemini dollar и ее пользователей. В будущем, возможно, мы пересмотрим это решение, если риски изменятся и станут актуальны более дорогостоящие и сложные контракты».
По согласованию с Gemini мы решили опубликовать эту статью в связи с тем, что антиспам-платежи подвергаются риску только при стечении определенных и маловероятных обстоятельств, а токенам GUSD ничто не угрожает.
Еще раз напоминаем всем о необходимости комплексно подходить к обеспечению безопасности при работе с криптовалютами и блокчейнами.