‘Smart contract vulnerability study’

Posted by ‘何嘉浩’ on November 21, 2018

Smart contract Vulnerability study

Reentrancy attack

  • Attack Method:This attack consists on recursively calling the call.value() method in a ERC20 token to extract the ether stored on the contract if the user is not updating the balance of the sender before sending the ether.
  • Manifest as a control flow abnormality:
    • Yes. In a normal execution the control flow of the contract does not introduce an reentrancy.

    • This vulnerability can be easily prevented by blocking the control flow of reentrancy.

    • i.e.

      contract Wallet {  
          function withdrawBalance(){  
              mapping(address => uint) private userBalances;  
              if(amountToWithdraw>0){  
                  msg.sender.call(userBalances[msg.sender]);  
                  userBalances[msg.sender] = 0;  
              }  
          }  
      }  
      contract AttackerContract{  
          function (){  
              wallet.withdrawBalance();  
          }  
      }  
      

Over and under flows

  • Attack Method:An overflow happens when the limit of the type variable uint256 , 2**256, is exceeded. What happens is that the value resets to zero instead of incrementing more.

  • i.e.

    function batchTransfer(address[] _receivers, uint256 _value) public whenNotPaused returns (bool) {
        uint cnt = _receivers.length;
        uint256 amount = uint256(cnt) * _value;
        require(cnt > 0 && cnt <= 20);
        require(_value > 0 && balances[msg.sender] >= amount);
        balances[msg.sender] = balances[msg.sender].sub(amount);
        for (uint i = 0; i < cnt; i++) {
            balances[_receivers[i]] = balances[_receivers[i]].add(_value);
            Transfer(msg.sender, _receivers[i], _value);
        }
        return true;
     }
    

    It may cause overflow when calculate amount without safemath Lib. Then the require may be out of operation. This vulnerability make BEC lose 6 billion CNY just with 1 line code.

Repay attack

  • Attack Method:The replay attack consists on making a transaction on one blockchain like the original Ethereum’s blockchain and then repeating it on another blockchain like the Ethereum’s classic blockchain.

Reordering attack

  • Attack Method:This attack consists in that a miner or other party tries to “race” with a smart contract participant by inserting their own information into a list or mapping so the attacker may be lucky in getting their own information stored on the contract.

Short address attack

  • Attack Method:
    • This attack affects ERC20 tokens, was discovered by the Golem team and consists of the following:
      • A user creates an ethereum wallet with a traling 0, which is not hard because it’s only a digit. For instance: 0xiofa8d97756as7df5sd8f75g8675ds8gsdg0
      • Then he buys tokens by removing the last zero:
    • Buy 1000 tokens from account 0xiofa8d97756as7df5sd8f75g8675ds8gsdg
      • If the token contract has enought amount of tokens and the buy function doesn’t check the length of the address of the sender, the Ethereum’s virtual machine will just add zeroes to the transaction until the address is complete.
      • The virtual machine will return 256000 for each 1000 tokens bought. This is a bug of the virtual machine that’s yet not fixed so whenever you want to buy tokens make sure to check the length of the address.

GasLess Send

  • Attack Method:The gasless send vulnerability is due to the fact that when using send the recipient contracts’s fallback function will be invoked but with a fixed gas(2300) as determined by the EVM
    • i.e. King of the Ether Throme
      • if previous king has a complex fallback function(just include a sstore operation), it will cause out of gas exception when send ether to previous king. However, the king still change without revert
      • this example contain both GasLess Send and Exception Disorder vulnerability.
        contract KoteEt{
        	   address public king;
        	   uint public claimPrice = 100;
        	   address owner;
               
        	   function KotEt(){
        		      owner = msg.sender; king = msg.sender;
        	   }
               
        	   function sweepCommission(uint amount){
        		    owner.send(amount);
        	   }
               
        	   function(){
        		       if(msg.value < claimPrice) throw;
        		       uint compensation = calcilateCompensation();
        		       king.send(compensation);
        		       king = msg.sender;
        		       claimPrice = calculateNewPrice();
        	    }
        }
        

Exception Disorder

  • Attack Method:When the contract use the call\delegatecall\send\callcode to call the external function, it can’t throw the exception above but return false. When developer did not check the return value, may cause unaware control flow.
  • Manifest as a control flow abnormality:
    • Yes.

Timestamp and Blocknumber Dependency

  • Attack Method:This attack happen when using Timestamp or Block Number as part of the conditions tp perform a critical operation or as source of entropy to generate random numbers.
  • Manifest as a control flow abnormality:
    • No.

Dangerous Delegatecall

  • Attack Method:When contract use delegatecall to call the external function, the code in callee function will executed in the context of the calling contract.

    • Attacker will call the attack function in Delegation with param, “pwn()”, the owner in Delegation may change to attacker address.
  • Manifest as a control flow abnormality:

    • Yes, attack use the vulnerability to change the owner of some contract with ETH, it may cause a control flow different with before.
      contract Delegate{
            address owner;
           
            function Delegate(address _owner) public {
                    owner = _owner;
            }
           
            function pwn() {
                    owner = msg.sender;
            }
      }
      contract Delegation {
            address public owner;
            Delegate delegate;
           
            function Delegation(address _delegateAddress) {
                    delegate = Delegate(_delegateAddress);
                    owner = msg.sender;
            }
           
            function attack(string a){
                    if(delegate.delegatecall(bytes4(keccak256(a)))){
                        this;
                }
          }
      }