Meerkat Finance and the 0 that was worth $31m
The rise of the Decentralized Finance space on the Binance Smart Chain (BSC) has been wild. Compatibility with Ethereum’s smart contracts and cheap transactions are proving to be very popular with both developers and users. A vast ecosystem of projects are currently doing their best to compete with each other and capture the hype of the ever increasing number of users flooding the new blockchain. New platforms appear every day with some seeing near-instant success and raising millions on launch, whilst others struggle to see the light of day.
Given how easy it is to fork any open-source project, several projects on the BSC have been so far met with success with very little innovation of their own. Merely bringing a new service to the new chain can attract a huge amount of interest rapidly.
This could have been the primary reason as to why "Alpaca Finance" was met with wild success after it appeared on BSC on the 27th of April. It pledged to provide services allowing for users to leverage their position while staking, something that was new to BSC. While the core feature is not released yet, users are able to provide liquidity with their BNB and BUSD and stake to earn the platform’s governance token, $ALPACA. Despite being only a few days' young, Alpaca Finance managed to attract hundreds of millions worth in staked funds.
Banking on that near-instant success, a project named "Meerkat Finance" was released on the 3rd of March. It was quickly pointed out that everything in Meerkat Finance's website looked to be exactly the same as as in the Alpaca Finance website. Meerkat didn't attempt to hide that they were imitators. Like many projects in the blockchain space, they travelled on the coattails of their successful competitor and created a 1:1 copy by forking Alpaca. The only parts that were seemingly changed were superficial such as images and the colour schemes.
Their first tweet even went on too admit this:
Under the pretence of building upon the sudden success of Alpaca Finance and with a promise of security through time locked contracts, users started flocking into Meerkat Finance. Most were probably attracted by the seemingly unmissable returns.
In the end, 31 million in USD value was locked in Meerkat's smart contracts.
The Events of the 4th of March
On the 4th of March 2021 at 08:53:10 AM UTC, Meerkat Finance's deployer (in layman terms, this is the address that created the contract) migrated their BUSD vault, and just a few seconds later their BNB vault was migrated as well. 13,968,039 BUSD were [transfered](https://bscscan.com/tx/0x13
fadcc5378b1cc90159e603b99e0b73ad992b1e6389e012af3872c8cae27d) out of the Meerkat BUSD vault at At 08:54:31AM UTC. This was closely followed by another transfer of 73,635 BNB (~17M USD as of writing) from their BNB vault. At the time of the transfer, the total value transfered out of the vaults was roughly 31,457,151 USD.
Meerkat told it's users in their telegram that they suffered a major attack, and someone used a number of vulnerabilities in their code to steal all user funds.
To the average BSC user, this probably looks like a genuine hack, but here at Obelisk, we work with evidence, and unlike humans, the code never lies. So let’s take a deeper look at what happened to figure things out, shall we?
But what does the code tell us?
The migration transaction came from their own deployer, which is not a smart contract, but an Externally Owned Address (EOA) under their control. The claim that they got their deployer private key hacked is suspicious. Given that their website and their telegram are down right now, we can easily make a conjecture about what really happened. Here at Obelisk, we work with evidence, and unlike humans, the code never lies. So let's take a deeper look at what happened to figure things out, shall we?
What Really Happened
If we take a closer look at this migration transaction called by the deployer, we can see in the input data that the deployer is the one calling the
upgradeTo() function, which transfers the entire contract implementation to a new address.
This extremely dangerous function is protected by the ifAdmin flag
In order to call
upgradeTo, the caller has to be the admin. That means that this function is safe ONLY if the admin is a smart contract, and not an Externally Owned Address (EOA). Let's first take a look at the
admin() function implementation, that is supposed to return the admin address.
This function returns the admin address
The function _admin() returns the admin address by loading-in the ADMIN_SLOT variable, and returning its address.
Meerkat Finance's proxy contract admin was allegedly changed to a timelock contract in this transaction.
So how was the deployer able to bypass the timelock? Let's dive deeper into the logs, and look at the supposed admin change.
At a first glance this looks like that
newAdmin is set to the timelock contract by the deployer address. Before we take this for granted we can take a closer look at the
changeAdmin function implementation.
This external function is supposed to change the admin to a new one.
Diving deeper down the rabbit hole, we can have a look at the
_setAdmin function implementation.
This is where the exploit is.
Here we can see that the
newAdmin variable is being assigned to
ADMIN_SL0T and stored. That's one of the oldest tricks in the book, and very likely intentional. 0 (number zero) and O (capital letter) can be very hard to differentiate between each other, also depending on the font. This is why bitcoin addresses make sure that uppercase letter "O", uppercase letter "I", lowercase letter "l" and the number "0" are never used in order to prevent any visual ambiguity.
This function set the
ADMIN_SL0T, which means
ADMIN_SLOT was never changed.
The 0 That Was Worth 31m
upgradeTo function from the first paragraph?
Since the deployer didn't change the admin of the vault to the timelock, they were able to call the proxy contract directly (bypassing the timelock), and to immediately change the implementation to a new one. The new implementation that the contract migrated to is in bytecode, so we can't directly see how the hackers were able to transfer the funds without decompiling the bytecode, which is outside of the scope of this article. However, they were able to easily transfer everything to multiple addresses under their control.
You can see the flow of transactions on this explorer, under the money flow tab.
The trick Meerkat Finance's developers played on their users was to simply alter the name of a variable to a similar looking one. With the way their smart contracts were written, this meant that their timelock was only there to create the illusion of security. In simple words, there was a clear backdoor to bypass all supposed safelocks and transfer a total of 31.4$ million out.
This is an incident where it becomes apparent how a simple variable naming trick can allow malicious changes to be made on smart contracts. Which is a clear demonstration of why a developer simply claiming to have smart contracts under timelock shouldn't be taken at face value. A smart contract audit could have prevented the theft of tens of millions in this case.
What Obelisk can do
At Obelisk our expertise lies in smart contract development and security. We believe that security is the foundation of building successful projects in the DeFi-sphere and we strive to help our partners succeed with their ambitions through our audit services. If you are an investor that wants to safely invest in a DeFi project, a developer that wants to launch a new blockchain project or perhaps a well-established project that wants to improve security and transparency for its users then we would love to hear from you. Get in touch about your audit now through the channels below: