Officer's Blog

Posted on Jun 07, 2023Read on Mirror.xyz

Read-only Reentrancy: In-Depth

Greetings, dear readers!

We continue our series of educational articles and today we’ll look at Read-Only Reentrancy Attack — one of the attacks that used to be very common in the Web3 smart contract-based projects, but has recently been relegated to the background, although they still pose a great danger!

To begin with, we will understand what Reentrancy is, what tools are currently available to detect it and, most importantly, how to reliably protect your project and your users from this type of attack.

That said, we tend to believe that there is no one who doubts that the basis of any secure implementation is a special approach to writing code. Consequently, this article will be focused only on those aspects that can be really useful for making your code safe and secure!

Therefore, below you will see not a typical article but a systematization of knowledge (SoK), in which I will rely on authors that I myself trust in this matter and, of course, our pessimistic.io auditors!

We will share our own observations and give some advice in the next article in our series, since our team has been working since 2016, we have accumulated quite a few of them. You will also find a list of tools and research for self-study, and we strongly recommend that you read it separately for better understanding.

A few months ago we finished our own research of Reentrancy attacks, in many ways, this article will rely on information from our old article so read it if you haven’t already:

https://officercia.mirror.xyz/RoWpSjah4hvKvCyrCgqtdyWX657e3-qUeShBZ2VtkUs

In the beginning, we would also like to express our heartfelt gratitude to the community, the authors of all resource materials, and, of course, our in-team auditors who have assisted us by providing much-needed information and breaking the veil of secrecy!

By the way, there are some vacant slots now so if your project needs an audit — feel free to write to us, visit our public reports page here!


I — Reentrancy Attacks

The issues surrounding Reentrancy in smart contracts, as is often the case with blockchain technology, do not originate in blockchain, but rather provide a novel and complex example of them.

Here’s the first ever documented reentrancy attack:

For a better understanding of Reentrancy attack variations, visit this amazing chronological and (hopefully) complete list of Reentrancy attacks to date.

Reentrancy is a term that has been used in computing for a long time to describe the process by which a process can be stopped in the middle of execution, a new occurrence of the same function can start, and both processes can then terminate.

We use reentrant functions in computing safely everyday. One good example is being able to begin an email draft in a server, exiting it to send another email, then being able to return to the draft to finish and send it.

https://officercia.mirror.xyz/TU9__AcmdWlGuXfN8FQlKvh42gs6V1VbS7vOt0iz3kA

Blockchain is a bit different — for example: If the target of an external call is a malicious contract controlled by the attacker, the attacker can execute the malicious logic when the attacked contract calls the malicious contract.

Then it will re-enter the attacked contract to make an unexpected external call, affecting the attack contract’s standard execution logic:

quantstamp.com/blog/what-is-a-re-entrancy-attack

However, Reentrancy mechanism could be used not only for attacks! For example, 1inch Network uses it for the Fusion mode — limit orders are being filled recursively via taker’s interaction reentrancy. Truly amazing, much thanks Anton Bukov for spotting this feature!


II — Read-Only Reentrancy

Most Reentrancy attacks are done by reentering the same function (Single Function Reentrancy) it is called from; however, there are also other variations that are harder to discover and prevent.

We won’t go into length about each of these in this post, but we will offer a couple of links at the conclusion for you to investigate further!

https://quillaudits.medium.com/decoding-220k-read-only-reentrancy-exploit-quillaudits-30871d728ad5

Typically, auditors and bug hunters are only concerned with entry points that modify state when looking for reentrancy. However, read-only reentrancy can occur when a protocol relies on reading the state of another.

Conditions for Read-Only Reentrancy

To protect yourself and your code during the development or auditing process, keep the following points in mind. Your code typically becomes vulnerable in these types of conditions:

  • There is some state: ;

  • There is an external call, and this state is modified after the call;

  • There is another contract, which depends on this state (utilized by getter).

Next, let’s examine the following screenshot:

Let’s examine the example and identify the cause of the problems shown on the screenshot above using the list mentioned above as a guide:

  • There is some state: (_number in this example);

  • There is an external call, and this state is modified after the call;

  • There is another contract (MinimalVictim), which depends on this state (utilized by getter).

Next, let’s examine another screenshot once we’ve finished with the first example. We recommend you pay close attention to this scenario because it will help you predict potential issues with your code:

  • In the following example, the state is located in a third contract (token balances). Since shares are burned first, during the msg.sender.call, getSharePrice() will return the higher prices, because balances are not updated yet. Which means, attacker can manipulate on share price, if some contract is depending on getSharePrice() function…

The classical examples of reentrancy typically reenter in a state-modifying function so that an inconsistent state is used to perform malicious writes on the contract’s storage. Typically, contracts guard themselves with reentrancy locks, protecting their state from such malicious actions.

TL;DR

The read-only reentrancy is a Reentrancy scenario where a view the function is reentered which in most cases is unguarded as it does not modify the contract’s state.

However, if the state is inconsistent, wrong values could be reported. Other protocols relying on a return value, can be tricked into reading the wrong state to perform unwanted actions. Check out this blog and this article to know more about this.


III — Countermeasures

To establish already existing reentrancy, auditors use different tools and methods — there are a lot of them. Just take a look at an awesome selection below and choose the one that will work out for you the best.

https://officercia.mirror.xyz/ucWYWnhBXmkKq54BIdJcH5GnrAB-nQkUsZ2F-ytEsR4

The majority of existing tools, both free and paid, can be used to detect this type of vulnerability. However, some of them can detect only one type of vulnerability while others can detect all of them.

Here is a list of some of the best tools for locating those vulnerabilities:

From our perspective, Slither is certainly the best at finding such vulnerabilities, but keep in mind that you need to configure it properly!

Our team would like to express our deepest gratitude to the Slither tool creators: Josselin Feist, Gustavo Grieco, and Alex Groce, as well as Crytic, Trail of Bits’ blockchain security division, and all the people who believe in the original tool and its evolution!

Check out our recent article about the Slither, if you haven’t already:

https://blog.pessimistic.io/slither-an-auditors-cornucopia-a8793ea96e67

Pre-auditing the code and using the tools and tips listed above will assist you in detecting Reentrancy, but I believe you’ll agree that it’s better not to let this happen at all!

Our Own Detector: Slitherin

In recent months we have been actively developing our own Slither detectors to help with code review and audit process. More recently, we have released our own detectors and we encourage you to use them for your initial internal audit, particularly the read-only Reentrancy detector:

https://github.com/pessimistic-io/slitherin/blob/master/slither_pess/detectors/read_only_reentrancy.py

Our aim was to increase the sensitivity of the detector to assist our auditors, so it is quite straightforward and not written in the “original style.” As a result, it produces FPs (False Positives) more frequently than “original Slither” ones.

So that, our detectors are a kind of automation of the checks implemented in the checklist, their main purpose is to look for issues and assist the code auditor!

Please let us know if you have discovered an issue/bug/vulnerability via our custom Slither detectors. You may contact us via opening a PR/Issue or directly, whichever is more convenient for you!

Slitherin Configuration

This detector highlights the use of getter functions that return a value that theoretically could be manipulated during the execution. Follow these steps to configure and install it:

  • Check: pess-readonly-reentrancy

  • Severity: High

  • Confidence: Low

Ensure that getter function values aren’t crucial and can’t be maliciously used in other contract parts during external calls before being updated!

Follow these links to use our detector:

If you have any further questions or suggestions, please join our Discord Server or Telegram chat. We hope to see you there, and we intend to support the community and its initiatives!

Defense Tactics:

But first, let’s define some concepts and for that I will refer you to this great study from the Immunefi team, in our opinion, it is one of the best current explanation of the mechanics of attacks and their types:

https://medium.com/immunefi/the-ultimate-guide-to-reentrancy-19526f105ac

A) Reentrancy-Guard (No Read-only Reentrancy)

It is much simpler for us to protect ourselves when we are not dealing with read-only reentrancy, for instance, by adhering to the following guidelines and practices. We will dissect these defense strategies in the point A before moving on to our main subject in point B, which is read-only reentrancy.

Anyway, let’s start from the simple to the complex and examine how the following types of reentrancy are protected. It is crucial to recognize the variations and parallels between these types of reentrancy:

In short, all of mess with mentioned Reentrancy types can be avoided if you improve the quality of your code, and we will now tell you exactly what you should take into account:

  • When writing code, you need to follow the coding standard (Checks-Effects-Interactions) of the first judgment and then write variables in external calls. You should also keep in mind that using CEI for all trusted contracts may be used with caution in order to prevent cross-contract read-only Reentrancy;

  • Add a Reentrancy guard; this prevents more than one function from being executed at a time by locking the contract.

The following is a code example of a reentry guard:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;
contract ReEntrancyGuard {
bool internal locked;
modifier noReentrant() {
require(!locked, “No re-entrancy”);
locked = true;
_;
locked = false;
}}

Auditors also suggest paying attention to the characteristics of reentrance vulnerabilities: all code locations involved in external contract calls are insecure. You need to focus on external calls and then deduce the possible harm of external calls to judge whether they can be exploited due to the reentry point!

We’d like to highlight the following learning resource in particular, use it to improve your security skills:

https://github.com/jcsec-security/all-things-reentrancy

B) Read-only Reentrancy: Countermeasures

In order to reduce the mess, you must raise the caliber of your code. We will now outline the specific considerations you must make:

  • In protocols:
  1. Check reentrancy lock on vulnerable view functions;

  2. Make reentrancy locks public viewable.

  • In integrated projects:
  1. Use lib/public reentrancy info;

  2. In case for legacy contracts: try to call reentrancy protected function.

That said, reentrancy attacks continue to be a major concern in the world of smart contracts. To reduce the risk of reentrancy attacks, developers must remain vigilant in their coding practices and implement best security practices; for now, check out:

For a better understanding of Reentrancy attack variations, visit this amazing chronological and (hopefully) complete list of Reentrancy attacks to date!

C) Monitoring & Active Protection

Auditors and security researchers are also important in identifying vulnerabilities and providing feedback to developers. Through bug bounties (for example — Immunefi) and audits, the blockchain community can continue to improve the security of smart contracts and prevent reentrancy attacks from causing further harm.

Auditors, in turn, can (and IMHO must!) contribute to the development of FOSS tools! But… when looking at this month’s never-ending hacks, one may wonder why they happen so frequently

Have audit firms actually gotten worse at what they do???

This, in our opinion, is not the case; yet, the topic is rather tricky because, in certain ways, you can reduce the risks to yourself and your project!

Risk mitigation is not something to set and forget; it’s a continuous process of monitoring, updating, and refining processes based on evolving market conditions. Please note, we are working on such a solution within the team and hope to deliver it shortly:

https://blog.pessimistic.io/spotters-digest-6-5b990fb1642

Check out our Pessimistic’s Spotter On-Chain Monitoring & Active Protection Service! Unlike the private version, the public version (this channel) reveals attacks selectively and does not allow you to track a specific address. To utilize the private version, which offers more features, fill out this form!

Thank you for reading to the end! We hope that this article was informative and useful for you! What instruments should we review? What would you be interested in reading about?

Please leave your comments, we will be happy to answer them, and the best answers and questions may be included in the next article!


IV — Resources & Tools

Important:

External:

Also Check Out:

We hope that this article was informative and useful for you! Thank you for reading!


By the way, there are some vacant slots now so if your project needs an audit — feel free to write to us, visit our public reports page here!

Support is very important to me, with it I can do what I love — educating users!

https://github.com/OffcierCia/support

If you want to support my work, you can send me a donation to the address:

Stay safe!

Recommended Reading