Constructors with Care
Constructors are special functions that often perform critical, privileged tasks when initializing contracts. Before Solidity v0.4.22, constructors were defined as functions that had the same name as the contract that contained them. In such cases, when the contract name is changed in development, if the constructor name isn’t changed too it becomes a normal, callable function. As you can imagine, this can lead (and has) to some interesting contract hacks.
For further insight, the reader may be interested in attempting the Ethernaut challenges (in particular the Fallout level).
The Vulnerability
If the contract name is modified, or there is a typo in the constructor’s name such that it does not match the name of the contract, the constructor will behave like a normal function. This can lead to dire consequences, especially if the constructor performs privileged operations. Consider the following contract:
contract OwnerWallet {
address public owner;
// constructor
function ownerWallet(address _owner) public {
owner = _owner;
}
// Fallback. Collect ether.
function () payable {}
function withdraw() public {
require(msg.sender == owner);
msg.sender.transfer(this.balance);
}
}
This contract collects ether and allows only the owner to withdraw it, by calling the withdraw
function. The issue arises because the constructor is not named exactly the same as the contract: the first letter is different! Thus, any user can call the ownerWallet
function, set themselves as the owner, and then take all the ether in the contract by calling withdraw
.
Preventative Techniques
This issue has been addressed in version 0.4.22 of the Solidity compiler. This version introduced a constructor
keyword that specifies the constructor, rather than requiring the name of the function to match the contract name. Using this keyword to specify constructors is recommended to prevent naming issues.
Real-World Example: Rubixi
Rubixi was another pyramid scheme that exhibited this kind of vulnerability. It was originally called DynamicPyramid
, but the contract name was changed before deployment to Rubixi
. The constructor’s name wasn’t changed, allowing any user to become the creator. Some interesting discussion related to this bug can be found on Bitcointalk. Ultimately, it allowed users to fight for creator status to claim the fees from the pyramid scheme. More detail on this particular bug can be found in “History of Ethereum Security Vulnerabilities, Hacks and Their Fixes”.