A Survey of Solidity Security Vulnerability
Ethereum brings the capability of running smart contracts on the decentralized platform. As the EVM is a simple stack machine, the capability and security of EVM remain a great concern among the community. The official list of know solidity bugs can be found here. In this article, we summarize the security vulnerability of smart contract and propose correct ways of preventing hacking. DUO network is making its best effort in writing the most secure contracts and we are willing to contribute our findings to the community.
- Overflow and Underflow
An overflow is when a number gets incremented above its maximum value. Solidity can handle up to 256-bit numbers (up to 2**256 -1), so incrementing the maximum value by 1 would result into 0. Likewise, decrementing the minimum value by 1 would result in the maximum value.
Example: BEC batchoverflow
This function batchTransfer take an array of receivers and token value to be sent to each receiver.
a). Invoke batchTransfer with _recerivers as 20 arbitrary ethereum address and _value as (2**256 –1) / 20 + 1
b). At line 3, the actual value of the amount should be 2**256 + 19. Due to overflow, the amount will be computed as 20.
c). Line 5 checking will pass
d). Each receiver will receive (2**256–1) / 20 + 1 token
e). As a result, many new tokens are issued
To prevent overflow or underflow, it is advised to use safeMath when doing the computation. EVM will throw when overflow or underflow occurs.
2. Short address attack
This vulnerability allows an attacker to abuse the transfer function and withdraws a larger amount of tokens than the attacker is allowed to. Let’s consider an exchange token wallet with a balance of 10000000 and a user with a balance of 32 tokens on that exchange’s wallet. Assume the user address is 0x00dCB44e6EC9011fE3A52fD0160b59b48a115600 (notice the trailing zeroes).
A usual transfer function is as below
a). A user invoke _transfer function with _to as 0x0x00dCB44e6EC9011fE3A52fD0160b59b48a1156 (without trailing zeroes), _value as 32.
b). Then, the EVM calculates the input data for the transaction to be executed by concatenating the function’s signature and the arguments.
sig : 0x6910ebc4 = web3.utils.sha3(“_transfer(address,address,uint)”).slice(0,10)
arg2: 00000020 = 32 in hexademical (0x20)
Transaction input data: 0x6910ebc400dCB44e6EC9011fE3A52fD0160b59b48a115600000020
As the transaction length is 2 bytes shorter, the EVM would pad the transaction with trailing zeroes, resulting in:
c). As a result, the receiver will receive 8192 (0x2000) tokens rather than 32 tokens.
To prevent short address attack, the smart contract needs to check the address size.
3. Re-entry attack
If a calling contract calls a called contract without any function signature matching, the called contract fallback function will be invoked. The fallback function can calls the calling contract again, which is called reentrancy.
Example: The DAO attack
The DAO was a contract implementing a crowdfunding platform, which raised $150M before being attacked on June 18th, 2016. A simplified version of SimpleDAO contract is as below.
In the contract, a user can donate ether into the contract by calling the function donate. The contract will update the user’s total donated amount in a mapping array credit. The user can call another function to withdraw to withdraw any amount less than his/her total credit.
a). Attacker deploys another contract called Mallory whose code is given below.
b). Attacker invokes attack function in Mallory. Mallory contract will donate 1 wei into SimpleDAO contract. After that, it invokes SimpleDAO’s withdraw function.
c). SimpleDAO contract will send 1 wei to Mallory contract account. Since the recipient is a contract, the callback function of Mallory will be invoked.
d). In line 15 of Mallory contract, it will call SimpleDAO contract’s withdraw function again. Remember that line 13 of SimpleDAO contract is not executed yet.
e). At the second call, the fallback function in Mallory is called again. This time, it will stop as performAttack is set false.
f). As a result, the line 13 of SimpleDAO contract is executed twice. At the first time the balance is updated as 0 (1–1). At the second time, the balance is updated as 2**259 -1 due to underflow.
g). To finalize the attack, the hacker invokes getJackpot function in Mallory contract and withdraw the full amount.
There are several ways to prevent reentrancy attack.
- Use safeMath to avoid underflow and overflow.
- Exchange line 12 and line 13. The balance will be updated first before transferring ether.
- Use mutex, the idea is to lock the balance and the code is as below
4. Exception disorder
In Solidity there are several situations where an exception may be raised, e.g.
(i) the execution runs out of gas;
(ii) the call stack reaches its limit;
(iii) the command throw is executed.
Now, assume contract Alice invokes a function call in contract Bob. in the call to contract Bob. If the call fails, only the side effects of that invocation are reverted, the call returns false, and the original execution in contract Alice continues.
Example: King of Ether Throne (KoET)
The King of the Ether Throne is a game where players compete for acquiring the title of King of the Ether. If someone wishes to be the king, he must pay some ether to the current king, plus a small fee to the contract. The prize to be king increases monotonically. Below is a simplified version of the KoET contract:
Whenever a player sends ether to the contract, he also triggers the execution of KotET’s fallback function. If sent ether is larger than claimPrice, the player is accepted as the new king. At this point, a compensation is sent to the previous king, and the player is crowned. The owner of KotET can withdraw the ether accumulated in the contract through sweepCommission.
a). Deploy an attacking contract with very expensive fallback function.
b). Use the attacking contract send ether to KotET and become the new king.
c). Line 18 execution will fail because king is a contract with very expensive fallback.
d). In this case, since send does not propagate exceptions, the compensation is kept by the contract and the contract owner can withdraw the compensation.
5. DOS (denial of service) attack
In the previous example, assume that an honest programmer wants to implement a fair variant of KotET, by replacing send with call at line 5, and by checking its return code
This variant is more trustworthy than the previous but vulnerable to a denial of service attack. Consider an attacker Mallory, whose fallback just throws an exception. The adversary calls unseatKing with the right amount of ether, so that Mallory becomes the new king. At this point, nobody else can get her crown, since every time KotET tries to send the compensation to Mallory, her fallback throws an exception, preventing the coronation to succeed.
Smart contract security remains the biggest concern in the community. DUO network, as an experienced team in developing DAPP, we are willing to share our knowledge in writing the most secure contracts.
We provide contract auditing service so as to safeguard the crypto world against any form of hacking.
Telegram Announcement channel: https://t.me/duo_channel