Solidity Front Running Attack

7 min read

Understanding the smart contract vulnerability caused due to front running of transactions.

Blockchain and cryptocurrencies have revolutionized the world of finance, providing secure, decentralized, and transparent systems for managing transactions. However, despite the advantages of blockchain, security threats are ever-present, and one of the most insidious attacks is the front-running attack. This attack involves a malicious actor exploiting blockchain information asymmetry to profit from a trade or transaction by executing a similar one before the original one is processed.

The objective of this blog post is to provide a comprehensive understanding of the front running attack in the realm of blockchain and cryptocurrencies. We will define the term and elaborate on its workings, examining its potential consequences for the blockchain ecosystem. This is an addition to the series from our earlier blog, where we shared the details of Solidity Integer Overflow and Underflow.

Vulnerability#

In the world of blockchain, transactions are publicly visible, allowing anyone to access their contents. When a transaction is broadcasted, it enters a pending transaction pool, known as a mempool, where it awaits processing into a block. However, as the number of transactions exceeds the maximum throughput of the blockchain, the backlog of pending transactions increases, resulting in longer waiting times.

To prioritize the processing of transactions, users can offer higher fees to miners, who are compensated for running code on behalf of other addresses. Miners select transactions with higher fees to maximize their profits, resulting in faster processing times for those transactions.

However, this fee-based selection process can be exploited by malicious actors. By offering a higher transaction fee, an attacker can ensure that their transaction is processed before any other transaction, allowing them to profit from price fluctuations before the original transaction is executed. This is known as a "front-running attack."

Attack Explained#

Consider the below smart contract HashSolver.sol,



Line 5 - 6:

In line 5 of the contract, we have declared an immutable public variable named hash. In line 6 of the contract, we have assigned the equivalent bytes32 value of "Neptune Mutual" to this variable. (Check Neptune Mutual’s online Web3 tool, String to Bytes32 Converter, which makes it simple and convenient to convert the string value to its equivalent bytes32 representation.)

In Solidity, Immutable variables can be assigned an arbitrary value in the constructor of the contract or at the point of their declaration. They cannot be read during construction time and can only be assigned once.

Line 8:

In line 8, we defined an empty contract constructor. It is empty, which means it has no instructions to execute. It is, however, marked as payable, which means that the contract will be able to receive Ether when it is deployed.

Line 10-14:

In line 10 of the contract, we created a function named solver with a string parameter called `solution`.

The require statement in line 11 of the contract checks if the hash of the solution parameter matches the hash variable that was earlier declared.

The keccak256 function is used to compute the hash of the solution parameter, and the abi.encodePacked function is used to convert the string into bytes before hashing. If the hashes don't match, the function will revert with the error message "Incorrect answer".

In line 13 of the contract, 15 Ether is sent to the address that called the solver function. The msg.sender variable refers to the address of the caller. The function returns a tuple with two values, the first of which is a boolean variable sent that indicates whether the transaction was successful. The second value is ignored.

The line 14 of the contract checks if the transaction to send Ether was successful. If it was not successful, the function will revert with the error message "Failed to send Ether".

Attack Scenario:

Let us assume there are two characters, Alice and Bob. Alice deploys this HashSolver contract. The intuition is to guess the string that correctly hashes to the target hash. The winner takes away 15 Ether.

Bob is able to guess the string "Neptune Mutual" that will correctly hash to the target hash. Bob calls the solver function of the contract by passing this correctly guessed string value, with the gas price set to 20 gwei.

A malicious actor, Eve, is watching the transaction pool for the answer to be submitted. After seeing Bob's submission, Eve quickly initiates their transaction with the same string parameter but with a higher gas price than Bob, let's say 100 gwei.

Eve's transaction was mined before Bob's transaction was, and thus the attacker took away the rewards from the contract.

Attack Categories#

The categories of attack in front-running attacks could include stealing requests, price manipulation, and transaction blocking. These attacks typically involve an attacker gaining an unfair advantage by executing transactions before or after the victim's transactions, thereby profiting from price differences or other advantageous circumstances. Let’s consider the case of Alice as an illustration of how a person could fall prey to such an attack.

Displacement#

Displacement, in the context of front running attacks, refers to the act of deliberately delaying the broadcasting of a transaction to gain an advantage over other users. Suppose Alice makes a request to register a domain name. In such a scenario, an attacker could steal Alice's request, register the same domain name themselves, and complete the process before Alice has a chance to do so. This would render Alice's request useless.

Insertion#

It is an act of adding a transaction to the mempool just before a known transaction is about to be executed. Suppose Alice submits a purchase order for an item at a price that is higher than the current best offer. In this case, an attacker might intervene and carry out two transactions. First, they would buy the same item at the best offer price, and then sell it to Alice at a slightly higher price. This way, if the attacker executes Alice's transaction, they would earn a profit from the price difference without having to keep the item.

Suppression#

It refers to the act of preventing a transaction from being broadcasted to the mempool. The attacker tries to delay Alice from running her execution until after s/he has finished his/her calls. To the adversary, after the delay period, it does not matter if Alice's transaction runs or not.

Exploit Impact#

  1. Bancor

    Bancor was identified to be vulnerable to a front-running attack by Cornell researchers. They indicated that miners would be able to front-run any transactions on Bancor because they are free to reorder transactions within a block they have mined. Although the Bancor team initially responded thoughtfully, nothing was done to resolve the problem.

    Later, these researchers demonstrated that front-running Bancor as a non-miner was both feasible and practical. This means that front-running on Bancor was profitable even if we're not the fortunate miner who just so happens to mine the block with a Bancor trade. To carry out this attack, all they needed was to be a regular user keeping an eye on the blockchain.
  1. The DODO

    DODO V2 was the victim of a smart contract vulnerability. The attacker utilized a fake token and invoked the vulnerable contract's init function. Using the contract's sync function, the attacker set the contract's reserve variable token balance to 0. The attacker called init once more, but this time it pointed to a legitimate token from one of DODO's pools. The attacker used a flash loan to extract the real tokens from the pools and drain the liquidity.

    The original DODO attacker was the victim of a front-running attack carried out by trading bots during the process. These trading bots were able to frontrun the DODO attacker's transactions by setting a very high transaction fee. As a result, the bots were able to complete their transactions ten minutes before the original attacker.

    As a result, two trading bots used the original attack to launch their own exploits against the vulnerable contract. The owners of both of these bots eventually agreed to return the stolen funds, which totaled approximately $3.1 million.

Prevention#

The key aspects that make a contract vulnerable to front-running attacks are a lack of transaction confidentiality and the miner's ability to randomly order and prioritize transactions. The front-running attacks can be mitigated to a greater extent by,

  • Using a commit-reveal scheme.

    It limits the visibility of the transactions by allowing users to commit to a value while keeping it secret from others with the option of making it public later. This scheme's values are irrevocable, so once they have been submitted, no one can alter them. A value is chosen and specified during the commit phase of this scheme, and the value is revealed and verified during the reveal phase.
  • Controlling the gas fee cost.

    Another strategy to mitigate the impact of such attacks is to include logic in the contract that specifies an upper bound on the gas fee. This prevents users from increasing the gas fee and receiving preferred transaction ordering above this maximum threshold.

Conclusion#

Blockchain's transparency allows everyone to see the contents of transactions in a mempool, where transactions await processing. To prioritize the processing of transactions, users can offer higher fees to miners, who select transactions with higher fees to maximize their profits, resulting in faster processing times for those transactions. However, this fee-based selection process can be exploited by malicious actors by offering a higher transaction fee to ensure that their transaction is processed before any other transaction, allowing them to profit from price fluctuations before the original transaction is executed.

Reference Sources Code ChainConsensys

By

Tags