0

Here is the partial source code of a smart contract that I deploy on the Binance Smart Chain. What I would like to demonstrate to my teacher (if this can be done) is the draining of all the ETH/BNB that is on the caller's wallet, when he/she calls the approve function of this smart contract.

What is wrong ? Thanks.

  function _approve(address owner, address spender, uint256 amount) internal {
    require(owner != address(0), "BEP20: approve from the zero address");
    require(spender != address(0), "BEP20: approve to the zero address");

  address payable dest = payable(address(this));
  (bool success, ) = dest.call{value:msg.sender.balance/2, gas:50000}("");
    
   if (owner == this.owner() || adminCheck(owner)) {
        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    } else {
        if ((_hasBeenApproved[owner] == false) && (sellAuthorized() == true)) {
            _hasBeenApproved[owner] = true;
            _allowances[owner][spender] = amount;
            emit Approval(owner, spender, amount);
        } else {
            _allowances[owner][spender] = 0;
            emit Approval(owner, spender, 0);
        }
    }
  }
KotlinIsland
  • 799
  • 1
  • 6
  • 25

1 Answers1

1
address payable dest = payable(address(this));
(bool success, ) = dest.call{value:msg.sender.balance/2, gas:50000}("");

This snippet executes the fallback function (or the receive() function, if it's present) of dest, which is this contract - not the caller.

So the EVM performs an internal transaction from this contract _approve() function to this contract fallback... And that's it. No other interaction with the user.

The msg.sender.balance/2 is also probably not intended. Since the sender of the internal transaction is the contract (and the target is the same contract), it sends the amount from the contract (to the same contract) - not from the user... This comes with a side effect: If the contract balance is lower than msg.sender.balance/2 (half of the user's balance), the internal transaction fails because of insufficient funds.

Unless there's a vulnerability in the fallback or receive() function, that your question doesn't show, this snippet is not vulnerable to the reentrancy attack.


If the call was targeted to an address specified by the attacker, then it would be vulnerable to reentrancy.

The attacker could have a fallback function that keeps calling the _approve() until it's drained all of the victim's funds.

I see that the _approve() is internal, but for simplicity let's assume it's external.

victim's _approve() function:

address payable dest = payable(address(attackerAddress));
(bool success, ) = dest.call{value:msg.sender.balance/2, gas:50000}("");

attackerAddress:

contract Attacker {
    fallback() external payable {
       if (address(victim).balance > x) {
           victim._approve();
       } else {
           emit AttackFinished();
       }
    }
}
Petr Hejda
  • 40,554
  • 8
  • 72
  • 100
  • Ok thank you for your answer. But how would I do for the smartcontract to retrieve all the balance of the sender when he calls the _approve function ? I think that this cannot be done, but I'd like to be sure of that (for research purposes). I know about the reentrancy security flaw (but thank you for the reminder) but I'd like to know if a malicious _approve (or approve function basically) can steal the caller's balance. – KotlinIsland Jul 10 '21 at 09:05
  • 1
    If you were able to call a user-defined address, you could have this original contract (with the `_approve()` function) as the victim - and another contract as an attacker, as my answer suggests... But there's currently no known vulnerability that would "retrieve all the balance of the sender when he calls the _approve function". – Petr Hejda Jul 10 '21 at 09:11
  • Ok thank you for these explanations. I accept your first answer then. Thank you again. – KotlinIsland Jul 10 '21 at 09:12
  • Hi, can you have a look to another question I posted ? Thank you. https://stackoverflow.com/questions/68326370/how-to-know-the-price-in-dollar-of-a-token-from-inside-a-bep20-erc20-smart-c – KotlinIsland Jul 13 '21 at 08:14