Contact

【CTO Tech Blog】LDK v0.1以下に存在した2つの脆弱性

  • CTO Tech blog

LDK(Lightning Development Kit )はLN対応アプリケーションを構築するためのライブラリ。

このLDKについて、先月末に2つの嫌がらせ攻撃を可能にする脆弱性が開示された。

流動性をロックする嫌がらせ

LDK 0.0.125以下に存在した脆弱性は、アンカーチャネルの資金をロックし、資金を回収するために手動でトランザクションを構築する必要がある攻撃を実行できるというもの↓

Disclosure: LDK Invalid Claims Liquidity Griefing – Implementation – Delving Bitcoin

通常、チャネルが強制的に閉鎖された場合、オンチェーンに展開されたコミットメントトランザクションから、自分の資金と特にタイムロックが適用されているHTLCを回収する必要がある。

HTLCを精算する条件は以下のいずれか

  • タイムロックによる精算(HTLC-Timeout)
  • プリイメージの提供による精算(HTLC-Success)

前者はHTLCの上流の当事者による回収で、後者は下流の当事者による回収となる。

バグの内容

LDKでは、HTLCを回収する際、そのトランザクション手数料を節約するため、できるだけ複数のHTLCを1つのトランザクションで一緒に回収するようになっている。

この時、集約したトランザクション内の1つのHTLCを相手が先に別のトランザクションで承認させると、集約トランザクション自体が無効になるので、競合を取り除くよう更新する必要があるけど、この更新ロジックにバグがあり、状況によって必要な更新が行われない場合があった。

LDKがHTLCを集約するトランザクションを2つ(AとBとする)以上作成していた場合に、攻撃者がAとB両方と競合するトランザクションCをオンチェーンで承認させた場合、LDKはその内の最初のトランザクションAとの競合を発見すると、そこで走査をやめてしまい、CとBの競合が検知されない。その結果、Bは無効な競合状態のまま残ってしまう。無効な集約トランザクションの資金はロックされたままで、有効になるよう手動でトランザクションを再構築しなければロックされた資金は回収できない。

修正

最初競合を見つけた後でも走査を継続するようbreak処理を削除する形でバグの修正が行われた↓

Fix package splitting logic · lightningdevkit/rust-lightning@a1d6356 · GitHub

2025-01-16にリリースされたLDK 0.1のリリースに上記修正が含まれている。

チャネル強制閉鎖の嫌がらせ

LDK 0.1以下に存在した脆弱性は、被害者のチャネルを強制的に閉じる嫌がらせ攻撃が可能になるというもの↓

Disclosure: LDK Duplicate HTLC Force Close Griefing – Implementation – Delving Bitcoin

チャネルに新しい支払いがルーティングされる度に、チャネル参加者(BとMとする)はそれぞれのコミットメントトランザクションを更新する。具体的な手順は↓

  1. B→Mにupdate_add_htlcメッセージを送って支払いをコミットメントトランザクションに追加するよう依頼し、
  2. B→Mに更新したトランザクション用のBの署名をcommitment_signedで送信
  3. M→Bにrevoke_and_ackで応答(古いトランザクションの取り消し)
  4. M→Bに更新したトランザクション用のMの署名をcommitment_signedで送信
  5. B→Mにrevoke_and_ackで応答(古いトランザクションの取り消し)

上記から分かるように、両者のコミットメントトランザクションの更新はアトミックには行われない。上記であれば、Mは2の時点で更新の前と後で2つの有効なコミットメントトランザクションを保持する瞬間がある。3で前のトランザクションが取り消されると1つに戻るけど、Bは2の段階でどちらのトランザクションがブロードキャストされたとしても対処する必要がある。

Mがコミットメントトランザクションをブロードキャストした場合、Bは自分が現在保持しているコミットメントトランザクションと比較して現在未処理のHTLCがあるかどうか検出し、

  • 承認されたMのトランザクションに含まれていないHTLCがある場合、そのHTLCは請求不可能と判断して、上流側にフェイルバックする必要がある。
  • Mのトランザクションに含まれているHTLCは、下流でオンチェーンで決済されるままアクティブとなる。

バグの内容

上記の検出の際、LDKは、HTLCSourceと呼ばれるいくつかの追加データを使って照合している。ただ、revoke_and_ackにより古いコミットメントトランザクションが取り消されると、このデータは削除される。もし、古いコミットメントトランザクションがオンチェーンで承認された場合、HTLCSourceはないので、HTLCに用いられているペイメントハッシュと金額を使って照合するようになっていた模様。

つまり、問題となるのは、取り消されたコミットメントトランザクションがブロードキャストされた場合の動作。悪意あるユーザーのチャネルをM1、M2としてM1からM2へBを経由して同じペイメントハッシュ、同じ金額のHTLCをN個送金した場合。Bを経由する際にBとチャネルを開いているA1〜ANのを経由するものとする。

     -- A1 --
    /         \
M1 --  ...  -- B -- M2
    \         /
     -- AN --

この状態で、M2がN個の内1つだけ含む古いコミットメントトランザクションをブロードキャストし承認された場合、その1つだけは上流側にフェイルバックされるけど、同じペイメントハッシュと金額を持つ、残りのHTLCはフェイルバックは行われずスタックし、N-1個のAのチャネルはBとのチャネルを閉じてオンチェーンでHTLCを解決しようとする。この結果、BのN-1個のチャネルは閉じられてしまう。

古いコミットメントトランザクションをブロードキャストしたM2は、ペナルティで資金が没収されてしまうけど、自分のチャネル残高を最小限まで減らしておけば、発生する損害(Bのチャネル開設コスト)よりかなり小さくできる。

修正

(副次的な効果として)取り消されたコミットメントトランザクションが承認された場合、(上記のようにペイメントハッシュと金額が)重複するHTLCが最終的にフェイルバックするよう修正された↓

Fail HTLC backwards before upstream claims on-chain by TheBlueMatt · Pull Request #3556 · lightningdevkit/rust-lightning · GitHub

2025-01-28にリリースされたLDK 0.1.1のリリースに上記修正が含まれている。

というのが最近開示されたLDKの2つの脆弱性。プロトコルで定義されていない実装レベルでのバグも色々あるよね。。

ブログ本文へのリンク

ブログ本文へはこちらから

https://techmedia-think.hatenablog.com/entry/2025/02/10/223240

Chaintopeでブロックチェーンの未来を共に創りませんか?

Chaintopeは、独自のブロックチェーン「Tapyrus」と、開発プラットフォーム「Tapyrus Platform」を活用し、デジタル社会の信頼基盤を構築しています。
私たちは、ブロックチェーン技術の可能性を最大限に引き出し、社会に新しい価値を提供することを目指しています。

募集職種:

ブロックチェーンエンジニア
アプリケーションエンジニア
インフラ・保守エンジニア
プロジェクトマネージャー
フィールドセールス

Chaintopeで働く魅力:

最先端のブロックチェーン技術に触れる機会
リモートワークやフレックスタイム制による柔軟な働き方
専門性の高いチームとの協働
ブロックチェーン技術に情熱を持つあなたのスキルを、私たちのチームで活かしませんか?
詳細は、採用情報をご覧ください。

https://www.chaintope.com/recruit/

 

話題のキーワード