Develop with pleasure!

福岡でCloudとかBlockchainとか。

Segwit Bugとは何なのか?

Segwit Bugというタイトルでニュースが出ており

decrypt.co

Trezorでも脆弱性対応のパッチが公開されていた↓

https://blog.trezor.io/details-of-firmware-updates-for-trezor-one-version-1-9-1-and-trezor-model-t-version-2-3-1-1eba8f60f2dd

ので、どんな脆弱性なのか見てみよう。

脆弱性の内容

まず、この脆弱性には、Segwit導入時に一緒に導入された署名時のメッセージダイジェストの生成方法の変更BIP-143が関係する↓

techmedia-think.hatenablog.com

非Segwitのトランザクションについて、TrezorはインプットのUTXOの量を確認することで、ユーザーの意図しない額の送金を防ぐ。Segwitトランザクションでは署名を作成する際に、BIP-143により署名対象のメッセージダイジェストにインプットが参照するコインの量が含まれることになる。そのため署名デバイスはオフラインでも使用するコインの量を必ず知ることができる。もし攻撃者がコインの量を騙そうと偽の量を署名デバイスに渡しても、署名デバイスが作成した署名は無効な署名になる。そういう意味では、BIP-143によるコインの量へのコミットは、オフラインの署名デバイスのセキュリティを向上する仕組みである。

今回、Saleem Rashidによって報告された上記を回避する脆弱性の実行手順は以下の通り。

  1. 被害者は15 BTCと20 BTCのSegwit UTXOを持っている。
  2. マルウェアが被害者に以下のインプットを持つ合計20.00000001 BTC使用するトランザクションを提示し、承認を求める。
    • インプット1:15 BTC のUTXO
    • インプット2: 5.00000001 BTC のUTXO
  3. 被害者が内容を承認した後、マルウェアはエラーを発生させ再度トランザクションを承認するよう求める。
  4. この時マルウェアはインプットを以下のインプットに置き換えたトランザクションにする。アウトプットは先程と同じ。
    • インプット1: 0.00000001 BTC
    • インプット2: 20 BTCのUTXO
  5. 被害者が確認するも、送金額は先程と同じ20.00000001 BTCであり、被害者は承認する。
  6. この後マルウェアは、トランザクションのインプットを以下のようにすげ替えたトランザクションを作成し、ブロードキャストする。
  7. 結果インプットの合計は15 BTC + 20 BTCになり、15 BTCちょっとが手数料として徴収される。

まとめると、2つ以上のインプットを持つトランザクションで、送金額の値は同じだけど金額の組み合わせが異なるUTXOのセットを2つ用意して、エラーを理由にインプットの組み合わせを変えて二度署名させ、最終的に送金額が最大になる組み合わせのUTXOを選択して、ユーザーの意図する額以上の送金トランザクションを作成させる攻撃。

最初↑の手順を見たときは、最初のトランザクションと2つめのトランザクションでUTXOが変わってるので、つまりインプットが参照するOutPointの値も変わるので、最後のマルウェアが作るトランザクションの署名は無効になるのでは?と思ったけど、最初と2つめのトランザクションのインプットのOutPointは両方とも最初から15 BTCと20 BTCのOutPointで、コインの量だけ変えてるだけか。デバイスがOutpointの値を実際に確認したらバレる。

Trezorの対応

対応は単純でSegwitのトランザクションについても、非Segwitトランザクションと同様、UTXOの金額の検証を行うようにしたと。

オフライン署名デバイスの安全性を向上させるためのメッセージダイジェストの仕様BIP-143だったけど、↑のようなケースを考えるとオフラインデバイスでも従来のトランザクションと同様の検証が求められると。

Trezorは対応したものの、Trezorと連携するアプリ側はまだSegwitトランザクションの場合UTXOの情報を提供しない仕様になっていることが多いので、そういったサードパーティのツールと連携している場合は注意が必要。

特にマルチパーティ間でトランザクションデータを連携する際の標準仕様であるPSBTをサポートしている場合、Segwitトランザクションの場合UTXOが参照するトランザクション情報は保持しない仕様になっているので、PSBT単体で評価せずにオンラインデバイスの場合はUTXOのトランザクション情報を確認するようにした方がいい。

Schnorr/Taprootによる改善

現在導入が検討されているSchnorr/Taprootでは、Schnorr署名のメッセージダイジェストの作成方法がBIP-143とは異なり、新しくBIP-341で定義されている。BIP-341ではメッセージダイジェストに、全インプットが参照するUTXOのコインの量が含まれるようになるため(↓のsha_amounts)、↑のような攻撃はできなくなる。

techmedia-think.hatenablog.com

BCHもBIP-143をサポート

ちなみにBitcoin Cashもハードフォークの際にリプレイプロテクションを導入するにあたって、BIP-143の内容を参考にしたメッセージダイジェストを生成するようになってる↓

https://github.com/bitcoincashorg/bitcoincash.org/blob/a86ce75cbdce8b14fa90b2315ebc7f0d78e6c9cb/spec/replay-protected-sighash.md

このためBCHのトランザクションもコインの量に署名でコミットするようになっている。ただ、BCH側も影響があるかどうかは、Trezorの確認方法がBitconのSegwitトランザクションと同様の確認方法になっていたかどうかによる。非Segwitトランザクションと同様のUTXOが参照するトランザクション情報の提示を求める仕様になっているのであれば影響はないが、同じ方法で検証しているのであれば影響する。

まとめ&所感

  • 影響があるのはBIP-143の仕様を採用し、UTXOのトランザクション情報を要求しないハードウェアウォレット。
  • 同様にPSBTを採用しているツールは、Segwitトランザクションの場合UTXOのトランザクション情報はPSBTフォーマットにはないので追加のチェックが必要。
  • 問題となったのはSegwit導入時に一緒に導入された新しい署名ダイジェストの計算仕様BIP-143のオフラインデバイスでの使用。
  • こうなるとPSBTの仕様についても、Segwitトランザクションでも(PSBT_IN_NON_WITNESS_UTXOキーみたいに)UTXOのトランザクションを保持するような設計変更が必要では?