While Part 1 discussed some more high profile or obvious vulnerabilities, this post will be about vulnerabilities that have not been exploited widely yet.

Let’s skip the introduction and jump straight to them:

4. Forcing ether to a contract

Solidity’s selfdestruct does two things.

It renders the contract useless, effectively deleting the bytecode at that address. It sends all the contract’s funds to a target address.

The special case here, is that if the receiving address is a contract, its fallback function does not get executed.

This means that if a contract’s function has a conditional statement that depends on that contract’s balance being below a certain amount, that statement can be potentially bypassed:

Due to the throwing fallback function, normally the contract cannot receive ether. However, if a contract selfdestructs with this contract as a target, the fallback function does not get called. As a result this.balance becomes greater than 0, and thus the attacker can bypass the require statement in onlyNonZeroBalance

Mitigation: Never use a contract’s balance as a guard.

5. Call to the Unknown (DoS with unexpected revert)

This vulnerability appeared in the King of the Ether smart contract.

In this case, an attacker’s contract could first claim leadership by sending enough ether to the insecure contract. Then, the transactions of another player who would attempt to claim leadership would throw due to line 25 in the above snippet.

Although a simple attack, this causes a permanent denial of service to the contract rendering it useless. This can be found in other ponzi scheme contracts that follow the same pattern.

6. Short Address Attack

This attack was discovered by the Golem team and described in this article. This vulnerability allows an attacker to abuse the transfer function and withdraw a larger amount of ERC20 tokens than he is allowed to.

Note: For simplicity we’ll use words half the normal size.

To explain this bug let’s consider an exchange having a wallet with 10000 tokens and a user with a balance of 32 tokens on that exchange’s wallet. Let’s also consider that this user’s address is 0x12345600 — notice the trailing zeroes — and that they want to withdraw an amount larger than their balance. To do that they would go to the exchange and click the token’s withdraw button and input their address without the trailing zeroes (the exchange does not perform input validation and allows the transaction to go through, even though the attacker’s address length is invalid).

Then, the EVM calculates the input data for the transaction to be executed by concatenating the function’s signature and the arguments.

The ERC20’s transfer function is formulated as transfer(address to, uint256 amount) . The 3 fields would be as follows:

sig : a9059cbb = web3.sha3("transfer(address,uint256)").slice(0,10)

arg1: 123456 = receiving address

arg2: 00000020 = 32 in hexademical (0x20)

----------------------------------------

Concatenated: a9059cbb 123456 00000020

Transaction input data: 0xa9059cbb12345600000020

The vulnerability

Looking closely, the transaction’s length is 2 bytes shorter (4 bytes in the real world with full words). The EVM in this case would pad the transaction with trailing zeroes, resulting in:

0xa9059cbb1234560000002000 // a9059cbb = web3.sha3("transfer(address,uint256)").slice(0,10)

// 12345600 = receiving address

// 00002000 = 8192 in hexademical (0x2000 == 0x20<<8)

That way, even though the attacker’s balance according to the exchange is 32 tokens , they are able to execute a perfectly legitimate transfer for an amount that is much larger. This of course relies on the fact that the sending account (the exchange’s wallet) has enough balance for the transfer.

Mitigations:

Throw if msg.data has invalid size

has invalid size Exchanges must perform input validation

Reddit comment describing validating msg.data size

Bonus: