Today, we’re going to take a look at a variety of different attacks, dissect the ways in which they differ from one another, and discuss ways to defend ourselves against them! Let’s get it started!
To begin, I’d like to point out that we’ll examine price manipulation attacks in the first part of today’s article, and reward manipulation attacks in the second; therefore subscribe to our blog — you’ll find a lot of interesting information there:
To begin with, smart contracts have been used in Web3 DeFi to implement a variety of lending and borrowing platforms, where market participants can either lend tokens to receive interest or borrow tokens to conduct other activities while paying interest.
Several days ago, Jimbo Protocol lost $8M because of the price manipulation attack, check out a detailed review & POC via this link!
Borrowers must provide collateral, which is stored in a smart contract within the DeFi system and can be liquidated by the Lender or other market participants if the Borrower fails to meet repayment schedule deadlines or the value of their collateral falls below a required threshold.
This deep dive aims to categorize the types of vulnerabilities in lending and borrowing platforms that auditors and developers should be aware of. However, today we will talk about only two of the types of attacks, and so first I’m going to talk about all types of attacks separately — because they are often confused…
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!
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! By the way, here are some vacant slots so if your project needs an audit — feel free to write to us, visit our public reports page here!
Let’s get in touch: gm@pessimistic.io!
So, today we are also going to study the hacks that have already happened and use each of them to analyze in detail how to write code to avoid getting in a similar situation.
But first, let’s define some concepts and for that I will refer you to this great study from the ChainLink team, in our opinion, it is the best current explanation of the mechanics of attacks and their types:
In the beginning, we would also like to express our heartfelt gratitude to the Chainlink VRF designers, community, everyone who supports it, 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!
Market manipulation occurs when the price of an asset is artificially manipulated by manipulating natural supply and demand forces. It is a deliberate action carried out by a malicious actor, usually with the intent of profiting at the expense of other traders.
Market manipulation, as a broad term, can refer to a wide range of techniques. The following are some examples of market manipulation techniques used in both traditional finance and DeFi:
Spoofing — Posting trade orders without the intention of executing them. A bot may be used to post a large number of orders that impact the behavior of buyers and sellers and then cancel those orders before they go through.
Ramping — Trades that artificially increase the market price of an asset to drive demand from actual buyers, who the malicious actor then sells to.
Bear raid — Attempts to artificially lower the market price of an asset through heavy selling or short selling.
Cross-market manipulation — Making trades in a trade environment to manipulate the price in another environment in order to make additional trades that profit from the divergence in price.
Wash trading — Both buying and selling an asset to give the impression of a higher trade volume in order to attract legitimate traders to the market.
Front-running — Making trades based on insider information that the rest of the market doesn’t have access to or before it can respond. In crypto, front-running is part of MEV. In the end of this article you can also find a list of tools and research for self-study, and we strongly recommend that you read it separately for better understanding!
These strategies can target a subset of an asset’s trading environment or the overall market price. A malicious actor may find it less expensive to target a smaller sector of a larger market, even if these attacks are more difficult to defend against and the opportunity to extract funds is smaller than manipulating the market-wide price.
I will refer you to this great study from the Hacken team, in our opinion, it is the best current explanation of the mechanics of attacks and their types! However, flash loans have become a popular feature in decentralized finance (DeFi) ecosystems, providing individuals and businesses with quick access to large amounts of capital without the need for collateral.
With flash loans, borrowers can receive funds that are immediately returned to the lending platform at the end of a single transaction block.
To execute a flash loan attack, an attacker typically follows a three-step process:
Borrowing: The attacker takes out a flash loan from a DeFi platform and borrows a large sum of cryptocurrency without providing any collateral.
Manipulating: Using the borrowed funds, the attacker manipulates the price of a targeted cryptocurrency or exploits a vulnerability in a DeFi smart contract.
Repaying: The attacker repays the flash loan, usually within the same transaction block, and returns the borrowed funds to the lending platform.
The ability to repay the loan within the same transaction block is critical to the success of a flash loan attack. This enables the attacker to take advantage of temporary liquidity without providing any collateral, making it difficult for lending platforms to defend themselves against such attacks.
It is critical to emphasize that, in most cases, flash loans are not vulnerabilities in and of themselves. Attackers use them to quickly obtain large sums of money, which can cause significant changes to the impacted systems.
Oracles deliver external data such as digital asset prices, the outcomes of sports matches, and weather information to blockchains and smart contracts.
Separately, our team recommends that you explore this amazing resource listed below for a deeper understanding of oracle manipulation; you’ll also find useful tools there:
An oracle exploit occurs when an oracle reports incorrect information about an event or the state of the outside world. This can occur if the oracle acts maliciously or negligently, or if the oracle’s data source is compromised.
The risk of oracle exploits can be mitigated with more secure oracle design.
Features of secure oracles include sourcing price data from across all trading environments to provide proper market-wide coverage, protections from external tampering that eliminate single points of failure via decentralization, and economic incentives to report faithfully that align oracles with their users.
A TWAP oracle is an oracle that provides information about the average price of an asset over a specific period. For example, if a user sets a 7-day interval for the TWAP oracle, the latter returns the average price of the asset across seven days.
Since flash loans are uncollateralized, attackers incur zero risk when performing price manipulation. The bZx exploit and Warp Finance exploit are prominent examples of flash loan attacks on lending protocols using on-chain price oracles. TWAP oracles attempt to solve the problem by making deliberate manipulation of a token’s price on a DEX costly.
When an oracle reports a price that differs from the correct market-wide price of an asset, this is referred to as misreporting.
Check out Chaos Labs — Uniswap v3 TWAP Oracle Risk Portal, which quantifies real-time pool manipulation risk.
Whether misreporting is caused by malicious or negligent behavior, any protocol that relies on a faulty oracle for price data may be vulnerable to an exploit.
Poor market coverage can also lead to oracles misreporting the price of an asset. Relying on only a subset of all trading environments makes them vulnerable to an oracle exploit if that subset is manipulated, even when the majority of trading environments and the market-wide price remain unaffected.
Below we listed just the only one instance of what might occur and what might trigger an attack. We are appreciative of the creator of the information below and urge you to thoroughly study the examples in order to comprehend the fundamental errors in lending regulations:
Care must be taken when implementing the repayment code such that the repayment is not lost by sending it to the zero address.
Review the following code from Cooler’s Sherlock contest:
function repay (uint256 loanID, uint256 repaid) external {
Loan storage loan = loans[loanID];
if (block.timestamp > loan.expiry)
revert Default();
uint256 decollateralized = loan.collateral * repaid / loan.amount;
// @audit loans[loanID] is deleted here
// which means that loan which points to loans[loanID]
// will be an empty object with default/0 member values
if (repaid == loan.amount) delete loans[loanID];
else {
loan.amount -= repaid;
loan.collateral -= decollateralized;
}
// @audit loan.lender = 0 due to the above delete
// hence repayment will be sent to the zero address
// some erc20 tokens will revert but many will happily
// execute and the repayment will be lost forever
debt.transferFrom(msg.sender, loan.lender, repaid);
collateral.transfer(owner, decollateralized);
}
“loan” points to storage loans[loanID], but loans[loanID] is deleted then afterward the repayment is transferred to loan.lender which will be 0 due to the previous deletion. Many ERC20 tokens will execute instead of reverting, causing the repayment to be delivered to the zero address and permanently lost.
This simple example seeks to demonstrate how even a minor logical mistake made during development can have catastrophic and irreversible effects. We’ll also look at examples of recent real-world hacker attacks as well as the outcomes of audits and bug bounties in the parts that follow, so let’s continue!
Market manipulation causes an asset’s price to change, whereas oracle attacks cause incorrect or invalid data to be reported, which does not reflect true asset pricing.
These issues have historically been confused and conflated because the end result is an asset price that leads to a loss of funds.
Market-based price attacks are based on changing an asset’s underlying supply and demand dynamics to the point where its price is affected.
Oracles that are properly designed report prices based on an asset’s actual market-wide price, regardless of the level of healthy liquidity in the asset’s underlying markets.
Even if the market-wide price of an asset has been manipulated, the oracle will still report that price because that is what oracles are designed to do.
What distinguishes oracle attacks is that market prices can still be determined by real supply and demand pressure. Instead, the oracle intentionally or unintentionally reports false information.
Below we have selected for you the most famous cases of such attacks, based on data from our databases, the list:
Today we are also going to study the hacks that have already happened and use each of them to analyze in detail how to write code to avoid getting in a similar situation!
Problem: the price oracle (keep3r v2) could take an arbitrarily small TWAP interval to calculate the collateral price, i.e. it was possible to manipulate the price in one block and perform an exploit in the next block.
Solution: you need to set the minimum TWAP interval to at least a few blocks, so that the attack is not economically profitable — arbitrageurs have time to balance the price in the pool. So, the longer the gap, the safer the solution, but the less relevant the price.
That said, During the audit, a non-compliance issue with the checks-effects-interactions pattern was identified in the
withdrawInternal()
function. When a position is collateralized with an ERC777 token, the user had the ability to withdraw the collateral while retaining their credit!
Separately, our team suggests that you examine the site below for a fuller knowledge of oracle manipulation; you’ll also discover useful tools there:
Problem: The Wdoge token takes commissions for transfers and additionally burns sender tokens in addition to the sent amount.
Exploit: This opens up the possibility of price manipulation in uniswap-like pools using skim(), since this function allows to burn tokens off the balance of the pair without doing a swap.
Solution: use tokens with transfer commissions only if you know what you are doing.
Sometimes even using Chainlink may not be enough to get an actual token price, and it’s often worth considering price feeds on-chain oracles as well.
But the protocol used bridge tokens (e.g. c.USDC.mad) for collateral, and Chainlink did not update their price. After the Nomad hack, the bridge tokens were deprecated, and in Moonwell it was possible to borrow with insufficient collateral.
Introduction: There is a thisAtoB() function in the RES token contract that swaps $RES to $ALL via $RES -> BSC-USD -> $ALL on PancakeSwap.
Problem: Inside thisAtoB() immediately after swap, burn $ALL tokens from BSCUSD-ALL pair.
Exploit: Swap BSC-USD to ALL manually on PancakeSwap. Then call thisAtoB(), which burns some tokens from the pair and thereby inflates the $ALL price. Then manually swap back to Pancake.
Solution: don’t do burn from the pair!
Introduction: There is a function scaledBalanceOf() in the contract that returns how much collateral the user has given.
Problem: This function counted as: sharesAmount.mul(_getTotalPooledApeBalance()).div(totalShares)
Here _getTotalPooledApeBalance could be manipulated by making an APE token deposit.
Exploit: Took flashloan, swapped to APE, deposited APE and then borrowed.
Solution: don’t rely/depend on balance!
Introduction: The token was deflationary. There is a deliver() function which decrements the _rate which is used to calculate the balance.
Problem: Similar to WDOGE-BNB pair exploit, attack by calling pancakeSwap skim() after transfer to pool, and selling tokens at high price after that.
Solution: be extremely careful with deflationary tokens!
Introduction: If receiver in transfer was a uniswap pool — then amount was added to sellPressure[user]. There is also releasePressure() function, which would burn sellPressure[user] from a uniswap pool, this function was triggered when transferring 0 token to itself.
Problem: Very strange design flow, but it is actually possible to burn tokens from pool.
Exploit: A hacker made swaps to raise sellPressure, then triggered releasePressure(), which burned the pool tokens, and then sold the tokens at a high price…
Solution: don’t do burn from a pair!
Introduction: A token has a procback function that burns tokens from the pool.
Problem: Because you can burn, you can manipulate the price in the pool.
Solution: Don’t burn a pair!
In order to prevent encountering similar situations, we will also review past hacks and use each one to thoroughly examine how to build code!
Introduction: There was an airdrop contract, giving rewards to token holders.
Problem: In order to get the drop, the user’s balance was checked (via balanceOf()), so a hacker could take a flashloan and brand almost all rewards by creating contracts and making a claim.
Solution: do not depend on the current token balance, use snapshot of the balances!
Introduction: Rewards were given for staking LP tokens.
Problem: Due to a problem in the contract logic, the reward was piling up. (adding a new reward instead of assigning one).
Solution: check logic, ask a question what happens if someone make claim several times in a row.
Introduction: You could deposit a token and a reward was given that depended on the deposit.
Problem: There was no time check in the contract for when you could pick up the reward. It was possible to take the reward on the same block as the deposit. Developers tried to limit contracts through “Address.isContract” (which checks address.codesize), but this can be bypassed through a constructor call.
Exploit: Hacker took a flashloan, made a deposit, took the rewards
Solution: check block by block that you can’t take the rewards right away.
Introduction: There was a contract where you could stake LP tokens, and get rewards…
Problem: The reward depended on the total number of LP tokens staked. The problem was that there was a withdrawTeam() function that could be used to send all LP tokens to the address specified by the developers, and this function was not protected by roles. In addition, in the transferFrom function, if the tokens were sent to the pool, a reward of 7% of the amount was added.
Exploit: The hacker took a flashloan, got the necessary tokens, called withdrawTeam(), sent to the pool via transferFrom, returned via skim(), deposited a small amount of LP tokens into the contract. Branded rewards and got big income.
Solution: withdrawTeam must be role-protected. You can’t allow everyone to get rewards (logic in transferFrom).
Separately, our team advises you to look into the following source for more information on auditing process and to access some useful tools:
Introduction: Rebasing token, when transferring from LP pool, everyone (except pool) has increased number of tokens depending on amount of transfer.
Problem: You can take a flashloan, send tokens to pool, call skim(), increase your balance and sell tokens.
Solution: Remember that a pool transfer does not necessarily == buy and that the user can take a flashloan.
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???
By the way, here are some vacant slots in the second quarter of 2023 now so if your project needs an audit — feel free to write to us, visit our public reports page here!
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:
Consider further layers of security in your dApp:
Circuit breakers — In the case of an extreme price event, the contract would pause operations for a limited period of time.
Contract update delays — Contracts would not update until the protocol had received a recent fresh input from the data feed.
Manual kill switch — If a vulnerability or bug is discovered in one of the upstream contracts, the user can manually cease operation and temporarily sever the connection to the data feed.
Monitoring — Some users create their own monitoring alerts based on deviations in the data feeds that they are using.
To add, in recent months we have been actively developing our own Slither detectors to help with code review and audit process. This repository contains everything you may require to work with them!
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 the following form:
Considered as a Price Manipulation Attack type.
In today’s article, we’ve just discussed price manipulation attacks, and in the next article, we’ll look at reward manipulation attacks! Considered as Oracle Manipulation Attack types.
Ede Finance: A Case Study of Price Manipulation and Exploitation
Oracle Manipulation Resources
Comparing Price Manipulation Attacks Across Layer 1 and Layer 2 Decentralized Exchange Platforms
Front-running — Making trades based on insider information that the rest of the market doesn’t have access to or before it can respond. In crypto, front-running is part of MEV. Considered as a Price Manipulation Attack type.
A list of 37 channels from my personal news feed… This is not an ad!
We hope that this article was informative and useful for you! Thank you for reading! What instruments should we review? What would you be interested in reading about?
We promise you that we’ll be posting a lot of interesting stuff soon! Make sure to read the rest of the series:
Support is very important to me, with it I can do what I love — educating users!
If you want to support my work, you can send me a donation to the address:
0xB25C5E8fA1E53eEb9bE3421C59F6A66B786ED77A or officercia.eth — ETH, BSC, Polygon, Optimism, Zk, Fantom, etc
4AhpUrDtfVSWZMJcRMJkZoPwDSdVG6puYBE3ajQABQo6T533cVvx5vJRc5fX7sktJe67mXu1CcDmr7orn1CrGrqsT3ptfds — Monero XMR