Proj 13.3: Hacking PoWHCoin (15 pts.)

What you need

Purpose

To reproduce the attack that stole $800k from PoWHCoin in Jan, 2018, as detailed here:

https://blog.goodaudience.com/how-800k-evaporated-from-the-powh-coin-ponzi-scheme-overnight-1b025c33b530

Ethereum Overview

Ethereum is the #2 cryptocurrency. It differs from Bitcoin because it provides an Ethereum Virtual Machine, which can be used to run programs on the blockchain.

For more information, see:

http://truffleframework.com/tutorials/ethereum-overview

Smart contracts are programs that run on the blockchain, replacing human directors. Contracts may be written in several languages, one of which is Solidity.

Opening Remix

In a Web browser, go to

http://remix.ethereum.org

Remix opens, as shown below. It's an online Solidity development platform.

Getting the PoWHCoin Source Code

In a Web browser, open a new tab, and go to

https://gist.github.com/borisd/42d48a9de261d4f8e6112b42835be3cf

Highlight all 306 lines of the PoWHCoin code and copy it into the Clipboard, as shown below.

In Remix, remove the "Ballot" code that is already there and paste in the PoWHCoin code, as shown below.

Launching a Simulated Blockchain

In Remix, at the top right, click the Run tab.

In the Environment box, select "JavaScript VM", as shown below.

This will launch a simulated Ethereum blockchain to run the contract on. It also creates several accounts to use, each with a starting balance of 100 Ether.

Deploying the Smart Contract

On the right side, in the center, "PonziTokenV3", the name of the contract appears. Below that name, click the pink Deploy button.

The bottom right pane now shows more pink buttons for methods like "transfer" and "withdraw", as shown below.

Investing Money

We'll send 50 Ether into the contract.

In Remix, at the top right, enter a "Value" of 50 as shown below.

To the right of the value, select a unit of ether.

At the bottom right, click the pink fund button.

The center bottom pane shows a log item labelled "transact to PonziTokenV3", as shown below

In Remix, at the top right, click the "Accounts" box. The field value pops up, as shown below.

Your account now contains slightly less than 50 Ether, because you invested 50 Ether into the PonziTokenV3 contract, and paid a transaction fee, also called "gas".

Notice that there are other accounts on the list, which still contain 100 Ether, because they haven't invested any Ether yet.

Adding Another Investor

In Remix, at the top right, click the "Accounts" box.

Select the second account, which contains 100 Ether.

Enter a "Value" of 1 and select a unit of ether, as shown below.

At the bottom right, click the pink fund button.

The second account's balance falls to just below 99 Ether, and another log item labelled "transact to PonziTokenV3" appears, as shown below.

Transferring Funds to a Friend

We want to transfer 1 Ether from account #2 to account #3, with these two steps:
  1. Approve a withdrawal by account #3
  2. Perform a withdrawal into account #3

Step 1: Approving a Withdrawal

In Remix, at the top right, the "Accounts" box currently shows Account #2, with a balance slightly less than 99 Ether.

Click the Accounts box and move to account #3, which has a balance of 100 Ether, as shown below.

To copy the account number into the clipboard, click the tiny icon to the right of the box, as shown below.

Now click the "Accounts" box again and select Account #2, with a balance slightly less than 99 Ether. This is necessary to ensure that the Approve action is performed using account #2.

At the lower right, click the down-arrow to the right of the line containing the pink "approve" button.

Two parameters appear: "_spender" and "_value", as shown below.

Paste the copied address into the "_spender" field, and enter 1 into the "_value" field, as shown below.

In the "approve" section, click the pink transact button.

Checking the Balance of Account #3

In the lower right, scroll down to the blue button labelled balanceOfOld. Paste in the account number for account #3, which is in your clipboard, as shown below.

Click the blue balanceOfOld button.

The result is zero, as shown below, because we haven't yet transferred any of the contract's Ether into this account.

Step 2: The Hack

To complete a normal transfer, we'd transfer funds from the contract into Account #3.

The hack is to transfer the Ether from Account #2 to the contract address instead, executing the transaction as Account #3.

The transaction is approved because it appears to be coming from Account #2, but it actually subtracts Ether from Account #3, which has a balance of zero, and rolls around to a huge positive value.

At the top right, verify that the "Accounts" box is showing Account #2, which has a balance slightly less than 99 Ether.

Click the tiny icon to the right of the box, to copy the account number into the clipboard, as shown below.

At the lower right, scroll down to the pink transferFrom button and click its down-arrow to expand it.

Paste the address from the clipboard into the _from field, as shown below.

On the right side, just above the pink (fallback) button, in the line labelled "PonziTokenV3 at 0x...", click the tiny icon to copy the address to the clipboard, as shown below.

At the lower right, in the transfer section, paste the address into the _to field. Add quotation marks before and after both the the _from and _to addresses, as shown in the image below.

Enter a _value of 1, as shown below.

At the top of the right pane, click the Accounts box and select Account #3, which contains approximately 100 Ether, as shown above.

At the lower right, in the transfer section, click the pink transact button.

Checking the Balance of Account #3

Scroll down and click the blue balanceOfOld button.

The account now has a huge balance, starting with "115", as shown below.

Recording your Success (15 pts.)

Find the first 8 dgits of the account balance, which is partially redacted in the image above.

Enter the first 8 digits into the form below to put your name on the WINNERS PAGE.

13.3: Recording Your Success (15 pts.)

Use the form below to record your score in Canvas.

If you don't have a Canvas account, see the instructions here.

Name or Email:
First 8 digits of balance:

Understanding the Vulnerability

In Remix, scroll down to line 133, as shown below, to see the transferFrom function.

This function makes sure that the transfer is no larger than the allowed value and calls the transferTokens function.

Scroll up to line 113 to see the transferTokens function, as shown below.

Line 114 makes sure that the balance in the _from account is sufficient for the withdrawal. We used Account #2 as the _from account, and it had a balance of 99 Eth, so this check passed.

Line 116 checks to see if we are sending coins to the contract itself, and we are, so this condition is true and it calls the sell function.

Scroll down to line 207 to see the sell function, as shown below.

The problem is in line 211. This deducts a coin from the msg.sender account, which is the account that originated the transaction, not necessarily the same as the _from account.

By sending the message from account #3, with a _from account of #2, we tricked this function into subtracting a coin from an empty account, resulting in an integer underflow.

Sources

Hacking an Ethereum contract
How $800k Evaporated from the PoWH Coin Ponzi Scheme Overnight


Posted 6-8-18 by Sam Bowne
More details about the vulnerability added 6-9-18
Added to CNIT 123 8-4-18