4 ms·
In short the backdoor is the following: bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; // t
by qqii 6y ago
In 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.
- sillysaurusx 6y agoIs there some way to contact you? I just wanted to say privately that I recognized how much thought and effort went into this, and I’m grateful you took your time to share it. But mostly, I was feeling kind of down today and wondering what your life was like, and how you ended up getting into smart contracts. No reason really, just saying hello. You can DM me on Twitter if you’re on.
- qqii 6y agoGlad you found it useful! Smart contacts are intersting stuff. Your best bet is probably a reddit pm (not their new chat feature), my username is the same. I should get twitter but it's one of those things I never really got into.
- 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.