防御力を高めよう~ハッキング事例の復習~
防御力は、クリプト運用で利益を継続的に出すために最も重要な能力の一つだ。年利100%で1~2年回せたとしても、1回のハッキングで資産を全て失ってしまうという話は全く珍しくない。本記事の読者であるということは少なくともクリプトやDeFiに興味があり、長期的にクリプト業界自体は発展していくという考え(生き残ってさえいれば大勝ちできる)の持ち主であろうと推察できるので、最後まで読んでくださった方が退場しないで長期的にクリプトを保持することで甘い蜜を享受できる状態になることが本記事の目標である。
資産を失うパターンの分類
まずは一撃で資産の多くを失うパターンをざっくり分類して列挙してみる。
運用資産を一気に失う主要パターン
セルフGOX
walletの秘密鍵流出
CEXの秘密鍵流出
チェーンの署名乗っ取られ
Rug Pull
DeFi Exploit
セルフGOX
これは自爆のことである。トークンをtransferする際に送付先アドレスを誤って入力してしまうと二度とそのトークンを引き出せなくなる。
CEXを使う時はアドレスを登録できたり、チェーンが合致するようにレコメンドしてくれたりするが、それでも注意が必要である。
筆者もこのセルフGOXの話を聞くたびに「そんなミスするわけないだろ」と鼻で笑っていたものの、多数のTxを深夜に捌いている時に、EthereumでETHを送付するところを誤ってBTCを送ってしまい死にそうになったことがある。この件は助かったのでセーフということにするが、ETHとBTCは価格が20倍前後異なるので、ETHで送ろうと思っていた数量のBTCを送付すると大事故を呼びかねない。
10回くらいのTransferであれば何とかミスなくやれるかもしれないが、その回数が1万回以上、100万回以上となってくるとミスをする可能性は高まっていくので、あまり自信を過度にトラストしないで「ミスをしない仕組み」を作ることが重要だ。
walletの秘密鍵流出
これは特に、インターネットに接続するソフトウェアwalletで起こりやすい。フィッシング攻撃でやられることもあるし、PCで何らかのリンクをクリックしたり変なアプリや拡張機能などをインストールした時にマルウェアがインストールされて、秘密鍵を入力するときにその情報を盗まれるということもある。
また、単純にシードフレーズを他人に見られる人為的ミスもあるし、シードフレーズの写真を撮ってインターネットに接続するデバイスに保存しておいて盗まれるということもある。ハッカーに乗っ取られた公共WiFiに接続して盗まれることもある。
CEXの秘密鍵流出
上記ではユーザーのwalletの秘密鍵流出の話をしたが、そのリスクはCEXにもある。CEXは個人ユーザーと比較すると大量の資金を預かっているため、サイバー攻撃の格好の的になる。
CEXから資産を盗む手段も巧妙化しており、Linkedin経由で接触し運営の技術責任者に職務経歴書を送るときにPDFを開かせてウィルス感染させ秘密鍵を盗むこともあるし、CEX従業員に経済的メリットと手法を説いて外部から犯行を持ちかけるということもある。
また、タイトルは秘密鍵流出としているが、ユーザー視点ではFTX事件のように顧客資産を流用されて資産を引き出せなくなるというリスクもあるのでそれは抑えておこう。
チェーンの署名乗っ取られ
Axie Infinity運営会社のSky Mavisが開発したRonin Networkというチェーンがあるが、トランザクションの承認に9つの署名が必要なところを5つの署名がハッカーによってなされて6.2億ドル相当 の ETHとUSDCが盗まれたという事件が過去にあった。

署名9つのうち4つはSkyMavis社のもの。AxieDAOのバリデーターはSkyMavis運営がアクセスできる設定のままになっていた(運営に署名権限を移譲していた)ので、SkyMavisが管理している秘密鍵を奪えば過半数の署名を集めることができる状態になっていたのが問題だった。
Dappsを触るときはそのDappsと利用トークンの安全性や収益性に注目してしまいがちだが、チェーンのセキュリティも必ず確認すべきだ。大元のチェーンへの攻撃が成功してしまうと、そのチェーンではなんでも盗み放題の状態になってしまう恐れがある。
Rug Pull
これは単純に、プロジェクトに投資したお金を持ち逃げされることである。国内のベンチャー投資のDDであれば創業者の顔と名前と経歴が本当だという証明はそこまで困難ではないかもしれないが、クリプトの場合は全てが嘘で固められている可能性があるので要注意である。
DeFi Exploit
本記事では後ほどこの領域をメインに執筆するのでここでの詳しい解説は控えるが、最近多いのはフラッシュローンを使った価格操作。Reentrancy Attackのように技術的なバグを突かれることもある。
DeFi Exploit
The DAO
The DAOとはEthereum上のスマートコントラクトで制御される投資DAO。分散型の投資ファンドとも言える。
投資家はETHをThe DAOに投資することでDAO Tokenを受け取ることができ、そのDAO Tokenを使ってDAO内での投票に参加して投資先(クリプト系の新興プロジェクト)の決定に関与できた。2016年にThe DAOから360万ETH(当時レートで$60M)が盗まれる事件が発生し、イーサリアムのハードフォークの引き起こしたことで有名。
攻撃手法としてはReentrancy Attackと呼ばれるもので、これはスマートコントラクトの脆弱性を悪用する攻撃手法。具体的には、攻撃者のコントラクトが、被害者のコントラクトの実行が完了する前に、再び被害者のコントラクトを呼び出すことで発生する。
投資家はDAOトークンを保有し、資金を払い戻すための仕組みがあったのだが、引き出しの順序としては下記の通りで、そこに脆弱性があった。
出資者がDAOから資金の払い戻しを要求すると、その資金が出資者の指定したアドレスに送金される
その後、出資者のトークン残高が減少するようにスマートコントラクトの内部データが更新される
これには、「資金が送金されてから残高が更新されるまでの間に、外部コントラクトから再び資金払い戻し要求ができてしまう」という問題があった。以下に脆弱性のあったThe DAOのコードとハッカーのコードの抜粋を掲載する。
// 脆弱性のあったThe DAOのコード抜粋
contract Dao {
mapping(address => uint256) public balances;
function withdraw() public {
require(balances[msg.sender] >= 1 ether, "Insufficient funds. Cannot withdraw");
uint256 bal = balances[msg.sender];
// 脆弱性のある部分: 残高更新前にETHを送金
(bool sent, ) = msg.sender.call{value: bal}("");
require(sent, "Failed to withdraw sender's balance");
// 残高更新が送金後に行われる
balances[msg.sender] = 0;
}
}// ハッカーのコード抜粋
contract Hacker {
IDao dao;
constructor(address _dao) {
dao = IDao(_dao);
}
function attack() public payable {
require(msg.value >= 1 ether, "Need at least 1 ether to commence attack.");
dao.deposit{value: msg.value}();
dao.withdraw();
}
fallback() external payable {
if(address(dao).balance >= 1 ether) {
dao.withdraw();
}
}
}
やはり問題点としては、withdraw関数内で、残高チェック後に資金を送金し、その後で残高を更新している点が挙げられる。
また、送金にcallを使用しているが、これは受信者のフォールバック関数を呼び出す可能性がある。フォールバック関数とは、Solidityで使われる関数のことで、コントラクトがETHを受け取ったがどの関数も呼び出されなかったり、呼び出された関数がコントラクト内に存在しない場合に実行される関数。
基本的にReentrancy Attackが成功するのは、脆弱なコントラクトが外部コントラクト(攻撃者のコントラクト)にコントロールを渡す瞬間があるためである。これは通常、ETHを送金する際に発生する。
Solidityには、主に
a) transfer()
b) send()
c) call{value: amount}("")
という送金方法があるが、このうち、callメソッドが最も柔軟で、ガス制限がないため、複雑な処理を可能にする。しかし、これが脆弱性の原因にもなる。
callメソッドの特徴は以下の通り。
受信者のアドレスに対して低レベルの呼び出しを行う。
呼び出されたアドレスがコントラクトの場合、そのコントラクトのフォールバック関数(またはreceive関数)が実行される。
呼び出し先のコントラクトに完全な制御を渡す。
繰り返しになるが、残高の更新前にETHを送金してしまうことと、callメソッドを使ってハッカーが作ったコントラクトに完全に制御を渡してしまう可能性があったことがこの事件の原因となった。
Curve

日時: 2023年7月30日
被害額: 約6,200万ドル相当
影響を受けたプール: crvUSD/USDT、alETH/ETH、msETH/ETH
MEVに詳しいプレイヤーによって被害拡大を食い止められた。
要は、MEVを極めていればTxの順番を入れ替えて注文先回りなどが可能なので、自分が儲けることもホワイトハッカーになることも可能。
攻撃の原因
Vyperコンパイラの脆弱性が主な原因。
具体的には、Vyperの古いバージョン(0.2.15、0.2.16、0.3.0)に存在したバグが悪用された。
攻撃の仕組み
攻撃者は、Vyperコンパイラのバグを利用して、プールコントラクトの初期化関数を再度呼び出すことができた。
VyperはEthereumスマートコントラクト開発に使用されるPython風の言語(SolidityはJavaScriptに近い)。
VyperはCurveやYearnなどで使われているが、大多数はSolidityで書いてる。
コンパイラはプログラミング言語で書かれたソースコード(人間が読み書きできる形式)を、コンピュータが直接実行できる機械語やバイトコードに変換するソフトウェアツール。
この再初期化により、攻撃者は自身のアドレスをプールの所有者として設定した。
これは特権なので資産を引き出したりコントラクトを変更したりできた。
所有者権限を獲得した後、攻撃者はプール内の資金を自由に引き出すことができた。
Euler Finance

Euler概要
パーミッションレスにリスティングできるレンディングプロトコル
Over-collateralized
トークンのボラティリティに応じて動的に借入条件を調整する「可変リスクパラメータ」
ChainlinkやUniswapのTWAP(Time-Weighted Average Price)をオラクルとして活用
フラッシュローンあり
事件の概要
日時: 2023年3月13日
被害額: 約1億9700万ドル相当
攻撃手法
攻撃者は3つのコントラクトを作成(メイン、違反用、清算用)
Aaveから3000万DAIをフラッシュローンで借入
2000万DAIをEulerに預け、約1960万eDAIを受け取る
1960万eDAIを担保に、約1億9560万eDAIと2億dDAIを借りる
残りの1000万DAIで一部債務を返済し、健全性スコアを改善
さらに1億9560万eDAIと2億dDAIを借りる
1億eDAIをEulerのリザーブに寄付
清算を実行し、2億5400万dDAIと3億1000万eDAIを獲得
Aaveに3000万DAIを返済し、約870万DAIの利益を得る
攻撃の核心部分:
donateToReserve関数に流動性チェックがなかった。
健全性スコアの計算に欠陥があった。
主な脆弱性:
donateToReserve関数の問題:
借り手の流動性状態を確認せずに寄付を受け付けていた。
これにより、担保不足の状態でレバレッジを利用できた。
健全性スコアの欠陥:
支払い能力のないアカウントが担保を引き出せるようになっていた。
攻撃者は担保不足のレバレッジを利用してこれを悪用。
参照
Gamma

時期: 2024年1月4日
原因: 価格操作の脆弱性を突かれた攻撃
損失: $6.3M
脆弱性:
GammaはステーブルコインやLSTのVaultにおいて、フラッシュローンに対する4つの主要なdeposit保護措置を備えていたが、そのうちの1つである「価格変動のしきい値を設定し、TWAPオラクル価格から指定された限界を超える価格変動がある場合にデポジットを禁止」という部分に脆弱性があった。
しきい値が高すぎたため、特定のLSTおよびステーブルコインのボールトで-50%から+100%の価格変動が可能となり、攻撃者はこの限界まで価格を操作し、異常に多くのLPトークンを生成できた。
該当Pool(https://blog.verichains.io/p/gamma-protocol-exploit-analysis 参照):
gDAI-DAI Vaultが最も大きく被害を受けた
Hypervisor(Gammaプロトコルの中核をなすスマートコントラクト)の機能
自動化された流動性管理:
Uniswap V3のような集中流動性プールにおいて、最適な価格範囲を自動的に設定。
流動性の追加と削除:
ユーザーの代わりに流動性の追加(addLiquidity)や削除(removeLiquidity)を行う。
リバランス:
市場状況に応じて、流動性の配分を自動的に調整。
シェアトークンの発行:
流動性提供者に対して、彼らの貢献度に応じたシェアトークンを発行します。
攻撃の流れ
大量のDAIの借り入れ
UniswapV3PoolとBalancerから400万DAI以上を借りた(フラッシュローン)
gDAI価格の人為的な引き上げ
借りたDAIを使って大量のgDAI(GainsNetworkにdepositしてトレーダーのカウンターパーティとして稼げるDAI)を購入し、gDAIの価格をHypervisorがサポートする価格範囲を超えて引き上げた。
Hypervisorへの流動性提供
この時点で、攻撃者はgDAIの価格を人為的に高くしている。
攻撃者は270,000 gDAI(価値が膨らんでいる)と、わずか1 wei(最小単位)のDAIをHypervisorに預ける。
通常なら、両方のトークンがバランス良く使われるはずだが、gDAIの価格が高すぎるため、Hypervisorは主にDAIだけを使ってUniV3に流動性を追加する。
(Hypervisorは、Uniswap V3のgDAI-DAIプール内の特定の価格範囲に流動性を集中させる役割を持っているので)
Hypervisorは、Uniswap V3のgDAI-DAIプール内の特定の価格範囲(ティック範囲)に流動性を追加
通常、この流動性はgDAIとDAIの両方で構成されるべき
しかし、攻撃者がgDAIの価格を人為的に引き上げたため、現在の価格がHypervisorの設定した価格範囲を超えてしまっていた
Hypervisorは、現在の価格が設定範囲の上限を超えていると判断
範囲外の状況では、Hypervisorは片側の資産(この場合はDAI)のみを使用してUniV3に流動性を追加
Hypervisorは、Uniswap V3プール内の設定された価格範囲の下限に、既存のDAI(攻撃者が提供する前から、Hypervisorが管理するUniswap V3プール内に存在していたDAI)だけを使って流動性を追加した
結果、Uniswap V3プール内の、Hypervisorが管理する特定の価格範囲に、DAIのみの流動性が追加され
攻撃者が預けたgDAIは、実際にはこの流動性追加に使用されず、Hypervisor内に残ったままだった
結果として、攻撃者は預けたgDAIの価値に基づいて大量のシェアトークンを受け取るが、実際にはそのgDAIは使われていない。
[この状況が問題である理由は、Hypervisorが片側の資産(DAI)のみを使用して流動性を追加したにもかかわらず、攻撃者に両方の資産(gDAIとDAI)に基づいたシェアトークンを発行してしまったこと]
これにより、攻撃者は実際に提供した流動性以上の価値のシェアトークンを得ることができ、後の攻撃ステップでこれを悪用できた
シェアトークン引き出しのメカニズム:
通常、Hypervisorなどの流動性プールでは、シェアトークンを引き出す際、ユーザーが資産の種類を選択することはできない。
代わりに、プール内の現在の資産比率に基づいて、両方の資産(この場合はgDAIとDAI)が自動的に返還される。
シェアの引き出しと利益の獲得
攻撃者は、Hypervisorから獲得したすべてのシェアトークンを引き出し
Hypervisorは、攻撃者に対して以下を返還した
プール内のDAIの大部分(攻撃者は1 weiのDAIしか預けていないのに)
攻撃者が預けたgDAIの一部
この結果、攻撃者は実際に預けた以上の価値をHypervisorから引き出すことに成功した。
gDAI価格の引き下げ:
攻撃者は、Hypervisorから得たgDAIの一部を外部のプール(UniV3 gDAI/DAI pool)でDAIに交換。
この交換により、gDAIの価格が下落し、Hypervisorがサポートする価格範囲(Hypervisorが効率的に流動性を管理できると想定している価格の範囲)を下回ります。
攻撃者は、この価格操作を次のステップのための準備として行います。
(急激な価格変動に対する適切な対応メカニズムがHypervisorに欠けていたことが、攻撃を可能にした一因)
残りのgDAIの利用を強制
価格が下がったことで、Hypervisorの状態が変わる。
攻撃者は少量のgDAIを預け入れる。これはトリガーの役割を果たす。
Hypervisorは、価格が下がったことを認識し、プールのバランスを調整しようとする。
この過程で、以前預けられたが使用されていなかったgDAIを使って、流動性を追加。
結果として、攻撃者は再びDAIを得ることができる。
参照:
本日はここまで。
Twitter: https://x.com/MakiCrypto0330
