8 ms·
I found it strange that the title and beginning of the article reffered to this as a "hack" instead of what the test of the article suggests - a rug pull by the
by qqii 6y ago
I found it strange that the title and beginning of the article reffered to this as a "hack" instead of what the test of the article suggests - a rug pull by the developers themselves.
Since everything has been scrubbed the only suggested that they've been hacked comes from a cropped screenshot of their telegram channel which I found in this article: https://obelisk.medium.com/meerkat-finance-and-the-0-that-was-worth-31m-769d9321d245 https://obelisk.medium.com/meerkat-finance-and-the-0-that-wa...
The article also clearly shows in the smart contact that this was premeditated.
Edit: It's also important for context to note that 31 Million TVL (Total Value Locked) isn't low but isn't high for a DeFi project.
You can get a sense of the TVLs by looking at other projects on Ethereum ($39B total https://defipulse.com/ https://defipulse.com/) and the Binance Smart Chain ($9B total https://www.defistation.io/ https://www.defistation.io/)
- qqii 6y agoIn short the backdoor is the following: bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; // this is the getter function _admin() internal view returns (address adm) { bytes32 slot = ADMIN_SLOT; assembly { // return the memory at slot adm := sload(slot) } } // notice the 0 and the different, off by 1 hash bytes32 internal constant ADMIN_SL0T = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6102; // this is the setter, this doesn't set the same value as the getter, in effect the admin cannot be changed function _setAdmin(address newAdmin) internal { bytes32 slot = ADMIN_SL0T; assembly { // set the memory at slot to the value of newAdmin sstore(slot, newAdmin) } } https://bscscan.com/address/0x7e0c621ea9f7afd5b86a50b0942eaee68b04a61c#code https://bscscan.com/address/0x7e0c621ea9f7afd5b86a50b0942eae... Then when you (indirectly) call _setAdmin you can pretend that you no longer have powers to upgrade the contract.
- sillysaurusx 6y agoI was ready to make fun of this, but damn, that's fairly clever. (Readers, be sure to read the actual code: https://bscscan.com/address/0x7e0c621ea9f7afd5b86a50b0942eaee68b04a61c#code https://bscscan.com/address/0x7e0c621ea9f7afd5b86a50b0942eae...) A casual glance through the code won't show anything amiss. The ADMIN_SLOT and ADMIN_SL0T are defined in very different places. SL0T is also the closet fake character you could use, except maybe ADM1N_SLOT. Then when you (indirectly) call _setAdmin you can pretend that you no longer have powers to upgrade the contract. I know nothing about smart contracts, though, so, question: why is that a backdoor? What does it mean?
- qqii 6y agoTo understand why this is a backdoor we need to look at more code: modifier ifAdmin() { if (msg.sender == _admin()) { _; // run the rest of the function being modified } else { // for our case this essentially does nothing _fallback(); } } // imagine the code inside the function in place of the _ in ifAdmin function upgradeTo(address newImplementation) external ifAdmin { // actually upgrades the contract in place _upgradeTo(newImplementation); } So this smart contract has the ability to upgrade itself in place if it is called by the administrator. This is widely accepted and normally a useful feature. As a gesture of goodwill a developer will relinquish control of the contract for a set amount of time via a timelock. During this time users can use the smart contract without worry that the developer will maliciously upgrade and steal their funds. This can be seen here: https://bscscan.com/tx/0xecd169b3a299d28495cbc9bd22b5690e263ecfabbac00525699876707715d733#eventlog https://bscscan.com/tx/0xecd169b3a299d28495cbc9bd22b5690e263... So here it looks like the administrator was changed but as we know it actually didn't. Now users begin to use the platform and deposit funds. Since the admin hasn't changed the developer calls upgradeTo and deploys a malicious change, seen here: https://bscscan.com/tx/0xf19fa4bcff4adaebeddd28c851458ba0f01ffedd52b62df56ace94e7c8842553#eventlog https://bscscan.com/tx/0xf19fa4bcff4adaebeddd28c851458ba0f01... This contract (https://bscscan.com/address/0xb2603fc47331e3500eaf053bd7a971b57e613d36#code https://bscscan.com/address/0xb2603fc47331e3500eaf053bd7a971...) is compiled so we can't easily see the source. This doesn't matter as we can easily see the resulting transactions (https://bscscan.com/tx/0x1332fadcc5378b1cc90159e603b99e0b73ad992b1e6389e012af3872c8cae27d https://bscscan.com/tx/0x1332fadcc5378b1cc90159e603b99e0b73a... and https://bscscan.com/tx/0xd8145dfe255a671428b9c082a006a145fe58d82175671e8bfbe02f4040ae8cd0 https://bscscan.com/tx/0xd8145dfe255a671428b9c082a006a145fe5...). Whats especially clever about this rug pull scam is that it is self contained. Instead of selling your tokens at an exchange which risks low liquidity and front running, the developer is in control the whole time and could have done this whenever he thought the deposits were enough.
- sillysaurusx 6y agoThis was a masterclass. Thank you so much.
- 6y ago
- hiq 6y agoSo I take it that no independent 3rd party audited this smart contract? Because defining a constant twice is already big enough of a code smell to warrant spending more than 10s on them (enough to distinguish a 0 from a O). They didn't even try that hard, e.g. "SLΟT" is way closer to "SLOT" than "SL0T". This speaks volume about how much you can get away with in this ecosystem. That's also a vulnerability which should have been exposed by tests (again, run by an independent 3rd party).
- qqii 6y agoThat's correct. Even any of the off the shelf tools would have spotted it so it's safe to conclude this was intentional. Audits aren't the be all end all either, a determined scammers could have added the backdoor after the audit.
- wlesieutre 6y ago> The article also clearly shows in the smart contact that this was premeditated. It's almost as if having a readable contract that the signers can all understand and a judge who can rule on reasonable interpretations of the contract is a feature, not a bug. Whatever component of the "smart contract" that allowed them to do this would have been negotiated out, but since it's a decentralized "the contract enforces itself" cryptosystem, people just trust that the contract does what it says on the tin. What should be the procedure before using these? Pay a security researcher for an independent review, like you would have a lawyer go over a contract? If you have to do that, why not just use a regular contract and lawyers where you have recourse when something goes wrong?
- hobofan 6y ago> Pay a security researcher for an independent review Yes, that is the normal practice, and any bigger project worth their salt pays for an external security auditor.
- notJim 6y agoDo we know that this project wasn't audited?
- hobofan 6y agoWhat is generally audited is the source code. You can then verify is that the audited source code matches the deployed source code. That ability is lost to some degree (or not as transparent) if you use upgradable proxy contracts (which Meerkat did). Given the young age I don't see any indication that anyone audited the proxy contracts and their usage. As explained in the blog post of the top comment here (https://obelisk.medium.com/meerkat-finance-and-the-0-that-was-worth-31m-769d9321d245 https://obelisk.medium.com/meerkat-finance-and-the-0-that-wa...), this was clearly an exit scam by the Meerkat developers, which is exactly why users shouldn't put any significant amount of money into contracts that haven't been audited by a reputable external auditor.
- qqii 6y ago