On August 3, 2023, an MEV Bot on Arbitrum was attacked, resulting in $800K in loss. The root cause of this attack was Insufficient User Input Verification.
Considering the intricate interactions between MEV Bots and their contracts unverified, it reveals that not being open-source does not guarantee security, especially for DeFi protocols.
Background
MEV Bot
MEV Bot (Maximum Extractable Value Bot) is designed to identify and execute profitable opportunities on the blockchain. It operates by analyzing pending transactions (i.e., those in the mempool) or on-chain states to generate profits through arbitrage.
Unlike typical front-running and sandwich attack MEV Bots, the MEV Bot targeted in this attack focused on executing strategies such as triangular arbitrage and debt liquidation. These bots themselves help to stabilize prices for AMMs and assist lending protocols with liquidation to ensure smooth operation, constituting an essential part of the healthy functioning of the DeFi ecosystem.
Flashloan
Flashloan represents a unique innovation within the DeFi ecosystem – a form of uncollateralized lending. You can borrow up to a billion dollars through Flashloan without any collateral, provided that the loan is repaid within the same transaction. If the loan is not repaid within that transaction, it will be reversed, as if the transaction never happened.
This mechanism is commonly used for arbitrage or leveraging other DeFi strategies to exploit temporary market inefficiencies.
The Vulnerability
In Short Version
The insufficient validation of user-input parameters enabled the attacker to introduce a FakeFlashloanProvider. The vault contract utilized this provider to initiate a flashloan. Subsequently, perhaps to settle the flashloan, the vault contract approved tokens to the FakeFlashloanProvider, leading to the unauthorized transfer of assets out of the vault.
In Detail Version
The exploited contract is:
Vault
: The victim contract 0xd614927acfb9744441180c2525faf4cedb70207f serves as a "Vault", providing reserves and facilitating flashloan from other protocols like AAVE and Balancer.Arbitrage Bot
: The vulnerable contract 0x8db0efee6a7622cd9f46a2cf1aedc8505341a1a7, functioning as an "Arbitrage Bot", holds the borrower role in the "Vault" contract.
The function 0x0582f20f()
in the "Arbitrage Bot" is the main entry point for launching arbitrages.
It first invokes the borrow()
in the "Vault" to acquire the original principal, then executes arbitrage logic through a delegatecall
to an external contract specified in the calldata and with no validation.
function 0x0582f20f(...) {
...
v67, /* uint256 */ v68 = address(0xd614927acfb9744441180c2525faf4cedb70207f).borrow(address(v39), address(v9[0]), v29).gas(msg.gas);
...
// 0x4da91757 = swap(address,address,address,uint256,uint256,uint256,address)
MEM[MEM[64] + 32] = uint224(address(MEM[0 + v4[v69]])) | 0x4da9175700000000000000000000000000000000000000000000000000000000;
v82 = address(v76 >> 96).delegatecall(MEM[(MEM[64]) len 228], MEM[(MEM[64]) len 0]).gas(msg.gas);
...
v189 = v170.refund(0x410085df, address(v9[0]), address(v39), v68, address(v9[0]), v29, v186, 4 + MEM[64] + (varg2.length << 5) - (4 + MEM[64]) + 192).gas(msg.gas);
...
}
Subsequently, it invokes the 0x512b7351()
in the "Vault", launching a flashloan to the attacker's FakeFlashloanProvider
contract.
The function 0x512b7351()
requires msg.sender
to be in the allowlist, but it was successfully bypassed by the previous delegatecall
, circumventing the check. This is a very critical step
function 0x512b7351(...) public nonPayable {
...
if (_borrow[msg.sender] >= 1) {
v0 = !_refund;
}
require(v0, Error('BBVault: FORBIDDEN'));
...
v38 = v23.length;
v39 = v23.data;
_refund = keccak256(v23);
...
<FakeFalshloanProvider>.flashloan(...);
...
}
During the flashloan callback, the executeOperation()
in the "Vault" first transfers the borrowed assets to the "Arbitrage Bot" MEVBot 0x8db0ef, then calls its 0x7fe3ba8b()
.
function executeOperation(...) {
...
require(_refund == keccak256(v3.data), Error('BBVault: STATUS'));
Token.transfer(ArbitrageBot, amountBorrowed);
<ArbitrageBot>.call(0x7fe3ba8b...);
}
The "Arbitrage Bot" trusting this external call, transfers the received assets back to the FakeFlashloanProvider
.
However, the "Vault" fails to recognize this and still grants approval to the FakeFlashloanProvider
for repaying the flashloan at the end of the executeOperation()
.
The Attack Process
Attack Tx: 0x864c8cfb8c54d3439613e6bd0d81a5ea2c5d0ad25c9af11afd190e5ea4dcfc1f
The attacker invokes the 0x0582f20f()
of the "Arbitrage Bot", which in turn performs a delegate call to the attacker's contract.
The hack_contract_2 then call the victim
's function 0x512b7351()
. The 0x512b7351()
requires msg.sender
to be in the allowlist, but it was successfully bypassed by the previous delegatecall
, circumventing the check.
The victim
then calls the attacker's FakeFlashloanProvider
contract, transferring all the flashloaned assets to the victim
and calling the executeOperation()
of the victim.
The 0x7fe3ba8b()
of the Arbitrage Bot
again performs a delegatecall
to the attacker's contract, this time transferring all the assets back to the attacker.
**At this point, the assets lent by the attacker’s Flashloan Provider have been repayed.
**
The victim("Vault") approves tokens to the FakeFlashloanProvider
, possibly with the intention of repay the flashloan.
The attacker exploits this approval to profit, using transferFrom to drain funds from the victim.
Security Recommendations
Non-open-source code does not guarantee security
Believing that non-open-source and obfuscated code ensures security is a misconception. This MEV Bot incident reveals that secrecy doesn't safeguard against exploits and may give developers a false sense of security.
Rigorous Input Validation
It's crucial to meticulously validate all contract interactions and calldata, especially when dealing with standard interfaces like flashloan and swap callbacks. Ensuring data integrity and security should be a priority in contract design and implementation.
Read other articles in this series:
- Lead-In: Top Ten "Awesome" Security Incidents in 2023
- #1: Harvesting MEV Bots by Exploiting Vulnerabilities in Flashbots Relay
- #2: Euler Finance Incident: The Largest Hack of 2023
- #3: KyberSwap Incident: Masterful Exploitation of Rounding Errors with Exceedingly Subtle Calculations
- #4: Curve Incident: Compiler Error Produces Faulty Bytecode from Innocent Source Code
- #5: Platypus Finance: Surviving Three Attacks with a Stroke of Luck
- #6: Hundred Finance Incident: Catalyzing the Wave of Precision-Related Exploits in Vulnerable Forked Protocols
- #7: ParaSpace Incident: A Race Against Time to Thwart the Industry's Most Critical Attack Yet
- #8: SushiSwap Incident: A Clumsy Rescue Attempt Leads to a Series of Copycat Attacks
- #10: ThirdWeb Incident: Incompatibility Between Trusted Modules Exposes Vulnerability