Smart Contract Exploits Part 4 — Featuring Capture the Ether (Miscellaneous)

Enigmatic
Coinmonks
5 min readSep 23, 2018

--

Fourth and final part — Just two challenges under Miscellaneous, challenges which can’t seem to find a home in the other sections. Let’s get into it right away.

For those who missed the first part: https://medium.com/@Enigmatic1256/smart-contract-exploits-part-1-featuring-capture-the-ether-lotteries-8a061ad491b

Whereas the second part is found here: https://medium.com/@Enigmatic1256/smart-contract-exploits-part-2-featuring-capture-the-ether-math-31a289da0427

And the third part is found here: https://medium.com/@Enigmatic1256/smart-contract-exploits-part-3-featuring-capture-the-ether-accounts-c86d7e9a1400

The website where these challenges could be found: https://capturetheether.com/challenges/
And the author of these challenges is the very brilliant smarx, catch him on his twitter handle @smarx.

As before, this article will require some prior knowledge with Solidity and its surrounding dev tools.

Without further ado — Huge spoilers ahead!

16. Assume Ownership

Source code as below.

This question is pretty much a free 300 points; However the implications could be serious and this was used as an actual exploit in the wild.

Looking at the contract itself, we can the function AssumeOwmershipChallenge() is suppose to be the constructor function of the contract. Due to the misspelling however, this becomes a normal callable function instead, allowing us to set the owner to our calling address and winning the challenge.

How it looks like when deployed on Remix.

From Solidity v0.4.22, we could now define our constructor function with constructor(arg1, arg2…), which allows the constructor function to stand out, also avoiding exploits of this nature.

So, to win this challenge, we simply need to copy the code into Remix, point it to the deployed contract address, call function AssumeOwmershipChallenge()and subsequently call authenticate().

17. Token Bank

Source code as below.

That’s a lot of code. Basically, the idea is that this contract acts as a “bank” which tracks our bank balance, and will issue a balance reflecting the number of tokens held, where 500,000 will be held by us, and another 500,000 will be held by the proxy contract which deploys Capture the Ether challenges. The underlying 1,000,000 ERC223 tokens are held in entirety by the challenge contract upon deployment acting as a token bank, as noticed when the ERC223 contract was created it assigns the total supply to the msg.sender. We are able to withdraw the number of tokens allocated to us per the bank balance, and the exploit requires us to withdraw all 1,000,000 ERC223 tokens away from the bank.

Looking through the contract, we can see a withdraw function, presumably one where we will somehow exploit, and it seems that we could, given that the balance is deducted only after the token.transfer line and there is a tokenFallback interface which we can use. We could model our exploit using an exploit contract, where the tokenFallback interface would trigger the same function on our exploit contract which carries out a second withdrawal, all without having the balance decremented for the require(balanceOf[msg.sender] >= amount) balance check to take place. This is in fact similar in nature to the re-entrance attack resulting in the closure of the DAO back during 2016.

Now that we have our exploit entry, what we need to do is to figure out how the full setup and sequence to execute the re-entrance attack, which will need a bank balance as a prerequisite.

To get some bank balance on our exploit contract, we could carry out the below sequence:

  1. Withdraw our 500,000 ERC223 tokens from the token bank.
  2. Create and deploy an exploit contract which implements a tokenFallback() function, which does nothing on its first call so we could transfer the tokens we currently own to this exploit contract.
  3. From the exploit contract, transfer the tokens back to the token bank. This triggers the token bank’s tokenFallback() function, giving our exploit contract 500,000 bank balance.

Now we can execute the actual exploit:

  1. Our exploit contract calls withdraw() of 500,000 tokens, which calls for our exploit contract’s tokenFallback() function.
  2. Our exploit contract’s tokenFallback() calls for withdraw() of 500,000 tokens again. And on the third re-entrance does not do anything.
  3. As the bank balance is deducted only after the token transfer, the re-entrance will execute successfully. (the balance will overflow but by now the challenge is completed)

Piecing together the code:

Our exploit contract.

We will do setup step 1 and 2 manually, which could be easily done through Remix. Step 3 could be done through the transferToTokenBank() function. Upon completion of the setup we just need to call execute() to run the exploit to completion.

Running the steps:

Step 1, withdrawing tokens.
Step 2, transferring all 500,000 ERC223 tokens to our exploit contract.
Step 3, execute transferToTokenBank() so our exploit contract gets loaded with a balance.
Our exploit contract now has some bank balance to execute to re-entrance attack.

Once we initialise the CodeToCall object with the Token Bank Challenge contract address, we are ready to carry out our exploit.

Execute exploit — Note how Transfer() was ran twice.

You might have suspected this, as since we deducted more balance than we actually have, our balance would have overflowed. And at this point, isComplete will be set to true, completing this challenge.

We are done!

Conclusion

This wraps up the fourth and final part of this multi-part series. Public blockchains deal with real value, and extra care should be taken when designing and building software directly accessing real value. While some of these exploits could be avoided on a language layer such as having robust bound checks and setting limits to recursive calls, I personally find many of these exploits are not entirely due to Solidity itself, but also building on blockchains do tend to require a different intuition and therefore a different approach.

Therefore keep hacking, breaking stuff, and reviewing how smart contracts react to different implementations. And we can work towards developing more secure and safe smart contracts for everyone.

Get Best Software Deals Directly In Your Inbox

--

--

Enigmatic
Coinmonks

Fond of blockchain related technology. Researches and code (albeit slowly with the latter). ❤ Coffee ❤