0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Sui上のCetus DEXを狙い、約2億6,000万ドル相当をハッキング

Posted at

1. ハックの概要

  • ハッカーはSui上のCetus DEXを狙い、約2億6,000万ドル(約3,600億円)相当を不正に引き出しました。盗まれた資金はUSDCにスワップされ、そのうち約6,000万ドル分がEthereumへブリッジされ、約21,938 ETHを取得しています(CryptoRank, CryptoSlate)。

2. 脆弱性のポイント

  • 問題箇所は clmm_math.moveget_delta_a 関数内:

let (numberator, overflowing) = math_u256::checked_shlw(
    full_math_u128::full_mul(liquidity, sqrt_price_diff)
);
if (overflowing) { abort EMULTIPLICATION_OVERFLOW };
  • ここで期待される「128ビット×128ビットの乗算結果を正しく256ビットで得る」処理が、実際には 乗算時のオーバーフローを検出 できず、結果が切り捨てられてしまう可能性があります。つまり、「かけ算」のチェックが抜けているわけです。
  • 本来は liquidity × sqrt_price_diff(128ビット×128ビット)の結果を「256ビットで正しく表せているか」を確かめる必要があります。ところがこのコードでは、その「かけ算」自体に異常が起きていても検出せずに先へ進んでしまいます。
  • その後のシフト(checked_shlw)でしかオーバーフローをチェックしないため、すでに壊れた値がそのまま使われ、後続の価格計算(分子)が小さく誤算出されます。

例えば「ビット幅を縮小したミニチュア版」でイメージしてみましょう。

例題:8ビット型×8ビット型 → 16ビット型を期待

  1. 本来の計算

    • liquidity = 200(8ビットで表せる最大は255)

    • sqrt_price_diff = 200

    • 期待する掛け算結果:

      $$
      200 \times 200 = 40,000
      $$

      これは16ビット(最大 65,535)までは余裕で表現できます。

  2. もし “full_mul” が壊れていて下位8ビットだけ返すと…

    • 本来の 40,000(0x9C40) を 8ビットに切り捨てると、0x9C40 の下位8ビットは 0x40(=64)になります。
    • つまり、本来「40,000」のはずが「64」になってしまう。
  3. シフト(ずらし)でのオーバーフローチェック

    • つづけて checked_shlw(ビットをずらす処理)で「オーバーフローしていないか」を見るとき、すでに値は壊れているので問題なしと判定される。
    • 例:左に1ビットシフトしても 64→128(0x80) なので「溢れていない」と見なされる。
  4. その後の分母・除算

    • たとえば分母(価格計算に使う値)を 100 × 100 = 10,000 とすると、

      • 本来 の結果:

        $$
        \frac{40,000}{10,000} = 4
        $$

      • 誤った 計算:

        $$
        \frac{64 ;(\text{切り捨て後})}{10,000} \approx 0.0064
        $$

        (整数型なので「0」になるか、round_up=true なら「1」になる)


何が起きる?

  • 本来は4トークン必要なはず の操作で、誤計算により 0〜1トークン 分しか徴収されない。
  • これを利用すると、プールから「ほんのわずかなコスト」で大量のトークンを取り出せてしまい、結果として大規模な資金抜き取り(ハック)が可能になります。

まとめ

  • かけ算の段階で本来必要な大きな値が「切り捨てられて」しまい、そのあとにオーバーフローチェックをしても気づかれない。
  • そのまま不正な(小さすぎる)必要量でトークンを引き出せてしまうのが、このバグの本質です。

3. 悪用手順

  1. 攻撃者は非常に大きな liquiditysqrt_price_diff を組み合わせ、128ビット乗算を意図的にオーバーフローさせる。
  2. 本来はここでabortすべきところ、乗算時点のオーバーフロー検出がないため、結果が切り捨てられたまま次に進む。
  3. その後の get_delta_a が返す ΔA(プールから必要なトークン量)が実際よりも極端に小さく計算され、swapremoveLiquidity 呼び出しで 極小のコストで大量の資産を引き出せる 状態に。
  4. プールが一気に枯渇し、ハッカーは多額の資金を瞬時に盗み取ることに成功。

まとめ

  • get_delta_a の乗算オーバーフロー検出が「シフト時のみ」だったため、壊れた値で価格計算が行われ、プールの価格影響や必要トークン量が異常に低く見積もられた
  • これを利用して、ハッカーはごくわずかな資金で巨額の資金を引き出し、約2億6,000万ドルを盗み取りました。
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?