18 мая 2021

Классическая атака Fake Stake на протоколы Proof-of-Stake

Перевод выполнен исследовательской командой CoinIndex и межавторским коллективом CryptoHedwig. Кому интересна самая суть протоколов и жесткая математика, научные статьи и исследования в крипте — подписывайтесь на наш канал Hedwig UnChained — там никаких токенов, только хардкор! 

Proof-of-Stake (PoS) криптовалюты, особенно те, которые на базе PoSv3  (Proof-of-Stake версия 3), похожи на Биткоин в том, что они используют модель UTXO и правила консенсуса самой длинной цепочки. Ключевое отличие состоит в том, что они заменяют Proof-of-Work на Proof-of-Ownership монет.

Потенциальные преимущества подхода PoS варьируются от снижения воздействия на окружающую среду до повышения безопасности против атаки 51%. Многие криптовалюты на самом деле являются форками (или, по крайней мере, наследниками) кодовой базы Биткоина с привитой функциональностью PoS. Так как некоторые идеи просто копируются, это приводит к новым уязвимостям, которых не было в исходной кодовой базе.

Обнаруженные уязвимости мы называем атаками «Fake Stake». По сути, они работают, потому что реализации PoSv3 не проводят адекватную проверку сетевых данных перед фиксацией ценных ресурсов (диска и памяти). Следствием этого является то, что злоумышленник без большого стейка (а в некоторых случаях и  вообще без него) может привести к отказу узла-жертвы, заполнив его диск или оперативную память фальшивыми данными.

Мы считаем, что все валюты, основанные на UTXO и модели Proof-of-Stake с самой длинной цепочкой, уязвимы для «Fake Stake». Список исследованных нами крипто-валют, которые, по нашему мнению, подвержены этим атакам, приведен в конце статьи.

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

Основы

Прежде чем вдаваться в подробности уязвимостей, мы дадим некоторую предысторию того, как работает proof-of-stake в блокчейне.

Майнинг Proof-of-Stake

Подобно майнингу Proof-of-Work, майнинг в PoS состоит из сравнения хэша заголовка блока с целевой сложностью. Высокоуровневая цель PoS — гарантировать, что шанс каждой заинтересованной стороны добыть следующий блок пропорционален количеству монет, которые они контролируют. Для достижения этого в PoS блокчейнах хэш зависит не только от заголовка блока, но и от количества монет, включенных в специальную транзакцию «coinstake», вставленную в блок заинтересованным лицом.

Детали PoS-майнинга могут быть несколько сложными, подробное объяснение можно найти в посте блога earlz. Для наших целей важно то, что проверка PoS зависит от

  1. транзакции коинстейка
  2. UTXO, потраченного на транзакцию коинстейка.

Роль Proof-of-Work в защите ресурсов проверки блока:

Хорошо известно, что Proof-of-Work (PoW) играет важную роль в консенсусе Биткоина. Но Proof-of-Work также играет вторую, несколько менее важную роль — защищает доступ к ограниченным ресурсам узла, таким как пространство диска, пропускная способность, память и CPU. В публичной криптовалютой сети нельзя доверять одноранговым узлам.

Итак, чтобы предотвратить атаки на исчерпание ресурсов, узлы Биткоин сначала проверяют PoW на наличие любых полученных блоков, прежде чем выделять дополнительные ресурсы, такие как сохранение блока в ОЗУ или на диске. Однако оказывается, что проверка Proof-of-Stake намного сложнее и контекстно-зависима, чем проверка Proof-of-Work. В результате многие реализации PoS блокчейнов обходятся без соответствующей проверки.

Чтобы понять, как это приводит к уязвимости, связанной с исчерпанием ресурсов, мы должны подробно рассказать о том, как блоки хранятся перед валидацией. Узел должен не только отслеживать самую длинную цепочку в текущий момент, но и дерево форков (любая из них может оказаться самой длинной цепочкой, и в этом случае узлу необходимо «реорганизоваться», чтобы переключиться на нее). Это может произойти, например, во время неудачного обновления, атаки с двойной тратой (атака 51% на ETC) или временного разделения сети.

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

Есть два основных подхода к полной валидации блоков при форке:

  1. Откат текущего состояния UTXO до точки перед началом форка, или
  2. хранить копии UTXO для всех предыдущих блоков.

Кодовая база Биткоина не поддерживает Вариант 2, и даже если бы это было сделано, это потребовало бы дополнительных затрат на хранение (производительность узла Биткоин зависит от агрессивного удаления ненужных данных).

Вариант 1 — это именно то, как кодовая база Биткоина в настоящее время обрабатывает реорганизацию. Однако это может быть очень дорого, поэтому откат и полная проверка откладываются до последнего возможного момента, когда Proof-of-Work в форке уже превышает текущую основную цепочку.

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

Перед сохранением блока на диск кодовая база Биткоина выполняет некоторую предварительную проверку на основе PoW (но игнорируя транзакции). Эта предварительная проверка зависит только от заголовка предыдущего блока и текущего заголовка, поэтому узел может сделать это очень быстро.

И это эффективная защита, потому что создание действительного PoW, которое его проходит, очень дорого. Например, несмотря на то, что можно обмануть узел Биткоин, чтобы он сохранил недопустимый блок на диске, организовать такую атаку исчерпания ресурсов будет непомерно дорого.

Аналогичная предварительная проверка в PoS заключается в проверке транзакции стейкинга и проверке того, что она проходит целевую сложность при хешировании с ядром предыдущего блока. Вычислить хеш стейкинг транзакции легко, но самая сложная часть — это проверка того, является ли входной UTXO для транзакции действительным и неизрасходованным, поскольку для этого требуется проверка набора UTXO, который, как упоминалось ранее, недоступен для предыдущих блоков.

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

Уязвимость №1: «Не могу поверить, что это не стейк»

Когда мы впервые исследовали эту проблему, мы обнаружили, что пять криптовалют, Qtum, Particl, Navcoin, HTMLcoin и Emercoin, демонстрируют довольно тривиальную форму этой уязвимости: а именно, они вообще не могут проверить любую стейкинг транзакцию перед фиксацией блока в ОЗУ или диск. Эти криптовалюты объединяет то, что они адаптировали функцию Биткоина «headers first», в которой распространение блоков было разделено на два отдельных сообщения: блок и заголовок.

Узлы запрашивают блок только после того, как заголовок проходит проверку PoW, и это самая длинная цепочка. Поскольку стейкинг-транзакция присутствует только в блоке, но не в заголовке, узел не может проверить заголовок самостоятельно. Вместо этого он напрямую сохраняет заголовок в структуре данных в памяти (mapBlockIndex).

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

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

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

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

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

Любая из этих уязвимостей может быть осуществлена без стейкинга в атакуемой сети. Версия атаки с оперативной памятью особенно тривиальна, но по техническим причинам версия атаки на дисковое пространство требует немного большей осторожности (хотя и тут стейкиг не требуется).

Более подробно об этом можно ознакомиться в небольшом документе Financial Cryptography 2019.

Уязвимость №2 и атака «Spent Stake»

Отслеживая происхождение этих кодовых баз, мы заметили, что уязвимость №1 была изначально представлена ​​при объединении функции Биткоина «сначала заголовок» в кодовую базу PoSv3.

Атака не работает на более ранних версиях (например, Peercoin), потому что есть две дополнительные предварительные проверки перед сохранением блоков на диске:

  1. Проверка, существует ли расходуемый выход в основной цепочке.
  2. Проверка, соответствует ли хэш ядра PoS целевой сложности.

Проверка 1 выполняется путем поиска в TxDB, базе данных транзакций, которая отслеживает все транзакции в текущей основной цепочке на данный момент.

Другими словами, предварительная проверка лучше, чем отсутствие проверки, но все же эвристическое и неполное приближение к полной проверке. Если вы дочитали до этого момента и понимаете о чем речь, то догадываетесь о наличии следующих проблем:

Проблема A: Проверка 1 гарантирует, что монета существует, но НЕ то, что она неизрасходована. Это понимание сразу же приводит к уязвимости, которую мы обсудим далее.

Проблема B: даже если мы проверяем блок в форке основной цепи, стейкинг транзакция проверяется по TxDB для самой основной цепочки.

Основываясь на проблеме А, мы нашли способ обмануть и эти проверки, используя более тонкую атаку, которую мы называем «атакой израсходованного стейка« (spent stake attack). Чтобы обойти проверку 1, мы используем вывод, который виден узлу, но уже израсходован.

Как правило, чтобы обойти Проверку 2, нам нужно добыть действительный блок, который проходит целевую сложность, что, в свою очередь, требует большего стейка. Однако оказывается, что мы можем злоупотребить неполной проверкой, чтобы сгенерировать произвольную сумму предполагаемого стейка, используя технику, которую мы называем «усилением стейка« (Stake Amplification).

Усиление ставки (Stake Amplification)

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

Только UTXO (n + 1) должен быть разрешен для стейкинга, но из-за проверки 2 выше мы можем делать ставки со всеми UTXO от 1 до n + 1, тем самым увеличивая кажущуюся ставку на n * k. Это увеличивает шансы найти блок PoS, поскольку злоумышленник может продолжать делать это, чтобы увеличить свою предполагаемую ставку. Иллюстрация «stake amplification step» в левой части рисунка.

Например, даже имея 0,01% доли в системе, злоумышленнику нужно всего 5000 транзакций, чтобы добыть блоки с кажущейся долей 50%. После того, как злоумышленник собрал большую сумму такого “видимого” стейка, он переходит к добыче блоков PoS задним числом, используя только что собранные выходные данные ложного стейка.

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

Скоординированное раскрытие уязвимостей

Сначала мы исследовали Уязвимость №1 в контексте криптовалют Particl и Qtum. Чтобы определить степень этой уязвимости, мы собрали список известных криптовалют на сайте coinmarketcap.com (9 августа 2018 г.), отсортированный по рыночной капитализации и по типу консенсуса PoS. Мы смотрели только на криптовалюты, кодовая база которых была создана на основе Биткоина.

В общей сложности мы исследовали 26 криптовалют и обнаружили, что только пять криптовалют (Qtum, Navcoin, HTMLcoin, Emercoin и Particl) были затронуты, но наша атака, похоже, не сработала с остальными. Чтобы подтвердить уязвимость, мы реализовали атаки в каждой из пяти затронутых кодовых баз. Мы использовали существующие наборы тестов в программном обеспечении Биткоина, в частности, regtest режим, который позволяет моделировать временные метки и легко создавать блоки, а также тестовый узел на основе Python (на основе Bitcoin TestFramework), который может быть расширен за счет поведения злоумышленника.

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

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

В конечном счете, мы решили сосредоточить свое внимание на общении с пятнадцатью командами разработчиков, связанных с криптовалютами, которые с наибольшей вероятностью подверглись атаке (входят в число 200 самых популярных криптовалют), а также отзывчивы (активность некоторых коммитов в течение 2018 г.).

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

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

Наш набор для воспроизведения обеих уязвимостей Github можно найти здесь, а наш краткий доклад об уязвимости №1 — здесь. Мы также зарезервировали CVE для уязвимостей, которые вскоре должны стать общедоступными.

Смягчения

В ответ на наше исследование мы увидели ряд мер реализованных командами по устранению уязвимостей. Некоторые криптовалюты реализовали меры по снижению рисков, которые обнаруживают атаки и отключаются от атакующих одноранговых узлов. Проще говоря, узел отслеживает ненормальное поведение своих узлов (например, отправляет много заголовков в форках).

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

Некоторые другие криптовалюты добавляли частичную проверку.  Если одноранговый узел получает блок, который разветвляется от основной цепочки после этой длины, то блок просто отбрасывается. Этот подход также используется, например, в кодовой базе ABC BCH (Bitcoin Cash), в которой используется скользящая контрольная точка из 10 блоков.

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

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

Риск разделения цепочки также вводит новые векторы атак для враждебных майнеров. Злоумышленник может попытаться секретно добыть длинную цепочку, а затем опубликовать ее в подмножестве узлов, чтобы вызвать разделение цепочки. Узлы в IBD (Initial Block Download, начальная загрузка блока) или узлы, которые только что перезапустились после длительного периода автономной работы, особенно уязвимы для этой атаки.

Такие атаки можно комбинировать с атаками eclipse, чтобы привести честные узлы в цепочку, контролируемую злоумышленником. Все эти меры по снижению риска затрудняют проведение атаки, но по-прежнему не заменяют полную проверку. Некоторые криптовалюты, такие как Qtum, планируют перейти к полной проверке блоков вне основной цепи в будущих обновлениях.

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

Мы еще не проверили уязвимости для всех валют и еще не выяснили, почему валюты, опровергающие наши претензии, не были затронуты.

Заключение

Несмотря на то, что «fake stake» атаки в принципе просты, они подчеркивают сложную конструктивную проблему: некоторые идеи, которые имеют смысл в Proof-of-Work, не могут быть безопасно переведены в Proof-of-Stake.

Учитывая высокую степень совместного использования кода Bitcoin Core как «восходящего потока» среди криптовалют PoSv3, мы считаем, что это заслуживает еще большего внимания. Изучая эти уязвимости, мы обнаружили несколько примеров из разных кодовых баз незавершенных работ (или закомментированного кода), которые направлены на различные меры по смягчению последствий и специальные меры защиты.

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

Хотя мы видели недавние примеры (например, CVE 2018–17144 в BTC), затрагивающие как минимум две кодовые базы, насколько нам известно, это первое скоординированное раскрытие уязвимостей безопасности в таком большом количестве (20+) независимых криптовалют.

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

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

Обсудить в Discord!