Prior to ZeroNights security conference, an ICO hacking contest had been announced. The first three contestants to solve the tasks could win invites to the conference. My motivation to participate in the contest was driven by the interest in smart contract security which is gaining popularity in various CTFs nowadays.

The ICO website was a dApp that interacted with two contracts on Rinkeby testnet via web3.js. The first contract was an ERC20 token for HACK coins so you could see your balance, number of sold coins, total supply, etc. The ultimate goal of the contest was to get more than 31337 HACK coins.

The other contract was a lottery game, here is a relevant fragment from it:

function spinLottery(uint number) public {

if (msg.sender != robotAddress) {

playerNumber[msg.sender] = number;

players.push(msg.sender);

NewLotteryBet(msg.sender);

} else {

require(block.number - lotteryBlock > 5);

lotteryBlock = block.number; for (uint i = 0; i < players.length; i++) {

if (playerNumber[players[i]] == number) {

desires[players[i]].active = true;

desires[players[i]].email = "*Use changeEmail func to set your email.*";

Proposal(players[i], desires[players[i]].email);

}

}

delete players; // flushing round

NewLotteryRound(lotteryBlock);

}

}

If you are lucky enough to guess the number your address will be added to the “desires” mapping. There was a whitepaper like in a real ICO which said that one should be manually whitelisted by the token owner to be able to buy tokens or you could try to win the lottery. Let’s try to beat it!

Winning the lottery

Looking at the code above you see that there is a robot that posts random numbers once in 5 blocks. These numbers are submitted in clear text, no seed is used. It means that this code is prone to Transaction Ordering Dependence or Frontrunning. In other words, if we are quick enough to look up the number submitted by the robot and issue our own transaction with this number so that both transaction appear in the same block, we can win the lottery provided that our transaction is executed before robot’s one. How can we achieve this? Very easy, we just need to increase gas price so that it is higher than in the robot’s transaction. After several attempts I managed to fit into the same block with the robot.