Smart contract gas griefing attack | The hidden danger

blog + secure coding + Smart contract + Solidity Z. Oualid today

Background
share close

To be able to perform the different tasks and execute the operations in its source code, smart contracts require a certain level of gas. This gas is paid by the user that tries to execute the smart contract using a transaction. However, when the user does not send enough gas for his operation, bad things could happen to the smart contract, if it does not manage this correctly. Therefore, what is a smart contract gas griefing attack?

A gas griefing attack happens when a user sends the amount of gas required to execute the target smart contract, but not its sub calls. In most cases, this results in uncontrolled behavior that could have a dangerous impact on the business logic.

Withing this blog post, I am going to explain in detail what this vulnerability means, its impact on the smart contract business, and how to fix it. In addition, I will give you some tools that you can use to discover this type of vulnerability. Moreover, we will discuss if this kind of vulnerability exists in other Blockchain technology. So if you are interested in learning more about this subject, just keep reading and leave a comment below.

What is a smart contract gas griefing attack?

A gas griefing attack happens when a user sends the amount of gas required to execute the target smart contract, but not its sub calls. This vulnerability exists in smart contract codes that either do not check the required gas to execute a sub call, or does not check the returned value of the call itself.

Let’s say, for example, you are building a smart contract-based game that requires the smart contract to send a portion of the user ethers to another smart contract to build an object. The object will then be used inside the contract to make payments inside the game. If the smart contract, does not check if the ether was successfully sent, then the attacker could fool the smart contract and bypass this payment.

This scenario may seem a little bit confusing, but I will give you another and a better one with a Solidity source code to better understand this vulnerability.

The fact that most Blockchain technologies that support creating smart contracts are still very new in the market this vulnerability is still not very known among the smart contract developers community. Therefore, most of those technologies are still not mature enough to be trusted to build a complex and secure application. In addition, a lot of vulnerabilities that can be introduced by developers during the building of those vulnerabilities are still not very known by the community.

If you want to know more about those vulnerabilities, I highly encourage you to take a look at my previous blog posts about some interesting vulnerabilities in the smart contract development:

Technical example of the gas griefing vulnerability

I always believe that the best way to understand the vulnerabilities is by looking at a vulnerable source code. Therefore, here is an example of such vulnerability:

Let’s suppose that the “Target” contract is the contract that the “Relayer” contract communicates with.

The relayer contract is the vulnerable contract, and the vulnerability is at the level of line 7. If you take a close look at this line, you will see that the smart contract tries to call the execute() function of the Target smart contract. As there is no check of the remaining gas nor the result of the call, the function continues its execution without any problem. This behavior can cause a serious impact on the application logic.

To better understand this concept, I highly recommend that you try to play with the example I have put here in Remix and Ropsten network. If you compile those two contracts and try to execute the relay function normally without increasing the gas limit, you will see that the contract will execute normally without any error. However, by checking the value of the result variable in the “Target” smart contract, you will notice that its value didn’t change.

This simply means that the smart contract “Target” didn’t finish its execution correctly (due to insufficient gas). To verify this, try to increase the gas limit and execute the smart contract function relay() again. Now you can see that the result variable value has changed.

This behavior is the one that creates this vulnerability in your smart contract and should be avoided by putting gas checks before performing the calls. If you want to learn how to prevent this vulnerability you can jump directly to the 5th section.

What is the impact of the gas griefing attack?

The impact of the gas griefing attack can go from a simple application revert to reaching a high financial loss. However, the actual impact of this vulnerability depends on the business logic of the smart contract.

How to detect the gas griefing vulnerability?

To detect this vulnerability, all you have to do is to look for the lines of codes that perform an external communication without result verification. Each time the smart contract sends, receive or even calls a smart contract function, there is a risk to find this vulnerability.

However, performing external communication without checking the results does not always mean that the vulnerability is exploitable or the impact is high. Therefore, to better discover and analyze this vulnerability you should first understand the business logic of the smart contract.

How to prevent the gas griefing vulnerability?

Preventing the gas griefing vulnerability is one of the most difficult tasks. In fact, the difficulty of this vulnerability comes from the fact that it requires an EVM update to be able to fix the issue. To my best knowledge, there is no effective technique for now to fix this issue. Even the solutions proposed by the Swcregistry and other still does not protect the users from this vulnerability.

Let’s first discuss why the proposed solution on Swcregistry website (which is by the way very popular) would not work correctly in some cases.

If we apply their solution, our vulnerable smart contract source code will become:

In this situation, the smart contract requires that the user itself specify the required gas to be sent to the “Target” smart contract to correctly work. If the gas left is less than the submitted value the transaction will revert. However, this does not mean that the Relayer will also revert if no gas was left for the execution of the “Target” smart contract. In addition, the user may also forget or maliciously specify a _gasLimit that is enough to execute the “Relayer” smart contract but not to call the “Target” smart contract.

Therefore, the risk will remain even with the proposed solution and a new one should be implemented. Here is the solution that I propose for this vulnerability:

In the first part of the solution, the developer needs to estimate the amount of gas that will be required by the call to correctly work. In addition, he needs to maximize that value to avoid at best the rise in gas in the future. This could be done like the following:

Before I start explaining this contract I would like to explain some key components of that source code:

  1. estimatedGasValue : this variable represent the amount of gas required by the call() function to correctly execute the Target smart contract function.
  2. gasNeededBetweenCalls: this is the estimated gas cost between lines 9 and 11
  3. gasAvailable/64 : this represents the amount of gas that will remain in the contract after calling the Target function. The 64 number comes from the fact that by default the smart contract leaves 1/64 of the amount of gas sent to the callee smart contract to allow the caller smart contract to finish its execution after that call finishes.

Line 9 of this smart contract calculates the amount of gas that will be available for the contract while reaching the call() function, at line 11.

Line 10 checks if the amount of gas after deducing that value from the gas sent by the user will remain higher than the estimatedGasValue for the call().

The idea here is actually the same as the one proposed by the Swcregistry. The only difference between them is in the fact that here the smart contract developer is the one who precise how much gas should be sent and not the user.

To enhance this solution, you can add functions to set the value of estimatedGasValue and gasNeededBetweenCalls as those values may change over time.

This solution is not perfect, as if the gas cost gets higher with time, the solution may fail. The best way to deal with this problem is by giving the EVM the ability to calculate the required gas for each call and revert the transaction if it is not sufficient.

Written by: Z. Oualid

Rate it

About the author
Avatar

Z. Oualid

I am a Cyber Security Expert, I have worked with many companies around the globe to secure their applications and their networks. I am certified OSCP and OSCE which are the most recognized and hard technical certifications in the industry of cybersecurity. I am also a Certifed Ethical hacker (CEH). I hope you enjoy my articles :).


Previous post

Post comments (0)

Leave a reply

Your email address will not be published. Required fields are marked *