Smart Contract Attacks: Hundred Million Dollar Heists, Rug-pullers, Front Runners, NFT Snipers, and Uninformed Auditors
The nefarious tactics being employed in the crypto universe are a useful study because they shed a light on the current state of risk and what needs to be improved in terms of trust. This write-up covers some recent security incidents, the analysis of root causes, and helps set the stage for an understanding of what’s to come in terms of the players involved and their future incentives.
$31 Million USD Stolen Because Someone Forgot an if Statement
On November 30, 2021, $31 Million USD was stolen from the MonoX Protocol smart contracts deployed on the Ethereum and Polygon network.
As shown in Figure 1, the hacker was able to steal millions of dollars of the MonoX smart contract. The hacker did this by exploiting a vulnerability in the contract responsible for swapping one crypto token for the other from the liquidity available in the MonoX contract.
Figure 2 highlights the _updateTokenInfo function that is called twice during the linear execution of the code. The job of this function is to update the price of the given token in the liquidity pool of the contract. When it is first invoked, it updates the price of the token that is being sent in. Since this token is being swapped in, the result of the function will be to lower the price of the token in the pool.
The second invocation of _updateTokenInfo is designed to update the price of the token that is being swapped out, i.e. proportionally increasing the price of the token in the pool.
The vulnerability here is that there is no check to make sure the tokens being swapped in and out are the same. The attacker exploited this by providing the MonoX token (relatively cheap at the time) and swapping it back for MonoX. The result of this is that the result of the first invocation of _updateTokenInfo was overwritten by the second invocation, resulting in the price of the MonoX token in the pool to go up. The attacker looped this swap multiple times causing the price of MonoX to skyrocket within the smart contract and then ultimately swapping out for $31 Million dollars worth of $ETH.
Polymathic Threat Libraries
Halborn and Peckshield, both popular smart contract auditing firms had audited this code and did not find this attack scenario and vulnerability. So why was this attack vector not caught prior?
At first glance, it may appear that the vulnerability was an elementary oversight in the smart contract code and that any competent smart contract coder or auditor should’ve caught this issue. However, the root cause is far much nuanced. From the vantage point of a foundational computer science principles, checking to see if the input and the output of a converter operation are the same is a matter of preserving efficiency and avoiding waste of compute, not preventing millions of dollars of theft. From the perspective of an auditor, this particular attack vector may not have been included in the checklist of common pitfalls to assess for as part of the audit methodology.
Code designed to own millions of dollars of collateral requires insight not just from those who know of common application security pitfalls, but also from financial experts who have studied and dealt with transactional fraud in various dimensions. In the near future, we are going to witness the pillage of billions of dollars from smart contract vulnerabilities such as these until we bring together a threat model derived from cross functional polymathic thinking rather than relying on our past knowledge of categories of common code flaws as a stand alone.
Front Runners, Flash Loans, and the General Public
The exploitation of the MonoX bug required that an attacker analyze the smart contract code to pin point the issue, yet opportunities to leverage token conversion rates for profit in real time are a feature of blockchain architectures where pending transactions are advertised publicly (mempool). This lends to transaction front running opportunities that are exploited in near real-time on an ongoing basis.
Take a look at the transactions in Figure 3. Notice that the transactions occur in pairs. This is a front running bot that monitors the blockchain mempool for pending transactions, gets ahead of a target transaction by providing very high gas fees and issuing its own transaction that has a material influence on the token price, and then cashes out by submitting a transaction to execute in the same block after the target transaction to make money on arbitrage from the price difference.
Figure 4 shows a transaction from the front running bot supplying a large amount of ETH to swap for the FTM token.
Figure 5 shows another transaction by the bot on the exact same block. Notice the extremely high transaction fee (3.1 ETH) offered for this transaction to make sure it was on the same block.
The bot supplied 245.99 ETH in the first transaction and swapped back out of FTM in the second transaction for 249.25 ETH. These two transactions were sandwiched before and after a target transaction that bought a large amount of FTM. In essence, the bot jacked up the price of FTM by buying it before the target transaction and then sold after the target transaction completed its purchase for a profit of 3.26 ETH. However, the bot paid 3.2 ETH in transaction fees and so its net profit was about 0.06 ETH. The price of Ether at the time of the transaction was about $3,002 so the bot made a profit of $180 USD.
Did the bot risk 245.99 ETH, i.e. $738,461 just to make $180 in profit? The bot didn’t risk anything because it leveraged a flash loan to come up with the ETH. In DeFi, it is possible to borrow large amounts of money without supplying any collateral as long as you pay back the money to the loan provider within the same block — this is called a flash loan. If the loan isn’t paid back within the same block, the transactions revert. Notice that both the bot transactions occurred in block 14043783 as expected. In other words, the bot did not risk any of its own collateral to make $180 in profit.
Front-running is possible because the public nature of blockchain transactions expose the pending transactions in the mempool that potential attackers can look at. The concept of reordering of transactions by miners based on parameters such as fees is formally referred to as Maximal Extractable Value (MEV). More on MEV and the status of possible future mitigations is available here https://ethereum.org/en/developers/docs/mev/.
When it comes to end users, a good rule of thumb is to make sure token swap transactions are set to use minimal “slippage”, i.e. the difference in the amount of output tokens the user is willing to accept should the swap go through.
However, some tokens have implemented tokenomics that take a fee for buying and selling the particular token to incentivize long term investments. Users are asked to increase their slippage tolerance to as much as 20% in some cases so that the swap goes through and the token smart contract is able to take the fee. This often causes confusion on part of end users who end up setting a high slippage setting in their default settings for these particular tokens and then subject themselves to front-runs in future transactions (forgetting to lower the slippage). The role of liquidity swap providers and crypto wallets issuing warnings will be crucial in minimizing front-run exposures on the end-user side.
NFT Fat Fingers and Value Inventory
End users not only have to worry about things like slippage, but also momentary typos that can lead to the loss of hundreds of thousands of dollars within seconds.
Figure 6 shows a listing of an NFT for 75 ETH ($300,000 USD at the time) followed by a listing of 0.75 ETH ($3,000 USD) which was immediately purchased by someone else and sold back in the market for 59.99 ETH ($240,000 USD). This NFT today is priced at 199.99 ETH ($800,00 USD).
Obviously, the listing of the NFT for 0.75 ETH was a typo on behalf of the NFT owner. There exist bots that scrape through these scenarios by detecting listings in near real time that show a significant drop of the listing price compared to the floor price or the listing price being a 10x factor divisible to indicate listing typos. Various NFT market places such as OpenSea are implementing warnings to prevent these types of mistakes from users.
Value driven NFT tokens are evolving to include features such as profit sharing where the NFT token itself collects passive revenue (in ETH) that can be claimed by the NFT owner.
Figure 7 shows the description the Autonomous Art token that once minted collects a price share of all future mints.
Since the NFT holds the value of revenue collected per token in ETH, its smart contract can be queried by anyone to figure out how much ETH has been collected and ready to be withdrawn given the tokenId of a given NFT. Figure 8 shows the response from the contract showing that NFT tokenId 305 has about 1.3 ETH ready to be withdrawn.
Figure 9 shows that tokenId 305 is on sale for 0.2 ETH. This means that anyone can purchase this NFT outright for 0.2ETH, and then claim the 1.3ETH in its piggy bank in the smart contract to make an immediate profit of 1.1ETH.
(Note that the images are for illustrative purposes and token 305 does not contain 1.1 worth of claimable ETH as of this writing, make sure to do your own research).
In the current ecosystem of NFT wallets, it is difficult to see this sort of claimable values per NFT in one place. NFT wallet projects and APIs will certainly bring order in the near future so that end users can see the inherent value of their NFTs in one place, but until that happens, there is opportunity for NFT snipers to go after these scenarios to make a quick profit (among other tactics).
$611 Million Drama
In August 2021, smart contracts managed by the Poly Network team were hacked to steal a total of $611 Million USD. The attacker exploited lack of verification checks across smart contracts to pull this off.
The verifyHeaderAndExecuteTx function in EthCrossChainManager shown in Figure 10 is public, meaning that anyone can call it directly. It ultimately makes a call to the _executeCrossChainTx function. The target of the call (derived into the toContract address) is constructed from the input chain.
The EthCrossChainData smart contract keeps track of trusted public keys (highlighted in Figure 11).
The putCurEpochConPubKeyBytes function in EthCrossChainData shown in Figure 12 can be invoked to reassign the set of trusted public keys. However, the function is set to OnlyOwner so it can’t be invoked publicly.
But who owns the EthCrossChainData smart contract? Answer: the EthCrossChainManager contract.
The attacker abused this chain of dependencies to send invoke verifyHeaderAndExecuteTx with the right payload so that the EthCrossChainManager contracted invoked putCurEpochConPubKeyBytes on EthCrossChainData to set the public key to be that of the attacker. For details of the payload, see Kevin Fichter’s walk through https://twitter.com/kelvinfichter/status/1425217046636371969.
A few moments after the incident, the attacker seemed to be eager to negotiate return of the funds as shown in Figure 13 by way of transaction 0x7b6009ea08c868d7c5c336bf1bc30c33b87a0eedd59dac8c26e6a8551b20b68a on the Ethereum blockchain.
It is probable this stance from the hacker was upon the realization that certain she or he made certain transactions to crypto exchanges that had perviously verified their identity.
Figure 14 illustrates a spreadsheet tracking the communication from and to the attacker and the refunds received. Make sure to double check every associated referenced transaction on the blockchain prior to relying on the information contained in the sheet which can be found here: https://docs.google.com/spreadsheets/d/11LUJwLoHX8ZCyfjhg5YZ0V99iU6PafMNL_NET45FSVc/.
Sophisticated Attack? Think Again
The community consensus seems to be that this was a technically sophisticated attack since it exploited multiple contracts and the trust between them. Perhaps the $611 Million price tag primes our psychology to think as much.
From the vantage point of a potential attacker with time on their hands (and not much to lose), the route towards discovering this vulnerability is quite elementary and in the checklist of any reasonably determined hacker: “look at every function in the smart contract that is designated as public and only give it up as an entry point once you understand it’s logic and dependencies to other code, internal or external”.
In other words, the idea of studying publicly exposed functions in smart contract as entry points to vulnerabilities is the most fundamental tactic in the arsenal of any hacker. In this case the attacker had additional hoops to jump that can easily be figured out with some additional research. Or perhaps, everything seems elementary in hindsight.
It’s important to consider the situation from the perspective of the developers. The idea of modular code and remote procedure calls is well understood in the traditional compute universe, however, the design of these models on top of the blockchain requires rewiring of the developers’ neural pathways to come to terms with both the powerful nature and the intricacies of decentralized design. It’ll be interesting to see if developers who have grown up to only code on blockchain architectures may have the opposite problem, but this scenario is unlucky any time soon because developers today have also to design for traditional web2 platforms to ultimately reach the end points and clients.
Reentrancies and Code Reuse
In terms of common attack vectors that most attackers check for, the most rewarding is the presence of a Reeentrancy attack scenario. In basic terms, this is when a smart contract initiates transfer of funds and delegates the execution path to the withdrawer without first updating math outcome within its own database.
In December 2020, Grim Finance, a popular DeFi service, lost $30 Million USD to a reentrancy vulnerability. Another DeFi service, Charge DeFi, also lost collateral where the attacker leveraged the same vulnerability. More details can be found here https://rekt.news/grim-finance-rekt/.
The codebase in scope here used by Charge was a fork of Grim, and so it is possible that the attacker knew of the existence of the same vulnerability across the code bases. Many attacks on forked smart contracts leverage code reuse to attack multiple contracts simultaneously.
Code reuse is rampant in the meme token ecosystem. Many of these code bases are riddled with backdoors that result in intentional and unintentional rug pulls where the smart contracts allow for tokens to be purchased but comment out the code required to sell the token, thereby skyrocketing the price of the token which in turn causes more people to want to buy in a quick frenzy until the community realizes that no one is able to sell. At this point, the smart contract owner, or the owner of the author of the code base (honeypot) can drain all the ETH or equivalent token deposited into the contract liquidity pool.
There are services online that track tokens for backdoors and potential rug pulls, yet many end users fall prey to them.
In the short term, the ability to eyeball DeFi smart contracts is a sort of a street-smart superpower that can be useful to any investor.
In the long term, the DeFi ecosystem will have to evolve and do a better job of detecting and warn investors using various forms of intelligence and analytics.
As the universe of DeFi and crypto catapults to higher and higher market caps, we are going to continue to witness smart contract hacks, rug-pulls, and the exploitation of the public nature of blockchain transactions. The explosion of the NFT market place will take on more attention of attackers in the short term and we can expect the roll out of much needed safeguards to protect end users.