ContractFuzzer: Fuzzing Smart Contracts for Vulnerability Detection ASE ’18, September 3–7, 2018, Montpellier, France
Exception Disorder. The Exception disorder is due to the
fact that Solidity is inconsistent in terms of exception handling,
which is dependent on the way contracts call each other. When a
contract calls the function of another, it may fail due to different
types of exceptions. When such exception occurs, the handling
mechanism is determined by how the calls are made. Given a
chain of nested calls where each call is a direct call to the function
of a contract, when exception occurs, all the transactions will be
reverted (including ether transfer). However, for a chain of nested
calls where at least one call is made through low-level call
methods on address (address.ca ll(), address.delegatecall(),or
address.send()), the rollback of the transaction will only stop at the
calling function and return false.Fromthatpoint,nootherside
effect can be reverted and no throw will be propagated. Such
inconsistencies in terms of exception handling will make the
calling contracts unaware of the errors happened during
execution.
Reentrancy. The reentrancy bug is due to the fact that some
ofthefunctionsarenotdesignedtobereentrantbythe
developers. However, a malicious contract deliberately invokes
such functions in a reentrant manner (e.g., through fallback
functions), it may lose ether. The famous “The DAO” attack just
made use of this vulnerability to cause $60 million US loss in
terms of ether.
Timestamp Dependency. The timestamp dependency
vulnerability exists when a smart contract uses the block
timestamp as part of the conditions to perform a critical operation
(e.g., sending ether) or as the source of entropy to generate
random numbers. In a distributed system like blockchain, the
miner has the freedom to set the timestamp of a block within a
short time interval less than 900 seconds [24]. However, if a smart
contract transfer ether based on timestamp, an attacker can
manipulate block timestamps to exploit the vulnerability.
Block Number Dependency. The block number dependency
vulnerability is like Timestamp dependency. It happens when a
smart contracts uses t he block.number as part of the conditions to
perform a critical operation (e.g., sending ether) or as the source
of generating random numbers. Indeed, both block.timestamp and
block.number are variable that can be manipulated by miners, so
they cannot be u sed as a source of entropy because of the miners’
incentive [30]. Moreover, even using the block.blockhash()
function with block.number as parameters for random number
generation is still vulnerable either due the execution mechanism
of EVM or due to the transparency of the blockchain.
Dangerous DelegateCall.Thedelegatecall is identical to a
message call except that the code at the target address is
executed in the context of the calling contract[27]. This means
that a contract can dynamically load code from a different address
atruntimewhilethestoragestill refers to the calling contract.
This is the way to imp l ement the “library” feature in Solidity for
reusing code. However, when the argument of the delegatecall is
set as msg.data, an attacker can craft the msg.data with the
signature of a function so that the attacker can make the victim
contract to call whatever function it provides. This is exemplified
by the outbreaks of the first round of parity wallet vulnerability
[32]. As shown in Table 1, at l ine 6 the Wallet contract contains a
delegatecall with msg.data as its parameter. This makes an
attacker can call any public function of _walletLibrary with the
data of Wallet. So, the attacker calls the initWallet function
(defined at line 10) of the _walletLibrary smart contract and
become the owner the wallet contract. Finally, he can send the
ether of the wallet to his own address to finish the attack. This
attack has led to $30 million loss to the parity wallet users.
Table 1. Dangerous Delegate Call in Parity Wallet Contract
1 contract Wallet{
2 function() payable { //fallback function
3 if (msg.value > 0)
4 Deposit(msg.sender, msg.value);
5 else if (msg.data.length > 0)
6 _walletLibrary.delegatecall(msg.data);
7 }
8 }
9 contract WalletLibrary {
10 function initWallet(address[] _owners, uint _required, uint
_daylimit) {
11 initDaylimit(_daylimit);
12 initMultiowned(_owners, _required);
13 }
14 }
Freezing Ether. Another type of vulnerable contract is the
freezing ether contract. These contracts can receive ether and can
send ether to o ther addresses via delegatecall.However,they
themselves contain no functions to send ether to other address. In
another word, they purely rely on the code of other contracts (via
delegatecall) to send ether. When the contracts providing the
ether manipulation code performs suicide or self-destruct
operation, the calling contract has no way to send out ether and
all its ether is frozen. The second round of attack on Parity wallet
vulnerability is just because many wallet contracts can only rely
on the parity library to manipulate their ether. When the parity
library was changed to a contract through initialization and then
killed by the hacker. All the ether within the wallets contracts
relying on the parity library is frozen.
3 Defining Testing Oracles for Vulnerabilities of
Smart Contracts
In this section, we will define test oracles for detecting each type
of vulnerabilities in smart contracts.
3.1 Test Oracle for Gasless Send
Within EVM, the send() is implemented as a special type of
call().SotheoracleGaslessSend ensures the call within EVM is
indeed a send() call and that the send() call returns an error code
of ErrOutOfGas during execution. To check a call is a send(),we
verify whether the input of the call is 0 and the gas limit of the
call is 2300.
3.2 Test Oracle for Exception Disor der
We define the test oracle ExceptionDisorder as follows: for a
chain of nested calls (or delegatecalls) originated from a root call
(or delegatecall), if the root call doesn’t throw exception while at
least one of its nested calls throws exception, we consider the call