Two Ways of Forcing Ether into a Contract
The last article on Dissecting an Ethereum Honey Pot was successful so I’ve taken time to compile all known Solidity exploits and hacks into a small manual.
I’ll be releasing each article every week for 21+ weeks. Some examples of what I’ll be covering:
- Re-Entrancy
- Denial of Service — Gas
- Denial of Service — Revert
- Force Ether — selfdestruct
- Force Ether — Predestination
- Storage Allocation Exploit
- Underflow / Overflow
- Re-Entrancy Honey Pot
- Function Call Honey Pot
The full source code with unit testing examples live in Github. The kindle version is normally $4.99 but its available for free on Amazon right now.
Forcing Ether to a Contract — selfDestruct
I know of two ways to force Ether into a contract.
For a smart contract written in Solidity to receive ether it requires the payable
decorator on the function signature:
function () payable {
...}
Without it, the EVM will throw an error.
If plain ether is sent to a contract the fallback function handles the transaction.
A fallback function can throw. Its default behavior is to throw to prevent accidentally sending ether to a contract. Any transaction that sends ether to its address will fail without a payable decorator.
This is misleading. It is still possible to force ether into the contract. Smart Contracts have a selfdestruct function that accepts an address parameter. It will forward the contract’s balance to the given address.
It comes directly from the Solidity documentation. Since everyone reads the manual, everyone knows that one ;)
The selfdestruct function is for removing data from the blockchain. A contract without a selfdestruct may still execute selfdestruct using delegatecall or callcode.
The selfdestruct function does not trigger a Smart Contract’s fallback function.
Forcing Ether to a Contract — Predestination
The second way of forcing ether to a contract is more interesting.
A contract address is deterministic. It’s is the rightmost 160 bits of the keccak256 hash of an RLP encoding of the Sender’s address and their tx nonce.
A mouthful, but a single line of Python.
def mk_contract_address(sender, nonce):
return sha3(rlp.encode([normalize_address(sender), nonce]))[12:]
This information is available to the contract deployer ahead of time — someone like an ICO dev. They may deposit ether to the contract ahead of time. Any logic or Mathematics relying on the contract balance will be wrong.
The blockchain is public. The address of every contract for every address is 1 line of Python away from reality.
This exploit sends Ether to the contract before it exists on the blockchain. The logic in the smart contract does not run retroactively.
Addendum: A Third Way
It is possible to mine to a contract address if it is recipient of the block coinbase transaction.
Mitigations
It is incorrect to assume that you can prevent someone sending ether to your contracts. Even if developers take measures to lock down a Smart Contract it is still possible to force ether into the contract.
For extra sensitivity, deploy contracts from a newly generated account.
Contracts should track an internal balance variable.