Skip to content

JIAMING-LI/FeiProtocolFuseExploit

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Rari & Fei protocol exploit demo

This is a demo to replay the Rari & Fei protocol expoloit happened on Apr-30-2022

https://etherscan.io/tx/0xadbe5cf9269a001d50990d0c29075b402bcc3a0b0f3258821881621b787b35c6

Installation & Run

npm install
npx hardhat run scripts/execute.js

Explanation

This is a typical reentrance exploit where the exitMarket is implemented without reentrance lock and the transfer of ETH is using call instead of transfer which only limit the gas to 2300.

  1. exploite first flashloan 80000 wstETH and 50000 WETH
  2. deposit 80000 wstETH into the wstETH vault and borrow 2392 ETH from fETH vault
  3. exit the market and withdraw 80000 wstETH from the vault.
  4. the exploiter repeat the above step to drain the fund.

Now, why the exploiter can exit the market while still have borrow balance ?

  1. The source code of transfering fund to user is using call instead of transfer which limit gas usage to 2300
function doTransferOut(address payable to, uint amount) internal {
    // Send the Ether and revert on failure
    (bool success, ) = to.call.value(amount)("");
    require(success, "doTransferOut failed");
}
  1. There is no reentrance lock in exitMarket
function exitMarket(address cTokenAddress) external returns (uint) {
    ...........
}
  1. The borrowing source code is not following Checks-Effects-Interactions pattern which is the major reason making this exploit possible. Checks-Effects-Interactions pattern is one of the most effective way to protect against re-entrancy exploit without side effect.
function borrowFresh(address payable borrower, uint borrowAmount) internal returns (uint) {
    .........more codes

    doTransferOut(borrower, borrowAmount);

    /* We write the previously calculated values into storage */
    accountBorrows[borrower].principal = vars.accountBorrowsNew;
    accountBorrows[borrower].interestIndex = borrowIndex;
    totalBorrows = vars.totalBorrowsNew;

    return uint(Error.NO_ERROR);
}

Disclaimer

This codebase is for demonstration purposes only

License

MIT

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published