本記事は2025年1月10日投稿のXRPL公式ブログ"Malicious transaction can cause network node(s) to crash and pause new transactions momentarily“の和訳です。
この脆弱性開示レポートには、2024年11月25日に報告されたXRP Ledgerのバグに関する技術的詳細が記載されています。
報告日: 2024年11月 影響を受けるバージョン: rippled 2.0.1 から rippled 2.2.x
脆弱性の概要
2024年11月25日 13:39 UTCに、XRP Ledgerでは複数のノードがほぼ同時刻にクラッシュし再起動する問題が発生しました。 結果として、ネットワークは復旧する間、約10分間にわたりトランザクションの処理を一時的に停止しました。 この期間中に資金の損失はありませんでした。 ネットワークは同日13:49 UTCに、影響を受けたノードが再起動した後、通常の動作に戻り、フォワードプログレスを再開しました。
影響
ノードの再起動中はフォワードプログレスが停止し、トランザクション処理に遅延が発生します。 不安定な期間中、XRPLネットワークのコンセンサスモデルは進行性よりも安全性を優先するため、ネットワークは復旧する間、約10分間トランザクションを処理しませんでした。 新規トランザクションの検証(Validation)が一時停止しました。 資金の損失はありませんでした。 ネットワークは同日13:49 UTCに通常の動作に戻り、フォワードプログレスを再開しました。
技術的詳細
発見の経緯
2024年11月18日、Mayukha Vadari(RippleXエンジニア)が、XLS-80 Permissioned Domainコードの自動テストを書いている際にこのバグを発見しました。 さらに調査を進めたところ、同じバグが他のライブトランザクションでも発生する可能性があることが判明しました。 具体的には、CheckCashトランザクションのCheckIDフィールドにアカウントのレジャーオブジェクトIDが使用されたとき、rippledがクラッシュしました。
この問題を引き起こしたトランザクションとフィールドは以下の通りです:
CheckCash/CheckCancel(CheckID)PaymentChannelClaim(Channel)NFTokenAcceptOffer(NFTokenBuyOffer/NFTokenSellOffer)- 複数のトランザクションにおける
CredentialIDフィールド(このコードはまだライブではありません)
脆弱性のあるトランザクションに共通していたのは、特定タイプのオブジェクト(例: check、ペイメントチャネル、NFTトークンオファー、クレデンシャルなど)のIDをトランザクション内で受け取り、それを使ってトランザクションが参照するオブジェクトをルックアップする点でした。 これは正常に動作するはずであり、(他にバグがないと仮定すれば)最悪のケースでも、見つかったオブジェクトが想定外の型であるというだけで、これはオブジェクトが見つからなかった場合と同じように扱われるはずでした。 しかしこのバグは、「想定外の型のオブジェクトが見つかった」状態を例外に変換してしまい、プログラムをクラッシュさせていました。
根本原因
この問題は、2024年1月のこのリファクタリングで導入されたバグに起因します。 このリファクタリングの目的は、特にパスファインディングサーバーにおけるメモリ負荷を軽減するため、キャッシュに保存されるデータの型を、一部のデータについては完全にシリアライズされたレジャーエントリから、そのレジャーデータをルックアップするのに必要なキーまたはダイジェストのみに変更することでした。 この変更の一環として、キャッシュ内で見つかったデータの型に対するチェックがコードのより後段に移動されました。
ある状況下で、型が適切にチェックされず、キャッシュレイヤーが返すデータに不整合が生じた結果、オブジェクトの型が想定と一致しない場合にサーバーがクラッシュする可能性がありました。 つまり一部のトランザクションでは、トランザクションが特定の型のオブジェクトを期待しているのに、別の型のオブジェクトのIDを受け取り、かつそのオブジェクトがサーバーのキャッシュ内にある場合、サーバーがクラッシュしていました。
このバグはリファクタリングのテスト中には検出されませんでしたが、本インシデント以前に攻撃された証拠はありません。
当初の調査では、不正なトランザクションを受け取ったノードはクラッシュするため、影響範囲はそのノードのみに限定されると考えられていました。 しかし、11月25日のインシデントでこの想定は誤りであったことが判明しました(おそらくキャッシュの予測しづらい性質によるものです)。
引き金となったトランザクション
11月25日、シーケンス番号以外は同一の3つのPaymentChannelClaimトランザクションが送信されました。 これらは(本来であればPayChannelオブジェクトを参照すべきところ)RippleState(トラストライン)レジャーオブジェクトを参照していました。 これら3つはすべて、クラッシュを引き起こすことなく、successfullyに失敗しました。 その後、同じアカウントがそのRippleStateオブジェクトに対するTrustSetを送信し、続けて同じPaymentChannelClaimトランザクションを再度送信しました。TrustSetトランザクションによってRippleStateレジャーオブジェクトがキャッシュに存在する可能性が高まり、続くPaymentChannelClaimトランザクションが、そのオブジェクトをキャッシュに持っている全てのノードをクラッシュさせることが可能となったのです。 これらのトランザクションの1つは、レジャー92346897で確認できます。
拡散についての現在の仮説は、一部のノードがそのRippleStateレジャーオブジェクトをキャッシュからフラッシュしていたために、トランザクションを処理して他のノードに伝播できた、というものです。 これにより、後にノードが追いつき始めた時点でもクラッシュが発生し続けた理由、そして最終的にはクラッシュが止まった理由(クラッシュ後はノードのキャッシュにオブジェクトが入っていないため、無効なPaymentChannelClaimを正しく処理できる)も説明がつきます。
補足
有効なPayChannelオブジェクトを持たないPaymentChannelClaimトランザクションは、トランザクション手数料を徴収するためにレジャーで処理および保存されます。 これは、ネットワークが処理する不正なトランザクションの送信にコストを発生させ、それによりスパムを抑制するために行われるものです。 このため、現在もこれらのトランザクションがレジャーに記録されており、また他のノードへ伝播してクラッシュを引き起こしたわけです。
修正対応
このバグは、キャッシュされたデータの型を適切にチェックすることで修正されました。 バグが比較的容易に悪用できることを踏まえ、より大規模なコミットに含めることで修正を難読化しました。
これらの変更は、11月25日にリリースされたバージョン2.3.0に含まれています。 もともとチームは、エンジニアリングサポートが手薄になる米国の祝日週でのリリース公開を避けるため、12月2日にリリースを予定していました。 しかし、QAがすでに2.3.0を検証済みであったこと、また小規模なリリースでは修正の難読化がうまくいかないことから、修正のみを含む2.2.4のリリースは見送られました。 当然ながら、緊急性を踏まえ、追加で土壇場の確認とUNLバリデーターとの調整を経た後、リリースが公開されました。
すべてのノードができるだけ早くアップデートする必要があった理由は、一度ノードがアップグレードされると、その無効なトランザクションを他のノードに伝播してしまい、まだアップデートしていないノードでクラッシュの波を引き起こす可能性があったためです。
再現手順
この完全開示の一環として、バグを引き起こす方法の例がこのユニットテストで取り上げられており、これはrippledのコードベースに追加される予定です。 ユニットテストの統制された環境において、このコードはキャッシュシステムの状態を、特定の一連の呼び出しで(修正がない場合に)バグが発生するように設定します。 このテストはrippled 2.3.0で修正を確認するために使用されましたが、ユーザーがrippledソフトウェアをアップグレードしている間にバグが悪意を持って悪用されることを避けるため、当時のリリースからは除外されました。
利用可能な修正/パッチ
問題を修正するパッチが実装されており、修正はrippled 2.3.0で利用可能です。
まだアップグレードを行っていない場合は、できるだけ早く2.3.0にアップグレードすることを強くお勧めします。
謝辞
この脆弱性の調査にご協力いただいたRippleX、Wietse Wind、Jon Nilsenの皆さん(特にMayukha Vadariさんに謝意を表します)、ありがとうございます。
そして、XRP Ledgerを稼働させ続け、ネットワークの安全性とセキュリティを守るために尽力されているバリデーター、開発者、コントリビューターのグローバルコミュニティの皆さんに感謝いたします。
参考資料
お問い合わせ
詳細情報、または追加の問題を報告される場合は、bugs@xrpl.orgまでチームへご連絡ください。
インシデント対応タイムライン
| 主なアクション | タイムスタンプ | 説明 |
|---|---|---|
| 初期発見 | 2024年11月25日 13:39 UTC | 問題が特定および報告される。 |
| 緩和措置 | 2024年11月25日 13:49 UTC | 新規トランザクション検証の一時停止を経て、ネットワークは13:49 UTCに通常動作とフォワードプログレスを再開。資金の損失はなし。 |
| 解決完了 | 2024年11月25日 | 脆弱性は完全に緩和され、修正はrippled 2.3.0リリースの一部として利用可能となった。 |
| ブログ公開 | 2024年11月27日 | プライベート開示と共にブログを公開し、rippled 2.3.0へのアップグレードを呼びかけた。 |
| レポート公開 | 2025年1月10日 | ネットワークの80%がrippled 2.3.0にアップグレードした後、技術的詳細を含むレポートを公開。 |