Solidity Security By Example #08: Unexpected Ether With Forcibly Sending Ether
Originally published in Valix Consulting’s medium.
Smart contract security is one of the biggest impediments to the mass adoption of the blockchain. For this reason, we are proud to present this series of articles regarding Solidity smart contract security to educate and improve the knowledge in this domain to the public.
Forcibly sending ether is an attacker’s technique to manipulate a target contract balance. This article will describe how a smart contract relying on improper balance checking can be attacked and how to avoid the issue. Enjoy reading. 😊
You can find all related source code at 👉 https://github.com/serial-coder/solidity-security-by-example/tree/main/08_unexpected_ether_with_forcibly_sending_ether.
The smart contracts in this article are used to demonstrate vulnerability issues only. Some contracts are vulnerable, some are simplified for minimal, some contain malicious code. Hence, do not use the source code in this article in your production.
Nonetheless, feel free to contact Valix Consulting for your smart contract consulting and auditing services. 🕵
Table of Contents
The following code exhibits the
InsecureMoonToken contract. The MOON is a non-divisible token with zero token decimals (line 12). Users can buy, sell, or transfer 1, 2, 3, or 46 MOONs but not 33.5 MOONs.
Besides the non-divisible characteristic, the MOON token is also a stablecoin pegged with the price of the ETH token (line 6). In other words, 1 MOON will always be worth 1 ETH.
InsecureMoonToken contract is vulnerable. Can you catch up on the issue? 👀
InsecureMoonToken contract, users can buy MOON tokens with the corresponding number of Ethers via the
buy function (lines 16–24). Users can also sell their MOONs through the
sell function (lines 26–36), transfer their MOONs via the
transfer function (lines 38–44), get their balances by consulting the
getUserBalance function (lines 50–52), and get the total number of Ethers locked in the contract by way of the
getEtherBalance function (lines 46–48).
As you can see, the
InsecureMoonToken contract is straightforward. However, the contract got an improper balance assertion issue in line 35 in the
sell function hires the
assert(getEtherBalance() == totalSupply * TOKEN_PRICE); statement to strictly assert that the Ether balance of the
InsecureMoonToken contract (i.e., the
getEtherBalance() part) must always be equal to the total supply of the MOON token (i.e., the
totalSupply * TOKEN_PRICE part). This assertion ensures that the number of locked Ethers balances the MOON total supply.
Nevertheless, relying on the contract’s Ether balance as the
sell function did is prone to attack. Consider if an attacker can send some small Ethers to lock into the
InsecureMoonToken contract. What would happen? 🤔
Gotcha! 😱 The assertion statement would always be evaluated as false because the contract’s Ether balance would no longer match the MOON token’s total supply. This results in reverting all
InsecureMoonToken contract does not implement the
fallback function, the contract regularly cannot receive any Ethers. But how can the attacker send Ethers into the contract? Figure 1 below illustrates the solution the attacker adopts to achieve the exploitation.
In Solidity, a special function named
selfdestruct is used for removing the bytecode from the contract address executing it. Besides the contract bytecode removal, one side effect is that the Ethers stored in the removing contract would be forcibly sent to any specified address.
selfdestruct function can forcibly send Ethers to even the contract that does not implement the
fallback function like the
InsecureMoonToken contract. 🤢
This way, if the attacker deploys and executes the
Attack contract containing the
selfdestruct function, they can forcibly send Ethers to the
InsecureMoonToken contract by specifying the
InsecureMoonToken contract address as the argument of the
selfdestruct function (i.e.,
The following code presents the
Attack contract that can be used to exploit the
To attack the
InsecureMoonToken, an attacker performs the attack steps as follows.
Attackcontract as well as specifying the
InsecureMoonTokencontract address as the contract deployment argument (line 6)
Attack.attack()function along with supplying some Ethers for attacking
After step 2, the supplied Ethers would be forcibly sent into the
InsecureMoonToken contract by way of the
selfdestruct function (line 14). Then, any
sell transactions would be reverted, leading to a denial-of-service attack to the
InsecureMoonToken contract. ☠️
Figure 2 displays the result of the attack. As you can see, two users bought 55 MOONs with 55 Ethers. But, after the attacker forcibly sent 1 Wei to the
InsecureMoonToken contract, the users were no longer selling their MOONs.
Surprise!! you can buy it but may not sell it. 😭
FixedMoonToken contract below is the remediated version of the
InsecureMoonToken contract. 👨🔧
The smart contract should avoid being dependent on the contract’s Ether balance (i.e.,
address(this).balance) as it can be artificially manipulated. If necessary, however, the contract should be prepared for such cases of contract balance manipulation.
To remediate the improper balance assertion issue, the
FixedMoonToken contract’s assertion statement was improved by using the
>= instead of the
== symbol as follows:
assert(getEtherBalance() >= totalSupply * TOKEN_PRICE); (line 37).
As a result, even if the contract balance is manipulated, the
sell function could still work fine.
In this article, you have learned that incorrectly depending on improper contract balance assertion can lead to a denial-of-service attack in the smart contract. You have understood how an attacker exploits the vulnerable contract and how to avoid the issue. We hope you find this article useful. Until next time.
Again, you can find all related source code at 👉 https://github.com/serial-coder/solidity-security-by-example/tree/main/08_unexpected_ether _with_forcibly_sending_ether.
Phuwanai Thummavet (serial-coder), Lead Blockchain Security Auditor and Consultant | Blockchain Architect and Developer.
See the author’s profile.
About Valix Consulting
Valix Consulting is a blockchain and smart contract security firm offering a wide range of cybersecurity consulting services. Our specialists, combined with technical expertise, industry knowledge, and support staff, strive to deliver consistently superior quality services.
For any business inquiries, please contact us via Twitter, Facebook, or email@example.com.
Originally published in Valix Consulting’s medium.