Analysis of An Attack on A Sandwich Bot
Fairyproof conducts an analysis of an attack on a sandwich bot.
The use of sandwich bots in crypto trading has become increasingly popular in daily transactions within the crypto landscape. These bots not only improve transaction efficiency but also effectively capture arbitrage opportunities within trades.
While utilizing bots in crypto trading has significant advantages, using them in unsafe or vulnerable trading scenarios can lead to unfavorable outcomes.
On August 29, at 06:04:39 UTC, an attack on a sandwich bot on the BNB Chain was observed. This attack resulted in the exploitation of crypto assets worth approximately US $390,000, including 207 WBNBs, 184,900 BSC-USDs, and 158,900 BUSDs.
Fairyproof promptly conducted an analysis of the incident and identified a lack of permission check in the function calling as the suspected cause of the attack.
When bots perform on-chain transactions on a decentralized exchange (DEX), they often interact directly with the trading pairs instead of the Router contract to reduce gas fees. In the case of a DEX implemented based on Uniswap's trading logic, the typical process involves borrowing assets first and repaying them later. This process requires invoking a specific callback function of the trader (in this case, pancakeV3SwapCallback) to inform the trader that the tokens have been borrowed and should be repaid later.
Therefore, it is crucial to verify that the caller of the callback function pancakeV3SwapCallback(msg.sender) has the necessary permission as both the legitimate trading pair and the initiator of the transaction (tx.origin). Due to the complexity of validating msg.sender (sometimes requiring intricate logic to ensure compatibility with Uniswap V2), most contracts only verify tx.origin.
While this approach is generally effective, it presents a risk if the transaction involves a malicious contract (such as the attacking token contract) because the permission check can be bypassed when the malicious contract calls pancakeV3SwapCallback using tx.origin.
In this incident, the attack occurred due to the lack of permission check to verify whether msg.sender is the pancakeV3 trading pool. The attacking token directly called the pancakeV3SwapCallback function and manipulated the transaction parameters, successfully passing the tx.origin permission check and stealing assets.
The relevant transaction hashes for this incident are as follows:
The contracts involved in the Sandwich bot attack are:
- Execution Contract(vulnerable): 0x5C936E535Bb591C979a7c8D36C48a6B31808Cef9
- Vault Contract: 0x6E47b1123ddcF74E853516F934f5296cEb17D404
The address of the attacking token is 0xb4864E14467B0D1a2AfB1F70b3f04D4aCd635e06.
The address of the trading pair is 0xf61F401041a1AF03875B0E0d4AAa9749a57AEB93.
The attacker's address is 0x30BA49Ca659B70d3723E3cA6ed96EA4EF0249893.
The internal transactions of the attack are as follows:
A screenshot of the transactions can be viewed at the following link:
https://explorer.phalcon.xyz/tx/bsc/0xf3705586e9b692dfeb53f983fe5595ee8c522552e38663bf38acf6e8c459de32
Based on the aforementioned transactions, the attacker executed the attack in the following steps:
Step 1: The attacker deployed the attacking token, initiated, and exposed a transaction to a Sandwich bot.
Step 2: The Sandwich bot called the swap function of the PancakeV3 pool deployed at 0xf61F401041a1AF03875B0E0d4AAa9749a57AEB93 to acquire the attacking token in the FrontRun transaction.
Step 3: The pool at 0xf61F401041a1AF03875B0E0d4AAa9749a57AEB93 sent the attacking token to the Sandwich bot based on Uniswap's "borrow first" rule. During this process, the attacking token's transfer function was called.
Step 4: The attacking token's transfer function called the Sandwich bot's pancakeV3SwapCallback() function and manipulated the parameters.
Step 5: The Sandwich bot's pancakeV3SwapCallback() function passed the permission check for tx.origin and transferred assets from the vault to the attacking token's contract, as the pancakeV3SwapCallback function typically transfers assets to msg.sender.
Step 6: The bot proceeded with a regular Sandwich trade and obtained 25 USDCs.
Step 7: The attacker withdrew the stolen assets, including WBNB, BSC-USD, and BUSD, as shown below:
A screenshot of the stolen assets can be viewed at the following link:
https://bscscan.com/address/0xb4864E14467B0D1a2AfB1F70b3f04D4aCd635e06#tokentxns
This incident clearly highlights the importance for contract developers to check the permission of a function caller, specifically msg.sender's permission. Simply checking tx.origin's permission is insufficient.
In similar scenarios, Fairyproof suggests the following approach:
When conducting a transaction through a contract's external interfaces, pass the trading pair's address to the contract and verify it in the callback function. After the transaction is executed, reset the trading pair's parameters. While this incurs additional gas costs, it significantly enhances security.
Force-code a Factory's address in smart contracts, calculate the corresponding trading pairs' addresses, and check their permission.
Additionally, performing contract audits is crucial to ensure the overall security of a project. If the project had undergone an audit, the vulnerability in this incident would likely have been uncovered.
Fairyproof offers professional, comprehensive, and rigorous security services for the blockchain ecosystem. Our services include smart contract audits, security consulting, security solutions, real-time monitoring, and asset tracking. We are dedicated to collaborating with partners in the ecosystem to build a secure environment and protect users' crypto assets.