How to steal Ethers: scanning for vulnerable contracts

Four years ago, I wrote an article “How to steal Bitcoins” that was about finding address corresponding to weak brainwallets, and some forensic evidence that it was exploited automatically, for profit.

This article is about Ethereum smart contracts, how you can automatically find bugs in them allowing you to steal money. I will also present forensic evidence that it happens in the wild.

Introduction

Smart contracts

Smart contracts are programs (executable code) that are stored in the Ethereum blockchain. That means that they are all publicly accessible!

These program are also “accounts” that can own money. Once created, the smart contract’s code is immutable, and it is the sole owner and manager of its own funds. Its code can call functions to receive and send money.

They are implemented in EVM bytecode (for Ethereum Virtual Machine). It’s a bit of an exotic architecture, and it’s purely a stack machine, but unlike x86 bytecode it is very simple. The EVM is described in Ethereum’s yellow paper.

The interactions with the environment are very limited (you can call other contracts, send/receive money but that’s pretty much it).

Because execution cost fees (called gas), these contracts are generally very simple, which make them perfect for automatically analyzing them.

Assuming you have Ether to pay for transaction fees, you can call any contract that lives on the blockchain.

Symbolic execution

Symbolic execution is the idea of executing a program but having user-controlled input be “symbols” (representing an unknown value). When we encounter a conditional statement, we execute both branches but we take note of the “constraints” that need to be respected for that branch to run.

For example, if we analyze that code:

function f(int user_input) {
   if (user_input % 2 == 0) {
      send_all_my_money();
   }
}

There is a valid execution that calls send_all_my_money(), and it is associated with the constraint user_input % 2 == 0.

An SMT solver like Z3 knows if such a constraint is satisfiable and will give us values for user_input where it would work.

I developed a tool called Pakala to do exactly that. It is slightly different than the other published tools because it first computes all the interesting execution paths that the program can take, and then try to stack these executions together to find bugs where multiple calls (executions) are needed.

Bugs we are looking for

My tool, Pakala, looks for two simple things:

  • Programs that can send back more ether that they are sent.

  • Programs that can self-destruct themselves and give us all their money.

These are basically the two ways we can get free money.

Some other checks leading to arbitrary code execution could be worth adding, and are checked by other existing tools.

Tell me more!

If you want to learn more about bugs in smart contracts, I recommend you look at at this publication: “Smashing Ethereum Smart Contracts for Fun and Actual Profit”.

You can also look at this talk (and paper) for something similar to what I did, presented in a more detailed and formal way.

Tooling

For my investigation, I needed two things:

  • A tool to symbolically execute smart contracts and find exploitable bugs. Mythril or Manticore are generic tools, but here I developed my own tool called Pakala, that specialize in finding exploitable bugs to steal money.

  • An Ethereum archive node (to look at historical data from smart contracts). I needed a dedicated 4 TB SSD, and a month of computation to replay Ethereum’s history. Want more details?.

  • A blockchain explorer (etherscan), and a disassembler for contracts without source code (eveem).

I scanned all the contracts in the blockchain, around mid-2018. I also had a real-time scanning tool running for a bit.

Vulnerable contracts found

I found quite a few interesting things. Here are examples of common findings:

Wrongly-named constructors

This was by far the most common bug I’ve seen in terms of volume.

It’s was a common mistake in old versions of the Solidity compiler: when your program is initialized, a special function is ran once: the constructor. It needs to have the same name as the name of your contract. Lots of people would have typos in the name of the constructor (or copy/paste code) and the constructor would end up having a different name, leading to a normal method that can be called by anybody.

Very often that means that a constructor supposed to initialize the “owner” of the contract (an address that can withdraw the money in it, most often) can be called by anybody, so anybody can become the owner.

A few examples:

  • HOTTO (old): a token contract with source code. If you look at the HOTTO contract you will see a method named HT() to set the owner. That was meant to be the constructor for sure.

  • HitexToken: another token contract named HitexToken with an intended constructor HTX().

  • Mobile switching: a token contract without the solidity source, but if you look at a disassembly there is a function (signature 0xc868d5ac) to change the owner that anybody can call.

Free withdrawal

Some contracts also don’t check anything, and allow anyone to get money out if you ask them nicely:

  • 0x768f3b7538C0285142D86e0A692A086b0f091d3F (disassembly): this one has a sendEth(address _receiver, uint256 amount) function in it that unconditionally sends the amount passed in, to the address passed in.

  • 0xeBE6c7a839A660a0F04BdF6816e2eA182F5d542C (disassembly): this one has a transfer() function that sends an arbitrary amount to the address of your choice, but it checks that call.value - _value >= 0, call.value being the money that you send to the contract and _value being the money you want it to send out. However it does so by using unsigned integers, so this condition always holds.

Honeypots

An interesting class of contracts I found are honeypots, that are not really vulnerable and result from inconsistency in the way Pakala models the way transactions are executed on Ethereum.

0x9F54d912a029380f2743aAf4dDD28C3f207cD719 is a good example: it’s a contract that tries to trick you into sending money to it, because you think that it will send you more money in return. But what actually happens is that it tries to send you more money than it has: that fails, but the contract keeps the money you sent it.

There is a list of such honeypots on GitHub, and you can learn more about honeypots in this article.

Ponzi schemes

That’s an interesting one! Pakala was able to find quite a few “games”, that are sorts of Ponzi schemes.

The most common is a contract that keeps the address of the last person who sent money to it. If there was nobody else who interacted with it after some time (say, 24h) then that last person wins the amount present in the contract.

For my tool, this fits the bill: you send some money to it, and you come back later enough to get all the money. That’s because I don’t model that other people can interact with the contract in the meantime.

You can look at DonutChain for an example that won its owner 48 ETH, and that Pakala detected.

As a side note, there is also Fomo3D in the same vein (that contained millions of dollars), but it’s much more complex. The last winner manipulated the blockchain to be able to win, I suggest looking at this article.

Scavengers siphoning buggy contracts

Let’s go through the contracts previously mentioned and that are actually vulnerable, but this time let’s look at what happened.

To investigate I simply used Etherscan, with both the “Transactions” and “Internal Txns” tabs. This last tab allow you to see how the money got out of the contract (transfers initiated by the contract itself).

It seems like 0xacc… was only exploiting token contracts with sources available and wrongly-named constructors (and did it a lot), while 0x38a… was more sophisticated: it exploited less trivial bugs and didn’t need Solidity source code.

This is just the tip of the iceberg, but as you can see there are a few addresses belonging to scavengers that actively exploit bugs to siphon contracts.

More?

The contracts mentioned here were just examples of things I found, but there is much more. I started a Twitter account to publish more of my findings, for people who are interested.

Also, if you are interested by the subject I suggest looking at Pakala, the tool I developed for that.

If you have any question on this article, please contact me: ethereum at palkeo dot com. I’m also available for contracting in that field.