|
| 1 | +# Oracle Manipulation Attack & Flash Loan |
| 2 | + |
| 3 | +**目次** |
| 4 | +- [オラクルとは](#オラクルとは) |
| 5 | +- [Oracle Manipulation Attackとは](#oracle-manipulation-attackとは) |
| 6 | +- [Oracle Manipulation Attackの具体例](#oracle-manipulation-attackの具体例) |
| 7 | + - [演習](#演習) |
| 8 | +- [Oracle Manipulation Attackの対策](#oracle-manipulation-attackの対策) |
| 9 | + - [Time Weighted Average Pricing (TWAP)](#time-weighted-average-pricing-twap) |
| 10 | + - [非中央集権型オラクル](#非中央集権型オラクル) |
| 11 | +- [Flash Loanとは](#flash-loanとは) |
| 12 | + - [演習](#演習-1) |
| 13 | +- [Flash Loanを利用したOracle Manipulation Attack](#flash-loanを利用したoracle-manipulation-attack) |
| 14 | + - [演習](#演習-2) |
| 15 | + |
| 16 | +## オラクルとは |
| 17 | + |
| 18 | +Oracle Manipulation Attackの説明をする前に、簡単にオラクル(oracle)について説明します。 |
| 19 | + |
| 20 | +ブロックチェーンにおけるオラクルとは、狭義には、オンチェーン(= チェーン内)のスマートコントラクトに、オフチェーン(= チェーン外)の情報を提供するプロトコルのことです。 |
| 21 | +広義には、オンチェーンだけで収集できる情報を加工して提供する関数やコントラクトもオラクルと呼びます。 |
| 22 | + |
| 23 | +ブロックチェーンの仕組み上、コントラクトはブロックチェーンの外で起こっている情報を得るために、オフチェーンの主体に依存する必要があります。 |
| 24 | +例えば、現実世界の天気や株式の価格などは、ブロックチェーン上に存在しないため、誰かが提供する必要があります。 |
| 25 | +これをオラクル問題と呼びます。 |
| 26 | + |
| 27 | +オラクル問題を非中央集権的に解決するために、オフチェーンの情報をオンチェーンに非中央集権的にコミットするプロトコルがあり、非中央集権型オラクル(Decentralized Oracle)と呼ばれます。 |
| 28 | +代表的な非中央集権型オラクルのプロトコルに[Chainlink](https://chain.link/)があります。 |
| 29 | +非中央集権型オラクルについては、後で詳しく説明します。 |
| 30 | + |
| 31 | +## Oracle Manipulation Attackとは |
| 32 | + |
| 33 | +Oracle Manipulation Attackとは、オラクルを故意に操作することでオラクルを利用するプロトコルからトークンの奪取などを行う攻撃の総称です。 |
| 34 | +特に、オラクルの広義の意味に含まれる「オンチェーンだけで収集できる情報を加工して提供する関数やコントラクト」は適切な利用を行わないと、この種の攻撃に脆弱になりやすいです。 |
| 35 | + |
| 36 | +## Oracle Manipulation Attackの具体例 |
| 37 | + |
| 38 | +Oracle Manipulation Attackの単純な例を説明します。 |
| 39 | + |
| 40 | +まず、ユーザー、レンディングプロトコル、オラクルの3つのパーティーがいるとしましょう。 |
| 41 | +ユーザーは、レンディングプロトコルにいくらかのETHをデポジットすれば、ある閾値までのUSDCを借りることができます。 |
| 42 | +レンディングプロトコルは、USDC/ETHの価格を提供するオラクルを利用して、その閾値を決定します。 |
| 43 | +オラクルは具体的には、UniswapなどのAMMを想定してもらって構いません。 |
| 44 | + |
| 45 | +悪意のない一般ユーザーがレンディングプロトコルから資産を借りる流れは以下の図のようになります。 |
| 46 | +(通常の矢印がアクションで、点線の矢印が単なる返り値を表しています。) |
| 47 | + |
| 48 | +```mermaid |
| 49 | +sequenceDiagram |
| 50 | + participant User |
| 51 | + participant Lending |
| 52 | + participant Oracle |
| 53 | +
|
| 54 | + User ->> Lending: 10 ETHデポジット |
| 55 | + User ->>+ Lending: 15,000 USDC貸して |
| 56 | + Lending ->>+ Oracle: USDC/ETHの値は? |
| 57 | + Oracle -->>- Lending: 2,000 USDC/ETH |
| 58 | + Note over Lending: Collateral Factor (75%)による条件チェック<br>2,000 * 10 * 0.75 = 15,000 USDC |
| 59 | + Lending ->>- User: 15,000 USDC送金 |
| 60 | +``` |
| 61 | + |
| 62 | +さて、ここでオラクルを操作することで何か攻撃を行うことはできないでしょうか? |
| 63 | + |
| 64 | +もしオラクルが提供する価格を操作できるとしましょう。 |
| 65 | +そうすると、本来借りれるはずの額よりも大きな額のUSDCを借りれてしまいます。 |
| 66 | +例えば、USDC/ETHの価格が現在の倍の4,000 USDC/ETHに出来たら、30,000 USDC借りることが出来ます。 |
| 67 | +攻撃者はそのUSDCを返さなければ、結果として、30,000 USDC - 2,000 USDC/ETH * 10 ETH = 10,000 USDC を利益にできてしまいます。 |
| 68 | + |
| 69 | +図に表すと以下の流れになります。 |
| 70 | + |
| 71 | +```mermaid |
| 72 | +sequenceDiagram |
| 73 | + participant Attacker |
| 74 | + participant Lending |
| 75 | + participant Oracle |
| 76 | +
|
| 77 | + Attacker ->> Oracle: (何かしらの操作) |
| 78 | + Attacker ->> Lending: 10 ETHデポジット |
| 79 | + Attacker ->>+ Lending: 30,000 USDC貸して |
| 80 | + Lending ->>+ Oracle: USDC/ETHの値は? |
| 81 | + Oracle -->>- Lending: 4,000 USDC/ETH |
| 82 | + Note over Lending: Collateral Factor (75%)による条件チェック<br>4,000 * 10 * 0.75 = 30,000 USDC |
| 83 | + Lending ->>- Attacker: 30,000 USDC送金 |
| 84 | +``` |
| 85 | + |
| 86 | +それでは、オラクルへの具体的な操作は何が考えられるでしょうか? |
| 87 | + |
| 88 | +オラクルの実態は取引所なので、ETHを大量に買い上げればUSDC/ETHの値が上がるでしょう。 |
| 89 | + |
| 90 | +その取引所の価格決定アルゴリズムが $xy = k$ 型で、USDC-ETHプールにあるUSDCとETHの総量がそれぞれ、20,000,000 USDCと10,000 ETHだとします。 |
| 91 | +もし2,000 USDC/ETHから4,000 USDC/ETHになったときのETHの量を $x$ とすれば、 $4000 x^2 = 20000000 \times 10000$ を満たします。 |
| 92 | +$x$ を求めると $7071$ 程度になります。 |
| 93 | +一方でUSDCの量は、 $4000x = 28284000$ 程度です。 |
| 94 | +つまり、8,284,000 USDCを所持していれば価格を4,000 USDC/ETHに釣り上げることが可能です。 |
| 95 | + |
| 96 | +USDC-ETHプールの交換手数料を0.3 %とすると、ざっくりと8,284,000 USDC * 0.3 % * 2回 = 49,704 USDCの手数料がかかります。 |
| 97 | +攻撃者の利益はレンディングプロトコルが持つUSDCの総量の1/3であるため、その総量が約49,704 * 3 = 149,112 USDC以上であれば、攻撃者は利益を得られることになります。 |
| 98 | + |
| 99 | +最終的に残ったETHをUSDCに戻せば攻撃完了です。 |
| 100 | + |
| 101 | +この攻撃の流れを図に表すと次のようになります。 |
| 102 | +8,284,000や7,071のような数値は $x,y$ などの記号にしています。 |
| 103 | + |
| 104 | + |
| 105 | +```mermaid |
| 106 | +sequenceDiagram |
| 107 | + participant Attacker |
| 108 | + participant Lending |
| 109 | + participant AMM |
| 110 | +
|
| 111 | + Attacker ->>+ AMM: x USDCをETHに交換して |
| 112 | + AMM ->>- Attacker: y ETH送金 |
| 113 | + Attacker ->> Lending: 100 ETHデポジット |
| 114 | + Attacker ->>+ Lending: 300,000 USDC貸して |
| 115 | + Lending ->>+ AMM: USDC/ETHの値は? |
| 116 | + AMM -->>- Lending: 4,000 USDC/ETH |
| 117 | + Note over Lending: Collateral Factor (75%)による条件チェック<br>4,000 * 100 * 0.75 = 300,000 USDC |
| 118 | + Lending ->>- Attacker: 300,000 USDC送金 |
| 119 | + Attacker ->>+ AMM: y' ETHをUSDCに交換して |
| 120 | + AMM ->>- Attacker: x' USDC送金 |
| 121 | +``` |
| 122 | + |
| 123 | +この攻撃では、一つ攻撃者にとって問題点があります。 |
| 124 | +それは、攻撃者が8,284,000 USDCを用意しなくてはならない点です。 |
| 125 | +しかし、後述するFlash Loanと組み合わせることで、攻撃者は無一文でも攻撃を行うことができます(厳密にはトランザクション手数料分のETHを保持している必要があります)。 |
| 126 | + |
| 127 | +### 演習 |
| 128 | + |
| 129 | +問題ディレクトリ: [challenge-oracle-manipulation](challenge-oracle-manipulation) |
| 130 | + |
| 131 | +プレイヤーは`A`トークンを初期状態で9,000,000持っています。 |
| 132 | +`Challenge.sol`の`LendingPool`コントラクトに対してOracle Manipulation Attackを行い、`A`トークンを全て排出して、プレイヤーのトークン`A`の総量を9,100,000以上にしてください。 |
| 133 | + |
| 134 | +以下のコマンドを実行して、テストがパスしたら成功です。 |
| 135 | + |
| 136 | +``` |
| 137 | +forge test -vvv --match-path course/oracle-manipulation/challenge-oracle-manipulation/Challenge.t.sol |
| 138 | +``` |
| 139 | + |
| 140 | +## Oracle Manipulation Attackの対策 |
| 141 | + |
| 142 | +Oracle Manipulation Attackの対策として、「Time Weighted Average Pricing (TWAP)」と「非中央集権型オラクル」の2つの技術を紹介します。 |
| 143 | + |
| 144 | +### Time Weighted Average Pricing (TWAP) |
| 145 | + |
| 146 | +TWAPは、複数のブロックの価格の平均を取ることで価格を決定するアルゴリズムです。 |
| 147 | +TWAPはUniswapなどのプロトコルで提供されています。 |
| 148 | + |
| 149 | +例えば、ある時点 $i$ での価格を $P_i$ とすると、 $[a,a+1,\ldots,b-1]$ のTWAPは次のように表せます。 |
| 150 | + |
| 151 | +$$\mathrm{TWAP} = \frac{P_{a}+P_{a+1}+\cdots + P_{b-1}}{b-a}$$ |
| 152 | + |
| 153 | +このTWAPを導入することで、先程紹介したようなOracle Manipulation Attackを防ぐことができます。 |
| 154 | + |
| 155 | +まず、TWAPを導入すれば、現在のトランザクション(あるいはブロック)の時点での価格だけ操作しても、価格を適正価格から大きく乖離できずに攻撃が失敗します。 |
| 156 | +具体的には、ある時点での価格操作の影響が $\frac{1}{b-a}$ になってしまいます。 |
| 157 | + |
| 158 | +次に、そもそも現在のブロックの価格がTWAPの計算に含まれないようなTWAPの場合は、そもそも価格への影響はありません。 |
| 159 | + |
| 160 | +さらに、攻撃を2つ以上のトランザクションに分けてTWAPを操作しようとしても、すぐに他のユーザーによるアービトラージが行われ、適正価格に修正されてしまいます。 |
| 161 | +適正価格に修正されると、何度も不利な価格でスワップすることになります。 |
| 162 | +結局、そのような攻撃は非常に高いコストがかかるため、攻撃しても損するだけでインセンティブがありません。 |
| 163 | + |
| 164 | +特に、Oracle Manipulation Attackは後述するFlash Loanと組み合わせられることがほとんどであり、Flash Loanを利用すると1トランザクションで攻撃を完結させないといけないため、TWAPは強力な対策の一つです。 |
| 165 | + |
| 166 | +また、TWAPは価格決定アルゴリズムの中では非常にシンプルであるため、オンチェーンで実装する上で相性が良いというメリットもあります。 |
| 167 | + |
| 168 | +ただし、急激な価格変化にすぐに追いつけないという性質はあります。 |
| 169 | + |
| 170 | +### 非中央集権型オラクル |
| 171 | + |
| 172 | +Chainlinkなどは、複数のある程度信頼できるパーティーからの価格データを収集し、そのデータをオンチェーンにコミットするプロトコルを非中央集権的に運用しています。 |
| 173 | +この非中央集権型オラクルを利用することでも、先程紹介したようなOracle Manipulation Attackを防ぐことがきます。 |
| 174 | + |
| 175 | +Chainlinkのノードがオンチェーンに価格データをコミットしなくてはならないため、チェーンが混雑しているときは、価格更新トランザクションがすぐに実行されない可能性があります。 |
| 176 | + |
| 177 | +## Flash Loanとは |
| 178 | + |
| 179 | +Flash Loanとは、トランザクションの終了までに借りた資産が返却される限り、無担保で資産を借入できるローンのことです。 |
| 180 | +借り手は、そのトランザクション内で借りた資産をどのように扱っても良いです。 |
| 181 | +手数料は発生しますが、借りた期間に基づく利子はありません。 |
| 182 | + |
| 183 | +Flash LoanはUniswapを始めとする様々な取引所で提供されています。 |
| 184 | + |
| 185 | +例えば、10,000 WETHを借りるFlash Loanは次のようなイメージです。 |
| 186 | + |
| 187 | +```mermaid |
| 188 | +sequenceDiagram |
| 189 | + participant User |
| 190 | + participant FlashLoanProvider |
| 191 | + |
| 192 | + User ->>+ FlashLoanProvider: 10,000 WETH借して |
| 193 | + FlashLoanProvider ->>+ User: 10,000 WETH |
| 194 | + Note over User: 任意の処理 |
| 195 | + User ->>- FlashLoanProvider: (10,000 + fee) WETH |
| 196 | + FlashLoanProvider -->>- User: (Flash Loan終了) |
| 197 | +``` |
| 198 | + |
| 199 | +### 演習 |
| 200 | + |
| 201 | +問題ディレクトリ: [challenge-flash-loan](challenge-flash-loan) |
| 202 | + |
| 203 | +Uniswap V2のフラッシュローン(Flash Swapと呼びます)を使って、`Flag`コントラクトの`solved`フラグを立ててください。 |
| 204 | +Flash Swapの使い方は、[Uniswapのドキュメント](https://docs.uniswap.org/contracts/v2/guides/smart-contract-integration/using-flash-swaps)を参照してください。 |
| 205 | + |
| 206 | +今までの演習問題と異なり、メインチェーンをフォークしていることに注意してください。 |
| 207 | + |
| 208 | +Flash Loanを行う際に使えるアドレスを参考までに載せておきます(これらアドレスを使わなくても構いません)。 |
| 209 | +- WETHのアドレス: `0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2` |
| 210 | +- USDC-WETH Pairのアドレス: `0xB4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc` |
| 211 | + |
| 212 | +以下のコマンドを実行して、テストがパスしたら成功です。 |
| 213 | + |
| 214 | +``` |
| 215 | +forge test -vvv --match-path course/oracle-manipulation/challenge-flash-loan/Challenge.t.sol |
| 216 | +``` |
| 217 | + |
| 218 | +## Flash Loanを利用したOracle Manipulation Attack |
| 219 | + |
| 220 | +最初の紹介したOracle Manipulation Attackでは、攻撃者が初期状態で大量のUSDCを持っている必要がありました。 |
| 221 | +しかし、今紹介したFlash Loanを利用することで、攻撃に必要な資産を準備する必要はもうありません。 |
| 222 | + |
| 223 | +Flash Loanと組み合わせたときのOracle Manipulation Attackは次のようなイメージになります。 |
| 224 | + |
| 225 | + |
| 226 | +```mermaid |
| 227 | +sequenceDiagram |
| 228 | + participant FlashLoanProvider |
| 229 | + participant Attacker |
| 230 | + participant Lending |
| 231 | + participant AMM |
| 232 | +
|
| 233 | + Attacker ->>+ FlashLoanProvider: x USDC貸して |
| 234 | + FlashLoanProvider ->>+ Attacker: x USDC送金 |
| 235 | + Attacker ->>+ AMM: x USDCをETHに交換して |
| 236 | + AMM ->>- Attacker: y ETH送金 |
| 237 | + Attacker ->> Lending: 100 ETHデポジット |
| 238 | + Attacker ->>+ Lending: 300,000 USDC貸して |
| 239 | + Lending ->>+ AMM: USDC/ETHの値は? |
| 240 | + AMM -->>- Lending: 4,000 USDC/ETH |
| 241 | + Note over Lending: Collateral Factor (75%)による条件チェック<br>4,000 * 100 * 0.75 = 300,000 USDC |
| 242 | + Lending ->>- Attacker: 300,000 USDC送金 |
| 243 | + Attacker ->>+ AMM: y' ETHをUSDCに交換して |
| 244 | + AMM ->>- Attacker: x' USDC送金 |
| 245 | + Attacker ->>- FlashLoanProvider: (x + fee) USDC送金 |
| 246 | + FlashLoanProvider -->>- Attacker: (Flash Loan終了) |
| 247 | +``` |
| 248 | + |
| 249 | +### 演習 |
| 250 | + |
| 251 | +問題ディレクトリ: [challenge-oracle-manipulation-with-flash-loan](challenge-oracle-manipulation-with-flash-loan) |
| 252 | + |
| 253 | +最初の演習と異なり、プレイヤーは`A`トークンを初期状態で所持していません。 |
| 254 | +今回の問題でもメインネットをフォークしています。 |
| 255 | +それに加えて、`A`トークンに`USDC`が、`B`トークンに`WETH`が割り当てられています。 |
| 256 | + |
| 257 | +`Challenge.sol`の`LendingPool`コントラクトに対して、Flash Loanを用いたOracle Manipulation Attackを行い`USDC`を全て排出して、プレイヤーの`USDC`の総量を100,000以上にしてください。 |
| 258 | + |
| 259 | +以下のコマンドを実行して、テストがパスしたら成功です。 |
| 260 | + |
| 261 | +``` |
| 262 | +forge test -vvv --match-path course/oracle-manipulation/challenge-oracle-manipulation-with-flash-loan/Challenge.t.sol |
| 263 | +``` |
0 commit comments