H 532: 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

In the Environments section, click the SOLIDITY button.

In the left bar, click the second icon to show the FILE EXPLORERS, as shown below.

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, in the "FILE EXPLORERS" pane, to the right of "browser", click the + button.

Enter a File Name of PoWHCoin.sol and click OK. Paste in the PoWHCoin code, as shown below.

Compiling the Contract

In Remix, in the left bar, click the third icon to compile the code, outlined in green in the image below.

In the "SOLIDITY COMPILER" pane, click the blue "Compile PoWHCoin.sol" button, as shown below.

Deploying the Smart Contract

In Remix, in the left bar, click the fourth icon to "Deploy & run transactions", outlined in green in the image below.

Use an Environment of "JavaScript VM (London)". If the account balances are not all 100 Ether, switch to "JavaScript VM (Berlin)" and back to "JavaScript VM (London)" to refresh the blockchain to its initial state.

In the "DEPLOY & RUN TRANSACTIONS" pane, click the orange Deploy button, as shown below.

Viewing Contract Methods

In the "DEPLOY & RUN TRANSACTIONS" pane, at the bottom, click the > next to "PONZITOKENv3".

Buttons appear, showing the actions available on this contract, such as "approve" and "fund", as shown below.

Understanding the Blockchain

Remix simulates an Ethereum blockchain in the browser, pre-populated with accounts and ether.

In the "DEPLOY & RUN TRANSACTIONS" pane, at the top, in the ACCOUNT box, click the up-and-down arrow.

Fifteen account numbers appear with their balances. Every account has approximately 100 ether, as shown below.

Funding the PonziToken Contract

We'll send 50 Ether into the contract.

In the "DEPLOY & RUN TRANSACTIONS" pane, at the top, in the ACCOUNT box, select the first account number.

In the VALUE line, enter 50 ether, as shown below.

In the "DEPLOY & RUN TRANSACTIONS" pane, at the bottom, click the red fund button.

The center bottom pane shows a log item labelled "transact to PonziTokenV3", outlined in green in the image below.

Viewing Account Balances

In the "DEPLOY & RUN TRANSACTIONS" pane, at the top, in the ACCOUNT box, click the up-and-down arrow.

The first account now has only approximately 50 ether, as shown below.

Adding Another Investor

In the "DEPLOY & RUN TRANSACTIONS" pane, at the top, in the ACCOUNT box, click the up-and-down arrow.

Select the second account, which contains 100 Ether.

In the VALUE line, enter 1 ether, as shown below.

In the "DEPLOY & RUN TRANSACTIONS" pane, at the bottom, click the red 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 the "DEPLOY & RUN TRANSACTIONS" pane, at the top, in the ACCOUNT box, click the up-and-down arrow.

Select the third account, which contains 100 Ether.

To copy the account number into the clipboard, click the tiny two-page icon to the right of the box, outlined in green in the image 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.

In the "DEPLOY & RUN TRANSACTIONS" pane, at the bottom, click the down-arrow to the right of orange "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, outlined in green in the image below.

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

Checking the Balance of Account #3

In the "DEPLOY & RUN TRANSACTIONS" pane, scroll down to reveal more buttons.

Next to the blue balanceOfOld button, 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.

In the "DEPLOY & RUN TRANSACTIONS" pane, scroll up to see the "Accounts" box.

Verify that the "Accounts" box is showing Account #2, which has a balance slightly less than 99 Ether, as shown below.

Click the tiny icon to the right of the box, to copy the account number into the clipboard, outlined in green in the image below.

In the "DEPLOY & RUN TRANSACTIONS" pane, scroll down to reveal more buttons.

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

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

In the "DEPLOY & RUN TRANSACTIONS" pane, scroll up to see box labelled "PONZITOKENV3 AT 0X...".

Click the tiny two-page icon to copy the address to the clipboard, outlined in green in the image below.

At the lower right, in the transferFrom section, paste the address into the _to field.

Enter a _value of 1, as shown below.

In the "DEPLOY & RUN TRANSACTIONS" pane, scroll to the top.

In the ACCOUNT box, click the up-and-down arrow.

Select the third account, which contains 100 Ether, as shown below.

In the "DEPLOY & RUN TRANSACTIONS" pane, scroll down to the transferFrom section, and click the orange 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.

H 532.1: Digits (15 pts)

Copy the five digits after "115", covered by a green rectangle in the image above.

That's the flag.

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.

Fix

Changing line 117 to "revert", as shown below, stops the attack.

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
Renumbered and updated 6-9-2020
Explanation of the London Javascript environment added 10-26-21
Fix added 10-27-21