Cause#
I saw a tweet from a friend mentioning a serious vulnerability in a certain smart contract.
Process Analysis#
The attacker batch calls the contract's VOTEToken()
function to create a large number of VOTETRUMP
tokens out of thin air, and then exchanges the VOTETRUMP
tokens for ETH
through Uinswap
, achieving arbitrage.
Vulnerability Analysis#
Recently, I participated in Solidity Cruel Co-learning (DeFiHackLabs x WTF Academy), and in the course's Lecture 11: Constructors and Modifiers, there is a description:
Note: The syntax of constructors is not consistent across different versions of Solidity. Before Solidity 0.4.22, constructors did not use the constructor keyword but instead used a function with the same name as the contract as the constructor. This old writing style can easily lead developers to make mistakes (for example, if the contract name is Parents, and the constructor name is written as parents), causing the constructor to become a regular function, leading to vulnerabilities. Therefore, from version 0.4.22 onwards, a new constructor syntax was adopted.
Looking at the contract code, it can be seen that the Solidity version used by the contract is ^0.4.11
, which is below 0.4.22
. This means that the constructor definition of this contract follows the old rules.
Constructor error: The contract name is VeritaseumToken, while the actual defined constructor name is VOTEToken. Due to the inconsistency, the VOTEToken function is not recognized as a constructor but rather becomes a regular public function. Additionally, the function does not use any visibility modifiers, so anyone can call it freely and increase their VOTETRUMP token balance to the maximum supply of the token.
This design flaw created conditions for the attacker, who minted a large number of VOTETRUMP tokens by calling the VOTEToken() function and ultimately arbitraged on decentralized exchanges.
Fixing the Vulnerability#
- Upgrade Solidity version: First, it is recommended to upgrade the Solidity version to 0.4.22 or higher to use the constructor keyword to define the constructor. This can avoid vulnerabilities caused by spelling errors in the constructor name.
- Correct the constructor definition: If upgrading the contract code version is not possible, it is essential to ensure that the constructor name matches the contract name. In this case, VOTEToken() should be changed to VeritaseumToken().
- Add appropriate access control: Even when using the old constructor definition, appropriate access control (such as the onlyOwner modifier) should be added to important functions to prevent any user from calling these functions for token minting.
Warning#
This vulnerability reminds us that when writing contracts using lower versions of Solidity, it is crucial to strictly follow the constructor naming rules to avoid serious security issues caused by spelling errors. Additionally, for any functions involving token minting, transferring, and other critical operations, access control mechanisms should be introduced to prevent malicious users from exploiting contract vulnerabilities.
Moreover, when designing contracts, it is advisable to use the latest stable version of Solidity to ensure the utilization of new features and fixes for known vulnerabilities, thereby enhancing the security of the contract.