Solidity Security By Example #10: Denial of Service With Gas Limit

Phuwanai Thummavet
Valix Consulting
Published in
5 min readMar 28, 2023

By Phuwanai Thummavet

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 Attack
  • The Solution
  • Summary

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 the depositFor 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:

  1. The number of depositor accounts grows over time due to the ordinary adoption
  2. 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. 😈

Figure 1. How to freeze the interest calculation service 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.

Figure 2. The attack result

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 the FixedNaiveBank contract in your production. The FixedNaiveBank 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.

--

--

Phuwanai Thummavet
Valix Consulting

Blockchain | Coding | Hacking — I’m a full-time bug collector. Most of the time I bring some bugs to life. Visit my website: www.serial-coder.com