Solidity Security By Example #10: Denial of Service With Gas Limit
Originally published in Valix Consulting’s Medium.
Smart contract security is one of the biggest impediments to the mass adoption of the blockchain. For this reason, we are proud to present this series of articles regarding Solidity smart contract security to educate and improve the knowledge in this domain to the public.
Denial of service with gas limit is often caused by a lack of understanding of how the Ethereum Virtual Machine (EVM) works, resulting in the contract being exploited or the contract cannot operate expectedly.
This article will explain how a vulnerable smart contract can be attacked and how to prevent it. Enjoy reading. 😊
You can find all related source code at 👉 https://github.com/serial-coder/solidity-security-by-example/tree/main/10_denial_of_service_with_gas_limit.
Disclaimer:
The smart contracts in this article are used to demonstrate vulnerability issues only. Some contracts are vulnerable, some are simplified for minimal, some contain malicious code. Hence, do not use the source code in this article in your production.
Nonetheless, feel free to contact Valix Consulting for your smart contract consulting and auditing services. 🕵
Table of Contents
The Vulnerability
The below code presents the InsecureNaiveBank
contract. This contract simulates a simple (and naive) on-chain banking system in which anyone can deposit their Ether funds to the contract via the depositFor
function (lines 26–36).
The deposited Ethers can be withdrawn anytime by way of executing the withdraw
function (lines 38–44).
The contract also implements the applyInterest
function (lines 46–57) in which a banker can calculate compound interests for all depositors. The interest rate is fixed at 5% (line 4). 💰💰💰
Further, a banker can deposit Ether funds into the contract through the depositBankFunds
function (lines 20–22).
Absolutely, the InsecureNaiveBank
contract is vulnerable. Can you discover any issues? 👀
|
|
We would like to note that the
InsecureNaiveBank
contract got a double spending issue on thedepositFor
function.
But, it is not in the scope we will focus on in this article. Nevertheless, we will explain that double spending issue in our future article definitely. Please stay tuned!! 🤳
The InsecureNaiveBank
contract got a design flaw in the applyInterest
function (lines 46–57). Specifically, the applyInterest
function iterates over all depositor accounts (lines 47–56) to calculate compound interest for each depositor (line 52).
However, suppose the number of depositor accounts is too large. In that case, the iteration can consume more gas than the block gas limit, permanently reverting the transaction when a banker calculates depositors’ compound interests. 😧
In other words, the InsecureNaiveBank
contract would incur the unbounded denial-of-service (DoS) issue. Subsequently, the contract could not operate the banking services anymore. 😡
Two situations that can cause the unbounded denial-of-service issue to the InsecureNaiveBank
contract:
-
The number of depositor accounts grows over time due to the ordinary adoption
-
The contract encounters a Sybil attack
Figure 1 below shows how an attacker executes a Sybil attack to freeze the interest calculation service of the InsecureNaiveBank
contract permanently. 😈
The attack is straightforward. An attacker executes the depositFor
function (Steps 1.1 and 1.2) to open a massive number of dummy accounts (Sybil) on the InsecureNaiveBank
contract.
To open the dummy accounts, the attacker only spends 1 wei for each account.
Once the dummy accounts make the list of depositor accounts too large, a banker’s transaction to invoke the applyInterest
function, for computing all depositors’ compound interests, would be reverted due to exceeding the block gas limit error (Step 2), eternally freezing the interest calculation service. 🤧
The Attack
The code below presents the Attack
contract that an attacker can use to exploit the InsecureNaiveBank
contract.
|
|
To exploit the InsecureNaiveBank
, an attacker executes the Attack.openDummyAccounts()
function (lines 15–22).
An attacker can specify a large number of dummy accounts (along with supplying 1 wei for each account) they would like to register into the InsecureNaiveBank
contract.
The result of the attack is shown in Figure 2. As you can see, the attacker could permanently freeze the interest calculation service of the InsecureNaiveBank
contract by performing the Sybil attack.
The cost of the attack was very cheap. The attacker only spent 6,000 wei (+ the transaction gas) to register 6,000 dummy accounts to halt the InsecureNaiveBank
contract’s banking services eternally. ☠️
The Solution
The below FixedNaiveBank
contract is the improved version of the InsecureNaiveBank
contract. 👨🔧
|
|
To remediate the denial-of-service issue on the applyInterest
function, we must redesign how to process the depositors’ interests. In lines 57–77 above, we introduce the batchApplyInterest
function instead.
The batchApplyInterest
function enables a banker to execute multiple transactions (batch processing) for computing all depositors’ compound interests.
This way, even if the number of depositor accounts is enormous, the interest calculation service of the FixedNaiveBank
contract would no longer be frozen.
Note that:
Please do not use theFixedNaiveBank
contract in your production. TheFixedNaiveBank
contract is just a proof of concept of the batch processing but it still implants several security issues.
Even the approaches to calculating the interests, or registering and tracking depositor accounts are still insecure.
Summary
In this article, you have learned how the improper design of a smart contract can lead to a denial-of-service (DoS) attack.
You have understood how an attacker exploits the vulnerable contract and how to fix the issue. That’s it for this article. See you in the next article.
Again, you can find all related source code at 👉 https://github.com/serial-coder/solidity-security-by-example/tree/main/10_denial_of_service_with_gas_limit.
Author Details
Phuwanai Thummavet (serial-coder), Lead Blockchain Security Auditor and Consultant | Blockchain Architect and Developer.
See the author’s profile.
About Valix Consulting
Valix Consulting is a blockchain and smart contract security firm offering a wide range of cybersecurity consulting services. Our specialists, combined with technical expertise, industry knowledge, and support staff, strive to deliver consistently superior quality services.
For any business inquiries, please contact us via Twitter, Facebook, or info@valix.io.
Originally published in Valix Consulting’s Medium.